WIP localisation - add po folder and wrap stuff in gettext

This commit is contained in:
Dvlv 2024-01-06 13:36:22 +00:00
parent a5320e9fe3
commit bc291be7ef
No known key found for this signature in database
GPG key ID: 1F4BD7220B7FDCFA
7 changed files with 316 additions and 39 deletions

137
Cargo.lock generated
View file

@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.75"
@ -20,10 +29,17 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]]
name = "block"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "boxbuddy-rs"
version = "0.1.0"
dependencies = [
"gettext-rs",
"gtk4",
"libadwaita",
]
@ -53,6 +69,15 @@ dependencies = [
"system-deps",
]
[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]]
name = "cfg-expr"
version = "0.15.5"
@ -200,6 +225,26 @@ dependencies = [
"system-deps",
]
[[package]]
name = "gettext-rs"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e49ea8a8fad198aaa1f9655a2524b64b70eb06b2f3ff37da407566c93054f364"
dependencies = [
"gettext-sys",
"locale_config",
]
[[package]]
name = "gettext-sys"
version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c63ce2e00f56a206778276704bbe38564c8695249fdc8f354b4ef71c57c3839d"
dependencies = [
"cc",
"temp-dir",
]
[[package]]
name = "gio"
version = "0.18.3"
@ -420,6 +465,12 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libadwaita"
version = "0.5.3"
@ -458,6 +509,28 @@ version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "locale_config"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d2c35b16f4483f6c26f0e4e9550717a2f6575bcd6f12a53ff0c490a94a6934"
dependencies = [
"lazy_static",
"objc",
"objc-foundation",
"regex",
"winapi",
]
[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
dependencies = [
"libc",
]
[[package]]
name = "memchr"
version = "2.6.4"
@ -473,6 +546,35 @@ dependencies = [
"autocfg",
]
[[package]]
name = "objc"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
dependencies = [
"malloc_buf",
]
[[package]]
name = "objc-foundation"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
dependencies = [
"block",
"objc",
"objc_id",
]
[[package]]
name = "objc_id"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
dependencies = [
"objc",
]
[[package]]
name = "once_cell"
version = "1.19.0"
@ -584,6 +686,35 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "rustc_version"
version = "0.4.0"
@ -684,6 +815,12 @@ version = "0.12.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a"
[[package]]
name = "temp-dir"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd16aa9ffe15fe021c6ee3766772132c6e98dfa395a167e16864f61a9cfb71d6"
[[package]]
name = "thiserror"
version = "1.0.50"

View file

@ -7,4 +7,5 @@ edition = "2021"
[dependencies]
adw = { version = "0.5.3", package = "libadwaita", features = ["v1_4"] }
gettext-rs = "0.7.0"
gtk = { version = "0.7.3", package = "gtk4", features = ["v4_12"] }

2
create-pot.sh Executable file
View file

@ -0,0 +1,2 @@
#!/bin/bash
/home/dvlv/.cargo/bin/xtr src/main.rs -o po/boxbuddy.pot

130
po/boxbuddy.pot Normal file
View file

@ -0,0 +1,130 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-01-06 13:06+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: src/main.rs:87
msgid "Create A Distrobox"
msgstr ""
#: src/main.rs:110
msgid "Distrobox not found!"
msgstr ""
#: src/main.rs:114
msgid "Distrobox could not be found, please ensure it is installed!"
msgstr ""
#: src/main.rs:199
msgid "Open Terminal"
msgstr ""
#: src/main.rs:211
msgid "Upgrade Box"
msgstr ""
#: src/main.rs:226
msgid "View Applications"
msgstr ""
#: src/main.rs:239
msgid "Delete Box"
msgstr ""
#: src/main.rs:263
msgid "Create New Distrobox"
msgstr ""
#: src/main.rs:266
msgid "Create"
msgstr ""
#: src/main.rs:269 src/main.rs:518
msgid "Cancel"
msgstr ""
#: src/main.rs:295
msgid "Name"
msgstr ""
#: src/main.rs:307
msgid "Image"
msgstr ""
#: src/main.rs:408
msgid "Installed Applications"
msgstr ""
#: src/main.rs:417
msgid "Loading..."
msgstr ""
#: src/main.rs:446
msgid "No Applications Installed"
msgstr ""
#: src/main.rs:450
msgid "Available Applications"
msgstr ""
#: src/main.rs:461
msgid "Add To Menu"
msgstr ""
#: src/main.rs:475
msgid "Run"
msgstr ""
#: src/main.rs:503
msgid "App Exported!"
msgstr ""
#: src/main.rs:511
msgid "Are you sure you want to delete "
msgstr ""
#: src/main.rs:514
msgid "Really Delete?"
msgstr ""
#: src/main.rs:519
msgid "Delete"
msgstr ""
#: src/main.rs:531
msgid "Box Deleted!"
msgstr ""
#: src/main.rs:553
msgid "Please install one of the supported terminals:"
msgstr ""
#: src/main.rs:557
msgid "No supported terminal found"
msgstr ""
#: src/main.rs:561
msgid "Ok"
msgstr ""
#: src/main.rs:573
msgid "No Boxes"
msgstr ""
#: src/main.rs:575
msgid "Click the + at the top-left to create your first box!"
msgstr ""

View file

@ -77,7 +77,6 @@ pub fn get_all_distroboxes() -> Vec<DBox> {
my_boxes
}
pub fn try_parse_distro_name_from_url(url: &str) -> String {
let distros = [
"alma",
@ -217,10 +216,7 @@ pub fn create_box(box_name: String, image: String) -> String {
args.push("--nvidia");
}
get_command_output(
String::from("distrobox"),
Some(args.as_slice()),
)
get_command_output(String::from("distrobox"), Some(args.as_slice()))
}
pub fn get_available_images_with_distro_name() -> Vec<String> {

View file

@ -1,3 +1,5 @@
use gettextrs::*;
use std::env;
use std::thread;
use adw::{
@ -14,7 +16,10 @@ mod distrobox_handler;
use distrobox_handler::*;
mod utils;
use utils::{get_distro_img, get_terminal_and_separator_arg, has_distrobox_installed, get_supported_terminals_list};
use utils::{
get_distro_img, get_supported_terminals_list, get_terminal_and_separator_arg,
has_distrobox_installed,
};
const APP_ID: &str = "io.github.dvlv.boxbuddyrs";
@ -27,6 +32,10 @@ enum BoxCreatedMessage {
}
fn main() -> glib::ExitCode {
textdomain(APP_ID).expect("failed to initialise gettext");
bind_textdomain_codeset(APP_ID, "UTF-8").expect("failed to bind textdomain for gettext");
bindtextdomain(APP_ID, "po").expect("Failed to bind textdomain");
// Create a new application
let app = Application::builder().application_id(APP_ID).build();
@ -77,13 +86,13 @@ fn build_ui(app: &Application) {
fn make_titlebar(window: &ApplicationWindow) {
let add_btn = gtk::Button::from_icon_name("list-add-symbolic");
add_btn.set_tooltip_text(Some("Create A Distrobox"));
add_btn.set_tooltip_text(Some(&gettext("Create A Distrobox")));
let win_clone = window.clone();
add_btn.connect_clicked(move |_btn| create_new_distrobox(&win_clone));
let about_btn = gtk::Button::from_icon_name("help-about-symbolic");
about_btn.set_tooltip_text(Some("About BoxBuddy"));
about_btn.set_tooltip_text(Some(&gettext(("About BoxBuddy"))));
let win_clone = window.clone();
about_btn.connect_clicked(move |_btn| show_about_popup(&win_clone));
@ -100,12 +109,12 @@ fn make_titlebar(window: &ApplicationWindow) {
}
fn render_not_installed(main_box: &gtk::Box) {
let not_installed_lbl = gtk::Label::new(Some("Distrobox not found!"));
let not_installed_lbl = gtk::Label::new(Some(&gettext("Distrobox not found!")));
not_installed_lbl.add_css_class("title-1");
let not_installed_lbl_two = gtk::Label::new(Some(
let not_installed_lbl_two = gtk::Label::new(Some(&gettext(
"Distrobox could not be found, please ensure it is installed!",
));
)));
not_installed_lbl_two.add_css_class("title-2");
main_box.append(&not_installed_lbl);
@ -189,7 +198,7 @@ fn make_box_tab(dbox: &DBox, window: &ApplicationWindow) -> gtk::Box {
.connect_clicked(move |_btn| on_open_terminal_clicked(term_bn_clone.clone()));
let open_terminal_row = ActionRow::new();
open_terminal_row.set_title("Open Terminal");
open_terminal_row.set_title(&gettext("Open Terminal"));
open_terminal_row.add_suffix(&open_terminal_button);
open_terminal_row.set_activatable_widget(Some(&open_terminal_button));
@ -201,7 +210,7 @@ fn make_box_tab(dbox: &DBox, window: &ApplicationWindow) -> gtk::Box {
upgrade_button.connect_clicked(move |_btn| on_upgrade_clicked(up_bn_clone.clone()));
let upgrade_row = ActionRow::new();
upgrade_row.set_title("Upgrade Box");
upgrade_row.set_title(&gettext("Upgrade Box"));
upgrade_row.add_suffix(&upgrade_button);
upgrade_row.set_activatable_widget(Some(&upgrade_button));
@ -216,7 +225,7 @@ fn make_box_tab(dbox: &DBox, window: &ApplicationWindow) -> gtk::Box {
});
let show_applications_row = ActionRow::new();
show_applications_row.set_title("View Applications");
show_applications_row.set_title(&gettext("View Applications"));
show_applications_row.add_suffix(&show_applications_button);
show_applications_row.set_activatable_widget(Some(&show_applications_button));
@ -229,7 +238,7 @@ fn make_box_tab(dbox: &DBox, window: &ApplicationWindow) -> gtk::Box {
delete_button.connect_clicked(move |_btn| on_delete_clicked(&win_clone, del_bn_clone.clone()));
let delete_row = ActionRow::new();
delete_row.set_title("Delete Box");
delete_row.set_title(&gettext("Delete Box"));
delete_row.add_suffix(&delete_button);
delete_row.set_activatable_widget(Some(&delete_button));
@ -253,13 +262,13 @@ fn create_new_distrobox(window: &ApplicationWindow) {
new_box_popup.set_default_size(700, 350);
new_box_popup.set_modal(true);
let title_lbl = gtk::Label::new(Some("Create New Distrobox"));
let title_lbl = gtk::Label::new(Some(&gettext("Create New Distrobox")));
title_lbl.add_css_class("header");
let create_btn = gtk::Button::with_label("Create");
let create_btn = gtk::Button::with_label(&gettext("Create"));
create_btn.add_css_class("suggested-action");
let cancel_btn = gtk::Button::with_label("Cancel");
let cancel_btn = gtk::Button::with_label(&gettext("Cancel"));
cancel_btn.connect_clicked(move |btn| {
let win = btn.root().and_downcast::<gtk::Window>().unwrap();
@ -285,7 +294,7 @@ fn create_new_distrobox(window: &ApplicationWindow) {
// name input
let name_entry_row = adw::EntryRow::new();
name_entry_row.set_hexpand(true);
name_entry_row.set_title("Name");
name_entry_row.set_title(&gettext("Name"));
// Image
let available_images = get_available_images_with_distro_name();
@ -297,7 +306,7 @@ fn create_new_distrobox(window: &ApplicationWindow) {
let image_select = gtk::DropDown::new(Some(imgs_strlist), exp);
let image_select_row = adw::ActionRow::new();
image_select_row.set_title("Image");
image_select_row.set_title(&gettext("Image"));
image_select_row.set_activatable_widget(Some(&image_select));
image_select_row.add_suffix(&image_select);
@ -398,7 +407,7 @@ fn on_show_applications_clicked(window: &ApplicationWindow, box_name: String) {
apps_popup.set_transient_for(Some(window));
apps_popup.set_default_size(700, 350);
apps_popup.set_modal(true);
apps_popup.set_title(Some("Installed Applications"));
apps_popup.set_title(Some(&gettext("Installed Applications")));
let main_box = gtk::Box::new(Orientation::Vertical, 10);
main_box.set_margin_start(10);
@ -407,7 +416,7 @@ fn on_show_applications_clicked(window: &ApplicationWindow, box_name: String) {
main_box.set_margin_bottom(10);
let loading_spinner = gtk::Spinner::new();
let loading_lbl = gtk::Label::new(Some("Loading..."));
let loading_lbl = gtk::Label::new(Some(&gettext("Loading...")));
loading_lbl.add_css_class("title-2");
main_box.append(&loading_lbl);
@ -436,11 +445,11 @@ fn on_show_applications_clicked(window: &ApplicationWindow, box_name: String) {
loading_spinner.stop();
if apps.is_empty() {
let no_apps_lbl = gtk::Label::new(Some("No Applications Installed"));
let no_apps_lbl = gtk::Label::new(Some(&gettext("No Applications Installed")));
no_apps_lbl.add_css_class("title-2");
main_box.append(&no_apps_lbl);
} else {
loading_lbl.set_text("Available Applications");
loading_lbl.set_text(&gettext("Available Applications"));
let boxed_list = gtk::ListBox::new();
boxed_list.add_css_class("boxed-list");
@ -451,7 +460,7 @@ fn on_show_applications_clicked(window: &ApplicationWindow, box_name: String) {
let img = gtk::Image::from_icon_name(&app.icon);
let add_menu_btn = gtk::Button::with_label("Add To Menu");
let add_menu_btn = gtk::Button::with_label(&gettext("Add To Menu"));
add_menu_btn.add_css_class("pill");
let box_name_clone = box_name.clone();
@ -465,7 +474,7 @@ fn on_show_applications_clicked(window: &ApplicationWindow, box_name: String) {
);
});
let run_btn = gtk::Button::with_label("Run");
let run_btn = gtk::Button::with_label(&gettext("Run"));
run_btn.add_css_class("pill");
// todo connect
let box_name_clone = box_name.clone();
@ -493,7 +502,7 @@ fn on_show_applications_clicked(window: &ApplicationWindow, box_name: String) {
fn add_app_to_menu(app: &DBoxApp, box_name: String, success_lbl: &gtk::Label) {
let _ = export_app_from_box(app.name.to_string(), box_name);
success_lbl.set_text("App Exported!");
success_lbl.set_text(&gettext("App Exported!"));
}
fn run_app_in_box(app: &DBoxApp, box_name: String) {
@ -501,14 +510,15 @@ fn run_app_in_box(app: &DBoxApp, box_name: String) {
}
fn on_delete_clicked(window: &ApplicationWindow, box_name: String) {
let are_you_sure_pre = &gettext("Are you sure you want to delete ");
let d = adw::MessageDialog::new(
Some(window),
Some("Really Delete?"),
Some(&format!("Are you sure you want to delete {box_name}?")),
Some(&gettext("Really Delete?")),
Some(&format!("{are_you_sure_pre} {box_name}?")),
);
d.set_transient_for(Some(window));
d.add_response("cancel", "Cancel");
d.add_response("delete", "Delete");
d.add_response("cancel", &gettext("Cancel"));
d.add_response("delete", &gettext("Delete"));
d.set_default_response(Some("cancel"));
d.set_close_response("cancel");
d.set_response_appearance("delete", adw::ResponseAppearance::Destructive);
@ -520,7 +530,7 @@ fn on_delete_clicked(window: &ApplicationWindow, box_name: String) {
delete_box(box_name.clone());
d.destroy();
let toast = adw::Toast::new("Box Deleted!");
let toast = adw::Toast::new(&gettext("Box Deleted!"));
if let Some(child) = win_clone.clone().child() {
let toast_area = child.downcast::<ToastOverlay>();
toast_area.unwrap().add_toast(toast);
@ -542,14 +552,15 @@ fn delayed_rerender(window: &ApplicationWindow) {
fn show_no_supported_terminal_popup(window: &ApplicationWindow) {
let supported_terminals = get_supported_terminals_list();
let supported_terminals_body = format!("Please install one of the supported terminals:\n\n{supported_terminals}");
let supported_terminals_pre = &gettext("Please install one of the supported terminals:");
let supported_terminals_body = format!("{supported_terminals_pre}\n\n{supported_terminals}");
let d = adw::MessageDialog::new(
Some(window),
Some("No supported terminal found"),
Some(&gettext("No supported terminal found")),
Some(&supported_terminals_body),
);
d.set_transient_for(Some(window));
d.add_response("ok", "Ok");
d.add_response("ok", &gettext("Ok"));
d.set_default_response(Some("ok"));
d.set_close_response("ok");
@ -561,10 +572,10 @@ fn render_no_boxes_message(main_box: &gtk::Box) {
main_box.remove(&child);
}
let no_boxes_msg = gtk::Label::new(Some("No Boxes"));
let no_boxes_msg_2 = gtk::Label::new(Some(
let no_boxes_msg = gtk::Label::new(Some(&gettext("No Boxes")));
let no_boxes_msg_2 = gtk::Label::new(Some(&gettext(
"Click the + at the top-left to create your first box!",
));
)));
no_boxes_msg.add_css_class("title-1");
no_boxes_msg_2.add_css_class("title-2");

View file

@ -136,7 +136,7 @@ pub fn get_terminal_and_separator_arg() -> (String, String) {
}
pub fn get_supported_terminals_list() -> String {
return String::from("- Gnome Terminal\n- Konsole\n- Tilix\n- Kitty\n- Alacritty\n- Xterm")
return String::from("- Gnome Terminal\n- Konsole\n- Tilix\n- Kitty\n- Alacritty\n- Xterm");
}
pub fn is_flatpak() -> bool {