FU.2: craft-proof — Australian English reads SCOWL's own en-AU dictionary (ProofLang::EnAu), with en-GB's spelling policy; en-NZ stays on en-GB

SCOWL en-AU has 238 words en-GB lacks (billabong, brumby, larrikinism, Australian place
names) and spells program, inquiry, livable, licorice, verandah the Australian way (no
programme, enquiry, liveable, dialog or veranda, as Hunspell en_AU says); -ise/-ize policy and
affix file are the same as en-GB's. craft-i18n already ships language-data/en-au.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
This commit is contained in:
Martin BallandClaude Opus 5.5 committed 2026-11-02 01:18:42 +00:00
1 parent e36fb5d069
commit 820695e951
9 files changed
+113 -65

No files matched your search

+6 -5
View File
@@ -13,7 +13,7 @@ craft-proof = { git = "https://github.com/storytold/craft-libs", rev = "<commit>
| Language | Spelling | Grammar | Hyphenation |
|---|---|---|---|
| English (en-US, en-CA, en-GB and the British-spelling Englishes such as en-AU, en-NZ) | SCOWL 2026 Hunspell dictionary per English + `en-extra.txt`, dialect policy (`en-variants.txt`); a dictionaries-folder English first; without SCOWL the installed Hunspell English, else the built-in Moby list ([below](#english-is-always-checked)) | yes | Moby list, our patterns, heuristic |
| English (en-US, en-CA, en-AU, en-GB and the British-spelling Englishes such as en-NZ) | SCOWL 2026 Hunspell dictionary per English + `en-extra.txt`, dialect policy (`en-variants.txt`); a dictionaries-folder English first; without SCOWL the installed Hunspell English, else the built-in Moby list ([below](#english-is-always-checked)) | yes | Moby list, our patterns, heuristic |
| Polish, Portuguese, Italian | the installed Hunspell dictionary | yes | TeX patterns (embedded, or a Language pack) |
| Croatian, Turkish, Russian, Czech, Indonesian, Spanish (es, es-MX, es-419, es-UY) | the installed Hunspell dictionary (Russian also `ru-extra.txt`) | yes | Turkish and Russian rules; English fallback otherwise |
| German | — | — | TeX patterns (embedded, or a Language pack) |
@@ -151,14 +151,15 @@ English spelling uses the first of these that is there; `english_source(lang)` s
or in WordCraft's own `dictionaries` folder. The user's choice comes first.
2. **Installed English pack:** reserved for Language packs (craft-libs#485, CP4.2).
3. **Embedded SCOWL:** the English's own SCOWL `rel-2026.02.25` Hunspell dictionary from
`CRAFT_I18N_DIR` (`language-data/en-us`, `en-gb` (British `-ise`) or `en-ca`, `spelling.aff` +
`spelling.dic`), read by the affix engine. en-AU, en-NZ, en-IE and the other British-spelling
Englishes read en-GB; Canadian English reads en-CA. A word is right when the English's own
`CRAFT_I18N_DIR` (`language-data/en-us`, `en-gb` (British `-ise`), `en-au` or `en-ca`,
`spelling.aff` + `spelling.dic`), read by the affix engine. Australian English reads en-AU
(Australian words such as `billabong`, with en-GB's spelling policy); en-NZ, en-IE and the
other British-spelling Englishes read en-GB; Canadian English reads en-CA. A word is right when the English's own
dictionary knows it (or `en-extra.txt` does), never because another English's does
(`colourblind` is wrong in en-US, `colorblind` in en-GB); suggestions come from the same
dictionary. SCOWL's size-60 lists keep one spelling per dialect, and Word accepts more, so
British English also takes the `-ize` spellings of its `-ise` words that American or Canadian
English spell so (`organize`, `realization`; never `wize` or `advize`), and `en-variants.txt` flags the other dialect's spellings and accepts this
English spell so (`organize`, `realization`; never `wize` or `advize`, and never `-yze`: `reanalyze` stays American), and `en-variants.txt` flags the other dialect's spellings and accepts this
dialect's other spellings of known words (`judgement` in en-US). English with no dialect
(`is_correct`) takes a word any of the three knows. Suggestions offer a missing space only
between two lower-case words of three letters or more, after every one-word candidate, and no
+4 -3
View File
@@ -16,9 +16,8 @@
//! `include_str!` takes a string, so a `CRAFT_I18N_DIR` that isn't valid UTF-8 can't be embedded:
//! it is treated like a folder without the data.
//!
//! English: SCOWL's en-US, en-GB (-ise) and en-CA dictionaries; en-AU is not embedded, as
//! Australian English is checked as British-spelling English (`ProofLang::EnGb`). The SCOWL
//! notice is embedded once (the four upstream READMEs differ only in their title and build line).
//! English: SCOWL's en-US, en-GB (-ise), en-CA and en-AU dictionaries. The SCOWL notice is
//! embedded once (the four upstream READMEs differ only in their title and build line).
use std::fmt::Write as _;
use std::path::{Path, PathBuf};
@@ -34,6 +33,8 @@ const FILES: &[(&str, &str, bool)] = &[
("EN_GB_SPELLING", "en-gb/spelling.dic", false),
("EN_CA_AFF", "en-ca/spelling.aff", false),
("EN_CA_SPELLING", "en-ca/spelling.dic", false),
("EN_AU_AFF", "en-au/spelling.aff", false),
("EN_AU_SPELLING", "en-au/spelling.dic", false),
("SCOWL_NOTICE", "en-us/LICENCE-SCOWL.txt", false),
("EN_US_PAT", "en-us/hyphenation.pat", false),
("EXTRA_EN", "en-us/en-extra.txt", false),
+3 -2
View File
@@ -1,5 +1,5 @@
//! American and British spellings of the same English word (#1281, #1045): which forms each
//! English ([`ProofLang::En`], [`ProofLang::EnCa`], [`ProofLang::EnGb`]) accepts, which it flags,
//! English ([`ProofLang::En`], [`ProofLang::EnCa`], [`ProofLang::EnGb`] and [`ProofLang::EnAu`]) accepts, which it flags,
//! and what it suggests instead (`colour` → `color` in American English).
//!
//! The pairs come from craft-i18n's `language-data/en-us/en-variants.txt`, our own list of base forms with a
@@ -77,7 +77,8 @@ fn column(lang: ProofLang) -> Option<usize> {
match lang {
ProofLang::En => Some(0),
ProofLang::EnCa => Some(1),
ProofLang::EnGb => Some(2),
// Australian English follows the British policy (`colour`, `centre`, `organise`).
ProofLang::EnGb | ProofLang::EnAu => Some(2),
_ => None,
}
}
+21 -8
View File
@@ -4,7 +4,7 @@
//! user keeps for WordCraft ([`crate::hunspell::user_dirs`]: the folder set in the options,
//! `WORDCRAFT_DICTIONARIES`, WordCraft's own `dictionaries` folder).
//! 2. **Installed English pack**: reserved for Language packs (craft-libs#485, CP4.2).
//! 3. **Embedded SCOWL**: the run's English's SCOWL dictionary (en-US, en-GB or en-CA) embedded
//! 3. **Embedded SCOWL**: the run's English's SCOWL dictionary (en-US, en-GB, en-AU or en-CA) embedded
//! from craft-i18n at build time ([`crate::scowl`]); a word it knows (British English: also
//! the `-ize` spelling of one it knows, [`ise_spelling`]), or the supplement ([`EXTRA`]), is
//! right; never one only another English knows. When it is there, the system locations aren't
@@ -18,8 +18,9 @@
//! embedded from craft-i18n is the same list; it is used for hyphenation only.)
//!
//! Hunspell dictionaries are found by [`crate::hunspell`] by their own English's names only
//! (`en_US` for American, `en_GB` for British, `en_CA` for Canadian English), each name in every
//! folder before the next name. Another English's dictionary is never used: it would mark this
//! (`en_US` for American, `en_GB` for British, `en_CA` for Canadian English; `en_AU`, then
//! `en_GB`, for Australian), each name in every folder before the next name. Another English's
//! dictionary is never used: it would mark this
//! English's spellings (`colour` in an `en_US` one). A file that can't be read is skipped for the
//! next name or folder, and one file is read once for every English that uses it. `COMPOUNDRULE`
//! (ordinals) and `OCONV` (suggestions are written as the dictionary says: `don’t`) are read;
@@ -90,15 +91,22 @@ fn names(lang: ProofLang) -> &'static [&'static str] {
match lang {
ProofLang::EnGb => &["en_GB", "en-GB"],
ProofLang::EnCa => &["en_CA", "en-CA"],
// Australian English's own, else a British one: the British-spelling dictionary it read
// before it had its own (a system en_GB on a build without SCOWL).
ProofLang::EnAu => &["en_AU", "en-AU", "en_GB", "en-GB"],
_ => &["en_US", "en-US"],
}
}
/// How many Englishes have a slot of their own ([`slot`]).
const ENGLISHES: usize = 4;
/// The slot of each English in [`State::slots`].
fn slot(lang: ProofLang) -> usize {
match lang {
ProofLang::EnGb => 1,
ProofLang::EnCa => 2,
ProofLang::EnAu => 3,
_ => 0,
}
}
@@ -109,7 +117,7 @@ type Loaded = Option<(Arc<AffixDict>, PathBuf)>;
/// The English Hunspell dictionaries, under one lock.
struct State {
/// Per English (see [`slot`]): `None` until first use, then what was found.
slots: [Option<Loaded>; 3],
slots: [Option<Loaded>; ENGLISHES],
/// Every `.dic` file read, so Englishes that use the same file share one copy.
files: Vec<(PathBuf, Arc<AffixDict>)>,
/// Counts reloads, so a load that started before one is not kept.
@@ -118,7 +126,7 @@ struct State {
impl State {
const fn new() -> Self {
State { slots: [None, None, None], files: Vec::new(), reloads: 0 }
State { slots: [None, None, None, None], files: Vec::new(), reloads: 0 }
}
}
@@ -181,7 +189,7 @@ fn already_read(state: &RwLock<State>, dic: &Path) -> Option<Arc<AffixDict>> {
/// Forget what `state` holds, so the next check looks again.
fn forget(state: &RwLock<State>) {
let mut s = state.write().unwrap_or_else(PoisonError::into_inner);
s.slots = [None, None, None];
s.slots = [None, None, None, None];
s.files.clear();
s.reloads = s.reloads.wrapping_add(1);
}
@@ -240,7 +248,7 @@ fn note_error(lang: ProofLang, error: Option<(PathBuf, String)>) {
/// folder changed).
pub(crate) fn reload() {
forget(&HUNSPELL);
for lang in [ProofLang::En, ProofLang::EnGb, ProofLang::EnCa] {
for lang in [ProofLang::En, ProofLang::EnGb, ProofLang::EnCa, ProofLang::EnAu] {
crate::hunspell::clear_load_error(key(lang));
}
}
@@ -609,7 +617,7 @@ mod tests {
fn lookup_order() {
let tiny = Arc::new(AffixDict::from_hunspell("", "1\nzzyzx\n", &[]).unwrap());
let file = PathBuf::from("/folder/en_US.dic");
for lang in [ProofLang::En, ProofLang::EnGb, ProofLang::EnCa] {
for lang in [ProofLang::En, ProofLang::EnGb, ProofLang::EnAu, ProofLang::EnCa] {
assert!(matches!(pick(Some((tiny.clone(), file.clone())), lang), Speller::Hunspell(_, p) if p == file), "{lang:?}");
let fallback = pick(None, lang);
if crate::scowl::dict(lang).is_some() {
@@ -638,6 +646,11 @@ mod tests {
assert_eq!(found(names(ProofLang::EnGb)), ["en_GB"], "a user's en_US doesn't stand in for SCOWL's en-GB");
assert_eq!(found(names(ProofLang::EnCa)), ["en_CA"]);
assert_eq!(found(names(ProofLang::En)), ["en_US"]);
// Australian English: its own, else the British one it read before it had its own.
assert_eq!(found(names(ProofLang::EnAu)), ["en_GB"]);
std::fs::write(dir.join("en_AU.aff"), "SET UTF-8\n").unwrap();
std::fs::write(dir.join("en_AU.dic"), "1\nzzyzx\n").unwrap();
assert_eq!(found(names(ProofLang::EnAu)), ["en_AU", "en_GB"]);
let _ = std::fs::remove_dir_all(&dir);
}
+23 -30
View File
@@ -5,7 +5,7 @@
/// A language WordCraft can proof, or [`ProofLang::Other`] for one it can't.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum ProofLang {
/// American English (`en`, `en-US`, and every region not listed for [`ProofLang::EnGb`] or
/// American English (`en`, `en-US`, and every region not listed for [`ProofLang::EnGb`], [`ProofLang::EnAu`] or
/// [`ProofLang::EnCa`]): SCOWL's en-US dictionary ([`crate::scowl`]), the English grammar rules and the
/// English hyphenation dictionary and patterns. British spellings (`colour`, `centre`,
/// `organise`) are flagged, with the American form suggested ([`crate::en_variants`]). Also
@@ -13,10 +13,14 @@ pub enum ProofLang {
/// Word's).
#[default]
En,
/// English with British spelling (`en-GB`, `en-AU`, `en-NZ`, `en-IE`, `en-ZA`, `en-IN`…):
/// English with British spelling (`en-GB`, `en-NZ`, `en-IE`, `en-ZA`, `en-IN`…):
/// [`ProofLang::En`]'s tools, but American spellings (`color`, `center`, `analyze`) are
/// flagged and `-ize` and `-ise` are both right, as in Oxford spelling.
EnGb,
/// Australian English (`en-AU`): [`ProofLang::EnGb`]'s spelling policy, against SCOWL's own
/// en-AU dictionary, which knows Australian words (`billabong`, `brumby`, `larrikin`) and
/// spells some words the Australian way (`program`, `inquiry`).
EnAu,
/// Canadian English (`en-CA`): British `-our`, `-re` and `-ence` (`colour`, `centre`,
/// `defence`) with American `-ize` (`organize`), `tire` and `program`.
EnCa,
@@ -86,9 +90,10 @@ pub enum ProofLang {
impl ProofLang {
/// Every language with a spelling dictionary, in display order.
pub const PROOFED: [ProofLang; 15] = [
pub const PROOFED: [ProofLang; 16] = [
ProofLang::En,
ProofLang::EnGb,
ProofLang::EnAu,
ProofLang::EnCa,
ProofLang::Pl,
ProofLang::Pt,
@@ -155,12 +160,13 @@ impl ProofLang {
}
}
/// The English of an English tag, by its [`region`]: Canada is [`ProofLang::EnCa`], regions
/// that spell the British way are [`ProofLang::EnGb`], and the United States, any other
/// The English of an English tag, by its [`region`]: Canada is [`ProofLang::EnCa`], Australia
/// [`ProofLang::EnAu`], other regions that spell the British way are [`ProofLang::EnGb`], and the United States, any other
/// region and no region are [`ProofLang::En`].
fn english(tag: &str) -> ProofLang {
match region(tag) {
Some(r) if r.eq_ignore_ascii_case("CA") => ProofLang::EnCa,
Some(r) if r.eq_ignore_ascii_case("AU") => ProofLang::EnAu,
Some(r) if BRITISH_SPELLING.iter().any(|b| b.eq_ignore_ascii_case(r)) => ProofLang::EnGb,
_ => ProofLang::En,
}
@@ -189,9 +195,10 @@ impl ProofLang {
}
}
/// Is this one of the Englishes ([`ProofLang::En`], [`ProofLang::EnGb`], [`ProofLang::EnCa`])?
/// Is this one of the Englishes ([`ProofLang::En`], [`ProofLang::EnGb`], [`ProofLang::EnAu`],
/// [`ProofLang::EnCa`])?
pub fn is_english(self) -> bool {
matches!(self, ProofLang::En | ProofLang::EnGb | ProofLang::EnCa)
matches!(self, ProofLang::En | ProofLang::EnGb | ProofLang::EnAu | ProofLang::EnCa)
}
/// Is this one of the Spanishes ([`ProofLang::Es`], [`ProofLang::EsMx`], [`ProofLang::Es419`],
@@ -208,7 +215,7 @@ impl ProofLang {
pub fn code(self) -> &'static str {
match self {
ProofLang::Pack(_) => "",
ProofLang::En | ProofLang::EnGb | ProofLang::EnCa => "en",
ProofLang::En | ProofLang::EnGb | ProofLang::EnAu | ProofLang::EnCa => "en",
ProofLang::Pl => "pl",
ProofLang::Bg => "bg",
ProofLang::Pt => "pt",
@@ -371,12 +378,12 @@ pub(crate) fn region(tag: &str) -> Option<&str> {
const LATIN_AMERICA: [&str; 22] =
["419", "005", "013", "029", "AR", "BO", "CL", "CO", "CR", "CU", "DO", "EC", "GT", "HN", "NI", "PA", "PE", "PR", "PY", "SV", "US", "VE"];
/// Regions whose English uses British spelling ([`ProofLang::EnGb`]): the United Kingdom (and
/// the non-standard `UK`), Ireland, Australia, New Zealand, South Africa, India and other
/// Regions whose English uses British spelling ([`ProofLang::EnGb`]; Australia has its own,
/// [`ProofLang::EnAu`]): the United Kingdom (and the non-standard `UK`), Ireland, New Zealand, South Africa, India and other
/// Commonwealth countries, the Crown dependencies and Europe (`150`).
const BRITISH_SPELLING: [&str; 26] = [
"GB", "UK", "IE", "AU", "NZ", "ZA", "IN", "SG", "HK", "MY", "MT", "CY", "GI", "IM", "JE", "GG", "JM", "TT", "BS", "BB", "BZ", "KE", "NG", "GH",
"PK", "150",
const BRITISH_SPELLING: [&str; 25] = [
"GB", "UK", "IE", "NZ", "ZA", "IN", "SG", "HK", "MY", "MT", "CY", "GI", "IM", "JE", "GG", "JM", "TT", "BS", "BB", "BZ", "KE", "NG", "GH", "PK",
"150",
];
/// A BCP 47 tag in canonical case (`pl-PL`, `en-GB`, `zh-Hant-TW`, `x-none`), or `None` when
@@ -469,26 +476,12 @@ mod tests {
fn tags_resolve_english_regions() {
assert_tags(&["en", "en-US", "EN_us", "en-Latn-US", "en-PH", "en-001", "eng", "en_US.UTF-8", "en-x-gb"], ProofLang::En);
assert_tags(
&[
"en-GB",
"EN_gb",
"en_GB.UTF-8",
"en-AU",
"en_AU",
"en-NZ",
"en-IE",
"en-ZA",
"en-IN",
"en-Latn-GB",
"en-UK",
"en-150",
"eng-GB",
"en_GB@euro",
],
&["en-GB", "EN_gb", "en_GB.UTF-8", "en-NZ", "en-IE", "en-ZA", "en-IN", "en-Latn-GB", "en-UK", "en-150", "eng-GB", "en_GB@euro"],
ProofLang::EnGb,
);
assert_tags(&["en-CA", "en_CA", "EN-ca", "en_CA.UTF-8", "en-Latn-CA"], ProofLang::EnCa);
for language in [ProofLang::En, ProofLang::EnGb, ProofLang::EnCa] {
assert_tags(&["en-AU", "en_AU", "EN-au", "en_AU.UTF-8", "en-Latn-AU"], ProofLang::EnAu);
for language in [ProofLang::En, ProofLang::EnGb, ProofLang::EnAu, ProofLang::EnCa] {
assert!(language.is_english() && language.is_proofed() && ProofLang::PROOFED.contains(&language), "{language:?}");
assert_eq!(language.code(), "en");
}
+34 -5
View File
@@ -340,7 +340,7 @@ pub fn installed_dictionaries() -> Vec<(ProofLang, Option<std::path::PathBuf>)>
/// checked yet reports `None` (#2830). For an English, its embedded SCOWL dictionary or the
/// English Hunspell dictionary that failed; English then uses the next source ([`english_source`]).
pub fn dictionary_load_error(lang: ProofLang) -> Option<String> {
if matches!(lang, ProofLang::En | ProofLang::EnGb | ProofLang::EnCa) {
if lang.is_english() {
return english::load_error(lang);
}
if let Some(l) = lang.spelling_locale() {
@@ -953,7 +953,7 @@ pub fn check_grammar_in(text: &str, lang: ProofLang) -> Vec<Issue> {
fn grammar_in(text: &str, lang: ProofLang, capital_first: bool) -> Vec<Issue> {
match lang {
ProofLang::En => grammar_en(text, capital_first),
ProofLang::EnGb | ProofLang::EnCa => grammar_en(text, capital_first).into_iter().map(|i| Issue { lang, ..i }).collect(),
ProofLang::EnGb | ProofLang::EnAu | ProofLang::EnCa => grammar_en(text, capital_first).into_iter().map(|i| Issue { lang, ..i }).collect(),
// `pt-pt` shares Portuguese's rules, its issues in its own language.
_ => language(lang.built_in())
.map_or_else(Vec::new, |l| (l.grammar)(text, lang, capital_first).into_iter().map(|i| Issue { lang, ..i }).collect()),
@@ -1197,7 +1197,7 @@ mod tests {
}
// 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);
let english = l.is_english();
assert_eq!(dictionary_needed(l, false).is_some(), !english, "{l:?}");
}
for l in [ProofLang::En, ProofLang::Other] {
@@ -2481,6 +2481,33 @@ mod tests {
}
}
/// Review follow-up: Australian English reads SCOWL's own en-AU dictionary (craft-i18n ships
/// it), not en-GB's: its Australian words are right and spelled as Hunspell's en_AU spells
/// them; British English doesn't take them. The British policy still applies: American
/// spellings are wrong, `-ise` and `-ize` both right.
#[cfg_attr(not(craft_proof_data), ignore = "needs the Language data (CRAFT_I18N_DIR)")]
#[test]
fn australian_english_reads_its_own_scowl() {
crate::hold_dictionary_tests();
let (au, gb) = (ProofLang::EnAu, ProofLang::EnGb);
assert!(scowl::is_british(au));
assert_eq!(english_source(au), Some(EnglishSource::Embedded));
for w in ["billabong", "brumby", "larrikinism", "bunyip", "corroboree", "Bundaberg", "Rockhampton"] {
assert!(is_correct_in(w, au), "en-AU: {w}");
assert!(!is_correct_in(w, gb), "en-GB: {w}");
assert!(is_correct_for(w, Some("en-AU")), "en-AU tag: {w}");
}
for w in ["colour", "centre", "organise", "organize", "analyse", "travelled", "defence"] {
assert!(is_correct_in(w, au), "en-AU: {w}");
}
for w in ["color", "center", "analyze", "reanalyze", "defense"] {
assert!(!is_correct_in(w, au), "en-AU: {w}");
}
let text = "The larrikin saw a brumby by the billabong and analysed the colour of the sky.";
assert!(check_spelling_in(text, au).is_empty(), "{:?}", check_spelling_in(text, au));
assert_eq!(check_spelling_in(text, gb).len(), 3, "larrikin, brumby, billabong: {:?}", check_spelling_in(text, gb));
}
/// More British spellings that must stay right in en-GB and en-AU (#1281): -re, single l, ae,
/// with their inflections.
#[test]
@@ -2488,7 +2515,7 @@ mod tests {
// English results depend on the dictionaries other tests install.
crate::hold_dictionary_tests();
let gb = ProofLang::EnGb;
assert_eq!(ProofLang::from_tag(Some("en-AU")), gb);
assert_eq!(ProofLang::from_tag(Some("en-AU")), ProofLang::EnAu);
for w in [
"goitre",
"goitres",
@@ -2513,6 +2540,7 @@ mod tests {
"encyclopaedias",
] {
assert!(is_correct_in(w, gb), "en-GB: {w}");
assert!(is_correct_in(w, ProofLang::EnAu), "en-AU: {w}");
}
let text = "The wilful knight took the sceptre to fulfil his enrolment, paid the instalment and read the encyclopaedia.";
assert!(check_spelling_in(text, gb).is_empty(), "{:?}", check_spelling_in(text, gb));
@@ -2529,7 +2557,8 @@ mod tests {
assert_eq!(english_source(l), Some(EnglishSource::Embedded));
assert_eq!(dictionary_load_error(l), None);
}
assert!(std::ptr::eq(scowl::dict(ProofLang::EnGb).unwrap(), scowl::dict(ProofLang::from_tag(Some("en-AU"))).unwrap()), "en-AU reads en-GB");
assert!(!std::ptr::eq(scowl::dict(ProofLang::EnGb).unwrap(), scowl::dict(ProofLang::EnAu).unwrap()), "en-AU reads its own");
assert!(std::ptr::eq(scowl::dict(ProofLang::EnGb).unwrap(), scowl::dict(ProofLang::from_tag(Some("en-NZ"))).unwrap()), "en-NZ reads en-GB");
let notice = scowl::notice().unwrap();
for credit in ["Kevin Atkinson", "Geoff Kuenning", "clause 4 removed", "Benjamin Titze"] {
assert!(notice.contains(credit), "{credit}");
+10 -4
View File
@@ -7,9 +7,10 @@
use crate::hyphen::{self, Limits, Source};
use crate::{EnglishSource, Options, ProofLang, dict, en_variants, patterns};
const LANGS: [ProofLang; 18] = [
const LANGS: [ProofLang; 19] = [
ProofLang::En,
ProofLang::EnGb,
ProofLang::EnAu,
ProofLang::EnCa,
ProofLang::Pl,
ProofLang::Bg,
@@ -45,9 +46,14 @@ const SAMPLES: [&str; 10] = [
#[test]
fn nothing_is_embedded() {
assert!(crate::data::EN_US_DIC.is_empty());
assert!(crate::data::EN_US_SPELLING.is_empty() && crate::data::EN_GB_SPELLING.is_empty() && crate::data::EN_CA_SPELLING.is_empty());
assert!(
crate::data::EN_US_SPELLING.is_empty()
&& crate::data::EN_GB_SPELLING.is_empty()
&& crate::data::EN_CA_SPELLING.is_empty()
&& crate::data::EN_AU_SPELLING.is_empty()
);
assert!(crate::scowl::notice().is_none());
for l in [ProofLang::En, ProofLang::EnGb, ProofLang::EnCa] {
for l in [ProofLang::En, ProofLang::EnGb, ProofLang::EnAu, ProofLang::EnCa] {
assert!(crate::scowl::dict(l).is_none() && crate::scowl::load_error(l).is_none());
}
assert!(dict::Dictionary::en_us().is_empty());
@@ -63,7 +69,7 @@ fn nothing_is_embedded() {
#[test]
fn english_spelling_still_marks_misspellings() {
crate::hold_dictionary_tests();
for l in [ProofLang::En, ProofLang::EnGb, ProofLang::EnCa] {
for l in [ProofLang::En, ProofLang::EnGb, ProofLang::EnAu, ProofLang::EnCa] {
let source = crate::english_source(l);
assert!(matches!(source, Some(EnglishSource::Hunspell(_) | EnglishSource::CoreList)), "{l:?}");
// Any English dictionary marks junk and knows `the`; the word-by-word results below are
+1 -1
View File
@@ -531,7 +531,7 @@ fn hyphenation_locales(lang: ProofLang) -> Vec<String> {
ProofLang::EsUy => &["es-uy", "es-419", "es"],
ProofLang::De => &["de", "de-1996", "de-de"],
ProofLang::Pack(l) => return crate::pack_lang::hyphenation_locales(l),
ProofLang::En | ProofLang::EnGb | ProofLang::EnCa | ProofLang::Other => &[],
ProofLang::En | ProofLang::EnGb | ProofLang::EnAu | ProofLang::EnCa | ProofLang::Other => &[],
};
names.iter().map(|n| (*n).to_string()).collect()
}
+11 -7
View File
@@ -2,8 +2,11 @@
//! dictionaries of craft-i18n's `language-data/en-us`, `en-gb` (British `-ise`) and `en-ca`,
//! embedded unmodified at build time and read by the affix engine ([`crate::affix`]) on first use.
//!
//! Each English has its own: American English reads en-US, the British-spelling Englishes
//! (en-GB, en-AU, en-NZ, en-IE…) read en-GB and Canadian English reads en-CA. Its suggestions
//! Each English has its own: American English reads en-US, Australian English en-AU (SCOWL's
//! Australian words: `billabong`, `brumby`; and `program`, `inquiry`), the other British-spelling
//! Englishes (en-GB, en-NZ, en-IE…) read en-GB and Canadian English reads en-CA. SCOWL has no
//! en-NZ: New Zealand English keeps `programme` and has few words of its own in SCOWL's en-AU
//! data, so it stays on en-GB. Its suggestions
//! come from its own dictionary, and a word is right when its own dictionary knows it: the other
//! dialects' dictionaries are never asked (en-US would take `colourblind` from en-GB's). SCOWL
//! picks one spelling per dialect (en-GB `-ise` has no `organize`, en-US no `judgement`), and Word
@@ -19,16 +22,17 @@ use std::sync::OnceLock;
use crate::ProofLang;
use crate::affix::AffixDict;
use crate::data::{EN_CA_AFF, EN_CA_SPELLING, EN_GB_AFF, EN_GB_SPELLING, EN_US_AFF, EN_US_SPELLING, SCOWL_NOTICE};
use crate::data::{EN_AU_AFF, EN_AU_SPELLING, EN_CA_AFF, EN_CA_SPELLING, EN_GB_AFF, EN_GB_SPELLING, EN_US_AFF, EN_US_SPELLING, SCOWL_NOTICE};
/// Per English (American, British, Canadian): the loaded dictionary, or why it isn't there.
static DICTS: [OnceLock<Result<AffixDict, String>>; 3] = [OnceLock::new(), OnceLock::new(), OnceLock::new()];
/// Per English (American, British, Canadian, Australian): the loaded dictionary, or why it isn't there.
static DICTS: [OnceLock<Result<AffixDict, String>>; 4] = [OnceLock::new(), OnceLock::new(), OnceLock::new(), OnceLock::new()];
/// The slot, `.aff` and `.dic` text of `lang`'s dictionary.
fn source(lang: ProofLang) -> (usize, &'static str, &'static str) {
match lang {
ProofLang::EnGb => (1, EN_GB_AFF, EN_GB_SPELLING),
ProofLang::EnCa => (2, EN_CA_AFF, EN_CA_SPELLING),
ProofLang::EnAu => (3, EN_AU_AFF, EN_AU_SPELLING),
_ => (0, EN_US_AFF, EN_US_SPELLING),
}
}
@@ -50,9 +54,9 @@ pub(crate) fn dict(lang: ProofLang) -> Option<&'static AffixDict> {
loaded.as_ref().ok()
}
/// Does `lang` read the British `-ise` dictionary (en-GB, en-AU, en-NZ…)?
/// Does `lang` read a British `-ise` dictionary (en-GB, and en-NZ… through it; en-AU)?
pub(crate) fn is_british(lang: ProofLang) -> bool {
source(lang).0 == 1
matches!(source(lang).0, 1 | 3)
}
/// Why `lang`'s embedded SCOWL dictionary failed to load, once something tried to load it.