diff options
author | Vika <vika@fireburn.ru> | 2024-09-01 19:04:08 +0300 |
---|---|---|
committer | Vika <vika@fireburn.ru> | 2024-09-04 19:51:50 +0300 |
commit | 237c09966cc05f5aeeedfd93ef342dc8ff52eba2 (patch) | |
tree | f59bfe86bbec5c92056f0a8f27e46073e10792af /src | |
parent | f8d61d957d4a2d086f4b97f2e3d7d19d0bb35f13 (diff) | |
download | bowl-237c09966cc05f5aeeedfd93ef342dc8ff52eba2.tar.zst |
Gettextize and add Russian translation
This is a very shitty translation, but it can be improved later. I added it mostly as a test for translations working correctly, since I know Russian and might as well translate the app into the language.
Diffstat (limited to 'src')
-rw-r--r-- | src/components/post_editor.rs | 21 | ||||
-rw-r--r-- | src/components/signin.rs | 19 | ||||
-rw-r--r-- | src/components/smart_summary.rs | 4 | ||||
-rw-r--r-- | src/lib.rs | 21 | ||||
-rw-r--r-- | src/main.rs | 7 |
5 files changed, 42 insertions, 30 deletions
diff --git a/src/components/post_editor.rs b/src/components/post_editor.rs index 534b0dd..d1a6cf0 100644 --- a/src/components/post_editor.rs +++ b/src/components/post_editor.rs @@ -1,3 +1,4 @@ +use gettextrs::*; use crate::components; use crate::components::tag_pill::*; use adw::prelude::*; @@ -138,7 +139,7 @@ impl<E: std::error::Error + std::fmt::Debug + Send + 'static> Component for Post #[name = "name_label"] gtk::Label { - set_markup: "Name", + set_markup: &gettext("Name"), set_margin_horizontal: 10, set_halign: gtk::Align::Start, set_valign: gtk::Align::Center, @@ -153,7 +154,7 @@ impl<E: std::error::Error + std::fmt::Debug + Send + 'static> Component for Post #[name = "summary_label"] gtk::Label { - set_markup: "Summary", + set_markup: &gettext("Summary"), set_margin_horizontal: 10, set_halign: gtk::Align::Start, set_valign: gtk::Align::Center, @@ -175,7 +176,7 @@ impl<E: std::error::Error + std::fmt::Debug + Send + 'static> Component for Post #[name = "tag_label"] gtk::Label { - set_markup: "Tags", + set_markup: &gettext("Tags"), set_margin_horizontal: 10, set_halign: gtk::Align::Start, set_valign: gtk::Align::Center, @@ -223,7 +224,7 @@ impl<E: std::error::Error + std::fmt::Debug + Send + 'static> Component for Post #[name = "content_label"] gtk::Label { - set_markup: "Content", + set_markup: &gettext("Content"), set_halign: gtk::Align::Start, set_valign: gtk::Align::Start, set_margin_vertical: 10, @@ -276,7 +277,7 @@ impl<E: std::error::Error + std::fmt::Debug + Send + 'static> Component for Post #[name = "visibility_label"] gtk::Label { - set_markup: "Visibility", + set_markup: &gettext("Visibility"), set_halign: gtk::Align::Start, set_valign: gtk::Align::Start, set_margin_vertical: 10, @@ -373,7 +374,7 @@ impl<E: std::error::Error + std::fmt::Debug + Send + 'static> Component for Post [] as [gtk::Expression; 0], glib::closure::RustClosure::new(|v| { let list_item = v[0].get::<adw::EnumListItem>().unwrap(); - Some(list_item.name().into()) + Some(gettext(list_item.name().as_str()).into()) }) ) )); @@ -489,7 +490,7 @@ impl<E: std::error::Error + std::fmt::Debug + Send + 'static> Component for Post Input::SmartSummary(components::SmartSummaryOutput::Error(err)) => { self.set_smart_summary_busy_guard(None); - let toast = adw::Toast::new(&format!("Smart Summary error: {}", err)); + let toast = adw::Toast::new(&gettext!("Smart Summary error: {}", err)); toast.set_timeout(0); toast.set_priority(adw::ToastPriority::High); root.add_toast(toast); @@ -536,8 +537,8 @@ impl<E: std::error::Error + std::fmt::Debug + Send + 'static> Component for Post self.summary_buffer.set_text(""); self.tags.guard().clear(); self.content_buffer.set_text(""); - let toast = adw::Toast::new("Post submitted"); - toast.set_button_label(Some("Open")); + let toast = adw::Toast::new(&gettext("Post submitted")); + toast.set_button_label(Some(&gettext("Open"))); toast.connect_button_clicked(move |toast| { gtk::UriLauncher::new(&location.to_string()).launch( None::<&adw::ApplicationWindow>, @@ -555,7 +556,7 @@ impl<E: std::error::Error + std::fmt::Debug + Send + 'static> Component for Post root.add_toast(toast); }, Input::SubmitError(err) => { - let toast = adw::Toast::new(&format!("Error sending post: {}", err)); + let toast = adw::Toast::new(&gettext!("Error sending post: {}", err)); toast.set_timeout(0); toast.set_priority(adw::ToastPriority::High); diff --git a/src/components/signin.rs b/src/components/signin.rs index 08e850a..156686e 100644 --- a/src/components/signin.rs +++ b/src/components/signin.rs @@ -1,3 +1,4 @@ +use gettextrs::*; use std::cell::RefCell; use adw::prelude::*; @@ -87,7 +88,7 @@ fn callback_handler(sender: AsyncComponentSender<SignIn>) -> impl Fn(&soup::Serv msg.set_response( Some("text/plain; charset=\"utf-8\""), soup::MemoryUse::Static, - "Thank you! This window can now be closed.".as_bytes() + gettext("Thank you! This window can now be closed.").as_bytes() ); msg.connect_finished(move |_| { sender.input(Input::Callback(Ok(response.take().unwrap()))); @@ -206,12 +207,12 @@ impl AsyncComponent for SignIn { gtk::Label { add_css_class: "title-1", - set_text: "Sign in", + set_text: &gettext("Sign in"), set_justify: gtk::Justification::Center, }, gtk::Label { - set_text: "Please sign in with your website to use Bowl.\nYour website needs to support IndieAuth and Micropub for this app to work.", + set_text: &gettext("Please sign in with your website to use Bowl.\nYour website needs to support IndieAuth and Micropub for this app to work."), set_wrap: true, set_halign: gtk::Align::BaselineCenter, set_valign: gtk::Align::BaselineCenter, @@ -240,12 +241,12 @@ impl AsyncComponent for SignIn { }, gtk::Label { #[watch] - set_text: if model.busy_guard.is_some() { - "Talking to your website..." + set_text: &if model.busy_guard.is_some() { + gettext("Talking to your website...") } else if model.callback_server.is_some() { - "Waiting for authorization..." + gettext("Waiting for authorization...") } else { - "Sign in" + gettext("Sign in") }, } }, @@ -451,7 +452,7 @@ impl AsyncComponent for SignIn { if res.state != self.state { return self.bail_out(widgets, sender, IndieauthError { kind: kittybox_indieauth::ErrorKind::InvalidRequest, - msg: Some("state doesn't match what we remember, ceremony aborted".to_owned()), + msg: Some(gettext("state doesn't match what we remember, ceremony aborted")), error_uri: None, }.into()) } @@ -459,7 +460,7 @@ impl AsyncComponent for SignIn { if res.iss != metadata.issuer { return self.bail_out(widgets, sender, IndieauthError { kind: kittybox_indieauth::ErrorKind::InvalidRequest, - msg: Some("issuer doesn't match what we remember, ceremony aborted".to_owned()), + msg: Some(gettext("issuer doesn't match what we remember, ceremony aborted")), error_uri: None, }.into()) } diff --git a/src/components/smart_summary.rs b/src/components/smart_summary.rs index fbfc80b..9da67af 100644 --- a/src/components/smart_summary.rs +++ b/src/components/smart_summary.rs @@ -1,4 +1,5 @@ use adw::prelude::*; +use gettextrs::*; use relm4::{gtk, prelude::{Component, ComponentParts}, ComponentSender}; #[derive(Debug, Default)] @@ -42,7 +43,8 @@ impl Component for SmartSummaryButton { connect_clicked => Input::ButtonPressed, #[watch] set_sensitive: !model.busy, - set_tooltip_markup: Some("<b>Smart Summary</b>\nAsk a language model for a single-sentence summary."), + // TRANSLATORS: please keep the newline and `<b>` tags + set_tooltip_markup: Some(gettext("<b>Smart Summary</b>\nAsk a language model for a single-sentence summary.")).as_deref(), if model.busy { gtk::Spinner { set_spinning: true } diff --git a/src/lib.rs b/src/lib.rs index 530eab6..ee92350 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +use gettextrs::*; use adw::prelude::*; use libsecret::prelude::{RetrievableExtManual, RetrievableExt}; use relm4::{actions::{RelmAction, RelmActionGroup}, gtk, loading_widgets::LoadingWidgets, prelude::{AsyncComponent, AsyncComponentController, AsyncComponentParts, AsyncController, ComponentController, Controller}, AsyncComponentSender, Component, RelmWidgetExt}; @@ -14,7 +15,7 @@ pub mod components { }; pub(crate) mod tag_pill; - // pub(crate) use tag_pill::{TagPill, TagPillDelete}; + // pub(crate) use tag_pill::{TagPill, TagPillDelete} pub mod signin; pub use signin::{SignIn, Output as SignInOutput}; @@ -127,7 +128,7 @@ impl App { fn about() -> adw::AboutDialog { adw::AboutDialog::builder() - .application_name("Bowl for Kittybox") + .application_name(gettext("Bowl for Kittybox")) .developer_name("Vika Shleina") .version(env!("CARGO_PKG_VERSION")) .website("https://kittybox.fireburn.ru/bowl/") @@ -165,9 +166,9 @@ impl AsyncComponent for App { menu! { main_menu: { - "Sign out" => SignOutAction, - "Preferences" => PreferencesAction, - "About" => AboutAction, + &gettext("Sign out") => SignOutAction, + &gettext("Preferences") => PreferencesAction, + &gettext("About") => AboutAction, } } @@ -181,10 +182,10 @@ impl AsyncComponent for App { #[watch] set_title: if model.micropub.is_none() { - Some("Bowl – Sign in with your website") + Some(gettext("Bowl - Sign in with your website")) } else { - Some("Bowl") - }, + Some(gettext("Bowl")) + }.as_deref(), adw::ToolbarView { add_top_bar = &adw::HeaderBar { @@ -197,7 +198,7 @@ impl AsyncComponent for App { }, pack_end = >k::Button { set_icon_name: "document-send-symbolic", - set_tooltip: "Send post", + set_tooltip: &gettext("Publish"), #[watch] set_visible: model.micropub.is_some(), #[watch] @@ -327,7 +328,7 @@ impl AsyncComponent for App { Some(&self.secret_schema), attributes.clone(), Some(libsecret::COLLECTION_DEFAULT), - &format!("Micropub access token for {}", &data.me), + &gettext!("Micropub access token for {}", &data.me), &data.access_token ).await { Ok(()) => {}, diff --git a/src/main.rs b/src/main.rs index d906a66..d7dd0a1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,13 @@ static GLIB_LOGGER: glib::GlibLogger = glib::GlibLogger::new( ); fn main() { + gettextrs::bindtextdomain( + env!("CARGO_PKG_NAME"), + env!("LOCALEDIR") + ).expect("failed to bind text domain"); + gettextrs::bind_textdomain_codeset(env!("CARGO_PKG_NAME"), "UTF-8").unwrap(); + gettextrs::textdomain(env!("CARGO_PKG_NAME")).unwrap(); + log::set_logger(&GLIB_LOGGER).unwrap(); log::set_max_level(log::LevelFilter::Debug); |