feat(i18n): multiple localization changes

Improved `tr!` macro to use enhanced arguments syntax;
Updated Indonesian;
Fixed formatting error for `close` string
This commit is contained in:
Observer KRypt0n_ 2023-08-02 15:32:33 +02:00
parent cab5a1f6f7
commit 7614561213
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
11 changed files with 88 additions and 59 deletions

View file

@ -13,7 +13,7 @@ failed-get-selected-wine = Gagal mendapatkan versi wine yang dipilih
downloading-failed = Gagal mengunduh
unpacking-failed = Gagal mengekstrak berkas
kill-game-process-failed = Failed to kill the game's process
kill-game-process-failed = Gagal menghentikan paksa proses game
game-file-repairing-error = Gagal memperbaiki file game
integrity-files-getting-error = Gagal mendapatkan integritas file

View file

@ -58,8 +58,8 @@ disable-mhypbase-description = Masih dalam pengujicobaan. Jika diaktifkan, launc
ask-superuser-permissions = Minta izin dari admin
ask-superuser-permissions-description = Launcher akan otomatis memperbarui file hosts Anda. Opsi ini tidak diperlukan jika Anda memakai edisi flatpak
launcher-behavior = Launcher behavior
launcher-behavior-description = What should launcher window do when it starts the game
launcher-behavior = Kelakuan launcher
launcher-behavior-description = Apa yang terjadi pada jendela launcher ketika memulai game
wine-tools = Peralatan wine
command-line = Command line

View file

@ -16,10 +16,17 @@ debug-file = File debug
wish-url = Buka wishes
about = Tentang
close = { $form ->
[verb] Menutup
*[noun] Tutup
}
close = Tutup
hide = Hide
nothing = Nothing
hide = { $form ->
[verb] Sembunyikan
*[noun] Sembunyi
}
nothing = Tidak berubah
save = Simpan
continue = Lanjutkan
resume = Lanjutkan
@ -64,7 +71,7 @@ update = Perbarui
download = Unduh
predownload-update = Pra-unduh pembaruan versi {$version} ({$size})
kill-game-process = Kill game process
kill-game-process = Hentikan paksa proses game
main-window--patch-unavailable-tooltip = Server patch tidak tersedia dan launcher tidak bisa memverifikasi status patch game. Anda bisa menjalankan game dengan resiko sendiri
main-window--patch-outdated-tooltip = Patch kadaluarsa atau sedang dalam persiapan sehingga tidak tersedia. Kembali lagi nanti untuk melihat status patch

View file

@ -88,10 +88,10 @@ pub fn format_lang(lang: &LanguageIdentifier) -> String {
/// With parameters:
///
/// ```no_run
/// println!("Translated message: {}", tr!("game-outdated", [
/// ("latest", "3.3.0")
/// ]));
/// ```
/// println!("Translated message: {}", tr!("game-outdated", {
/// "latest" = "3.3.0"
/// }));
/// ```
macro_rules! tr {
($id:expr) => {
{
@ -104,19 +104,22 @@ macro_rules! tr {
}
};
($id:expr, $args:expr) => {
($id:expr, { $($key:literal = $value:expr),* }) => {
{
use std::collections::HashMap;
use fluent_templates::Loader;
use fluent_templates::fluent_bundle::FluentValue;
let mut args = HashMap::new();
$(
args.insert($key, FluentValue::from($value));
)*
#[allow(unused_unsafe)]
$crate::i18n::LOCALES
.lookup_with_args(
unsafe { &$crate::i18n::LANG },
$id,
&std::collections::HashMap::from_iter($args.into_iter()
.map(|(key, value)| (key, FluentValue::from(value))))
)
.lookup_complete(unsafe { &$crate::i18n::LANG }, $id, Some(&args))
.expect(&format!("Failed to find a message with given id: {}", stringify!($id)))
}
};

View file

@ -98,6 +98,9 @@ fn main() {
// Forcely run the game
let just_run_game = std::env::args().any(|arg| &arg == "--just-run-game");
// Forcely disable verbode tracing output in stdout
let no_verbose_tracing = std::env::args().any(|arg| &arg == "--no-verbose-tracing");
// Prepare stdout logger
let stdout = tracing_subscriber::fmt::layer()
.pretty()
@ -108,8 +111,8 @@ fn main() {
LevelFilter::WARN
}
})
.with_filter(filter_fn(|metadata| {
!metadata.target().contains("rustls")
.with_filter(filter_fn(move |metadata| {
!metadata.target().contains("rustls") && !no_verbose_tracing
}));
// Prepare debug file logger

View file

@ -243,7 +243,7 @@ impl SimpleAsyncComponent for DefaultPathsApp {
gtk::Button {
set_label: &if model.migrate_installation {
tr!("close")
tr!("close", { "form" = "noun" })
} else {
tr!("exit")
},

View file

@ -175,7 +175,9 @@ impl SimpleAsyncComponent for DependenciesApp {
for package in packages {
if !is_available(package) {
sender.output(Self::Output::Toast {
title: tr!("package-not-available", [("package", package)]),
title: tr!("package-not-available", {
"package" = package
}),
description: None
});

View file

@ -285,7 +285,7 @@ impl SimpleComponent for FirstRunApp {
let dialog = adw::MessageDialog::new(MAIN_WINDOW.as_ref(), Some(&title), Some(&description));
dialog.add_response("close", &tr!("close"));
dialog.add_response("close", &tr!("close", { "form" = "noun" }));
dialog.add_response("save", &tr!("save"));
dialog.set_response_appearance("save", adw::ResponseAppearance::Suggested);

View file

@ -308,13 +308,13 @@ impl SimpleComponent for App {
set_width_request: 44,
#[watch]
set_tooltip_text: Some(&tr!("predownload-update", [
("version", match model.state.as_ref() {
set_tooltip_text: Some(&tr!("predownload-update", {
"version" = match model.state.as_ref() {
Some(LauncherState::PredownloadAvailable { game, .. }) => game.latest().to_string(),
_ => String::from("?")
}),
},
("size", match model.state.as_ref() {
"size" = match model.state.as_ref() {
Some(LauncherState::PredownloadAvailable { game, voices }) => {
let mut size = game.downloaded_size().unwrap_or(0);
@ -326,8 +326,8 @@ impl SimpleComponent for App {
}
_ => String::from("?")
})
])),
}
})),
#[watch]
set_visible: matches!(model.state.as_ref(), Some(LauncherState::PredownloadAvailable { .. })),
@ -1002,9 +1002,9 @@ impl SimpleComponent for App {
}
StateUpdating::Voice(locale) => {
sender.input(AppMsg::SetLoadingStatus(Some(Some(tr!("loading-launcher-state--voice", [
("locale", locale.to_name())
])))));
sender.input(AppMsg::SetLoadingStatus(Some(Some(tr!("loading-launcher-state--voice", {
"locale" = locale.to_name()
})))));
}
StateUpdating::Patch => {
@ -1189,7 +1189,7 @@ impl App {
Some(description.as_ref())
);
dialog.add_response("close", &tr!("close"));
dialog.add_response("close", &tr!("close", { "form" = "noun" }));
dialog.add_response("save", &tr!("save"));
dialog.set_response_appearance("save", adw::ResponseAppearance::Suggested);

View file

@ -397,10 +397,10 @@ impl SimpleAsyncComponent for GeneralApp {
#[watch]
set_css_classes: match model.game_diff.as_ref() {
Some(diff) => match diff {
VersionDiff::Latest { .. } => &["success"],
VersionDiff::Predownload { .. } => &["accent"],
VersionDiff::Diff { .. } => &["warning"],
VersionDiff::Outdated { .. } => &["error"],
VersionDiff::Latest { .. } => &["success"],
VersionDiff::Predownload { .. } => &["accent"],
VersionDiff::Diff { .. } => &["warning"],
VersionDiff::Outdated { .. } => &["error"],
VersionDiff::NotInstalled { .. } => &[]
}
@ -411,17 +411,21 @@ impl SimpleAsyncComponent for GeneralApp {
set_tooltip_text: Some(&match model.game_diff.as_ref() {
Some(diff) => match diff {
VersionDiff::Latest { .. } => String::new(),
VersionDiff::Predownload { current, latest, .. } => tr!("game-predownload-available", [
("old", current.to_string()),
("new", latest.to_string())
]),
VersionDiff::Diff { current, latest, .. } => tr!("game-update-available", [
("old", current.to_string()),
("new", latest.to_string())
]),
VersionDiff::Outdated { latest, ..} => tr!("game-outdated", [
("latest", latest.to_string())
]),
VersionDiff::Predownload { current, latest, .. } => tr!("game-predownload-available", {
"old" = current.to_string(),
"new" = latest.to_string()
}),
VersionDiff::Diff { current, latest, .. } => tr!("game-update-available", {
"old" = current.to_string(),
"new" = latest.to_string()
}),
VersionDiff::Outdated { latest, ..} => tr!("game-outdated", {
"latest" = latest.to_string()
}),
VersionDiff::NotInstalled { .. } => String::new()
}
@ -439,8 +443,13 @@ impl SimpleAsyncComponent for GeneralApp {
set_text: &match model.player_patch.as_ref() {
Some(patch) => match patch.status() {
PatchStatus::NotAvailable => tr!("patch-not-available"),
PatchStatus::Outdated { current, .. } => tr!("patch-outdated", [("current", current.to_string())]),
PatchStatus::Outdated { current, .. } => tr!("patch-outdated", {
"current" = current.to_string()
}),
PatchStatus::Preparation { .. } => tr!("patch-preparation"),
PatchStatus::Testing { version, .. } |
PatchStatus::Available { version, .. } => version.to_string()
}
@ -452,9 +461,11 @@ impl SimpleAsyncComponent for GeneralApp {
set_css_classes: match model.player_patch.as_ref() {
Some(patch) => match patch.status() {
PatchStatus::NotAvailable => &["error"],
PatchStatus::Outdated { .. } |
PatchStatus::Preparation { .. } |
PatchStatus::Testing { .. } => &["warning"],
PatchStatus::Available { .. } => unsafe {
let path = match Config::get() {
Ok(config) => config.game.path.for_edition(config.launcher.edition).to_path_buf(),
@ -476,12 +487,15 @@ impl SimpleAsyncComponent for GeneralApp {
set_tooltip_text: Some(&match model.player_patch.as_ref() {
Some(patch) => match patch.status() {
PatchStatus::NotAvailable => tr!("patch-not-available-tooltip"),
PatchStatus::Outdated { current, latest, .. } => tr!("patch-outdated-tooltip", [
("current", current.to_string()),
("latest", latest.to_string())
]),
PatchStatus::Outdated { current, latest, .. } => tr!("patch-outdated-tooltip", {
"current" = current.to_string(),
"latest" = latest.to_string()
}),
PatchStatus::Preparation { .. } => tr!("patch-preparation-tooltip"),
PatchStatus::Testing { .. } => tr!("patch-testing-tooltip"),
PatchStatus::Available { .. } => unsafe {
let path = match Config::get() {
Ok(config) => config.game.path.for_edition(config.launcher.edition).to_path_buf(),
@ -582,8 +596,8 @@ impl SimpleAsyncComponent for GeneralApp {
set_model: Some(&gtk::StringList::new(&[
&tr!("nothing"),
&tr!("hide", [("form", "verb")]),
&tr!("close", [("form", "verb")]),
&tr!("hide", { "form" = "verb" }),
&tr!("close", { "form" = "verb" }),
])),
set_selected: match CONFIG.launcher.behavior {
@ -873,9 +887,9 @@ impl SimpleAsyncComponent for GeneralApp {
if let Err(err) = result {
sender.input(GeneralAppMsg::Toast {
title: tr!("wine-run-error", [
("executable", executable.join(" "))
]),
title: tr!("wine-run-error", {
"executable" = executable.join(" ")
}),
description: Some(err.to_string())
});

View file

@ -154,7 +154,7 @@ impl SimpleAsyncComponent for PreferencesApp {
let dialog = adw::MessageDialog::new(PREFERENCES_WINDOW.as_ref(), Some(&title), Some(&description));
dialog.add_response("close", &tr!("close"));
dialog.add_response("close", &tr!("close", { "form" = "noun" }));
dialog.add_response("save", &tr!("save"));
dialog.set_response_appearance("save", adw::ResponseAppearance::Suggested);