i18n(hu): complete the Hungarian catalog again (#842)

* i18n: add Hungarian (hu) interface translation

- crates/ui-egui/src/i18n/hu.tsv: complete catalog, all 1,572 keys of
  es.tsv in the same order, written clean-room from the plain meaning
  of the English labels; placeholders, escapes and trailing ellipses
  kept. Commands are nouns, messages use the informal second person,
  and only the first word of a label is capitalised. A noun after a
  number stays singular in Hungarian, so the context-free format needs
  no plural forms.
- LANGUAGES gains `hu` (Magyar); `hu`, `hu-HU` and `hu_HU.UTF-8`
  resolve to it.
- The Font dialog's preview sample is "AaBbYyZz ŐőŰű", so All Caps
  shows the double acute capitals.
- Tests: locale resolution and saved preference, key parity with the
  Spanish catalog, sample translations, count wording, the sample's
  capitals and Hungarian letters in the bundled interface fonts.
- Docs: new localization-hu.md (conventions, terminology, scope);
  README, ROADMAP, localization-parity and control-protocol list the
  new language; ATTRIBUTION row for hu.tsv.

* i18n(hu): built-in style names, equation gallery and citation styles

- hu.tsv now carries every key of the Russian catalog: built-in style
  names (Normal, No Spacing, Subtitle, TOC {n}…), the equation gallery
  and structure labels, paper sizes, watermarks and the Backstage
  greetings, plus the citation style names (1,946 entries).
- The interface audit (untranslated_interface_text) checks Hungarian
  alongside Russian and reports every language's gaps in one run.
- Tests: Hungarian keys cover the Russian catalog; built-in style
  names and numbered style templates show in Hungarian.
- Docs: entry counts and scope in localization-hu, localization-parity
  and ROADMAP.

* Review fixes for #731: Hungarian stays a partial catalog

- The i18n audit requires completeness from Russian only again: hu.tsv lacks ~280 strings of the
  dialogs that landed since (Compare Documents, Math AutoCorrect, …), so it can't claim to be
  complete. The catalog test no longer asserts it holds every Russian/Spanish key.
- 43 Hungarian rows for tab and command labels that reached main since (charts, content controls,
  Developer tab, templates and the styles organizer, WordArt), which every_tab_and_command_is_translated
  requires.
- Docs say partial, with the entry count (1,989); localization-parity's header keeps its quote
  marker and the #505 note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Review fixes for #731: Hungarian rows for the Outlining tab

24 rows for Outline view's tab and commands, which landed on main meanwhile; 2,013 entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Review fixes for #731: ROADMAP header keeps main's SmartArt note

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* i18n(hu): complete the Hungarian catalog again

- hu.tsv: 374 new rows for the strings that reached main while #731 was
  in review (Compare Documents, Restrict Editing, Math AutoCorrect,
  charts, SmartArt, the Options sections, the print page and more).
  The catalog now holds every key of ru.tsv again: 2,397 entries.
- The completeness checks are back: the interface audit requires
  Hungarian alongside Russian, and the catalog test asserts hu.tsv holds
  every key of ru.tsv and es.tsv. The docs describe a complete catalog.
- Seven review rows follow the catalog's existing patterns: Text Pane
  (Szöveg panel, like the other panes), Design Mode (Tervezőmód, one
  compound), Picture and Date Picker Content Control (clearer compounds),
  Promote to Heading 1 / Demote to Body Text (style name after a colon,
  no case ending) and Reset Graphic (Ábra visszaállítása, shorter).

* Hungarian: translate interface strings added on main since this PR

Adds the 10 strings main gained with Polish proofing (spelling and grammar
messages, Do Not Check Spelling or Grammar, comment/browse buttons), so
hu.tsv again covers every key of the other catalogs (2,419 entries), and
drops the stale "Wildcards (regex)" row; updates the documented counts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <brandon@storyteller.ai>
This commit is contained in:
authored and GitHub committed 2026-10-12 06:45:30 -04:00
1 parent feaff0f22b
commit e22ce1d05e
10 files changed
+2648 -22

No files matched your search

+1
View File
@@ -70,4 +70,5 @@ Generated-in-code art is original and has no file to list: the UI icon set (`cra
| `crates/ui-egui/src/i18n/de.tsv` | @arekown with Kimi | Original translation from the English interface labels in this repository; no other product localisation copied | MIT OR Apache-2.0 | German interface catalog |
| `crates/ui-egui/src/i18n/ru.tsv` | Dmitrii Khlapov with Claude | Original translation from the English interface labels in this repository; no other product localisation copied | MIT OR Apache-2.0 | Russian interface catalog; reviewed by a native speaker |
| `crates/ui-egui/src/i18n/tr.tsv` | @PbyLoyth with Codex and Claude Code | Original translation from the English interface labels in this repository; no other product localisation copied | MIT OR Apache-2.0 | Turkish interface catalog |
| `crates/ui-egui/src/i18n/hu.tsv` | @Skaywalker | Original translation from the English interface labels in this repository; no other product localisation copied | MIT OR Apache-2.0 | Hungarian interface catalog |
| `crates/ui-egui/src/i18n/fr.tsv` | @pechnikov2026-star | Original translation from the English interface labels in this repository; no other product localisation copied | MIT OR Apache-2.0 | French interface catalog |
+1 -1
View File
@@ -117,7 +117,7 @@ Every screenshot below is WordCraft itself, rendered offscreen by its own UI tes
| **References** | Table of contents, footnotes and endnotes, citations and bibliography (APA, MLA, Chicago, IEEE), captions, table of figures, cross-references, index, table of authorities |
| **Review** | Spelling and grammar with suggestions (English and Polish, by each run's language), thesaurus, word count, comments in margin balloons or a pane, track changes, accept/reject, compare documents, restrict editing, accessibility checker, document inspector |
| **Mailings** | Mail merge from CSV, merge fields, address block, greeting line, rules, preview, finish to a document; envelopes and labels |
| **View** | Print layout, web layout, draft, read mode, focus, zoom, one/multiple pages, page width, Navigation pane, rulers, gridlines, dark mode; interface in English, 简体中文, 繁體中文, 日本語, Português (Brasil), Español, Українська, Српски / Srpski, Eesti, Türkçe, Русский, Italiano, Deutsch, Polski, Čeština or Français (follows the system language by default) |
| **View** | Print layout, web layout, draft, read mode, focus, zoom, one/multiple pages, page width, Navigation pane, rulers, gridlines, dark mode; interface in English, 简体中文, 繁體中文, 日本語, Português (Brasil), Español, Українська, Српски / Srpski, Eesti, Türkçe, Русский, Italiano, Deutsch, Polski, Čeština, Magyar or Français (follows the system language by default) |
| **Files** | .docx read/write (opens in Word), Word 97-2003 .doc import, PDF export, .odt, .rtf, .html, .md, .tex, .txt import/export, page images |
The honest picture, area by area, is in [ROADMAP.md](ROADMAP.md), the
+6 -3
View File
@@ -2,7 +2,7 @@
**Stage: alpha** · next: beta, ~15 points (60% → 75% ready for real work) and ~150–230 h away
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** trivial (Reading Mode completed; previously trivial: Insert › SmartArt landed, #497: catalog 429/451 → 437/458 (95.4%); previously trivial: Turkish interface landed; previously trivial: formatting revisions landed, #41; previously trivial: Draw tab ink, #307, and Draw Table and Eraser, #303, landed: catalog 402/434; previously minor: readiness table with hours per audience; full number back to the additive weighted sum, 60%; mainstream and essentials numbers added; alpha gate checked; previously major: full re-measure against Word for Mac 16.113.4; restructured to the craftrules progress-docs standard) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** trivial (Hungarian interface landed; previously minor: Polish interface and Polish proofing; previously trivial: table borders and the resize handle drag on the page, #217; previously trivial: Turkish interface landed; previously trivial: formatting revisions landed, #41; previously trivial: Draw tab ink, #307, and Draw Table and Eraser, #303, landed: catalog 402/434; previously minor: readiness table with hours per audience; full number back to the additive weighted sum, 60%; mainstream and essentials numbers added; alpha gate checked; previously major: full re-measure against Word for Mac 16.113.4; restructured to the craftrules progress-docs standard) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
WordCraft aims for complete parity with Microsoft Word, then goes further on speed, openness and
agent control. This page is the summary; the assessment is
@@ -102,7 +102,7 @@ Weights and evidence per area: [docs/target-app-parity.md](docs/target-app-parit
| Spanish | es | partial | ~95% |
| Hindi | hi | none | 0% |
| Arabic | ar | none (document shaping and bidi work; no mirrored UI) | 0% |
| French | fr | none | 0% |
| French | fr | partial (interface) | ~95% |
| Portuguese | pt-br (pt-PT none) | partial | ~95% |
| Indonesian | id | none | 0% |
| Japanese | ja | partial | ~95% |
@@ -111,7 +111,8 @@ Weights and evidence per area: [docs/target-app-parity.md](docs/target-app-parit
| Vietnamese | vi | none | 0% |
Also shipped: Traditional Chinese (`zh-hant`), Ukrainian (`uk`), Serbian (`sr`, `sr-latn`, #250), Russian (`ru`) and Polish (`pl`), all partial (~95%). Estonian (`et`), Turkish (`tr`), Italian (`it`, #594) and Czech (`cs`) now have complete interface catalogs with
system-locale selection and a saved language choice (Italian also has 51 strings none of the others had yet); Estonian, Turkish, Italian and Czech proofing are not included.
system-locale selection and a saved language choice (Italian also has 51 strings none of the others had yet); Estonian, Turkish, Italian and Czech proofing are not included. Hungarian (`hu`) has a
complete 2,419-entry catalog, also without proofing.
Proofing: English and Polish (spelling, grammar, hyphenation), chosen per run from its language. Word ships
30 interface languages and proofing for ~50. Detail: [docs/localization-parity.md](docs/localization-parity.md).
@@ -193,6 +194,7 @@ Ranked, to beta (detail and remaining milestones in [docs/roadmap.md](docs/roadm
| 2026-10-12 | Native saves use exclusively created sibling temporary files, synchronize before replacement and clean up on failure; existing temporary-name files/links and original files on failed saves are protected. Synthetic CLI and focused tests on macOS; no new Word parity or readiness claim. |
| 2026-10-11 | Field codes like Word's field keys (#339): show codes (Alt+F9, Shift+F9), edit, unlink, lock and step through fields |
| 2026-10-11 | Word's common keyboard shortcuts (#330): 101 → 125 of ~250 |
| 2026-10-11 | Hungarian (`hu`) interface: all 2,419 catalog entries, built-in style names translated, `hu-HU` system locales and a saved language choice; locale, catalog and bundled-font tests; no Hungarian proofing resources |
| 2026-10-11 | Turkish (`tr`) interface: all 1,307 catalog entries, `tr-TR`/`tr-CY` system locales and a saved language choice; command search keeps Turkish dotted and dotless I apart (`italik` finds İtalik); locale, catalog, search and bundled-font tests; no Turkish proofing resources |
| 2026-10-11 | Italian (`it`) interface (#594): 2,399 entries, feature names as Italian Word users know them, locale and saved-preference tests, bundled-font checks; no Italian proofing resources |
| 2026-10-11 | Citations and bibliography in all 12 of Word's styles: Harvard, ISO 690 (author-date and numerical), Turabian, GB/T 7714, GOST (name and title sort) and SIST02 join APA, MLA, Chicago and IEEE; numbered styles count in order of first citation (#383) |
@@ -254,6 +256,7 @@ Ranked, to beta (detail and remaining milestones in [docs/roadmap.md](docs/roadm
| 2026-10-12 | trivial | Native saves protect existing temporary-name entries and originals on pre-replacement failure; synthetic macOS evidence, explicit durability/platform limits; readiness unchanged |
| 2026-10-11 | trivial | Word's common keyboard shortcuts (#330): 125 of ~250 |
| 2026-10-11 | trivial | Collapsed duplicate rows left by parallel merges |
| 2026-10-11 | trivial | Hungarian interface (`hu`): progress log and shipped languages |
| 2026-10-11 | trivial | Turkish interface (`tr`): progress log and shipped languages |
| 2026-10-11 | trivial | Progress log: eight more bibliography styles (#383) |
| 2026-10-10 | trivial | Progress log: Draw tab ink (#307) |
+15 -8
View File
@@ -311,12 +311,13 @@ fn untranslated_interface_text() {
report.push_str(&format!("{:?} [{}]\n", pseudo::unmarked(text), states.join(", ")));
}
assert!(found.is_empty(), "{} interface texts skip translation (wrap them in tl!):\n{report}", found.len());
russian_has_every_string_the_interface_looked_up(pseudo::looked_up());
complete_catalogs_have_every_string_the_interface_looked_up(pseudo::looked_up());
}
/// Russian covers everything the audit saw translated, plus the equation gallery's labels (shown
/// in menus the audit doesn't open one by one). Numbered style names go through a template.
fn russian_has_every_string_the_interface_looked_up(mut keys: std::collections::BTreeSet<String>) {
/// Russian and Hungarian cover everything the audit saw translated, plus the equation gallery's
/// labels (shown in menus the audit doesn't open one by one). Numbered style names go through a
/// template.
fn complete_catalogs_have_every_string_the_interface_looked_up(mut keys: std::collections::BTreeSet<String>) {
use wordcraft_engine::math_gallery::{BUILT_INS, STRUCTURES, SYMBOL_SETS};
keys.extend(BUILT_INS.iter().map(|(_, label, _)| label.to_string()));
keys.extend(SYMBOL_SETS.iter().map(|(name, _)| name.to_string()));
@@ -327,10 +328,16 @@ fn russian_has_every_string_the_interface_looked_up(mut keys: std::collections::
keys.extend(templates.iter().map(|t| t.label.to_string()));
}
}
let ru = super::Lang::from_code("ru").unwrap_or(super::Lang::EN);
let numbered = |s: &str| ["Heading ", "TOC "].iter().any(|p| s.strip_prefix(p).is_some_and(|n| n.chars().all(|c| c.is_ascii_digit())));
// Names that read the same in Russian.
// Names that read the same in these languages.
let same = |s: &str| matches!(s, "LaTeX" | "LaTeX (*.tex)" | "Unicode" | "I. II. III." | "i. ii. iii.");
let missing: Vec<String> = keys.into_iter().filter(|s| english_words(s) && !super::has(ru, s) && !numbered(s) && !same(s)).collect();
assert!(missing.is_empty(), "{} strings have no Russian entry:\n{missing:#?}", missing.len());
let mut report = String::new();
for code in ["ru", "hu"] {
let lang = super::Lang::from_code(code).unwrap_or(super::Lang::EN);
let missing: Vec<&String> = keys.iter().filter(|s| english_words(s) && !super::has(lang, s) && !numbered(s) && !same(s)).collect();
if !missing.is_empty() {
report.push_str(&format!("{} strings have no {code} entry:\n{missing:#?}\n", missing.len()));
}
}
assert!(report.is_empty(), "{report}");
}
File diff suppressed because it is too large. Load diff
+3 -1
View File
@@ -52,7 +52,7 @@ pub struct LangInfo {
}
/// The registry. English first: it is the fallback and the source language.
pub static LANGUAGES: [LangInfo; 17] = [
pub static LANGUAGES: [LangInfo; 18] = [
LangInfo { code: "en", name: "English", source: "", prefer_hans: false, editing_lang: None, catalog: OnceLock::new() },
// Simplified Chinese; `zh`, `zh-CN`, `zh-SG` and `zh-Hans-*` resolve here (see `candidates`).
LangInfo {
@@ -121,6 +121,8 @@ pub static LANGUAGES: [LangInfo; 17] = [
LangInfo { code: "tr", name: "Türkçe", source: include_str!("tr.tsv"), prefer_hans: false, editing_lang: None, catalog: OnceLock::new() },
// Italian; `it-IT`, `it-CH` and `it-*` resolve here.
LangInfo { code: "it", name: "Italiano", source: include_str!("it.tsv"), prefer_hans: false, editing_lang: None, catalog: OnceLock::new() },
// Hungarian; `hu`, `hu-HU` and `hu_HU.UTF-8` resolve here.
LangInfo { code: "hu", name: "Magyar", source: include_str!("hu.tsv"), prefer_hans: false, editing_lang: None, catalog: OnceLock::new() },
// French; `fr`, `fr-FR`, `fr_CA` and other regions resolve here.
LangInfo { code: "fr", name: "Français", source: include_str!("fr.tsv"), prefer_hans: false, editing_lang: None, catalog: OnceLock::new() },
];
+83 -2
View File
@@ -753,6 +753,87 @@ fn bundled_interface_fonts_cover_turkish_without_system_fallbacks() {
assert!(!lang("tr").uses_cjk());
}
#[test]
fn hungarian_locales_and_saved_preference_work_without_changing_the_document() {
let hu = lang("hu");
for tag in ["hu", "hu-HU", "hu_HU.UTF-8", "HU_hu.UTF-8@euro", "hu-Latn-HU"] {
assert_eq!(lang_from_tag(tag), Some(hu), "{tag}");
}
assert_eq!(first_supported(["sv-SE", "hu-HU", "en-US"]), Some(hu));
assert_eq!(normalize_pref("HU"), Some("hu"));
let mut app = crate::WordApp::new(wordcraft_engine::Session::new(wordcraft_engine::sample::sample_document()), Default::default());
let before = serde_json::to_value(&app.session.doc).unwrap();
let result = app.run("ui.language", serde_json::json!({"value": "hu"})).unwrap();
assert_eq!(result["effective"], "hu");
assert!(result["available"].as_array().unwrap().iter().any(|l| l["code"] == "hu" && l["name"] == "Magyar"));
assert_eq!(serde_json::to_value(&app.session.doc).unwrap(), before);
let saved = serde_json::to_string(&app.ui).unwrap();
let restored: crate::UiState = serde_json::from_str(&saved).unwrap();
assert_eq!(Lang::from_pref(&restored.language), hu);
app.run("ui.language", serde_json::json!({"value": "auto"})).unwrap();
assert_eq!(app.ui.language, AUTO);
}
#[test]
fn hungarian_covers_the_entire_existing_interface_catalog() {
use std::collections::HashSet;
let keys = |source| parse_entries(source).0.into_iter().map(|e| e.source).collect::<HashSet<_>>();
// Every key of the most complete catalog: built-in style names, equation gallery labels, paper
// sizes and watermarks included.
assert!(keys(lang("hu").0.source).is_superset(&keys(lang("ru").0.source)));
assert!(keys(lang("hu").0.source).is_superset(&keys(lang("es").0.source)));
let hu = lang("hu");
for (source, expected) in [
("Home", "Kezdőlap"),
("Font", "Betűtípus"),
("Review", "Véleményezés"),
("Header", "Élőfej"),
("Track Changes", "Változáskövetés"),
("Save", "Mentés"),
("Redo", "Újra"),
("UPPERCASE", "NAGYBETŰS"),
("WordCraft", "WordCraft"),
("unknown future label", "unknown future label"),
] {
assert_eq!(super::tr(hu, source), expected);
}
assert_eq!(fmt(super::tr(hu, "Page {page} of {pages}"), &[("page", "3"), ("pages", "9")]), "Oldal: 3/9");
// A noun after a number stays singular in Hungarian, whatever the count.
for count in [0, 1, 2, 21, 1000] {
let words = count.to_string();
assert_eq!(fmt(super::tr(hu, "{words} words"), &[("words", &words)]), format!("{count} szó"));
}
// The Font dialog uppercases its preview sample for All Caps.
assert_eq!(super::tr(hu, "AaBbYyZz").to_uppercase(), "AABBYYZZ ŐŐŰŰ");
set_current(hu);
// Built-in styles show translated names; numbered families go through their template.
for (style, expected) in [("Normal", "Normál"), ("No Spacing", "Nincs térköz"), ("Heading 2", "Címsor 2"), ("TOC 3", "Tartalomjegyzék 3")] {
assert_eq!(builtin_style_name(style), expected);
}
assert_eq!(builtin_style_name("My Own Style"), "My Own Style");
assert_eq!(location("Home › Font"), "Kezdőlap › Betűtípus");
assert_eq!(prefixed("Undo", "Bold"), "Visszavonás: Félkövér");
set_current(Lang::EN);
}
#[test]
fn bundled_interface_fonts_cover_hungarian_without_system_fallbacks() {
let db = wordcraft_fonts::FontDb::with_font_dirs(Vec::new());
let (entries, errors) = parse_entries(lang("hu").0.source);
assert!(errors.is_empty());
let extra = "ÁáÉéÍíÓóÖöŐőÚúÜüŰű";
let chars: std::collections::HashSet<char> =
entries.iter().flat_map(|e| e.translation.chars()).filter(|c| extra.contains(*c)).chain(extra.chars()).collect();
for (family, style) in [("Inter", "Regular"), ("Inter", "Medium"), ("Inter", "SemiBold"), ("JetBrains Mono", "Regular")] {
let face = db.face(family, style);
assert_eq!(face.family, family, "must use the bundled interface face");
for ch in &chars {
assert_ne!(face.glyph_for(*ch), 0, "{family} {style} lacks {ch}");
}
}
assert!(!lang("hu").uses_cjk());
}
#[test]
fn french_locales_and_saved_preference_work_without_changing_the_document() {
let fr = lang("fr");
@@ -833,9 +914,9 @@ fn polish_covers_every_key_of_every_other_catalog() {
use std::collections::HashSet;
let keys = |source| parse_entries(source).0.into_iter().map(|e| e.source).collect::<HashSet<_>>();
let polish = keys(lang("pl").0.source);
// Russian and Italian also translate the built-in style names and the equation gallery,
// Russian, Italian and Hungarian also translate the built-in style names and the equation gallery,
// which the others don't yet; Polish matches every other catalog.
for other in Lang::all().filter(|l| *l != Lang::EN && !matches!(l.code(), "pl" | "ru" | "it")) {
for other in Lang::all().filter(|l| *l != Lang::EN && !matches!(l.code(), "pl" | "ru" | "it" | "hu")) {
let mut missing: Vec<String> = keys(other.0.source).difference(&polish).cloned().collect();
missing.sort();
assert!(missing.is_empty(), "pl lacks {}'s {missing:?}", other.code());
+1 -1
View File
@@ -50,7 +50,7 @@ and set `WORDCRAFT_CONTROL_KEY` to that app's key.
| Method | Params | Result |
|---|---|---|
| `engine.execute` | `command`, `params` | the command's result (any id from `engine.commands`, including UI commands `ui.tab`, `ui.dialog`, `ui.backstage`, `ui.zotero.*` (see `docs/zotero.md`), `ui.language` (`{"value": "auto"|"en"|"zh-hans"|"zh-hant"|"ja"|"pt-br"|"es"|"uk"|"sr"|"sr-latn"|"et"|"tr"|"ru"|"pl"|"de"|"it"|"cs"|"fr"}`), `ui.theme` (`{"value": "system"|"light"|"dark"}`; `system` follows the OS appearance, light when it reports none), `ui.interfaceSize` (`{"percent": 80–200}`, clamped; no value reads it; scales the interface on top of the system display scale, document zoom stays `view.zoom`), `ui.animations` (`{"value": "system"|"on"|"off"}`; no value reads it; `system` follows the system's animation setting, which the desktop app reads on Windows, macOS, Linux and the BSDs and the web app from `prefers-reduced-motion`, and means on where the system doesn't say; the result's `enabled` is what the setting comes to and `system` what the system reports, `null` when it doesn't say), `ui.fileBrowser` (desktop: `{"purpose": "document"|"picture"|"recipients"|"save"}` opens WordCraft's own file browser, for when the system file dialog doesn't show up, #576), `ui.caretAnimation` (`{"value": true|false}`; no value reads it; off, the caret jumps and blinks on and off instead of gliding and fading)…) |
| `engine.execute` | `command`, `params` | the command's result (any id from `engine.commands`, including UI commands `ui.tab`, `ui.dialog`, `ui.backstage`, `ui.zotero.*` (see `docs/zotero.md`), `ui.language` (`{"value": "auto"|"en"|"zh-hans"|"zh-hant"|"ja"|"pt-br"|"es"|"uk"|"sr"|"sr-latn"|"et"|"tr"|"ru"|"pl"|"de"|"it"|"cs"|"hu"|"fr"}`), `ui.theme` (`{"value": "system"|"light"|"dark"}`; `system` follows the OS appearance, light when it reports none), `ui.interfaceSize` (`{"percent": 80–200}`, clamped; no value reads it; scales the interface on top of the system display scale, document zoom stays `view.zoom`), `ui.animations` (`{"value": "system"|"on"|"off"}`; no value reads it; `system` follows the system's animation setting, which the desktop app reads on Windows, macOS, Linux and the BSDs and the web app from `prefers-reduced-motion`, and means on where the system doesn't say; the result's `enabled` is what the setting comes to and `system` what the system reports, `null` when it doesn't say), `ui.fileBrowser` (desktop: `{"purpose": "document"|"picture"|"recipients"|"save"}` opens WordCraft's own file browser, for when the system file dialog doesn't show up, #576), `ui.caretAnimation` (`{"value": true|false}`; no value reads it; off, the caret jumps and blinks on and off instead of gliding and fading)…) |
| `engine.commands` | — | every command: id, label, location, shortcut, params, enabled |
| `document.inspect` | `text?` | blocks (text, style, runs, lists, tables), parts, sections, selection, pages |
| `ui.inspect` | — | UI state, view, dialog, window size, page rects on screen, caret, comment balloons (`balloons`: id + screen rect; `balloon`: the selected one), perf |
+75
View File
@@ -0,0 +1,75 @@
# Hungarian interface
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-11 · **Change:** minor (Hungarian interface catalog and regression checks) · **Target:** WordCraft 0.5.0
Choose **File › Options › Interface language › Magyar**, or follow a Hungarian system display
language (`hu-HU`, `hu_HU.UTF-8`). The catalog code is `hu`; `ui.language` with `{"value":"hu"}`
selects it explicitly, and `WORDCRAFT_LANGUAGE=hu-HU` does the same for a headless screenshot or a
launch while the preference is `auto`. The choice is saved with the other interface settings.
Document text, command ids, CLI/MCP/control responses and file paths do not change.
`crates/ui-egui/src/i18n/hu.tsv` has 2,419 entries: every key of the Russian catalog (built-in style
names, equation gallery labels, paper sizes, watermarks and greetings included) plus the citation
style names. It is written from the meaning of the English labels; no proprietary translation resources were consulted. The catalog
format has no plural forms, and Hungarian doesn't need them: a noun after a number stays singular
(`0 szó`, `1 szó`, `21 szó`). Placeholders, `\n` breaks in ribbon labels and dialog ellipses are
kept, and strings added later fall back to English until they are translated.
## Conventions
- Commands are nouns (`Mentés`, `Másolás`, `Beillesztés`); messages address the user with the
informal second person (`Mentsd a dokumentumot`).
- Only the first word of a label is capitalised, as Hungarian spelling requires
(`Összes módosítás elfogadása`).
- Decimal comma (`1,5-es sorköz`) and Hungarian quotation marks („…”).
- A placeholder never takes a case ending, because the value is not known when the text is
written. The wording puts it after a colon or in parentheses instead
(`Undo {action}` → `Visszavonás: {action}`, `Couldn't open {path}: {error}` →
`Nem sikerült megnyitni: {path} ({error})`).
- Text columns and table columns are different words: `Hasábok` (Layout › Columns, column break)
and `Oszlopok` (table rows and columns).
## Terminology
| Source | Hungarian |
|---|---|
| Home / Insert / Draw / Design / Layout | Kezdőlap / Beszúrás / Rajzolás / Tervezés / Elrendezés |
| References / Mailings / Review / View / Help | Hivatkozások / Levelezés / Véleményezés / Nézet / Súgó |
| Font / Paragraph / Styles | Betűtípus / Bekezdés / Stílusok |
| Header / Footer / Heading | Élőfej / Élőláb / Címsor |
| Footnote / Endnote / Caption | Lábjegyzet / Végjegyzet / Felirat |
| Table of Contents / Index | Tartalomjegyzék / Tárgymutató |
| Citation / Bibliography | Forráshivatkozás / Irodalomjegyzék |
| Link / Hyperlink | Link |
| Track Changes / Accept / Reject | Változáskövetés / Elfogadás / Elutasítás |
| Comment / Markup | Megjegyzés / Jelölések |
| Mail Merge / Recipients / Merge Field | Körlevél / Címzettek / Egyesítési mező |
| Columns (text) / Columns (table) | Hasábok / Oszlopok |
| Section / Section Break | Szakasz / Szakasztörés |
| Undo / Redo / Repeat | Visszavonás / Újra / Ismétlés |
| Undo {action} | Visszavonás: {action} |
| Page {page} of {pages} | Oldal: {page}/{pages} |
| Ribbon / Pane / Quick Access Toolbar | Menüszalag / Panel / Gyorselérési eszköztár |
| Proofing / Word Count | Nyelvi ellenőrzés / Szavak száma |
Product and format names stay as they are (WordCraft, PDF, DOCX, Markdown, MCP, Zotero). The Font
dialog's preview sample is `AaBbYyZz ŐőŰű`, so the All Caps preview shows the Hungarian double
acute capitals.
## Verification and remaining scope
`cargo test -p wordcraft-ui-egui --lib i18n::tests` covers Hungarian locale tags and preference
order, saving and restoring `hu`, unchanged document content, every key of the Russian catalog,
built-in style names, placeholders, count wording, the font sample's capitals, English fallback,
and the glyphs `ÁáÉéÍíÓóÖöŐőÚúÜüŰű` in the bundled Inter (Regular, Medium, SemiBold) and JetBrains Mono. The shared catalog checks
(validation, every tab and command translated) include Hungarian automatically, and the on-demand
interface audit (`untranslated_interface_text`) checks Hungarian alongside Russian.
Spelling, grammar and hyphenation stay English-only: this is an interface translation, not
Hungarian proofing. A native-speaker review of the catalog is welcome.
## Revision history
| Date | Change | Summary |
|---|---|---|
| 2026-10-11 | minor | Hungarian catalog (2,419 entries: built-in style names, equation gallery, citation styles), conventions, terminology, scope and regression checks |
+10 -6
View File
@@ -1,6 +1,6 @@
# Localization parity with Microsoft Word
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (French interface added; previously minor: Polish interface; Polish proofing — spelling, grammar, hyphenation — and a proofing language per run; previously minor: Turkish interface added; previously major: first version; catalogs measured from `crates/ui-egui/src/i18n`, Word's languages from its bundle listing) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (Hungarian interface added; previously minor: Polish interface; Polish proofing — spelling, grammar, hyphenation — and a proofing language per run; previously minor: Turkish interface added; previously major: first version; catalogs measured from `crates/ui-egui/src/i18n`, Word's languages from its bundle listing) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
Interface languages, script support and proofing per language. How translation works (catalog
format, adding a language, clean-room rule): `crates/ui-egui/src/i18n/mod.rs`.
@@ -19,9 +19,9 @@ native-speaker review (human).
## What WordCraft ships (measured)
- **17 interface languages**: English plus `zh-hans`, `zh-hant`, `ja`, `uk`, `es`, `pt-br`,
Serbian `sr`/`sr-latn` (#250), Estonian `et`, Turkish `tr`, Russian `ru`, Italian `it` (#594), German `de` (#574), Polish `pl`, Czech `cs` and French `fr`. Catalogs have 2,021–2,399 entries
each; Polish has every key of every other catalog (a test checks it). A test (`every_tab_and_command_is_translated`) enforces that every ribbon tab, command
- **18 interface languages**: English plus `zh-hans`, `zh-hant`, `ja`, `uk`, `es`, `pt-br`,
Serbian `sr`/`sr-latn` (#250), Estonian `et`, Turkish `tr`, Russian `ru`, Italian `it` (#594), German `de` (#574), Polish `pl`, Czech `cs`, Hungarian `hu` and French `fr`. Catalogs have 2,021–2,419 entries
each; Polish has every key of every other catalog except the style names and equation gallery labels only Russian, Italian and Hungarian translate so far (a test checks it). A test (`every_tab_and_command_is_translated`) enforces that every ribbon tab, command
label and ribbon location is translated in every language.
`pl`, `pl-PL` and `pl_PL.UTF-8` system locales pick Polish automatically.
- Of the 675 English strings a scan extracts from `tl!(…)` calls and command labels/locations, each
@@ -57,8 +57,8 @@ shared items below.
| Korean | ko | 0 | ❌ | Hangul ✅; macOS Korean IME fixes pending (#163, #164) | no | none | 3–5 |
| Vietnamese | vi | 0 | ❌ | Latin with stacked diacritics, untested | no | none | 3–4 |
Other shipped languages: **10** — Traditional Chinese (`zh-hant`), Ukrainian (`uk`), Serbian
Cyrillic and Latin (`sr`, `sr-latn`, #250), Estonian (`et`), Turkish (`tr`), Russian (`ru`), Italian (`it`, #594), Polish (`pl`) and Czech (`cs`), all partial.
Other shipped languages: **12** — Traditional Chinese (`zh-hant`), Ukrainian (`uk`), Serbian
Cyrillic and Latin (`sr`, `sr-latn`, #250), Estonian (`et`), Turkish (`tr`), Russian (`ru`), Italian (`it`, #594), Polish (`pl`), Czech (`cs`), Hungarian (`hu`) and French (`fr`), all partial.
Estonian uses the existing fonts, follows `et-EE` system locales, and is available in Options or
through `ui.language` with `{"value":"et"}`. Its 1,307 entries cover the existing interface catalog.
Estonian spelling, grammar, dates and document templates are not added by the interface catalog.
@@ -66,6 +66,9 @@ Turkish works the same way (`tr-TR` and `tr-CY` system locales, `{"value":"tr"}`
entries. Command search folds the Turkish dotted and dotless I (`italik` finds İtalik, `YAZI TİPİ`
finds Yazı Tipi) while English labels and ASCII command ids keep their usual matching. Turkish
proofing is not included; terminology and checks: [`localization-tr.md`](localization-tr.md).
Hungarian follows `hu-HU` system locales and `{"value":"hu"}`, with a complete catalog of 2,419 entries: every key of
the Russian catalog, built-in style names shown translated, plus the citation style names. Hungarian proofing is not included; terminology and conventions:
[`localization-hu.md`](localization-hu.md).
Polish is the only one besides English with proofing tools, and a Polish interface writes new
documents in Polish (`pl-PL`).
@@ -111,6 +114,7 @@ allows); all other text is written from the meaning of the English. No Italian p
| 2026-10-11 | minor | Font list shows installed fonts by their names in the interface language (宋体 for SimSun in Chinese, Japanese and Korean names likewise) and finds them by either name; a Chinese, Japanese or Korean font is stored as `w:eastAsia` too (#505) |
| 2026-10-11 | minor | Chinese/Japanese interface fonts: a test checks every catalog character has a glyph; an installed CJK font follows the embedded faces whenever they miss one; macOS font asset folders searched for PingFang (#486) |
| 2026-10-10 | minor | Russian interface (#300; 1,524 entries, built-in style names shown translated; covers everything the interface audit finds) |
| 2026-10-11 | minor | Hungarian interface catalog (2,419 entries, built-in style names shown translated; covers everything the interface audit finds), locale selection, saved preference and font coverage checks |
| 2026-10-11 | minor | Turkish interface catalog (1,307 entries), locale selection, saved preference, Turkish casing in command search and font coverage checks; catalog sizes re-counted |
| 2026-10-11 | trivial | English spelling (#520): our supplement `assets/spelling/en-extra.txt` adds ~220 common modern words the Moby list lacks ("desktop", "download", "email"…) |
| 2026-10-10 | minor | Estonian interface catalog, locale selection, saved preference and font coverage checks; count labels put the noun first so they read right at 1 |