summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/post_editor.rs21
-rw-r--r--src/components/signin.rs19
-rw-r--r--src/components/smart_summary.rs4
-rw-r--r--src/lib.rs21
-rw-r--r--src/main.rs7
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 = &gtk::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);