Merge Portuguese translations by terry #1036

Terry Yiu (5):
      Export strings for translation
      Add human-readable names to locales in settings
      Internationalize ShowNoteClientOptions labels
      Import translations
      Add Portuguese (Brazil) language and translations
This commit is contained in:
William Casarin
2025-07-29 10:25:56 -07:00
12 changed files with 815 additions and 54 deletions

View File

@@ -5,16 +5,28 @@ use std::borrow::Cow;
use std::collections::HashMap;
use unic_langid::{langid, LanguageIdentifier};
const EN_XA: LanguageIdentifier = langid!("en-XA");
const EN_US: LanguageIdentifier = langid!("en-US");
const EN_XA: LanguageIdentifier = langid!("en-XA");
const DE: LanguageIdentifier = langid!("de");
const ES_419: LanguageIdentifier = langid!("es-419");
const ES_ES: LanguageIdentifier = langid!("es-ES");
const FR: LanguageIdentifier = langid!("FR");
const TH: LanguageIdentifier = langid!("TH");
const ZH_CN: LanguageIdentifier = langid!("ZH_CN");
const ZH_TW: LanguageIdentifier = langid!("ZH_TW");
const NUM_FTLS: usize = 9;
const FR: LanguageIdentifier = langid!("fr");
const PT_BR: LanguageIdentifier = langid!("pt-BR");
const TH: LanguageIdentifier = langid!("th");
const ZH_CN: LanguageIdentifier = langid!("zh-CN");
const ZH_TW: LanguageIdentifier = langid!("zh-TW");
const NUM_FTLS: usize = 10;
const EN_US_NATIVE_NAME: &str = "English (US)";
const EN_XA_NATIVE_NAME: &str = "Éñglísh (Pséúdólóçàlé)";
const DE_NATIVE_NAME: &str = "Deutsch";
const ES_419_NATIVE_NAME: &str = "Español (Latinoamérica)";
const ES_ES_NATIVE_NAME: &str = "Español (España)";
const FR_NATIVE_NAME: &str = "Français";
const PT_BR_NATIVE_NAME: &str = "Português (Brasil)";
const TH_NATIVE_NAME: &str = "ภาษาไทย";
const ZH_CN_NATIVE_NAME: &str = "简体中文";
const ZH_TW_NATIVE_NAME: &str = "繁體中文";
struct StaticBundle {
identifier: LanguageIdentifier,
@@ -46,6 +58,10 @@ const FTLS: [StaticBundle; NUM_FTLS] = [
identifier: FR,
ftl: include_str!("../../../../assets/translations/fr/main.ftl"),
},
StaticBundle {
identifier: PT_BR,
ftl: include_str!("../../../../assets/translations/pt-BR/main.ftl"),
},
StaticBundle {
identifier: TH,
ftl: include_str!("../../../../assets/translations/th/main.ftl"),
@@ -70,6 +86,8 @@ pub struct Localization {
available_locales: Vec<LanguageIdentifier>,
/// Fallback locale
fallback_locale: LanguageIdentifier,
/// Native names for locales
locale_native_names: HashMap<LanguageIdentifier, String>,
/// Cached string results per locale (only for strings without arguments)
string_cache: HashMap<LanguageIdentifier, HashMap<String, String>>,
@@ -95,15 +113,30 @@ impl Default for Localization {
ES_419.clone(),
ES_ES.clone(),
FR.clone(),
PT_BR.clone(),
TH.clone(),
ZH_CN.clone(),
ZH_TW.clone(),
];
let locale_native_names = HashMap::from([
(EN_US, EN_US_NATIVE_NAME.to_owned()),
(EN_XA, EN_XA_NATIVE_NAME.to_owned()),
(DE, DE_NATIVE_NAME.to_owned()),
(ES_419, ES_419_NATIVE_NAME.to_owned()),
(ES_ES, ES_ES_NATIVE_NAME.to_owned()),
(FR, FR_NATIVE_NAME.to_owned()),
(PT_BR, PT_BR_NATIVE_NAME.to_owned()),
(TH, TH_NATIVE_NAME.to_owned()),
(ZH_CN, ZH_CN_NATIVE_NAME.to_owned()),
(ZH_TW, ZH_TW_NATIVE_NAME.to_owned()),
]);
Self {
current_locale: default_locale.to_owned(),
available_locales,
fallback_locale,
locale_native_names,
use_isolating: true,
normalized_key_cache: HashMap::new(),
string_cache: HashMap::new(),
@@ -391,6 +424,10 @@ impl Localization {
&self.fallback_locale
}
pub fn get_locale_native_name(&self, locale: &LanguageIdentifier) -> Option<&str> {
self.locale_native_names.get(locale).map(|s| s.as_str())
}
/// Gets cache statistics for monitoring performance
pub fn get_cache_stats(&self) -> Result<CacheStats, Box<dyn std::error::Error + Send + Sync>> {
let mut total_strings = 0;

View File

@@ -103,6 +103,39 @@ impl<'a> SettingsView<'a> {
}
}
/// Get the localized name for a language identifier
fn get_selected_language_name(&mut self) -> String {
if let Ok(lang_id) = self.selected_language.parse::<LanguageIdentifier>() {
self.i18n
.get_locale_native_name(&lang_id)
.map(|s| s.to_owned())
.unwrap_or_else(|| lang_id.to_string())
} else {
self.selected_language.clone()
}
}
/// Get the localized label for ShowNoteClientOptions
fn get_show_note_client_label(&mut self, option: ShowNoteClientOptions) -> String {
match option {
ShowNoteClientOptions::Hide => tr!(
self.i18n,
"Hide",
"Option in settings section to hide the source client label in note display"
),
ShowNoteClientOptions::Top => tr!(
self.i18n,
"Top",
"Option in settings section to show the source client label at the top of the note"
),
ShowNoteClientOptions::Bottom => tr!(
self.i18n,
"Bottom",
"Option in settings section to show the source client label at the bottom of the note"
),
}.to_string()
}
pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<SettingsAction> {
let id = ui.id();
let mut action = None;
@@ -190,19 +223,22 @@ impl<'a> SettingsView<'a> {
.text_style(NotedeckTextStyle::Small.text_style()),
);
ComboBox::from_label("")
.selected_text(self.selected_language.to_owned())
.selected_text(self.get_selected_language_name())
.show_ui(ui, |ui| {
for lang in self.i18n.get_available_locales() {
let name = self.i18n
.get_locale_native_name(lang)
.map(|s| s.to_owned())
.unwrap_or_else(|| lang.to_string());
if ui
.selectable_value(
self.selected_language,
lang.to_string(),
lang.to_string(),
&name,
)
.clicked()
{
action =
Some(SettingsAction::SetLocale(lang.to_owned()))
action = Some(SettingsAction::SetLocale(lang.to_owned()))
}
}
})
@@ -387,7 +423,7 @@ impl<'a> SettingsView<'a> {
ShowNoteClientOptions::Top,
ShowNoteClientOptions::Bottom,
] {
let label = option.clone().to_string();
let label = self.get_show_note_client_label(option);
if ui
.selectable_value(