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:
5 files changed
+1595
-5
No files matched your search
@@ -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/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/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/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/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/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 |
|
| 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,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 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 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 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 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 KOREAN: Catalog = Catalog::new("ko", "한국어", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../../assets/locales/ko.json")));
|
||||||
static PORTUGUESE_BR: Catalog =
|
static PORTUGUESE_BR: Catalog =
|
||||||
@@ -55,6 +56,7 @@ pub const LOCALES: &[&Catalog] = &[
|
|||||||
&SPANISH,
|
&SPANISH,
|
||||||
&FRENCH,
|
&FRENCH,
|
||||||
&GALICIAN,
|
&GALICIAN,
|
||||||
|
&ITALIAN,
|
||||||
&JAPANESE,
|
&JAPANESE,
|
||||||
&KOREAN,
|
&KOREAN,
|
||||||
&PORTUGUESE_BR,
|
&PORTUGUESE_BR,
|
||||||
@@ -238,8 +240,8 @@ mod tests {
|
|||||||
ENGLISH.messages().values().map(String::as_str).collect()
|
ENGLISH.messages().values().map(String::as_str).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Catalogs delivered complete. English is the source catalog; Japanese was completed
|
/// Catalogs delivered complete. English is the source catalog; Czech, Italian, Japanese and Chinese
|
||||||
/// upstream, Chinese and Czech land complete here. German, Korean, Russian, French and Ukrainian
|
/// are complete. German, Korean, Russian, French and Ukrainian
|
||||||
/// are partial (German and Korean predate the coverage guards; 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
|
/// 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
|
/// 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");
|
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
|
/// `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
|
/// 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
|
/// `ui.palette_points` without colliding with "Profile" / "Points" elsewhere (see the
|
||||||
|
|||||||
@@ -21,6 +21,24 @@ fn japanese_dialog_keeps_english_scenario_handles() {
|
|||||||
assert!(h.widget("Cancel").is_some());
|
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]
|
#[test]
|
||||||
fn sketch_palette_profile_and_points_rows_show_their_own_translation() {
|
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
|
// 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", "브라우저", "선택 필터", "면"),
|
("ko", "브라우저", "선택 필터", "면"),
|
||||||
("ru", "БРАУЗЕР", "Фильтр выделения", "Грани"),
|
("ru", "БРАУЗЕР", "Фильтр выделения", "Грани"),
|
||||||
("fr", "NAVIGATEUR", "Filtre de sélection", "Faces"),
|
("fr", "NAVIGATEUR", "Filtre de sélection", "Faces"),
|
||||||
|
("it", "STRUTTURA", "Filtro di selezione", "Facce"),
|
||||||
("uk", "БРАУЗЕР", "Фільтр виділення", "Грані"),
|
("uk", "БРАУЗЕР", "Фільтр виділення", "Грані"),
|
||||||
] {
|
] {
|
||||||
let mut h = Harness::new();
|
let mut h = Harness::new();
|
||||||
@@ -135,6 +154,22 @@ fn home_page_renders_in_the_active_language() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let cases = [
|
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",
|
"ja",
|
||||||
[
|
[
|
||||||
|
|||||||
+11
-3
@@ -1,7 +1,7 @@
|
|||||||
# UI localization
|
# UI localization
|
||||||
|
|
||||||
SolidCraft embeds its translations and works offline. English, Japanese, German, French, Galician, Korean,
|
SolidCraft embeds its translations and works offline. English, Czech, German, Spanish, French, Galician, Italian,
|
||||||
Brazilian Portuguese, Russian, Ukrainian, Turkish and Chinese are currently registered in `crates/ui-egui/src/i18n.rs`. Adding a language requires an
|
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
|
embedded catalog and one registration there; the preferences selector and validation use the same
|
||||||
registry.
|
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`
|
- `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,
|
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
|
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
|
failing the build. A new label needs en, ja, zh, de and ko; Russian, French and Ukrainian may
|
||||||
follow later.
|
follow later.
|
||||||
@@ -59,6 +59,14 @@ claim it, or the English-text lookup would silently pick one.
|
|||||||
|
|
||||||
## Rendering and coverage
|
## 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
|
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.
|
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
|
Standalone translated panels enter the same scope. Measure rendered text to size custom
|
||||||
|
|||||||
Reference in new issue
Block a user