Add complete Italian UI localization (#1941)

* Add complete Italian UI localization

Translate all 1509 English catalog entries originally, register Italiano, guard complete coverage and exercise Italian labels and UI rendering.

Co-authored-by: Copilot App <[email protected]>

* i18n: Italian is a partial catalog

it.json lacks 19 messages main has gained since this branch began, so as a
complete catalog it would fail every_complete_catalog_carries_every_english_message.
Like the other community languages, Italian is now partial: its gaps fall
back to English and new labels don't require an Italian string. The docs
line goes back to main's wording, with Italian among the partial catalogs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM

---------

Co-authored-by: Copilot App <[email protected]>
Co-authored-by: Ben Herbruck <[email protected]>
Co-authored-by: bherbruck <[email protected]>
Co-authored-by: jyviko <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
authored and GitHub committed 2026-10-17 22:28:04 -04:00
1 parent c39bd23d07
commit 48986041ed
5 files changed
+1595 -5

No files matched your search

+1
View File
@@ -93,6 +93,7 @@ Editable drawing code, native projects and shipped exports are collected under `
| assets/locales/es.json | jawler | Spanish (Spain) translation of the English catalog, contributed upstream | MIT OR Apache-2.0 |
| assets/locales/fr.json | rlartot | French translation of the English catalog, contributed upstream | MIT OR Apache-2.0 |
| assets/locales/gl.json | Pablo López (pablopeza) | Galician translation of the English catalog, contributed upstream | MIT OR Apache-2.0 |
| assets/locales/it.json | SolidCraft contributors | Original Italian translation of SolidCraft's English catalog; no commercial CAD text used | MIT OR Apache-2.0 |
| assets/locales/ja.json | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 |
| assets/locales/ko.json | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 |
| assets/locales/ru.json | Alex Pro (del000) | Russian translation of the English catalog, contributed upstream | MIT OR Apache-2.0 |
File diff suppressed because it is too large. Load diff
+37 -2
View File
@@ -37,6 +37,7 @@ static GERMAN: Catalog = Catalog::new("de", "Deutsch", include_str!(concat!(env!
static SPANISH: Catalog = Catalog::new("es", "Español (España)", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../../assets/locales/es.json")));
static FRENCH: Catalog = Catalog::new("fr", "Français", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../../assets/locales/fr.json")));
static GALICIAN: Catalog = Catalog::new("gl", "Galego", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../../assets/locales/gl.json")));
static ITALIAN: Catalog = Catalog::new("it", "Italiano", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../../assets/locales/it.json")));
static JAPANESE: Catalog = Catalog::new("ja", "日本語", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../../assets/locales/ja.json")));
static KOREAN: Catalog = Catalog::new("ko", "한국어", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../../assets/locales/ko.json")));
static PORTUGUESE_BR: Catalog =
@@ -55,6 +56,7 @@ pub const LOCALES: &[&Catalog] = &[
&SPANISH,
&FRENCH,
&GALICIAN,
&ITALIAN,
&JAPANESE,
&KOREAN,
&PORTUGUESE_BR,
@@ -238,8 +240,8 @@ mod tests {
ENGLISH.messages().values().map(String::as_str).collect()
}
/// Catalogs delivered complete. English is the source catalog; Japanese was completed
/// upstream, Chinese and Czech land complete here. German, Korean, Russian, French and Ukrainian
/// Catalogs delivered complete. English is the source catalog; Czech, Italian, Japanese and Chinese
/// are complete. German, Korean, Russian, French and Ukrainian
/// are partial (German and Korean predate the coverage guards; Russian, French and Ukrainian
/// are kept partial so a new label doesn't need more translations), so their gaps fall back
/// to English and are reported by `cargo xtask i18n` without failing the build, while
@@ -392,6 +394,39 @@ mod tests {
assert_eq!(Locale(&PARTIAL).text("ui.extrude"), "Extrude");
}
#[test]
fn italian_labels_templates_and_names_preserve_technical_values() {
assert!(is_supported("it"));
let it = Locale::for_language("it");
assert_eq!(it.name(), "Italiano");
for (source, expected) in [
("Sketch", "Schizzo"),
("Extrude", "Estrusione"),
("Fillet", "Raccordo"),
("Chamfer", "Smusso"),
("Body", "Corpo"),
("New Component", "Nuovo componente"),
("CONSTRAINTS", "VINCOLI"),
("Draft", "Sformo"),
("Counterbore", "Lamatura"),
("Countersink", "Svasatura"),
] {
assert_eq!(it.label(source), expected, "{source}");
}
assert_eq!(it.dynamic("Sketch12"), "Schizzo12");
assert_eq!(it.dynamic("Body2"), "Corpo2");
assert_eq!(it.dynamic("Component3"), "Componente3");
assert_eq!(it.dynamic("Units: mm"), "Unità: mm");
assert_eq!(it.dynamic("4 degrees of freedom"), "4 gradi di libertà");
assert_eq!(it.given_name("Fillet"), "Fillet");
assert_eq!(it.label("solid.extrude"), "solid.extrude");
assert_eq!(it.format("document.save_changes", &[("name", "Staffa {v2}")]), "Salvare le modifiche a Staffa {v2}?");
assert_eq!(
it.format("ui.command_palette_hint", &[("example", "solid.extrude {\"distance\": 20}")]),
"Digita un comando, ad es. solid.extrude {\"distance\": 20} — oppure premi S per cercare"
);
}
/// `label()`'s id fallback (an argument that matches no other entry's English text is
/// looked up as an id directly) is how the Sketch Palette reaches `ui.palette_profile` and
/// `ui.palette_points` without colliding with "Profile" / "Points" elsewhere (see the
+35
View File
@@ -21,6 +21,24 @@ fn japanese_dialog_keeps_english_scenario_handles() {
assert!(h.widget("Cancel").is_some());
}
#[test]
fn italian_dialog_keeps_english_scenario_handles() {
let mut h = Harness::new();
h.app.preferences.language = "it".into();
h.app.home.open = false;
h.call("ui.start", json!({"command":"sketch.create"}));
h.frames(3);
assert!(h.widget("Piano").is_some());
assert!(h.widget("Annulla").is_some());
assert!(!scenario::handles("dialog:Plane").is_empty());
assert_eq!(crate::i18n::tr("ui.preferences"), "Preferences");
h.app.preferences.language = "en".into();
h.frames(3);
assert!(h.widget("Plane").is_some());
assert!(h.widget("Cancel").is_some());
}
#[test]
fn sketch_palette_profile_and_points_rows_show_their_own_translation() {
// ui.palette_profile / ui.palette_points are reached by id, not by the usual English-text
@@ -67,6 +85,7 @@ fn window_chrome_renders_in_the_active_language() {
("ko", "브라우저", "선택 필터", "면"),
("ru", "БРАУЗЕР", "Фильтр выделения", "Грани"),
("fr", "NAVIGATEUR", "Filtre de sélection", "Faces"),
("it", "STRUTTURA", "Filtro di selezione", "Facce"),
("uk", "БРАУЗЕР", "Фільтр виділення", "Грані"),
] {
let mut h = Harness::new();
@@ -135,6 +154,22 @@ fn home_page_renders_in_the_active_language() {
}
}
let cases = [
(
"it",
[
"Nuovo progetto",
"Apri…",
"Documentazione",
"Segnala un problema",
"Novità",
"Scorciatoie da tastiera",
"Preferenze",
"Recenti",
"Esempi",
"Piastra di esempio",
],
"non presente\nAperto 2 h fa",
),
(
"ja",
[
+11 -3
View File
@@ -1,7 +1,7 @@
# UI localization
SolidCraft embeds its translations and works offline. English, Japanese, German, French, Galician, Korean,
Brazilian Portuguese, Russian, Ukrainian, Turkish and Chinese are currently registered in `crates/ui-egui/src/i18n.rs`. Adding a language requires an
SolidCraft embeds its translations and works offline. English, Czech, German, Spanish, French, Galician, Italian,
Japanese, Korean, Brazilian Portuguese, Russian, Turkish, Ukrainian and Chinese are currently registered in `crates/ui-egui/src/i18n.rs`. Adding a language requires an
embedded catalog and one registration there; the preferences selector and validation use the same
registry.
@@ -31,7 +31,7 @@ that looks untranslated. Two guards catch that in the build:
- `every_complete_catalog_carries_every_english_message` — adding a key to `en.json`
without giving it to a complete catalog fails the tests. English is the source catalog,
Japanese and Chinese are delivered complete; German, Galician, Korean, Brazilian Portuguese, Russian, French, Ukrainian and
Japanese and Chinese are delivered complete; German, Spanish, Galician, Italian, Korean, Brazilian Portuguese, Russian, French, Ukrainian and
Turkish are partial — their gaps fall back to English and are reported by `cargo xtask i18n` without
failing the build. A new label needs en, ja, zh, de and ko; Russian, French and Ukrainian may
follow later.
@@ -59,6 +59,14 @@ claim it, or the English-text lookup would silently pick one.
## Rendering and coverage
The Italian catalog uses original translations of SolidCraft's English messages, not text
extracted from commercial CAD software. Its core terminology is Schizzo (Sketch),
Estrusione (Extrude), Raccordo (Fillet), Smusso (Chamfer), Corpo (Body), Componente
(Component) and Vincolo (Constraint). Draft geometry is Sformo, while a report draft
is Bozza; Counterbore is Lamatura and Countersink is Svasatura. Established technical
terms such as Loft, Sweep, Spline and Offset remain unchanged. Command IDs, shortcuts,
file formats, units and user-provided names are not translated.
One immutable `Locale` type handles all translations. Table widgets without an app reference
use a render scope that restores the previous locale when it exits, including nested renders.
Standalone translated panels enter the same scope. Measure rendered text to size custom