mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-28 12:27:11 -06:00
Merge origin/main into spanish-proofing
Upstream merged #3177 (dictionary hints for every Hunspell language) and #3480. Resolve the conflicts in crates/proof/src/lib.rs by taking #3177's dictionary_loaded/dictionary_needed structure and adding the four Spanish varieties to it, and in docs/spelling-dictionaries.md keeping both sides.
This commit is contained in:
@@ -11,7 +11,8 @@ permissions:
|
||||
|
||||
concurrency:
|
||||
group: sonarcloud-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
# A push to main is the run that publishes coverage; superseded runs there would never finish.
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||
|
||||
jobs:
|
||||
sonarcloud:
|
||||
|
||||
@@ -7,6 +7,7 @@ use wordcraft_doc::resolve::ResolvedChar;
|
||||
use wordcraft_doc::{InlineObject, PartKind, Pos, RevisionKind, StoryRef};
|
||||
|
||||
use super::sel_result;
|
||||
use super::tools::{is_turkic, lower_char, upper_char};
|
||||
use crate::{CmdError, CmdResult, CommandSpec, Session, p};
|
||||
|
||||
/// Word's font size list.
|
||||
@@ -453,7 +454,16 @@ fn change_case(s: &mut Session, v: &Value) -> CmdResult {
|
||||
let to = if path == b.path { b.off } else { p.len() };
|
||||
let chars = live_chars(p, from, to);
|
||||
let src: String = chars.iter().map(|(_, c)| c).collect();
|
||||
case_groups(p, &chars, &convert_chars(&src, &mode, from == 0))
|
||||
// Turkish, Azerbaijani and Crimean Tatar text follows the same case mapping as
|
||||
// AutoCorrect (#1923); each run's own language decides (#3479).
|
||||
let turkic: Vec<bool> = chars
|
||||
.iter()
|
||||
.map(|(off, _)| {
|
||||
let lang = s.doc.styles.resolve_char(p.props.style.as_deref(), p.props_of_char(*off)).lang;
|
||||
is_turkic(lang.as_deref().or(s.editing_lang.as_deref()))
|
||||
})
|
||||
.collect();
|
||||
case_groups(p, &chars, &convert_chars(&src, &mode, from == 0, &turkic))
|
||||
};
|
||||
if groups.is_empty() {
|
||||
continue;
|
||||
@@ -587,37 +597,47 @@ fn is_title(t: &str) -> bool {
|
||||
|
||||
#[cfg(test)]
|
||||
fn convert(src: &str, mode: &str, para_start: bool) -> String {
|
||||
convert_chars(src, mode, para_start).concat()
|
||||
let turkic = vec![false; src.chars().count()];
|
||||
convert_chars(src, mode, para_start, &turkic).concat()
|
||||
}
|
||||
|
||||
/// The case-converted form of each character of `src`, in order (one entry per char, so a
|
||||
/// change of length such as ß → SS or İ → i̇ can be applied run by run).
|
||||
fn convert_chars(src: &str, mode: &str, para_start: bool) -> Vec<String> {
|
||||
/// change of length such as ß → SS or İ → i̇ can be applied run by run). `turkic` is one flag
|
||||
/// per char: true when that character's run is Turkish, Azerbaijani or Crimean Tatar.
|
||||
fn convert_chars(src: &str, mode: &str, para_start: bool, turkic: &[bool]) -> Vec<String> {
|
||||
let chars: Vec<char> = src.chars().collect();
|
||||
// Greek capital sigma lowers to the final form at the end of a word (as `str::to_lowercase`).
|
||||
let lower = |i: usize, c: char| -> String {
|
||||
let prev = i.checked_sub(1).and_then(|j| chars.get(j)).is_some_and(|p| p.is_alphabetic());
|
||||
let next = chars.get(i + 1).is_some_and(|n| n.is_alphabetic());
|
||||
if c == 'Σ' && prev && !next { "ς".to_string() } else { c.to_lowercase().collect() }
|
||||
if c == 'Σ' && prev && !next {
|
||||
"ς".to_string()
|
||||
} else if turkic.get(i).copied().unwrap_or(false) {
|
||||
lower_char(c, true)
|
||||
} else {
|
||||
c.to_lowercase().collect()
|
||||
}
|
||||
};
|
||||
// Title case capitalises the first word of any selection; sentence case only at a paragraph start.
|
||||
let mut up = mode == "title" || para_start;
|
||||
let mut out = Vec::with_capacity(chars.len());
|
||||
for (i, &c) in chars.iter().enumerate() {
|
||||
let turkic = turkic.get(i).copied().unwrap_or(false);
|
||||
let upper = |c: char| upper_char(c, turkic);
|
||||
let new = match mode {
|
||||
"upper" => c.to_uppercase().collect(),
|
||||
"upper" => upper(c),
|
||||
"lower" => lower(i, c),
|
||||
"toggle" => {
|
||||
if c.is_uppercase() {
|
||||
lower(i, c)
|
||||
} else {
|
||||
c.to_uppercase().collect()
|
||||
upper(c)
|
||||
}
|
||||
}
|
||||
"title" => {
|
||||
let n = if up && c.is_alphabetic() {
|
||||
up = false;
|
||||
c.to_uppercase().collect()
|
||||
upper(c)
|
||||
} else {
|
||||
lower(i, c)
|
||||
};
|
||||
@@ -630,7 +650,7 @@ fn convert_chars(src: &str, mode: &str, para_start: bool) -> Vec<String> {
|
||||
// Sentence case.
|
||||
let n = if up && c.is_alphabetic() {
|
||||
up = false;
|
||||
c.to_uppercase().collect()
|
||||
upper(c)
|
||||
} else {
|
||||
lower(i, c)
|
||||
};
|
||||
|
||||
@@ -1028,7 +1028,7 @@ fn prev_token(before: &str) -> String {
|
||||
}
|
||||
|
||||
/// Turkish, Azerbaijani (and Crimean Tatar) map `i`/`İ` and `ı`/`I` as pairs (#1923).
|
||||
fn is_turkic(lang: Option<&str>) -> bool {
|
||||
pub(crate) fn is_turkic(lang: Option<&str>) -> bool {
|
||||
if wordcraft_proof::ProofLang::from_tag(lang) == wordcraft_proof::ProofLang::Tr {
|
||||
return true; // tr, tur, any region, same normalisation as proofing
|
||||
}
|
||||
@@ -1038,7 +1038,7 @@ fn is_turkic(lang: Option<&str>) -> bool {
|
||||
}
|
||||
|
||||
/// A letter in capitals: `i` → `İ` in Turkic languages, otherwise the Unicode default.
|
||||
fn upper_char(c: char, turkic: bool) -> String {
|
||||
pub(crate) fn upper_char(c: char, turkic: bool) -> String {
|
||||
if turkic && c == 'i' {
|
||||
return "\u{130}".to_string();
|
||||
}
|
||||
@@ -1047,7 +1047,7 @@ fn upper_char(c: char, turkic: bool) -> String {
|
||||
|
||||
/// A letter in lowercase: `I` → `ı` in Turkic languages. `İ` is always the single letter `i`,
|
||||
/// never `i` plus a combining dot.
|
||||
fn lower_char(c: char, turkic: bool) -> String {
|
||||
pub(crate) fn lower_char(c: char, turkic: bool) -> String {
|
||||
match c {
|
||||
'I' if turkic => "\u{131}".to_string(),
|
||||
'\u{130}' => "i".to_string(),
|
||||
|
||||
@@ -2075,6 +2075,46 @@ fn autocorrect_capitalisation_follows_turkic_case_mapping() {
|
||||
assert_eq!(s.doc.plain_text(StoryRef::Body), "İngilizce ", "no combining dot in any language");
|
||||
}
|
||||
|
||||
/// #3479: Format > Change Case follows the same Turkic case mapping as AutoCorrect, using
|
||||
/// each run's own language; other languages keep the Unicode default.
|
||||
#[test]
|
||||
fn change_case_follows_turkic_case_mapping() {
|
||||
for tag in ["tr-TR", "az-AZ"] {
|
||||
for (mode, input, want) in [
|
||||
("upper", "istanbul", "İSTANBUL"),
|
||||
("lower", "IŞIK", "ışık"),
|
||||
("title", "istanbul güzel", "İstanbul Güzel"),
|
||||
("sentence", "istanbul. izmir", "İstanbul. İzmir"),
|
||||
("toggle", "iI", "İı"),
|
||||
] {
|
||||
let mut s = s();
|
||||
run(&mut s, "review.language", json!({"lang": tag, "default": true}));
|
||||
run(&mut s, "text.insert", json!({"text": input, "raw": true}));
|
||||
run(&mut s, "select.all", json!({}));
|
||||
run(&mut s, "format.changeCase", json!({"mode": mode}));
|
||||
assert_eq!(s.doc.plain_text(StoryRef::Body), want, "{tag} {mode}");
|
||||
}
|
||||
}
|
||||
// Other languages keep the Unicode default.
|
||||
let mut s = self::s();
|
||||
run(&mut s, "text.insert", json!({"text": "istanbul", "raw": true}));
|
||||
run(&mut s, "select.all", json!({}));
|
||||
run(&mut s, "format.changeCase", json!({"mode": "title"}));
|
||||
assert_eq!(s.doc.plain_text(StoryRef::Body), "Istanbul", "en-US");
|
||||
// Mixed runs: each run's own language decides.
|
||||
let mut s = self::s();
|
||||
run(&mut s, "text.insert", json!({"text": "IŞIK IŞIK", "raw": true}));
|
||||
run(&mut s, "caret.set", json!({"pos": Pos::body(0, 0)}));
|
||||
run(&mut s, "caret.set", json!({"pos": Pos::body(0, 5), "extend": true}));
|
||||
run(&mut s, "review.language", json!({"lang": "tr-TR"}));
|
||||
run(&mut s, "caret.set", json!({"pos": Pos::body(0, 6)}));
|
||||
run(&mut s, "caret.set", json!({"pos": Pos::body(0, 11), "extend": true}));
|
||||
run(&mut s, "review.language", json!({"lang": "en-US"}));
|
||||
run(&mut s, "select.all", json!({}));
|
||||
run(&mut s, "format.changeCase", json!({"mode": "lower"}));
|
||||
assert_eq!(s.doc.plain_text(StoryRef::Body), "ışık işik", "mixed runs");
|
||||
}
|
||||
|
||||
// Spelling as you type (#1552): the word being typed gets no red squiggle until the caret leaves
|
||||
// it; F7 and the Spelling pane still report it. See docs/typing-parity.md. Paragraphs start with
|
||||
// a correct word so AutoCorrect's sentence capital doesn't change the misspelled one.
|
||||
|
||||
@@ -42,10 +42,11 @@ pub fn dictionary() -> Arc<AffixDict> {
|
||||
|
||||
fn load_installed() -> AffixDict {
|
||||
let Some((aff, dic)) = crate::hunspell::find(NAMES) else {
|
||||
crate::hunspell::clear_load_error(NAMES[0]);
|
||||
log::info!("Czech spelling: no Hunspell cs_CZ dictionary installed");
|
||||
return AffixDict::default();
|
||||
};
|
||||
crate::hunspell::load(&aff, &dic).unwrap_or_else(|e| {
|
||||
crate::hunspell::note_load(NAMES[0], &dic, crate::hunspell::load(&aff, &dic)).unwrap_or_else(|e| {
|
||||
log::warn!("Czech spelling: {e}");
|
||||
AffixDict::default()
|
||||
})
|
||||
|
||||
+50
-23
@@ -417,17 +417,13 @@ pub fn has_dictionary(lang: Option<&str>) -> bool {
|
||||
ProofLang::from_tag(lang).is_proofed()
|
||||
}
|
||||
|
||||
/// The Hunspell dictionary name (`pl_PL`, `pt_BR`) a proofing language needs but doesn't have
|
||||
/// The Hunspell dictionary name (`pl_PL`, `it_IT`) a proofing language needs but doesn't have
|
||||
/// installed, for a status-bar hint (#1167). `None` when the language's dictionary is available,
|
||||
/// or when it needs none (English has a built-in word list; unproofed languages aren't offered
|
||||
/// one). Reads the dictionary once (it is cached afterwards).
|
||||
pub fn missing_dictionary(lang: Option<&str>) -> Option<&'static str> {
|
||||
match ProofLang::from_tag(lang) {
|
||||
ProofLang::Pl => dictionary_needed(ProofLang::Pl, pl::has_dictionary()),
|
||||
ProofLang::Pt => dictionary_needed(ProofLang::Pt, pt::has_dictionary()),
|
||||
l if l.is_spanish() => dictionary_needed(l, es::has_dictionary(l)),
|
||||
_ => None,
|
||||
}
|
||||
let lang = ProofLang::from_tag(lang);
|
||||
dictionary_needed(lang, dictionary_loaded(lang)?)
|
||||
}
|
||||
|
||||
/// The Hunspell name, `.dic` file and reason of a dictionary that is installed for this language
|
||||
@@ -435,26 +431,40 @@ pub fn missing_dictionary(lang: Option<&str>) -> Option<&'static str> {
|
||||
/// loaded, or when no file exists (then [`missing_dictionary`] names it). Reads the dictionary
|
||||
/// once (it is cached afterwards).
|
||||
pub fn unreadable_dictionary(lang: Option<&str>) -> Option<(&'static str, std::path::PathBuf, String)> {
|
||||
let (proof_lang, loaded) = match ProofLang::from_tag(lang) {
|
||||
ProofLang::Pl => (ProofLang::Pl, pl::has_dictionary()),
|
||||
ProofLang::Pt => (ProofLang::Pt, pt::has_dictionary()),
|
||||
l if l.is_spanish() => (l, es::has_dictionary(l)),
|
||||
_ => return None,
|
||||
};
|
||||
let name = dictionary_needed(proof_lang, false)?;
|
||||
if loaded {
|
||||
return None;
|
||||
}
|
||||
let lang = ProofLang::from_tag(lang);
|
||||
let name = dictionary_needed(lang, dictionary_loaded(lang)?)?;
|
||||
hunspell::load_error(name).map(|(file, reason)| (name, file, reason))
|
||||
}
|
||||
|
||||
/// The Hunspell name `lang` needs when `installed` is false; Polish, Portuguese and Spanish (per
|
||||
/// variety: `es_ES`, `es_MX`, `es_419`, `es_UY`) name one.
|
||||
/// Did the Hunspell dictionary of `lang` load? `None` for languages that use none (English).
|
||||
fn dictionary_loaded(lang: ProofLang) -> Option<bool> {
|
||||
Some(match lang {
|
||||
ProofLang::Pl => pl::has_dictionary(),
|
||||
ProofLang::Pt => pt::has_dictionary(),
|
||||
ProofLang::It => it::has_dictionary(),
|
||||
ProofLang::Hr => hr::has_dictionary(),
|
||||
ProofLang::Tr => tr::has_dictionary(),
|
||||
ProofLang::Ru => ru::has_dictionary(),
|
||||
ProofLang::Cs => cs::has_dictionary(),
|
||||
ProofLang::Id => id::has_dictionary(),
|
||||
l if l.is_spanish() => es::has_dictionary(l),
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// The Hunspell name `lang` needs when `installed` is false (the first name its module looks for;
|
||||
/// a Spanish variety's is its own: `es_ES`, `es_MX`, `es_419`, `es_UY`).
|
||||
fn dictionary_needed(lang: ProofLang, installed: bool) -> Option<&'static str> {
|
||||
match lang {
|
||||
_ if installed => None,
|
||||
ProofLang::Pl => Some("pl_PL"),
|
||||
ProofLang::Pt => Some("pt_BR"),
|
||||
ProofLang::It => Some("it_IT"),
|
||||
ProofLang::Hr => Some("hr_HR"),
|
||||
ProofLang::Tr => Some("tr_TR"),
|
||||
ProofLang::Ru => Some("ru_RU"),
|
||||
ProofLang::Cs => Some("cs_CZ"),
|
||||
ProofLang::Id => Some("id_ID"),
|
||||
l if l.is_spanish() => Some(es::dictionary_name(l)),
|
||||
_ => None,
|
||||
}
|
||||
@@ -1012,10 +1022,27 @@ mod tests {
|
||||
assert_eq!(dictionary_needed(ProofLang::Pt, false), Some("pt_BR"));
|
||||
assert_eq!(dictionary_needed(ProofLang::Pl, true), None);
|
||||
assert_eq!(dictionary_needed(ProofLang::Pt, true), None);
|
||||
// #3360: each Spanish variety names its own.
|
||||
for (l, name) in [(ProofLang::Es, "es_ES"), (ProofLang::EsMx, "es_MX"), (ProofLang::Es419, "es_419"), (ProofLang::EsUy, "es_UY")] {
|
||||
assert_eq!(dictionary_needed(l, false), Some(name));
|
||||
assert_eq!(dictionary_needed(l, true), None);
|
||||
// Every Hunspell language is named by the first name its module looks for (#3150).
|
||||
for (l, name) in [
|
||||
(ProofLang::It, "it_IT"),
|
||||
(ProofLang::Hr, "hr_HR"),
|
||||
(ProofLang::Tr, "tr_TR"),
|
||||
(ProofLang::Ru, "ru_RU"),
|
||||
(ProofLang::Cs, "cs_CZ"),
|
||||
(ProofLang::Id, "id_ID"),
|
||||
// #3360: each Spanish variety names its own.
|
||||
(ProofLang::Es, "es_ES"),
|
||||
(ProofLang::EsMx, "es_MX"),
|
||||
(ProofLang::Es419, "es_419"),
|
||||
(ProofLang::EsUy, "es_UY"),
|
||||
] {
|
||||
assert_eq!(dictionary_needed(l, false), Some(name), "{l:?}");
|
||||
assert_eq!(dictionary_needed(l, true), None, "{l:?}");
|
||||
}
|
||||
// Every proofed language other than English has a Hunspell dictionary to report.
|
||||
for l in ProofLang::PROOFED {
|
||||
let english = matches!(l, ProofLang::En | ProofLang::EnGb | ProofLang::EnCa);
|
||||
assert_eq!(dictionary_needed(l, false).is_some(), !english, "{l:?}");
|
||||
}
|
||||
for l in [ProofLang::En, ProofLang::Bg, ProofLang::De, ProofLang::Other] {
|
||||
assert_eq!(dictionary_needed(l, false), None);
|
||||
|
||||
@@ -63,10 +63,11 @@ pub fn dictionary() -> Arc<AffixDict> {
|
||||
|
||||
fn load_installed() -> AffixDict {
|
||||
let Some((aff, dic)) = crate::hunspell::find(NAMES) else {
|
||||
crate::hunspell::clear_load_error(NAMES[0]);
|
||||
log::info!("Russian spelling: no Hunspell ru_RU dictionary installed");
|
||||
return AffixDict::default();
|
||||
};
|
||||
crate::hunspell::load(&aff, &dic).unwrap_or_else(|e| {
|
||||
crate::hunspell::note_load(NAMES[0], &dic, crate::hunspell::load(&aff, &dic)).unwrap_or_else(|e| {
|
||||
log::warn!("Russian spelling: {e}");
|
||||
AffixDict::default()
|
||||
})
|
||||
|
||||
@@ -7,6 +7,23 @@ use wordcraft_doc::{PartKind, StoryRef};
|
||||
use crate::theme::{Tokens, TypeRung, fit_text, medium, paint_text, regular, semibold, text_width};
|
||||
use crate::{WordApp, icons};
|
||||
|
||||
/// Why the caret's language isn't spell-checked (dictionary unreadable or missing), if it isn't.
|
||||
pub(crate) fn dictionary_problem(lang: &str, unreadable: &Option<(std::path::PathBuf, String)>, missing: Option<&str>) -> Option<String> {
|
||||
match (unreadable, missing) {
|
||||
(Some((file, reason)), _) => Some(crate::i18n::fmt(
|
||||
tl!("The spelling dictionary for {language} couldn't be read, so it isn't checked. File: {file}. Reason: {reason}"),
|
||||
&[("language", lang), ("file", &file.to_string_lossy()), ("reason", reason)],
|
||||
)),
|
||||
(None, Some(name)) => Some(crate::i18n::fmt(
|
||||
tl!(
|
||||
"No spelling dictionary for {language} is installed, so it isn't checked. WordCraft looks for the Hunspell dictionary {name} in the WORDCRAFT_DICTIONARIES folder and in the usual system locations."
|
||||
),
|
||||
&[("language", lang), ("name", name)],
|
||||
)),
|
||||
(None, None) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// The Quick Access Toolbar's button for command `id`.
|
||||
pub(crate) fn qat_button_id(id: &str) -> egui::Id {
|
||||
egui::Id::new(("qat_button", id))
|
||||
@@ -590,17 +607,7 @@ pub fn status_bar(app: &mut WordApp, ui: &mut Ui) {
|
||||
} else {
|
||||
lang.clone()
|
||||
};
|
||||
let tip = match (&unreadable, missing) {
|
||||
(Some((file, reason)), _) => crate::i18n::fmt(
|
||||
tl!("The spelling dictionary for {language} couldn't be read, so it isn't checked. File: {file}. Reason: {reason}"),
|
||||
&[("language", &lang), ("file", &file.to_string_lossy()), ("reason", reason)],
|
||||
),
|
||||
(None, Some(name)) => crate::i18n::fmt(
|
||||
tl!("No spelling dictionary for {language} is installed, so it isn't checked. WordCraft looks for the Hunspell dictionary {name} in the WORDCRAFT_DICTIONARIES folder and in the usual system locations."),
|
||||
&[("language", &lang), ("name", name)],
|
||||
),
|
||||
(None, None) => tl!("Language").to_string(),
|
||||
};
|
||||
let tip = dictionary_problem(&lang, &unreadable, missing).unwrap_or_else(|| tl!("Language").to_string());
|
||||
let resp = st(ui, &shown).on_hover_text(tip);
|
||||
egui::Popup::menu(&resp).show(|ui| {
|
||||
ui.set_min_width(200.0);
|
||||
|
||||
@@ -2184,7 +2184,9 @@
|
||||
Show the mini toolbar when text is selected Показване на мини лентата с инструменти при избран текст
|
||||
Spaces Интервали
|
||||
Spelling Правопис
|
||||
Spelling and grammar are checked in English (United States). Правописът и граматиката се проверяват на английски (САЩ).
|
||||
Spelling and grammar are checked in {language}. Език за проверка на правописа и граматиката: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Текстът при курсора е отбелязан с: Без проверка на правописа и граматиката.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft все още не проверява правописа и граматиката на този език.
|
||||
Tab characters Знаци за табулация
|
||||
These marks show even when Show/Hide ¶ is off. Тези знаци се показват дори когато „Показване/скриване на ¶“ е изключено.
|
||||
Typing replaces selected text Въвежданият текст замества избрания текст
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 7 and column 25.
|
@@ -2277,7 +2277,9 @@ preview Title Ukázka
|
||||
Show the mini toolbar when text is selected Při výběru textu zobrazit miniaturní panel nástrojů
|
||||
Spaces Mezery
|
||||
Spelling Pravopis
|
||||
Spelling and grammar are checked in English (United States). Pravopis a mluvnice se kontrolují v angličtině (Spojené státy).
|
||||
Spelling and grammar are checked in {language}. Jazyk kontroly pravopisu a mluvnice: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Text v místě vkládání je označen: Nekontrolovat pravopis ani mluvnici.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft v tomto jazyce zatím nekontroluje pravopis ani mluvnici.
|
||||
Tab characters Znaky tabulátoru
|
||||
These marks show even when Show/Hide ¶ is off. Tyto značky se zobrazují, i když je vypnuto Zobrazit/skrýt ¶.
|
||||
Typing replaces selected text Psaný text nahrazuje vybraný text
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 7 and column 25.
|
@@ -1990,7 +1990,9 @@
|
||||
Spaces Mellemrum
|
||||
Special Særlige
|
||||
Spelling Stavning
|
||||
Spelling and grammar are checked in English (United States). Stavning og grammatik kontrolleres på engelsk (USA).
|
||||
Spelling and grammar are checked in {language}. Sprog til stave- og grammatikkontrol: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Teksten ved indsætningspunktet er markeret: Kontrollér ikke stavning eller grammatik.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft kontrollerer endnu ikke stavning eller grammatik på dette sprog.
|
||||
Stacked Bar Stablet søjlediagram
|
||||
Stacked Column Stablet kolonnediagram
|
||||
Standard Standard
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 756 and column 23.
|
@@ -1480,7 +1480,9 @@
|
||||
Show the mini toolbar when text is selected Minisymbolleiste bei Textauswahl anzeigen
|
||||
Spaces Leerzeichen
|
||||
Spelling Rechtschreibung
|
||||
Spelling and grammar are checked in English (United States). Rechtschreibung und Grammatik werden auf Englisch (USA) geprüft.
|
||||
Spelling and grammar are checked in {language}. Sprache für Rechtschreibung und Grammatik: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Der Text an der Einfügemarke ist markiert: Rechtschreibung und Grammatik nicht prüfen.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft prüft Rechtschreibung und Grammatik in dieser Sprache noch nicht.
|
||||
Tab characters Tabstoppzeichen
|
||||
These marks show even when Show/Hide ¶ is off. Diese Zeichen werden auch angezeigt, wenn ¶ ein-/ausblenden deaktiviert ist.
|
||||
Typing replaces selected text Eingabe ersetzt markierten Text
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 25.
|
@@ -182,7 +182,9 @@
|
||||
Show the mini toolbar when text is selected Mostrar la minibarra de herramientas al seleccionar texto
|
||||
Spaces Espacios
|
||||
Spelling Ortografía
|
||||
Spelling and grammar are checked in English (United States). La ortografía y la gramática se revisan en inglés (Estados Unidos).
|
||||
Spelling and grammar are checked in {language}. Idioma de revisión de ortografía y gramática: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. El texto en el punto de inserción está marcado como: No revisar la ortografía ni la gramática.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft todavía no revisa la ortografía ni la gramática en este idioma.
|
||||
Tab characters Caracteres de tabulación
|
||||
Tab stop position: Posición de la tabulación:
|
||||
Default tab stops: Tabulaciones predeterminadas:
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 25.
|
@@ -764,7 +764,9 @@
|
||||
Spelling & Grammar Õigekiri ja grammatika
|
||||
Spelling &\nGrammar Õigekiri ja\ngrammatika
|
||||
Spelling Suggestions Õigekirjasoovitused
|
||||
Spelling and grammar are checked in English (United States). Õigekirja ja grammatikat kontrollitakse inglise keeles (Ameerika Ühendriigid).
|
||||
Spelling and grammar are checked in {language}. Õigekirja ja grammatika kontrolli keel: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Sisestuskohal olev tekst on märgitud: Ära kontrolli õigekirja ega grammatikat.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft ei kontrolli selles keeles veel õigekirja ega grammatikat.
|
||||
Split Tükelda
|
||||
Split Cells Tükelda lahtrid
|
||||
Split Table Tükelda tabel
|
||||
|
||||
|
@@ -1941,7 +1941,9 @@
|
||||
Show the mini toolbar when text is selected Afficher la mini barre d’outils lors de la sélection de texte
|
||||
Spaces Espaces
|
||||
Spelling Orthographe
|
||||
Spelling and grammar are checked in English (United States). L’orthographe et la grammaire sont vérifiées en anglais (États-Unis).
|
||||
Spelling and grammar are checked in {language}. Langue de vérification de l’orthographe et de la grammaire : {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Le texte au point d’insertion est marqué : Ne pas vérifier l’orthographe ni la grammaire.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language} : WordCraft ne vérifie pas encore l’orthographe ni la grammaire dans cette langue.
|
||||
Tab characters Caractères de tabulation
|
||||
These marks show even when Show/Hide ¶ is off. Ces marques s’affichent même lorsque Afficher/Masquer ¶ est désactivé.
|
||||
Typing replaces selected text La frappe remplace le texte sélectionné
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 7 and column 25.
|
@@ -2102,7 +2102,9 @@ template Letter Pismo
|
||||
Spelling & Grammar Pravopis i gramatika
|
||||
Spelling &\nGrammar Pravopis i\ngramatika
|
||||
Spelling Suggestions Pravopisni prijedlozi
|
||||
Spelling and grammar are checked in English (United States). Pravopis i gramatika provjeravaju se na engleskom (Sjedinjene Američke Države).
|
||||
Spelling and grammar are checked in {language}. Jezik provjere pravopisa i gramatike: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Tekst na točki umetanja označen je: Ne provjeravaj pravopis ni gramatiku.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft na ovom jeziku još ne provjerava pravopis ni gramatiku.
|
||||
Split Podijeli
|
||||
Split Cells Podijeli ćelije
|
||||
Split Table Podijeli tablicu
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 25.
|
@@ -1613,7 +1613,9 @@
|
||||
Show the mini toolbar when text is selected Mini eszköztár megjelenítése szövegkijelöléskor
|
||||
Spaces Szóközök
|
||||
Spelling Helyesírás
|
||||
Spelling and grammar are checked in English (United States). A helyesírás- és nyelvhelyesség-ellenőrzés nyelve: angol (Egyesült Államok).
|
||||
Spelling and grammar are checked in {language}. A helyesírás- és nyelvhelyesség-ellenőrzés nyelve: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. A beszúrási pontnál lévő szöveg jelölése: Nincs helyesírás- és nyelvhelyesség-ellenőrzés.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: a WordCraft ezen a nyelven még nem ellenőrzi a helyesírást és a nyelvhelyességet.
|
||||
Tab characters Tabulátorok
|
||||
These marks show even when Show/Hide ¶ is off. Ezek a jelek akkor is látszanak, ha a Megjelenítés/elrejtés ¶ ki van kapcsolva.
|
||||
Typing replaces selected text A gépelés felülírja a kijelölt szöveget
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 25.
|
@@ -1558,7 +1558,9 @@
|
||||
Show the mini toolbar when text is selected Mostra la barra di formattazione rapida quando selezioni il testo
|
||||
Spaces Spazi
|
||||
Spelling Ortografia
|
||||
Spelling and grammar are checked in English (United States). L'ortografia e la grammatica vengono controllate in inglese (Stati Uniti).
|
||||
Spelling and grammar are checked in {language}. Lingua del controllo ortografico e grammaticale: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Il testo nel punto di inserimento è contrassegnato: Non controllare ortografia e grammatica.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft non controlla ancora ortografia e grammatica in questa lingua.
|
||||
Tab characters Caratteri di tabulazione
|
||||
These marks show even when Show/Hide ¶ is off. Questi segni vengono mostrati anche quando Mostra tutto è disattivato.
|
||||
Typing replaces selected text Il testo digitato sostituisce la selezione
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 25.
|
@@ -197,7 +197,9 @@
|
||||
Show the mini toolbar when text is selected テキストを選択したときにミニ ツール バーを表示する
|
||||
Spaces スペース
|
||||
Spelling スペル チェック
|
||||
Spelling and grammar are checked in English (United States). スペルと文法は英語 (米国) でチェックされます。
|
||||
Spelling and grammar are checked in {language}. スペルと文法のチェック言語: {language}
|
||||
The text at the insertion point is marked Do not check spelling or grammar. 挿入ポイントのテキストの設定: スペルチェックと文章校正を行わない
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft はこの言語のスペルと文法をまだチェックしません。
|
||||
Tab characters タブ
|
||||
Tab stop position: タブ位置:
|
||||
Default tab stops: 既定のタブ間隔:
|
||||
|
||||
|
@@ -161,7 +161,9 @@
|
||||
Show the mini toolbar when text is selected 텍스트를 선택할 때 미니 도구 모음 표시
|
||||
Spaces 공백
|
||||
Spelling 맞춤법
|
||||
Spelling and grammar are checked in English (United States). 맞춤법과 문법은 영어(미국)로 검사합니다.
|
||||
Spelling and grammar are checked in {language}. 맞춤법 및 문법 검사 언어: {language}
|
||||
The text at the insertion point is marked Do not check spelling or grammar. 삽입 위치의 텍스트 설정: 맞춤법 및 문법 검사 안 함
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft는 아직 이 언어의 맞춤법 및 문법을 검사하지 않습니다.
|
||||
Tab characters 탭 문자
|
||||
Tab stop position: 탭 위치:
|
||||
Default tab stops: 기본 탭 위치:
|
||||
|
||||
|
@@ -1990,7 +1990,9 @@
|
||||
Spaces Spaties
|
||||
Special Speciaal
|
||||
Spelling Spelling
|
||||
Spelling and grammar are checked in English (United States). Spelling en grammatica worden gecontroleerd in het Engels (Verenigde Staten).
|
||||
Spelling and grammar are checked in {language}. Controletaal voor spelling en grammatica: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. De tekst bij de invoegpositie is gemarkeerd: Spelling of grammatica niet controleren.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft controleert in deze taal nog geen spelling of grammatica.
|
||||
Stacked Bar Gestapeld staafdiagram
|
||||
Stacked Column Gestapeld kolomdiagram
|
||||
Standard Standaard
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 756 and column 23.
|
@@ -2055,7 +2055,9 @@
|
||||
Spaces Spacje
|
||||
Special Specjalne
|
||||
Spelling Pisownia
|
||||
Spelling and grammar are checked in English (United States). Pisownia i gramatyka są sprawdzane w języku angielskim (Stany Zjednoczone).
|
||||
Spelling and grammar are checked in {language}. Język sprawdzania pisowni i gramatyki: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Tekst w punkcie wstawiania jest oznaczony: Nie sprawdzaj pisowni ani gramatyki.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft nie sprawdza jeszcze pisowni ani gramatyki w tym języku.
|
||||
Stacked Bar Słupkowy skumulowany
|
||||
Stacked Column Kolumnowy skumulowany
|
||||
Standard Standardowe
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 25.
|
@@ -177,7 +177,9 @@
|
||||
Show the mini toolbar when text is selected Mostrar a minibarra de ferramentas ao selecionar texto
|
||||
Spaces Espaços
|
||||
Spelling Ortografia
|
||||
Spelling and grammar are checked in English (United States). A ortografia e a gramática são verificadas em inglês (Estados Unidos).
|
||||
Spelling and grammar are checked in {language}. Idioma da verificação de ortografia e gramática: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. O texto no ponto de inserção está marcado como: Não verificar ortografia nem gramática.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: o WordCraft ainda não verifica ortografia nem gramática neste idioma.
|
||||
Tab characters Caracteres de tabulação
|
||||
Tab stop position: Posição da tabulação:
|
||||
Default tab stops: Tabulações padrão:
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 25.
|
@@ -2222,7 +2222,9 @@
|
||||
Spelling & Grammar Ortografie și gramatică
|
||||
Spelling &\nGrammar Ortografie și\ngramatică
|
||||
Spelling Suggestions Sugestii de ortografie
|
||||
Spelling and grammar are checked in English (United States). Ortografia și gramatica se verifică în engleză (Statele Unite).
|
||||
Spelling and grammar are checked in {language}. Limba de verificare a ortografiei și gramaticii: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Textul de la punctul de inserare este marcat: Nu verifica ortografia și gramatica.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft nu verifică încă ortografia și gramatica în această limbă.
|
||||
Spike Spike
|
||||
Split Împărțire
|
||||
Split Cells Împărțire celule
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 25.
|
@@ -2483,7 +2483,9 @@ preview Title Пример
|
||||
Show the mini toolbar when text is selected Показывать мини-панель при выделении текста
|
||||
Spaces Пробелы
|
||||
Spelling Орфография
|
||||
Spelling and grammar are checked in English (United States). Орфография и грамматика проверяются для английского языка (США).
|
||||
Spelling and grammar are checked in {language}. Язык проверки орфографии и грамматики: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Текст в точке вставки помечен: Не проверять орфографию и грамматику.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft пока не проверяет орфографию и грамматику на этом языке.
|
||||
Tab characters Знаки табуляции
|
||||
These marks show even when Show/Hide ¶ is off. Эти знаки видны, даже когда «Показать все знаки» выключено.
|
||||
Typing replaces selected text Ввод заменяет выделенный текст
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 7 and column 25.
|
@@ -2194,7 +2194,9 @@
|
||||
Spelling Črkovanje
|
||||
Spelling & Grammar Črkovanje in slovnica
|
||||
Spelling &\nGrammar Črkovanje\nin slovnica
|
||||
Spelling and grammar are checked in English (United States). Črkovanje in slovnica se preverjata v angleščini (Združene države).
|
||||
Spelling and grammar are checked in {language}. Jezik preverjanja črkovanja in slovnice: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Besedilo na mestu vstavljanja je označeno: Ne preverjaj črkovanja ali slovnice.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft v tem jeziku še ne preverja črkovanja ali slovnice.
|
||||
Spelling Suggestions Predlogi za črkovanje
|
||||
Split Razdeli
|
||||
Split Cells Razdeli celice
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 7 and column 25.
|
@@ -254,7 +254,9 @@
|
||||
Show the mini toolbar when text is selected Prikaži mini traku sa alatkama pri izboru teksta
|
||||
Spaces Razmaci
|
||||
Spelling Pravopis
|
||||
Spelling and grammar are checked in English (United States). Pravopis i gramatika se proveravaju na engleskom (Sjedinjene Države).
|
||||
Spelling and grammar are checked in {language}. Jezik provere pravopisa i gramatike: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Tekst na mestu umetanja je označen: Ne proveravaj pravopis ni gramatiku.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft još ne proverava pravopis ni gramatiku na ovom jeziku.
|
||||
Tab characters Znakovi tabulatora
|
||||
Tab stop position: Položaj tabulatora:
|
||||
Default tab stops: Podrazumevani tabulatori:
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 25.
|
@@ -258,7 +258,9 @@
|
||||
Show the mini toolbar when text is selected Прикажи мини траку са алаткама при избору текста
|
||||
Spaces Размаци
|
||||
Spelling Правопис
|
||||
Spelling and grammar are checked in English (United States). Правопис и граматика се проверавају на енглеском (Сједињене Државе).
|
||||
Spelling and grammar are checked in {language}. Језик провере правописа и граматике: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Текст на месту уметања је означен: Не проверавај правопис ни граматику.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft још не проверава правопис ни граматику на овом језику.
|
||||
Tab characters Знакови табулатора
|
||||
Tab stop position: Положај табулатора:
|
||||
Default tab stops: Подразумевани табулатори:
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 11 and column 25.
|
@@ -176,7 +176,9 @@
|
||||
Show the mini toolbar when text is selected Visa miniverktygsfältet när text är markerad
|
||||
Spaces Blanksteg
|
||||
Spelling Stavning
|
||||
Spelling and grammar are checked in English (United States). Stavning och grammatik kontrolleras på engelska (USA).
|
||||
Spelling and grammar are checked in {language}. Språk för stavnings- och grammatikkontroll: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Texten vid insättningspunkten är markerad: Kontrollera inte stavning eller grammatik.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft kontrollerar inte stavning eller grammatik på det här språket än.
|
||||
Tab characters Tabbtecken
|
||||
Tab stop position: Tabbstoppets position:
|
||||
Default tab stops: Standardtabbstopp:
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 7 and column 25.
|
@@ -2482,7 +2482,9 @@ preview Title Örnek
|
||||
Show the mini toolbar when text is selected Metin seçildiğinde mini araç çubuğunu göster
|
||||
Spaces Boşluklar
|
||||
Spelling Yazım
|
||||
Spelling and grammar are checked in English (United States). Yazım ve dil bilgisi İngilizce (Amerika Birleşik Devletleri) için denetlenir.
|
||||
Spelling and grammar are checked in {language}. Yazım ve dil bilgisi denetimi dili: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Ekleme noktasındaki metin şu şekilde işaretli: Yazım ve dil bilgisini denetleme.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft bu dilde henüz yazım ve dil bilgisi denetimi yapmıyor.
|
||||
Tab characters Sekme karakterleri
|
||||
These marks show even when Show/Hide ¶ is off. Bu işaretler, Göster/Gizle ¶ kapalıyken de görünür.
|
||||
Typing replaces selected text Yazmak seçili metnin yerine geçer
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 808 and column 23.
|
@@ -179,7 +179,9 @@
|
||||
Show the mini toolbar when text is selected Показувати міні-панель інструментів під час виділення тексту
|
||||
Spaces Пробіли
|
||||
Spelling Правопис
|
||||
Spelling and grammar are checked in English (United States). Правопис і граматика перевіряються англійською (США).
|
||||
Spelling and grammar are checked in {language}. Мова перевірки правопису та граматики: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Текст у точці вставлення позначено: Не перевіряти правопис і граматику.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft поки що не перевіряє правопис і граматику цією мовою.
|
||||
Tab characters Символи табуляції
|
||||
Tab stop position: Позиція табуляції:
|
||||
Default tab stops: Типові позиції табуляції:
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 31.
|
@@ -2177,7 +2177,9 @@
|
||||
Show the mini toolbar when text is selected Hiện thanh công cụ mini khi chọn chữ
|
||||
Spaces Khoảng trắng
|
||||
Spelling Chính tả
|
||||
Spelling and grammar are checked in English (United States). Soát chính tả và ngữ pháp bằng tiếng Anh (Mỹ).
|
||||
Spelling and grammar are checked in {language}. Ngôn ngữ soát chính tả và ngữ pháp: {language}.
|
||||
The text at the insertion point is marked Do not check spelling or grammar. Văn bản tại điểm chèn được đánh dấu: Không kiểm tra chính tả hoặc ngữ pháp.
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}: WordCraft chưa soát chính tả và ngữ pháp cho ngôn ngữ này.
|
||||
Tab characters Ký tự tab
|
||||
These marks show even when Show/Hide ¶ is off. Các dấu này vẫn hiện cả khi đã tắt Hiện/Ẩn ¶.
|
||||
Typing replaces selected text Gõ sẽ thay thế văn bản đã chọn
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 7 and column 25.
|
@@ -209,7 +209,9 @@
|
||||
Show the mini toolbar when text is selected 选择文本时显示浮动工具栏
|
||||
Spaces 空格
|
||||
Spelling 拼写
|
||||
Spelling and grammar are checked in English (United States). 拼写和语法按英语(美国)检查。
|
||||
Spelling and grammar are checked in {language}. 拼写和语法检查语言:{language}
|
||||
The text at the insertion point is marked Do not check spelling or grammar. 插入点处的文本已标记为:不检查拼写或语法
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}:WordCraft 暂不检查此语言的拼写和语法
|
||||
Tab characters 制表符
|
||||
Tab stop position: 制表位位置:
|
||||
Default tab stops: 默认制表位:
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 7 and column 25.
|
@@ -198,7 +198,9 @@
|
||||
Show the mini toolbar when text is selected 選取文字時顯示迷你工具列
|
||||
Spaces 空格
|
||||
Spelling 拼字
|
||||
Spelling and grammar are checked in English (United States). 拼字和文法依英文(美國)檢查。
|
||||
Spelling and grammar are checked in {language}. 拼字和文法檢查語言:{language}
|
||||
The text at the insertion point is marked Do not check spelling or grammar. 插入點處的文字已標示為:不要檢查拼字或文法
|
||||
{language}: WordCraft doesn't check spelling or grammar in this language yet. {language}:WordCraft 暫不檢查此語言的拼字和文法
|
||||
Tab characters 定位字元
|
||||
Tab stop position: 定位點位置:
|
||||
Default tab stops: 預設定位點間距:
|
||||
|
||||
|
@@ -464,9 +464,17 @@ fn language(app: &mut WordApp, ui: &mut Ui) {
|
||||
// #414 (detect the document's language) goes here.
|
||||
ui.add_space(8.0);
|
||||
section(ui, "Proofing language");
|
||||
// The document's default language (Review › Language › Set As Default changes it).
|
||||
let tag = app.session.doc.styles.default_chr.lang.clone();
|
||||
note(ui, &crate::ribbon::language_name(tag.as_deref()));
|
||||
let lang = crate::ribbon::caret_language(app);
|
||||
let text = if crate::ribbon::caret_no_proof(app) {
|
||||
tl!("The text at the insertion point is marked Do not check spelling or grammar.").to_string()
|
||||
} else if !crate::ribbon::caret_language_proofed(app) {
|
||||
crate::i18n::fmt(tl!("{language}: WordCraft doesn't check spelling or grammar in this language yet."), &[("language", &lang)])
|
||||
} else {
|
||||
let unreadable = crate::ribbon::caret_unreadable_dictionary(app);
|
||||
crate::chrome::dictionary_problem(&lang, &unreadable, crate::ribbon::caret_missing_dictionary(app))
|
||||
.unwrap_or_else(|| crate::i18n::fmt(tl!("Spelling and grammar are checked in {language}."), &[("language", &lang)]))
|
||||
};
|
||||
ui.label(RichText::new(text).small().weak());
|
||||
}
|
||||
|
||||
fn accessibility(app: &mut WordApp, ui: &mut Ui) {
|
||||
|
||||
@@ -913,11 +913,27 @@ pub(crate) fn caret_language(app: &WordApp) -> String {
|
||||
tl!(&language_name(caret_lang_tag(app).as_deref())).to_string()
|
||||
}
|
||||
|
||||
/// The language tag at the caret, resolved through the styles and the document default.
|
||||
fn caret_lang_tag(app: &WordApp) -> Option<String> {
|
||||
/// The formatting at the caret, resolved through the styles and the document default.
|
||||
fn caret_char(app: &WordApp) -> wordcraft_doc::resolve::ResolvedChar {
|
||||
let s = &app.session;
|
||||
let style = s.doc.para_at(&s.sel.focus).and_then(|p| p.props.style.clone());
|
||||
s.doc.styles.resolve_char(style.as_deref(), &s.typing_props()).lang
|
||||
s.doc.styles.resolve_char(style.as_deref(), &s.typing_props())
|
||||
}
|
||||
|
||||
/// The language tag at the caret, resolved through the styles and the document default.
|
||||
fn caret_lang_tag(app: &WordApp) -> Option<String> {
|
||||
caret_char(app).lang
|
||||
}
|
||||
|
||||
/// Is the text at the caret itself marked Do not check spelling or grammar? (`format.state`
|
||||
/// looks at the whole word around a caret, so a partly marked word would read as checked.)
|
||||
pub(crate) fn caret_no_proof(app: &WordApp) -> bool {
|
||||
caret_char(app).no_proof
|
||||
}
|
||||
|
||||
/// Does WordCraft check spelling and grammar in the caret's language at all (Bulgarian: no)?
|
||||
pub(crate) fn caret_language_proofed(app: &WordApp) -> bool {
|
||||
wordcraft_engine::proof::has_dictionary(caret_lang_tag(app).as_deref())
|
||||
}
|
||||
|
||||
/// The Hunspell dictionary the caret's language needs but doesn't have (`pl_PL`), if any (#1167).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Installing spelling dictionaries
|
||||
|
||||
> **Last reviewed:** 2026-10-16 · **Last updated:** 2026-10-22 · **Change:** minor (Spanish: `es_ES`, `es_MX`, `es_419` and `es_UY` with their fallbacks, #3360, #3553; previously trivial: ISO 8859-1 dictionaries are read, #2824; previously major: first version)
|
||||
> **Last reviewed:** 2026-10-16 · **Last updated:** 2026-10-23 · **Change:** minor (Spanish: `es_ES`, `es_MX`, `es_419` and `es_UY` with their fallbacks, #3360, #3553; previously trivial: every Hunspell language shows (no dictionary), not only Polish and Portuguese, and Indonesian is listed, #3150; previously trivial: ISO 8859-1 dictionaries are read, #2824)
|
||||
|
||||
English spelling works out of the box. Polish, Russian, Portuguese, Czech, Italian, Croatian,
|
||||
Turkish, Indonesian and Spanish spelling use a standard **Hunspell** dictionary (an `.aff` and a `.dic` file) that
|
||||
@@ -29,6 +29,7 @@ WordCraft looks for the first of these file names (each name means a `<name>.aff
|
||||
| Italian | `it_IT`, `it_CH`, `it-IT`, `it` | LibreOffice `dict-it` |
|
||||
| Croatian | `hr_HR`, `hr-HR`, `hr` | LibreOffice `dict-hr` |
|
||||
| Turkish | `tr_TR`, `tr-TR`, `tr` | LibreOffice `dict-tr` |
|
||||
| Indonesian | `id_ID`, `id-ID`, `id`, `in_ID` | LibreOffice `dict-id` |
|
||||
| Spanish (Spain) | `es_ES`, `es-ES`, `es_ANY`, `es` | LibreOffice `dict-es` (RLA-ES) |
|
||||
| Spanish (Mexico) | `es_MX`, `es-MX`, `es_419`, `es-419`, `es_ANY`, `es` | LibreOffice `dict-es` (RLA-ES) |
|
||||
| Spanish (Latin America, and the other Spanish regions of the Americas) | `es_419`, `es-419`, `es_ANY`, `es`, `es_US`, `es_MX`, `es_AR`, `es-AR` | LibreOffice `dict-es` (RLA-ES) |
|
||||
@@ -139,6 +140,7 @@ Never commit dictionary files to this repository: they stay on the user's system
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-22 | minor | Spanish (#3360, #3553): the file names for Spain, Mexico, Latin America and Uruguay and their fallbacks |
|
||||
| 2026-10-22 | trivial | Italian, Croatian, Turkish, Russian, Czech and Indonesian without a dictionary now show **(no dictionary)** (or **(dictionary unreadable)**) too, as this page already said; before, only Polish and Portuguese did. Indonesian is listed with its file names (#3150) |
|
||||
| 2026-10-18 | trivial | ISO 8859-1 (`SET ISO8859-1`) dictionaries are read, so the original VERO `pt_BR` works without converting it to UTF-8 (#2824) |
|
||||
| 2026-10-18 | minor | An installed dictionary that can't be read shows **(dictionary unreadable)** in the status bar, with the file and reason in its tooltip and in File › Options › Proofing (#2830) |
|
||||
| 2026-10-16 | major | First version: the file names per language, the search order and folders on Windows, macOS and Linux, installing `pt_BR` on each, and how to check it works |
|
||||
|
||||
@@ -187,8 +187,9 @@ Applied when a word is finished by a space, punctuation **or Enter** (`enter_fin
|
||||
`İngilizce`, `ılık` → `Ilık`; observed in Word for Mac with Turkish proofing). Lowercasing `İ`
|
||||
gives the single letter `i` in every language, never `i` + combining dot. Other languages keep
|
||||
the Unicode default (`istanbul` → `Istanbul` in English)
|
||||
(`autocorrect_capitalisation_follows_turkic_case_mapping`). Format > Change Case is not yet
|
||||
Turkish-aware.
|
||||
(`autocorrect_capitalisation_follows_turkic_case_mapping`); Format > Change Case follows the
|
||||
same Turkic mapping from each run's language, while other languages keep the Unicode default
|
||||
(`change_case_follows_turkic_case_mapping`, #3479).
|
||||
- Names of days are capitalised (`monday` → `Monday`). AutoCorrect Options (#412,
|
||||
`tools.autocorrect`, saved per user) switch each of these off: replacements, sentence and
|
||||
table-cell capitals, days, smart quotes, fractions, ordinals, dashes, links, bulleted and
|
||||
|
||||
@@ -99,6 +99,34 @@ fi
|
||||
|
||||
# ---- AppImage -----------------------------------------------------------------------------------
|
||||
if has appimage; then
|
||||
APPIMAGETOOL_VERSION=1.9.1
|
||||
# appimagetool would otherwise embed type2-runtime's `continuous` build, unchecked.
|
||||
RUNTIME_VERSION=20251108
|
||||
case "$ARCH" in
|
||||
x86_64)
|
||||
APPIMAGETOOL_SHA256=ed4ce84f0d9caff66f50bcca6ff6f35aae54ce8135408b3fa33abfc3cb384eb0
|
||||
RUNTIME_SHA256=2fca8b443c92510f1483a883f60061ad09b46b978b2631c807cd873a47ec260d
|
||||
;;
|
||||
aarch64)
|
||||
APPIMAGETOOL_SHA256=f0837e7448a0c1e4e650a93bb3e85802546e60654ef287576f46c71c126a9158
|
||||
RUNTIME_SHA256=00cbdfcf917cc6c0ff6d3347d59e0ca1f7f45a6df1a428a0d6d8a78664d87444
|
||||
;;
|
||||
*) APPIMAGETOOL_SHA256='' RUNTIME_SHA256='' ;;
|
||||
esac
|
||||
if [[ -z "$RUNTIME_SHA256" ]]; then
|
||||
echo "no pinned AppImage runtime for $ARCH" >&2
|
||||
exit 2
|
||||
fi
|
||||
# Downloads $1 to $3 once and checks it against SHA-256 $2, the cached copy again on every run.
|
||||
fetch_pinned() {
|
||||
if [[ ! -x "$3" ]]; then
|
||||
curl --proto '=https' -fsSL -o "$3.download" "$1"
|
||||
printf '%s %s\n' "$2" "$3.download" | sha256sum -c -
|
||||
chmod 755 "$3.download"
|
||||
mv "$3.download" "$3"
|
||||
fi
|
||||
printf '%s %s\n' "$2" "$3" | sha256sum -c -
|
||||
}
|
||||
APPDIR="$WORK/WordCraft.AppDir"
|
||||
cp -R "$STAGE" "$APPDIR"
|
||||
mv "$APPDIR/usr/share/doc" "$WORK/doc-unused"
|
||||
@@ -109,17 +137,23 @@ if has appimage; then
|
||||
|
||||
TOOL="${APPIMAGETOOL:-$(command -v appimagetool || true)}"
|
||||
if [[ -z "$TOOL" ]]; then
|
||||
TOOL="$CARGO_TARGET_DIR/appimagetool-$ARCH.AppImage"
|
||||
if [[ ! -x "$TOOL" ]]; then
|
||||
curl --proto '=https' -fsSL -o "$TOOL" "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-$ARCH.AppImage"
|
||||
chmod +x "$TOOL"
|
||||
if [[ -z "$APPIMAGETOOL_SHA256" ]]; then
|
||||
echo "no pinned appimagetool for $ARCH; set APPIMAGETOOL or put appimagetool on PATH" >&2
|
||||
exit 2
|
||||
fi
|
||||
TOOL="$CARGO_TARGET_DIR/appimagetool-$APPIMAGETOOL_VERSION-$ARCH.AppImage"
|
||||
fetch_pinned "https://github.com/AppImage/appimagetool/releases/download/$APPIMAGETOOL_VERSION/appimagetool-$ARCH.AppImage" \
|
||||
"$APPIMAGETOOL_SHA256" "$TOOL"
|
||||
fi
|
||||
RUNTIME="$CARGO_TARGET_DIR/appimage-runtime-$RUNTIME_VERSION-$ARCH"
|
||||
fetch_pinned "https://github.com/AppImage/type2-runtime/releases/download/$RUNTIME_VERSION/runtime-$ARCH" \
|
||||
"$RUNTIME_SHA256" "$RUNTIME"
|
||||
# Absolute, because appimagetool runs in $DIST below (CARGO_TARGET_DIR or APPIMAGETOOL may be
|
||||
# relative, e.g. target/agent-<name>).
|
||||
OUT="$(cd "$DIST" && pwd)/$BASENAME.AppImage"
|
||||
APPDIR="$(cd "$APPDIR" && pwd)"
|
||||
TOOL="$(cd "$(dirname "$TOOL")" && pwd)/$(basename "$TOOL")"
|
||||
RUNTIME="$(cd "$(dirname "$RUNTIME")" && pwd)/$(basename "$RUNTIME")"
|
||||
# A .zsync left by an earlier run would hide a missing zsyncmake and describe another file.
|
||||
rm -f "$OUT.zsync"
|
||||
# Update information: AppImageUpdate, AppImageLauncher and the like read it from the file and
|
||||
@@ -128,10 +162,11 @@ if has appimage; then
|
||||
# pre-release. A fork's builds point at its own releases through GITHUB_REPOSITORY.
|
||||
REPO="${GITHUB_REPOSITORY:-storytold/wordcraft}"
|
||||
UPDATE_INFO="gh-releases-zsync|${REPO%%/*}|${REPO#*/}|latest|wordcraft-*-linux-$ARCH.AppImage.zsync"
|
||||
# Extract-and-run: works without FUSE (containers, CI). The output embeds the static runtime,
|
||||
# so users don't need libfuse2 either. With zsyncmake on the host (CI installs the zsync
|
||||
# Extract-and-run: works without FUSE (containers, CI). The output embeds the pinned static
|
||||
# runtime, so users don't need libfuse2 either. With zsyncmake on the host (CI installs the zsync
|
||||
# package) appimagetool also writes the .zsync, into its working directory, hence the cd.
|
||||
(cd "$DIST" && ARCH="$ARCH" APPIMAGE_EXTRACT_AND_RUN=1 "$TOOL" --no-appstream -u "$UPDATE_INFO" "$APPDIR" "$OUT")
|
||||
(cd "$DIST" && ARCH="$ARCH" APPIMAGE_EXTRACT_AND_RUN=1 "$TOOL" --no-appstream \
|
||||
--runtime-file "$RUNTIME" -u "$UPDATE_INFO" "$APPDIR" "$OUT")
|
||||
echo "wrote $OUT"
|
||||
if [[ -s "$OUT.zsync" ]]; then
|
||||
echo "wrote $OUT.zsync"
|
||||
|
||||
@@ -56,8 +56,8 @@ if (-not $haveCert -and -not $haveAzure) {
|
||||
|
||||
$script:SignTool = Find-SignTool
|
||||
$common = @('sign', '/v', '/fd', 'SHA256', '/td', 'SHA256', '/d', 'WordCraft', '/du', 'https://github.com/storytold/wordcraft')
|
||||
$tmp = Join-Path ([IO.Path]::GetTempPath()) "wordcraft-sign-$PID"
|
||||
New-Item -ItemType Directory -Force -Path $tmp | Out-Null
|
||||
$tmp = Join-Path ([IO.Path]::GetTempPath()) "wordcraft-sign-$([IO.Path]::GetRandomFileName())"
|
||||
New-Item -ItemType Directory -Path $tmp | Out-Null
|
||||
|
||||
try {
|
||||
if ($haveCert) {
|
||||
@@ -73,8 +73,15 @@ try {
|
||||
Write-Output "Signing with Azure Trusted Signing ($env:AZURE_SIGNING_ACCOUNT / $env:AZURE_CERT_PROFILE): $($Files -join ', ')"
|
||||
# The dlib authenticates with DefaultAzureCredential, which reads AZURE_TENANT_ID,
|
||||
# AZURE_CLIENT_ID and AZURE_CLIENT_SECRET from the environment.
|
||||
$trustedSigningVersion = '1.0.95'
|
||||
$trustedSigningSha256 = '3bfcf1e0a3cb42af1692f0a8ed45c15de070c2de86f28a59b2795d904d8a920f'
|
||||
$pkg = Join-Path $tmp 'trusted-signing.zip'
|
||||
Invoke-WebRequest -Uri 'https://www.nuget.org/api/v2/package/Microsoft.Trusted.Signing.Client' -OutFile $pkg
|
||||
$uri = "https://api.nuget.org/v3-flatcontainer/microsoft.trusted.signing.client/$trustedSigningVersion/microsoft.trusted.signing.client.$trustedSigningVersion.nupkg"
|
||||
Invoke-WebRequest -Uri $uri -OutFile $pkg
|
||||
$actualHash = (Get-FileHash -Path $pkg -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
if ($actualHash -ne $trustedSigningSha256) {
|
||||
throw "Microsoft.Trusted.Signing.Client $trustedSigningVersion checksum mismatch"
|
||||
}
|
||||
Expand-Archive -Path $pkg -DestinationPath (Join-Path $tmp 'client') -Force
|
||||
$dlib = Get-ChildItem -Path (Join-Path $tmp 'client') -Recurse -Filter Azure.CodeSigning.Dlib.dll |
|
||||
Where-Object { $_.FullName -match '\\x64\\' } | Select-Object -First 1
|
||||
|
||||
Reference in New Issue
Block a user