mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-25 18:27:02 -06:00
Merge pull request #515 from callmeBalloch/i18n-italian
Fix #514: Italian interface (it)
This commit is contained in:
@@ -194,7 +194,7 @@ milestones, and honest time-to-parity estimates.
|
||||
"a power user can't tell the difference". Everyday vector illustration is close to usable: drawing and path tools,
|
||||
Pathfinder and Shape Builder, paint, gradients, appearance and transparency, type with styles, threading and Hebrew/Arabic bidirectional layout, and
|
||||
files (SVG, PDF and PDF-compatible `.ai` with PDF/X, EPS, DXF, EMF/WMF, raster formats and PSD, Print, Package). The interface
|
||||
speaks English, Japanese, Traditional and Simplified Chinese and Spanish (and Czech and Brazilian Portuguese in the menus).
|
||||
speaks English, Japanese, Traditional and Simplified Chinese, Spanish and Italian (and Czech and Brazilian Portuguese in the menus).
|
||||
The scores are
|
||||
self-assessed, so the [honest assessment](ROADMAP.md#honest-assessment-2026-10-05) explains how far to trust them.
|
||||
|
||||
|
||||
+3
-3
File diff suppressed because one or more lines are too long
@@ -21,3 +21,7 @@
|
||||
real_name = "Brandon Thomas"
|
||||
display_name = "Brandon Thomas"
|
||||
sync_github_name = false
|
||||
|
||||
[people.callmeBalloch]
|
||||
real_name = "Riccardo Balloch"
|
||||
sync_github_name = false
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -64,7 +64,7 @@ fn plural_czech(n: u64) -> usize {
|
||||
}
|
||||
|
||||
/// The registry. English first: it is the fallback and the source language.
|
||||
pub static LANGUAGES: [LangInfo; 7] = [
|
||||
pub static LANGUAGES: [LangInfo; 8] = [
|
||||
LangInfo { code: "en", name: "English", source: "", plural: plural_one_other, complete_menus: false, catalog: OnceLock::new() },
|
||||
// Japanese: the whole interface (every menu string and `tl!` literal), keeping the product,
|
||||
// workspace and perspective preset names in English (`MENU_KEEP_AS_IS`).
|
||||
@@ -81,6 +81,16 @@ pub static LANGUAGES: [LangInfo; 7] = [
|
||||
complete_menus: true,
|
||||
catalog: OnceLock::new(),
|
||||
},
|
||||
// Italian: the whole interface and the status and error messages, keeping the same names in
|
||||
// English as Spanish; every `it-*` locale (`it-IT`, `it-CH`, `it-SM` …) resolves here.
|
||||
LangInfo {
|
||||
code: "it",
|
||||
name: "Italiano",
|
||||
source: include_str!("it.tsv"),
|
||||
plural: plural_one_other,
|
||||
complete_menus: true,
|
||||
catalog: OnceLock::new(),
|
||||
},
|
||||
// Brazilian Portuguese: every menu label (`menu_catalogs_translate_every_menu_label`), every
|
||||
// `tl!` literal and the plural messages; left English on purpose are the `MENU_KEEP_AS_IS`
|
||||
// strings (product name, language names, workspace names, perspective grid presets).
|
||||
|
||||
@@ -15,6 +15,10 @@ fn tags_map_to_languages() {
|
||||
for tag in ["es", "es_ES.UTF-8", "es-MX", "es_AR", "es-419", "es-US"] {
|
||||
assert_eq!(lang_from_tag(tag), Lang::from_code("es"), "{tag}");
|
||||
}
|
||||
// Italian: Italy, Switzerland and San Marino share the one catalog.
|
||||
for tag in ["it", "it_IT.UTF-8", "it-CH", "it_SM"] {
|
||||
assert_eq!(lang_from_tag(tag), Lang::from_code("it"), "{tag}");
|
||||
}
|
||||
// Traditional Chinese: by region, by script, and with a region after the script.
|
||||
assert_eq!(lang_from_tag("zh_TW.UTF-8"), Some(ZH()));
|
||||
assert_eq!(lang_from_tag("zh-TW"), Some(ZH()));
|
||||
@@ -391,9 +395,9 @@ fn cs() -> Lang {
|
||||
}
|
||||
|
||||
/// Languages whose catalogs leave [`MENU_KEEP_AS_IS`] in English.
|
||||
const KEEPS_MENU_NAMES: [&str; 4] = ["cs", "es", "ja", "pt-br"];
|
||||
const KEEPS_MENU_NAMES: [&str; 5] = ["cs", "es", "it", "ja", "pt-br"];
|
||||
|
||||
/// Menu labels the menu-complete catalogs (Czech, Spanish, Japanese, Brazilian Portuguese) show as they are: the product name, a format name, the built-in workspace
|
||||
/// Menu labels the menu-complete catalogs (Czech, Spanish, Italian, Japanese, Brazilian Portuguese) show as they are: the product name, a format name, the built-in workspace
|
||||
/// names and the perspective grid presets (names, shown untranslated wherever else they appear).
|
||||
/// Each language's own name in the Language menu is left alone too.
|
||||
const MENU_KEEP_AS_IS: &[&str] = &[
|
||||
@@ -483,7 +487,7 @@ fn toggled_labels() -> Vec<String> {
|
||||
labels
|
||||
}
|
||||
|
||||
/// Czech, Spanish, Japanese and Brazilian Portuguese cover every menu label, the Show/Hide pairs
|
||||
/// Czech, Spanish, Italian, Japanese and Brazilian Portuguese cover every menu label, the Show/Hide pairs
|
||||
/// and the canvas context menu included (panels and dialogs not yet).
|
||||
#[test]
|
||||
fn menu_catalogs_translate_every_menu_label() {
|
||||
@@ -514,12 +518,17 @@ fn menu_catalogs_translate_every_menu_label() {
|
||||
assert_eq!(tr(Lang::from_code("ja").expect("ja"), "File"), "ファイル");
|
||||
assert_eq!(tr(Lang::from_code("pt-br").expect("pt-br"), "File"), "Arquivo");
|
||||
assert_eq!(tr(es(), "File"), "Archivo");
|
||||
assert_eq!(tr(it(), "Edit"), "Modifica");
|
||||
}
|
||||
|
||||
fn es() -> Lang {
|
||||
Lang::from_code("es").expect("es registered")
|
||||
}
|
||||
|
||||
fn it() -> Lang {
|
||||
Lang::from_code("it").expect("it registered")
|
||||
}
|
||||
|
||||
/// Spanish uses the vector-illustration vocabulary its users know, has two plural forms like
|
||||
/// English, and reads the same in the menus and in the panels.
|
||||
#[test]
|
||||
@@ -541,6 +550,27 @@ fn spanish_reads_as_spanish() {
|
||||
assert_eq!(trn(es(), 3, "{n} Layer", "{n} Layers"), "3 capas");
|
||||
}
|
||||
|
||||
/// Italian uses the vector-illustration vocabulary its users know, has two plural forms like
|
||||
/// English (zero takes the plural), and reads the same in the menus and in the panels.
|
||||
#[test]
|
||||
fn italian_reads_as_italian() {
|
||||
for (en, want) in [
|
||||
("Artboard Tool", "Strumento Tavola da disegno"),
|
||||
("Swatches", "Campioni"),
|
||||
("Pathfinder", "Elaborazione tracciati"),
|
||||
("Stroke", "Traccia"),
|
||||
("Fill", "Riempimento"),
|
||||
("Direct Selection Tool", "Strumento Selezione diretta"),
|
||||
("Save As…", "Salva con nome…"),
|
||||
("Undo", "Annulla"),
|
||||
] {
|
||||
assert_eq!(tr(it(), en), want);
|
||||
}
|
||||
assert_eq!(trn(it(), 1, "{n} Layer", "{n} Layers"), "1 livello");
|
||||
assert_eq!(trn(it(), 0, "{n} Layer", "{n} Layers"), "0 livelli");
|
||||
assert_eq!(trn(it(), 3, "{n} Layer", "{n} Layers"), "3 livelli");
|
||||
}
|
||||
|
||||
/// Catalogs written with spaces between words keep a fragment's leading and trailing spaces: the
|
||||
/// hint bar and a few labels are joined from pieces (" to finish", "Press ").
|
||||
#[test]
|
||||
@@ -559,11 +589,11 @@ fn czech_plurals_have_three_forms() {
|
||||
assert_eq!(forms, [2, 0, 1, 1, 2, 2, 2]);
|
||||
}
|
||||
|
||||
/// Czech and Spanish letters (and the punctuation their text uses) come from each family's own first font, not
|
||||
/// Czech, Spanish and Italian letters (and the punctuation their text uses) come from each family's own first font, not
|
||||
/// from a fallback further down the stack. (`has_glyph` can't tell: it counts characters of the
|
||||
/// face that draws missing glyphs, the first one, as missing.)
|
||||
#[test]
|
||||
fn czech_and_spanish_glyphs_are_available_without_system_fonts() {
|
||||
fn czech_spanish_and_italian_glyphs_are_available_without_system_fonts() {
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
let mut output = ctx.run_ui(egui::RawInput::default(), |_| {});
|
||||
@@ -574,7 +604,8 @@ fn czech_and_spanish_glyphs_are_available_without_system_fonts() {
|
||||
let first = first.unwrap();
|
||||
let mut font = fonts.fonts.font(&family);
|
||||
let chars = font.characters();
|
||||
for ch in "áčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ„“‚‘…–ñÑüÜ¿¡”".chars() {
|
||||
for ch in "áčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ„“‚‘…–ñÑüÜ¿¡”àèìòùÀÈÌÒÙ«»’".chars()
|
||||
{
|
||||
assert!(chars.get(&ch).is_some_and(|fonts| fonts.contains(&first)), "{first} ({family:?}) has no {ch}");
|
||||
}
|
||||
}
|
||||
@@ -651,7 +682,7 @@ fn complete_languages_translate_every_message() {
|
||||
}
|
||||
|
||||
/// Languages whose catalogs cover every status and error message.
|
||||
const COMPLETE_MESSAGES: &[&str] = &["es"];
|
||||
const COMPLETE_MESSAGES: &[&str] = &["es", "it"];
|
||||
|
||||
/// Crates whose error and status messages reach the status bar.
|
||||
const MESSAGE_CRATES: &[&str] = &["ui-egui", "engine", "doc", "format", "svg", "pdf", "eps", "text", "plugins", "metafile", "cad"];
|
||||
|
||||
+4
-3
@@ -124,7 +124,8 @@ Languages shipped: English (`en`, the source), Traditional Chinese (`zh-hant`, c
|
||||
in Taiwan; `zh-TW`, `zh-HK`, `zh-MO` and `zh-Hant-*` locales all resolve to it), Simplified Chinese (`zh-hans`,
|
||||
complete, in the vocabulary used in mainland China; `zh-CN`, `zh-SG`, `zh-Hans-*` and a bare `zh` resolve to it,
|
||||
so the two scripts never mix), Japanese (`ja`, complete), Spanish (`es`, complete, in neutral
|
||||
international Spanish; every `es-*` locale such as `es-ES`, `es-MX`, `es-AR` or `es-419` resolves to it), Czech (`cs`, every menu label) and Brazilian Portuguese
|
||||
international Spanish; every `es-*` locale such as `es-ES`, `es-MX`, `es-AR` or `es-419` resolves to it), Italian (`it`,
|
||||
complete; `it-IT`, `it-CH` and every other `it-*` locale resolve to it), Czech (`cs`, every menu label) and Brazilian Portuguese
|
||||
(`pt-br`, every menu label and every `tl!` literal). Untranslated text falls back to English until its rows are added.
|
||||
|
||||
- `tl!("…")` translates a literal into the language the UI is drawn in; `i18n::t(s)` is the same for a
|
||||
@@ -152,10 +153,10 @@ international Spanish; every `es-*` locale such as `es-ES`, `es-MX`, `es-AR` or
|
||||
control channel, MCP and tests read them) and are translated only where the status bar draws them
|
||||
(`i18n::msg`). `@msg` catalog rows hold a whole message or a template such as
|
||||
`Couldn't open {name}: {e}`; `{_1}`, `{_2}` … stand for the format string's `{}`, and the values in the
|
||||
placeholders are translated in turn (the reason after `: {e}` is often a message too). Spanish covers every
|
||||
placeholders are translated in turn (the reason after `: {e}` is often a message too). Spanish and Italian cover every
|
||||
message literal the test scan finds (`complete_languages_translate_every_message`, languages listed in
|
||||
`COMPLETE_MESSAGES`): a new `Err("…")`, `Other(…)`, `#[error(…)]` or `status(…)` message needs an `es.tsv`
|
||||
row (`VECTORCRAFT_I18N_DUMP_MESSAGES=messages.txt cargo test -p vectorcraft-ui-egui
|
||||
and an `it.tsv` row (`VECTORCRAFT_I18N_DUMP_MESSAGES=messages.txt cargo test -p vectorcraft-ui-egui
|
||||
complete_languages_translate_every_message` lists them all). Other languages show messages in English
|
||||
until they add `@msg` rows.
|
||||
- Not translated on purpose: names that are user data (layers, swatches, fonts, documents), the tab
|
||||
|
||||
Reference in New Issue
Block a user