Merge pull request #103 from RicSchonfelder/i18n-pt-br

i18n: add Brazilian Portuguese (pt-br) UI translation
This commit is contained in:
Brandon Thomas authored and GitHub committed 2026-10-07 22:13:15 -04:00
commit e97d98977f
3 files changed
+1059 -4

No files matched your search

+21 -2
View File
@@ -2,10 +2,19 @@
//! menu items and panel names. Untranslated strings stay English. The translations are our own.
mod ar;
mod pt_br;
/// Supported interface languages: (code, name in that language).
pub const LANGUAGES: &[(&str, &str)] =
&[("", "English"), ("de", "Deutsch"), ("fr", "Français"), ("es", "Español"), ("ja", "日本語"), ("zh", "简体中文"), ("ar", "العربية")];
pub const LANGUAGES: &[(&str, &str)] = &[
("", "English"),
("de", "Deutsch"),
("fr", "Français"),
("es", "Español"),
("ja", "日本語"),
("zh", "简体中文"),
("ar", "العربية"),
("pt-br", "Português (Brasil)"),
];
/// English → [German, French, Spanish, Japanese, Simplified Chinese].
const TABLE: &[(&str, [&str; 5])] = &[
@@ -2674,6 +2683,9 @@ pub fn tr<'a>(lang: &str, s: &'a str) -> &'a str {
if lang == "ar" {
return ar::TABLE.iter().find(|(en, _)| *en == s).map_or(s, |(_, t)| *t);
}
if lang == "pt-br" {
return pt_br::TABLE.iter().find(|(en, _)| *en == s).map_or(s, |(_, t)| *t);
}
let Some(c) = column(lang) else { return s };
match TABLE.iter().find(|(en, _)| *en == s) {
Some((_, t)) => t[c],
@@ -2709,11 +2721,18 @@ mod tests {
assert_eq!(tr("", "File"), "File");
assert_eq!(tr("ar", "File"), "ملف");
assert_eq!(tr("ar", "Unknown label"), "Unknown label");
assert_eq!(tr("pt-br", "File"), "Arquivo");
assert_eq!(tr("pt-br", "New Document…"), "Novo documento…");
assert_eq!(tr("pt-br", "Unknown label"), "Unknown label");
assert!(is_rtl("ar"));
for (i, (en, translation)) in ar::TABLE.iter().enumerate() {
assert!(ar::TABLE[..i].iter().all(|(key, _)| key != en), "duplicate {en}");
assert!(!translation.is_empty(), "{en}");
}
for (i, (en, translation)) in pt_br::TABLE.iter().enumerate() {
assert!(pt_br::TABLE[..i].iter().all(|(key, _)| key != en), "duplicate {en}");
assert!(!translation.is_empty(), "{en}");
}
// Every row is unique and complete.
for (i, (en, t)) in TABLE.iter().enumerate() {
assert!(TABLE[..i].iter().all(|(e, _)| e != en), "duplicate {en}");
File diff suppressed because it is too large. Load diff
+14 -2
View File
@@ -38,7 +38,7 @@ pub const UI_COMMANDS: &[(&str, &str, Option<&str>, &str)] = &[
"app.language",
"Interface Language",
None,
"{lang: \"\"|de|fr|es|ja|zh|ar} — menus and panel names (the macOS menu bar follows on the next launch)",
"{lang: \"\"|de|fr|es|ja|zh|ar|pt-br} — menus and panel names (the macOS menu bar follows on the next launch)",
),
(
"app.flattener",
@@ -233,6 +233,7 @@ pub const MENUS: &[(&str, &[&str])] = &[
"ui:app.language|日本語|{\"lang\": \"ja\"}",
"ui:app.language|简体中文|{\"lang\": \"zh\"}",
"ui:app.language|العربية|{\"lang\": \"ar\"}",
"ui:app.language|Português (Brasil)|{\"lang\": \"pt-br\"}",
"<",
">Transparency Flattener Presets",
"ui:app.flattener|None (keep transparency)|{\"preset\": \"\"}",
@@ -2127,6 +2128,17 @@ mod tests {
for (title, _) in menu_tree() {
assert_ne!(crate::i18n::tr("ja", title), title, "{title}");
}
run_ui(&mut app, "app.language", &json!({"lang": "pt-br"})).unwrap().unwrap();
assert_eq!(app.ui.language, "pt-br");
assert_eq!(checked(&app, "app.language", &json!({"lang": "pt-br"})), Some(true));
for (title, _) in menu_tree() {
// "Layout" is the natural Brazilian Portuguese word, so it stays identical
// to English; every other title must be translated.
if title != "Layout" {
assert_ne!(crate::i18n::tr("pt-br", title), title, "{title}");
}
}
}
#[test]
@@ -2156,7 +2168,7 @@ mod tests {
crate::dialogs::confirm(&mut app).unwrap();
frame(&mut app);
assert_eq!(app.session.documents().len(), 1);
for lang in ["zh", "", "ar"] {
for lang in ["zh", "", "ar", "pt-br"] {
app.run("app.language", json!({"lang": lang})).unwrap();
frame(&mut app);
}