Commit 0ff496d5 authored by Daniel García Moreno's avatar Daniel García Moreno

Use i18n functions instead of direct gettext

parent c934f38c
Pipeline #16184 passed with stages
in 20 minutes and 40 seconds
i18n.gettext(meson.project_name(),
args: ['--keyword=i18n', '--keyword=i18n_f', '--keyword=i18n_k'],
args: ['--keyword=i18n', '--keyword=i18n_f', '--keyword=i18n_k',
'--keyword=ni18n', '--keyword=ni18n_f', '--keyword=ni18n_k'],
preset: 'glib')
extern crate gettextrs;
use self::gettextrs::gettext;
use i18n::i18n;
use app::App;
use appop::RoomPanel;
......@@ -65,11 +62,11 @@ pub fn backend_loop(rx: Receiver<BKResponse>) {
APPOP!(get_token_phone, (sid, secret));
}
Ok(BKResponse:: GetTokenEmailUsed) => {
let error = gettext("Email is already in use");
let error = i18n("Email is already in use");
APPOP!(show_three_pid_error_dialog, (error));
}
Ok(BKResponse:: GetTokenPhoneUsed) => {
let error = gettext("Phone number is already in use");
let error = i18n("Phone number is already in use");
APPOP!(show_three_pid_error_dialog, (error));
}
Ok(BKResponse:: SubmitPhoneToken(sid, secret)) => {
......@@ -201,29 +198,29 @@ pub fn backend_loop(rx: Receiver<BKResponse>) {
// errors
Ok(BKResponse::AccountDestructionError(err)) => {
let error = gettext("Couldn’t delete the account");
let error = i18n("Couldn’t delete the account");
println!("ERROR: {:?}", err);
APPOP!(show_error_dialog, (error));
},
Ok(BKResponse::ChangePasswordError(err)) => {
let error = gettext("Couldn’t change the password");
let error = i18n("Couldn’t change the password");
println!("ERROR: {:?}", err);
APPOP!(show_password_error_dialog, (error));
},
Ok(BKResponse::GetTokenEmailError(err)) => {
let error = gettext("Couldn’t add the email address.");
let error = i18n("Couldn’t add the email address.");
println!("ERROR: {:?}", err);
APPOP!(show_three_pid_error_dialog, (error));
},
Ok(BKResponse::GetTokenPhoneError(err)) => {
let error = gettext("Couldn’t add the phone number.");
let error = i18n("Couldn’t add the phone number.");
println!("ERROR: {:?}", err);
APPOP!(show_three_pid_error_dialog, (error));
},
Ok(BKResponse::NewRoomError(err, internal_id)) => {
println!("ERROR: {:?}", err);
let error = gettext("Can’t create the room, try again");
let error = i18n("Can’t create the room, try again");
let panel = RoomPanel::NoRoom;
APPOP!(remove_room, (internal_id));
APPOP!(show_error, (error));
......@@ -231,13 +228,13 @@ pub fn backend_loop(rx: Receiver<BKResponse>) {
},
Ok(BKResponse::JoinRoomError(err)) => {
println!("ERROR: {:?}", err);
let error = format!("{}", gettext("Can’t join the room, try again."));
let error = format!("{}", i18n("Can’t join the room, try again."));
let panel = RoomPanel::NoRoom;
APPOP!(show_error, (error));
APPOP!(room_panel, (panel));
},
Ok(BKResponse::LoginError(_)) => {
let error = gettext("Can’t login, try again");
let error = i18n("Can’t login, try again");
let st = AppState::Login;
APPOP!(show_error, (error));
APPOP!(set_state, (st));
......@@ -253,13 +250,13 @@ pub fn backend_loop(rx: Receiver<BKResponse>) {
APPOP!(retry_send);
},
_ => {
let error = gettext("Error sending message");
let error = i18n("Error sending message");
APPOP!(show_error, (error));
}
}
}
Ok(BKResponse::DirectoryError(_)) => {
let error = gettext("Error searching for rooms");
let error = i18n("Error searching for rooms");
APPOP!(reset_directory_state);
APPOP!(show_error, (error));
}
......
extern crate gtk;
extern crate gettextrs;
use i18n::i18n;
use self::gtk::prelude::*;
use self::gettextrs::gettext;
use app::App;
......@@ -62,7 +62,7 @@ impl App {
other_homeserver_url_entry.set_sensitive(false);
}
directory_choice_label.set_text(&gettext("Default Matrix Server"));
directory_choice_label.set_text(&i18n("Default Matrix Server"));
}));
other_protocol_radio.connect_toggled(clone!(directory_choice_label, other_protocol_radio, protocol_combo, protocol_model, other_homeserver_url_entry => move |_| {
......
extern crate gtk;
extern crate gettextrs;
use i18n::i18n;
use self::gtk::prelude::*;
use self::gettextrs::gettext;
use appop::AppOp;
use globals;
......@@ -16,15 +16,15 @@ impl AppOp {
let dialog = gtk::AboutDialog::new();
dialog.set_logo_icon_name(globals::APP_ID);
dialog.set_comments(gettext("A Matrix.org client for GNOME").as_str());
dialog.set_copyright(gettext("© 2017–2018 Daniel García Moreno, et al.").as_str());
dialog.set_comments(i18n("A Matrix.org client for GNOME").as_str());
dialog.set_copyright(i18n("© 2017–2018 Daniel García Moreno, et al.").as_str());
dialog.set_license_type(gtk::License::Gpl30);
dialog.set_modal(true);
dialog.set_version(env!("CARGO_PKG_VERSION"));
dialog.set_program_name("Fractal");
dialog.set_website("https://wiki.gnome.org/Fractal");
dialog.set_website_label(gettext("Learn more about Fractal").as_str());
dialog.set_translator_credits(gettext("translator-credits").as_str());
dialog.set_website_label(i18n("Learn more about Fractal").as_str());
dialog.set_translator_credits(i18n("translator-credits").as_str());
dialog.set_transient_for(&window);
dialog.set_artists(&[
......@@ -40,7 +40,7 @@ impl AppOp {
"Eisha Chen-yen-su",
]);
dialog.add_credit_section(gettext("Name by").as_str(), &["Regina Bíró"]);
dialog.add_credit_section(i18n("Name by").as_str(), &["Regina Bíró"]);
dialog.connect_response(move |d, _| { d.destroy(); });
dialog.show();
......
......@@ -2,7 +2,8 @@ extern crate glib;
extern crate gdk;
extern crate gdk_pixbuf;
extern crate gtk;
extern crate gettextrs;
use i18n::i18n;
use std::fs::File;
use std::io::prelude::*;
......@@ -12,7 +13,6 @@ use failure::Error;
use failure::err_msg;
use self::gtk::prelude::*;
use self::gettextrs::gettext;
use appop::AppOp;
use app::InternalCommand;
......@@ -57,7 +57,7 @@ impl AppOp {
.expect("Can't find main_window in ui file.");
let img = gtk::Image::new();
let dialog = gtk::Dialog::new_with_buttons(
Some(gettext("Image from Clipboard").as_str()),
Some(i18n("Image from Clipboard").as_str()),
Some(&window),
gtk::DialogFlags::MODAL|
gtk::DialogFlags::USE_HEADER_BAR|
......@@ -71,8 +71,8 @@ impl AppOp {
if let Some(hbar) = dialog.get_header_bar() {
let bar = hbar.downcast::<gtk::HeaderBar>().unwrap();
let closebtn = gtk::Button::new_with_label(gettext("Cancel").as_str());
let okbtn = gtk::Button::new_with_label(gettext("Send").as_str());
let closebtn = gtk::Button::new_with_label(i18n("Cancel").as_str());
let okbtn = gtk::Button::new_with_label(i18n("Send").as_str());
okbtn.get_style_context().unwrap().add_class("suggested-action");
bar.set_show_close_button(false);
......
extern crate gtk;
extern crate gettextrs;
use i18n::i18n;
use std::env;
use std::fs;
use self::gtk::prelude::*;
use self::gtk::ResponseType;
use self::gettextrs::gettext;
use glib;
......@@ -20,15 +20,15 @@ impl AppOp {
.expect("Cant find main_window in ui file.");
let file_chooser = gtk::FileChooserDialog::new(
Some(&gettext("Save media as")),
Some(&i18n("Save media as")),
Some(&main_window),
gtk::FileChooserAction::Save,
);
file_chooser.set_modal(true);
file_chooser.add_buttons(&[
(&gettext("_Cancel"), ResponseType::Cancel.into()),
(&gettext("_Save"), ResponseType::Accept.into()),
(&i18n("_Cancel"), ResponseType::Cancel.into()),
(&i18n("_Save"), ResponseType::Accept.into()),
]);
file_chooser.set_current_folder(env::home_dir().unwrap_or_default());
file_chooser.set_current_name(&name);
......@@ -41,13 +41,13 @@ impl AppOp {
gtk::DialogFlags::MODAL | gtk::DialogFlags::DESTROY_WITH_PARENT,
gtk::MessageType::Question,
gtk::ButtonsType::YesNo,
&gettext("Do you want to overwrite the file?")
&i18n("Do you want to overwrite the file?")
);
confirm_dialog.connect_response(clone!(fcd, src => move |cd, res| {
if ResponseType::from(res) == ResponseType::Yes {
if let Err(_) = fs::copy(src.clone(), fcd.get_filename().unwrap_or_default()) {
let msg = gettext("Could not save the file");
let msg = i18n("Could not save the file");
APPOP!(show_error, (msg));
}
cd.destroy();
......@@ -60,7 +60,7 @@ impl AppOp {
confirm_dialog.show_all();
} else {
if let Err(_) = fs::copy(src.clone(), fcd.get_filename().unwrap_or_default()) {
let msg = gettext("Could not save the file");
let msg = i18n("Could not save the file");
APPOP!(show_error, (msg));
}
fcd.destroy();
......
extern crate gtk;
extern crate gettextrs;
use i18n::{i18n, i18n_k};
use self::gtk::prelude::*;
use self::gettextrs::gettext;
use appop::AppOp;
use appop::member::SearchType;
......@@ -134,10 +134,9 @@ impl AppOp {
if let Some(aroom) = self.active_room.clone() {
if let Some(r) = self.rooms.get(&aroom) {
if let &Some(ref name) = &r.name {
let sentence_template = gettext("Invite to {name}");
title.set_text(&sentence_template.replace("{name}", name));
title.set_text(&i18n_k("Invite to {name}", &[("name", name)]));
} else {
title.set_text(gettext("Invite").as_str());
title.set_text(i18n("Invite").as_str());
}
}
}
......@@ -206,16 +205,15 @@ impl AppOp {
.expect("Can't find invite_dialog in ui file.");
let room_name = r.name.clone().unwrap_or_default();
let title = format!("{} {}?", gettext("Join"), room_name);
let title = i18n_k("Join {room_name}?", &[("room_name", &room_name)]);
let secondary;
if let Some(ref sender) = r.inv_sender {
let sender_name = sender.get_alias();
let sentence_template = gettext("You’ve been invited to join to <b>{room_name}</b> room by <b>{sender_name}</b>");
secondary = sentence_template.replace("{room_name}", room_name.as_str())
.replace("{sender_name}", sender_name.as_str());
secondary = i18n_k("You’ve been invited to join to <b>{room_name}</b> room by <b>{sender_name}</b>",
&[("room_name", &room_name), ("sender_name", &sender_name)]);
} else {
let sentence_template = gettext("You’ve been invited to join to <b>{room_name}</b>");
secondary = sentence_template.replace("{room_name}", room_name.as_str());
secondary = i18n_k("You’ve been invited to join to <b>{room_name}</b>",
&[("room_name", &room_name)]);
}
dialog.set_property_text(Some(&title));
......
extern crate gtk;
extern crate gettextrs;
use i18n::i18n;
use globals;
use self::gtk::prelude::*;
use self::gettextrs::gettext;
use appop::AppOp;
use appop::state::AppState;
......@@ -110,11 +110,11 @@ impl AppOp {
if username.clone().unwrap_or_default().is_empty() ||
password.clone().unwrap_or_default().is_empty() {
login_error.set_text(gettext("Invalid username or password").as_str());
login_error.set_text(i18n("Invalid username or password").as_str());
login_error.show();
return;
} else {
login_error.set_text(gettext("Unknown Error").as_str());
login_error.set_text(i18n("Unknown Error").as_str());
login_error.hide();
}
......@@ -177,7 +177,7 @@ impl AppOp {
};
if password != passconf {
self.show_error(gettext("Passwords didn’t match, try again"));
self.show_error(i18n("Passwords didn’t match, try again"));
return;
}
......
extern crate gtk;
extern crate gettextrs;
use i18n::ni18n_k;
use self::gtk::prelude::*;
use self::gettextrs::ngettext;
use std::collections::HashMap;
......@@ -84,10 +84,9 @@ impl AppOp {
}
if members.len() > self.member_limit {
let sentence_template = ngettext("and one more", "and {member_count} more",
(members.len() - self.member_limit) as u32);
let newlabel = sentence_template.replace("{member_count}",
&(members.len() - self.member_limit).to_string());
let n = (members.len() - self.member_limit) as u32;
let newlabel = ni18n_k("and one more", "and {member_count} more", n,
&[("member_count", &n.to_string())]);
self.more_members_btn.set_label(&newlabel);
self.more_members_btn.show();
} else {
......
extern crate gtk;
extern crate comrak;
extern crate chrono;
extern crate gettextrs;
extern crate tree_magic;
use i18n::i18n;
use std::path::Path;
use self::gtk::prelude::*;
use self::chrono::prelude::*;
use self::comrak::{markdown_to_html, ComrakOptions};
use self::gettextrs::gettext;
use app::InternalCommand;
use appop::AppOp;
......@@ -169,7 +169,7 @@ impl AppOp {
};
if last == LastViewed::Inline && msg.sender != self.uid.clone().unwrap_or_default() {
let divider: gtk::ListBoxRow = widgets::divider::new(gettext("New Messages").as_str());
let divider: gtk::ListBoxRow = widgets::divider::new(i18n("New Messages").as_str());
match msgpos {
MsgPos::Bottom => messages.add(&divider),
MsgPos::Top => messages.insert(&divider, 2),
......@@ -411,7 +411,7 @@ impl AppOp {
Some(&window),
gtk::FileChooserAction::Open);
let btn = dialog.add_button(gettext("Select").as_str(), 1);
let btn = dialog.add_button(i18n("Select").as_str(), 1);
btn.get_style_context().unwrap().add_class("suggested-action");
let internal = self.internal.clone();
......
extern crate gtk;
extern crate gettextrs;
use i18n::i18n;
use std::sync::mpsc::Sender;
use std::collections::HashMap;
use gio::ApplicationExt;
use self::gtk::prelude::*;
use self::gettextrs::gettext;
use globals;
use backend::BKCommand;
......@@ -116,7 +116,7 @@ impl AppOp {
ui: ui,
gtk_app: app,
load_more_spn: gtk::Spinner::new(),
more_members_btn: gtk::Button::new_with_label(gettext("Load more members").as_str()),
more_members_btn: gtk::Button::new_with_label(i18n("Load more members").as_str()),
backend: tx,
internal: itx,
autoscroll: true,
......
extern crate gtk;
extern crate gdk_pixbuf;
extern crate rand;
extern crate gettextrs;
use i18n::{i18n, i18n_k};
use self::gtk::prelude::*;
use self::gettextrs::gettext;
use appop::AppOp;
use appop::AppState;
......@@ -251,7 +251,8 @@ impl AppOp {
.expect("Can't find leave_room_dialog in ui file.");
if let Some(r) = self.rooms.get(&self.active_room.clone().unwrap_or_default()) {
dialog.set_property_text(Some(&format!("{} {}?", gettext("Leave"), r.name.clone().unwrap_or_default())));
let text = i18n_k("Leave {room_name}?", &[("room_name", &r.name.clone().unwrap_or_default())]);
dialog.set_property_text(Some(&text));
dialog.present();
}
}
......@@ -590,11 +591,10 @@ impl AppOp {
};
let name = match n {
0 => gettext("EMPTY ROOM"),
0 => i18n("EMPTY ROOM"),
1 => String::from(m1),
2 => gettext("{m1} and {m2}").replace("{m1}", m1.as_str())
.replace("{m2}", m2.as_str()),
_ => gettext("{m1} and Others").replace("{m1}", m1.as_str()),
2 => i18n_k("{m1} and {m2}", &[("m1", &m1), ("m2", &m2)]),
_ => i18n_k("{m1} and Others", &[("m1", &m1)]),
};
r.name = Some(name);
......
extern crate gettextrs;
use self::gettextrs::gettext;
use i18n::i18n;
use appop::AppOp;
......@@ -9,7 +8,7 @@ use backend::BKCommand;
impl AppOp {
pub fn initial_sync(&self, show: bool) {
if show {
self.inapp_notify(&gettext("Syncing, this could take a while"));
self.inapp_notify(&i18n("Syncing, this could take a while"));
self.stickers_load();
} else {
self.hide_inapp_notify();
......
extern crate gettextrs;
extern crate regex;
use self::gettextrs::gettext;
use self::gettextrs::ngettext;
use self::regex::Captures;
use self::regex::Regex;
pub fn i18n(format: &str) -> String {
gettext(format)
}
pub fn i18n_f(format: &str, args: &[&str]) -> String {
let s = gettext(format);
let mut parts = s.split("{}");
#[allow(dead_code)]
fn freplace(input: String, args: &[&str]) -> String {
let mut parts = input.split("{}");
let mut output = parts.next().unwrap_or("").to_string();
for (p, a) in parts.zip(args.iter()) {
output += &(a.to_string() + &p.to_string());
......@@ -18,8 +15,9 @@ pub fn i18n_f(format: &str, args: &[&str]) -> String {
output
}
pub fn i18n_k(format: &str, kwargs: &[(&str, &str)]) -> String {
let mut s = gettext(format);
#[allow(dead_code)]
fn kreplace(input: String, kwargs: &[(&str, &str)]) -> String {
let mut s = input.clone();
for (k, v) in kwargs {
if let Ok(re) = Regex::new(&format!("\\{{{}\\}}", k)) {
s = re.replace_all(&s, |_: &Captures| v.to_string().clone())
......@@ -30,6 +28,40 @@ pub fn i18n_k(format: &str, kwargs: &[(&str, &str)]) -> String {
s
}
#[allow(dead_code)]
pub fn i18n(format: &str) -> String {
gettext(format)
}
#[allow(dead_code)]
pub fn i18n_f(format: &str, args: &[&str]) -> String {
let s = gettext(format);
freplace(s, args)
}
#[allow(dead_code)]
pub fn i18n_k(format: &str, kwargs: &[(&str, &str)]) -> String {
let s = gettext(format);
kreplace(s, kwargs)
}
#[allow(dead_code)]
pub fn ni18n(single: &str, multiple: &str, number: u32) -> String {
ngettext(single, multiple, number)
}
#[allow(dead_code)]
pub fn ni18n_f(single: &str, multiple: &str, number: u32, args: &[&str]) -> String {
let s = ngettext(single, multiple, number);
freplace(s, args)
}
#[allow(dead_code)]
pub fn ni18n_k(single: &str, multiple: &str, number: u32, kwargs: &[(&str, &str)]) -> String {
let s = ngettext(single, multiple, number);
kreplace(s, kwargs)
}
#[cfg(test)]
mod tests {
use super::*;
......@@ -37,6 +69,11 @@ mod tests {
fn test_i18n() {
let out = i18n("translate1");
assert_eq!(out, "translate1");
let out = ni18n("translate1", "translate multi", 1);
assert_eq!(out, "translate1");
let out = ni18n("translate1", "translate multi", 2);
assert_eq!(out, "translate multi");
}
#[test]
......@@ -52,6 +89,11 @@ mod tests {
let out = i18n_f("multiple {} and {}", &["one", "two"]);
assert_eq!(out, "multiple one and two");
let out = ni18n_f("singular {} and {}", "plural {} and {}", 2, &["one", "two"]);
assert_eq!(out, "plural one and two");
let out = ni18n_f("singular {} and {}", "plural {} and {}", 1, &["one", "two"]);
assert_eq!(out, "singular one and two");
}
#[test]
......@@ -73,5 +115,10 @@ mod tests {
let out = i18n_k("multiple {one} and {one}", &[("one", "1"), ("two", "two")]);
assert_eq!(out, "multiple 1 and 1");
let out = ni18n_k("singular {one} and {two}", "plural {one} and {two}", 1, &[("one", "1"), ("two", "two")]);
assert_eq!(out, "singular 1 and two");
let out = ni18n_k("singular {one} and {two}", "plural {one} and {two}", 2, &[("one", "1"), ("two", "two")]);
assert_eq!(out, "plural 1 and two");
}
}
......@@ -2,12 +2,11 @@ extern crate gtk;
extern crate chrono;
extern crate pango;
extern crate glib;
extern crate gettextrs;
use app::App;
use i18n::i18n;
use self::gtk::prelude::*;
use self::gettextrs::gettext;
use types::Message;
use types::Member;
......@@ -330,7 +329,7 @@ impl<'a> MessageBox<'a> {
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
let download_btn = gtk::ModelButton::new();
download_btn.set_label(&gettext("Download"));
download_btn.set_label(&i18n("Download"));
download_btn.connect_clicked(clone!(name, url, backend => move |_| {
let (tx, rx): (Sender<String>, Receiver<String>) = channel();
......@@ -340,7 +339,7 @@ impl<'a> MessageBox<'a> {
gtk::timeout_add(50, clone!(name => move || match rx.try_recv() {
Err(TryRecvError::Empty) => gtk::Continue(true),
Err(TryRecvError::Disconnected) => {
let msg = gettext("Could not download the file");
let msg = i18n("Could not download the file");
APPOP!(show_error, (msg));
gtk::Continue(true)
......@@ -357,7 +356,7 @@ impl<'a> MessageBox<'a> {
vbox.pack_start(&download_btn, false, false, 6);
let open_btn = gtk::ModelButton::new();
open_btn.set_label(&gettext("Open"));
open_btn.set_label(&i18n("Open"));
open_btn.connect_clicked(clone!(url, backend => move |_| {
backend.send(BKCommand::GetMedia(url.clone())).unwrap();
......
......@@ -3,13 +3,13 @@ extern crate gdk;
extern crate gdk_pixbuf;
extern crate cairo;
extern crate pango;
extern crate gettextrs;
use i18n::i18n;
use self::gtk::prelude::*;
use self::gdk_pixbuf::Pixbuf;
use self::gdk_pixbuf::PixbufExt;
use self::gdk::ContextExt;
use self::gettextrs::gettext;
use fractal_api::util::AvatarMode;
use fractal_api::util::draw_identicon;
......@@ -117,7 +117,7 @@ impl<'a> RoomBox<'a> {
let members_count = gtk::Label::new(&format!("{}", room.n_members)[..]);
members_count.get_style_context().map(|c| c.add_class("dim-label"));
let join_button = gtk::Button::new_with_label(gettext("Join").as_str());
let join_button = gtk::Button::new_with_label(i18n("Join").as_str());
let room_id = room.id.clone();
let backend = self.op.backend.clone();
join_button.connect_clicked(move |_| {
......
......@@ -3,7 +3,8 @@ extern crate url;
extern crate gtk;
extern crate pango;
extern crate gdk;
extern crate gettextrs;
use i18n::i18n;
use glib;
use self::gdk::DragContextExtManual;
......@@ -11,7 +12,6 @@ use self::gdk::DragContextExtManual;
use self::url::Url;
use std::collections::HashMap;
use self::gtk::prelude::*;
use self::gettextrs::gettext;
use globals;
use widgets::roomrow::RoomRow;
......@@ -431,12 +431,12 @@ impl RoomList {
let widget = gtk::Box::new(gtk::Orientation::Vertical, 6);
let baseu = get_url(url);
let inv = RGroup::new(&baseu, gettext("Invites").as_str(),
gettext("You don’t have any invitations").as_str());
let fav = RGroup::new(&baseu, gettext("Favorites").as_str(),
gettext("Drag and drop rooms here to add them to your favorites").as_str());
let rooms = RGroup::new(&baseu, gettext("Rooms").as_str(),
gettext("You don’t have any rooms yet").as_str());
let inv = RGroup::new(&baseu, i18n("Invites").as_str(),
i18n("You don’t have any invitations").as_str());
let fav = RGroup::new(&baseu, i18n("Favorites").as_str(),
i18n("Drag and drop rooms here to add them to your favorites").as_str());
let rooms = RGroup::new(&baseu, i18n("Rooms").as_str(),
i18n("You don’t have any rooms yet").as_str());
let rl = RoomList {
baseu,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment