i18n: Use gettext function instead of wrapper
No need to deviate from the default here. Part-of: <https://gitlab.gnome.org/Incubator/loupe/-/merge_requests/170>
This commit is contained in:
parent
695693cf74
commit
f8cc9f5f84
16 changed files with 83 additions and 274 deletions
|
|
@ -1,13 +1,7 @@
|
||||||
i18n.gettext(
|
i18n.gettext(
|
||||||
meson.project_name(),
|
meson.project_name(),
|
||||||
args: [
|
args: [
|
||||||
'--keyword=i18n',
|
'--keyword=gettext_f',
|
||||||
'--keyword=i18n_f',
|
|
||||||
'--keyword=i18n_k',
|
|
||||||
'--keyword=ni18n:1,2',
|
|
||||||
'--keyword=ni18n_f:1,2',
|
|
||||||
'--keyword=ni18n_k:1,2'
|
|
||||||
],
|
],
|
||||||
preset: 'glib'
|
preset: 'glib'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
use crate::deps::*;
|
use crate::deps::*;
|
||||||
use crate::i18n::*;
|
use crate::util::gettext::*;
|
||||||
|
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
|
|
@ -184,10 +184,10 @@ impl LpApplication {
|
||||||
// an object and set all relevant properties very
|
// an object and set all relevant properties very
|
||||||
// easily in a way that's idiomatic to Rust.
|
// easily in a way that's idiomatic to Rust.
|
||||||
let about = adw::AboutWindow::builder()
|
let about = adw::AboutWindow::builder()
|
||||||
.application_name(i18n("Loupe"))
|
.application_name(gettext("Loupe"))
|
||||||
.application_icon(config::APP_ID)
|
.application_icon(config::APP_ID)
|
||||||
.version(config::VERSION)
|
.version(config::VERSION)
|
||||||
.developer_name(i18n("The Loupe Team"))
|
.developer_name(gettext("The Loupe Team"))
|
||||||
.website("https://gitlab.gnome.org/Incubator/loupe")
|
.website("https://gitlab.gnome.org/Incubator/loupe")
|
||||||
.issue_url("https://gitlab.gnome.org/Incubator/loupe/-/issues/new")
|
.issue_url("https://gitlab.gnome.org/Incubator/loupe/-/issues/new")
|
||||||
.developers([
|
.developers([
|
||||||
|
|
@ -196,8 +196,8 @@ impl LpApplication {
|
||||||
])
|
])
|
||||||
.designers(["Allan Day", "Jakub Steiner", "Tobias Bernard"])
|
.designers(["Allan Day", "Jakub Steiner", "Tobias Bernard"])
|
||||||
// Translators: Replace "translator-credits" with your names, one name per line
|
// Translators: Replace "translator-credits" with your names, one name per line
|
||||||
.translator_credits(i18n("translator-credits"))
|
.translator_credits(gettext("translator-credits"))
|
||||||
.copyright(i18n("Copyright © 2020–2023 Christopher Davis et al."))
|
.copyright(gettext("Copyright © 2020–2023 Christopher Davis et al."))
|
||||||
.license_type(gtk::License::Gpl30)
|
.license_type(gtk::License::Gpl30)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::decoder::tiling::{self, FrameBufferExt};
|
use crate::decoder::tiling::{self, FrameBufferExt};
|
||||||
use crate::deps::*;
|
use crate::deps::*;
|
||||||
use crate::i18n::*;
|
use crate::util::gettext::*;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
|
@ -28,7 +28,7 @@ impl Heif {
|
||||||
log::debug!("Loading HEIF");
|
log::debug!("Loading HEIF");
|
||||||
updater.spawn_error_handled(move || {
|
updater.spawn_error_handled(move || {
|
||||||
let ctx = HeifContext::read_from_file(&path.display().to_string())
|
let ctx = HeifContext::read_from_file(&path.display().to_string())
|
||||||
.context(i18n("Failed to read image"))?;
|
.context(gettext("Failed to read image"))?;
|
||||||
let handle = ctx.primary_image_handle()?;
|
let handle = ctx.primary_image_handle()?;
|
||||||
|
|
||||||
tiles.set_original_dimensions((handle.width(), handle.height()));
|
tiles.set_original_dimensions((handle.width(), handle.height()));
|
||||||
|
|
@ -61,7 +61,7 @@ impl Heif {
|
||||||
|
|
||||||
let mut image = LIBHEIF
|
let mut image = LIBHEIF
|
||||||
.decode(&handle, ColorSpace::Rgb(rgb_chroma), None)
|
.decode(&handle, ColorSpace::Rgb(rgb_chroma), None)
|
||||||
.context(i18n("Failed to decode image"))?;
|
.context(gettext("Failed to decode image"))?;
|
||||||
|
|
||||||
let plane = image
|
let plane = image
|
||||||
.planes_mut()
|
.planes_mut()
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::decoder::tiling::{self, FrameBufferExt};
|
use crate::decoder::tiling::{self, FrameBufferExt};
|
||||||
use crate::deps::*;
|
use crate::deps::*;
|
||||||
use crate::i18n::*;
|
use crate::util::gettext::*;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use arc_swap::ArcSwap;
|
use arc_swap::ArcSwap;
|
||||||
|
|
@ -35,7 +35,8 @@ impl ImageRsOther {
|
||||||
path: &Path,
|
path: &Path,
|
||||||
format: image_rs::ImageFormat,
|
format: image_rs::ImageFormat,
|
||||||
) -> anyhow::Result<image_rs::io::Reader<BufReader<File>>> {
|
) -> anyhow::Result<image_rs::io::Reader<BufReader<File>>> {
|
||||||
let mut reader = image_rs::io::Reader::open(path).context(i18n("Failed to open image"))?;
|
let mut reader =
|
||||||
|
image_rs::io::Reader::open(path).context(gettext("Failed to open image"))?;
|
||||||
reader.set_format(format);
|
reader.set_format(format);
|
||||||
Ok(reader)
|
Ok(reader)
|
||||||
}
|
}
|
||||||
|
|
@ -88,7 +89,7 @@ impl ImageRsOther {
|
||||||
|
|
||||||
reader.limits(image_rs::io::Limits::no_limits());
|
reader.limits(image_rs::io::Limits::no_limits());
|
||||||
|
|
||||||
let dynamic_image = reader.decode().context(i18n("Failed to decode image"))?;
|
let dynamic_image = reader.decode().context(gettext("Failed to decode image"))?;
|
||||||
|
|
||||||
let decoded_image = Decoded { dynamic_image };
|
let decoded_image = Decoded { dynamic_image };
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ pub use image_rs_other::ImageRsOther;
|
||||||
pub use svg::{Svg, RSVG_MAX_SIZE};
|
pub use svg::{Svg, RSVG_MAX_SIZE};
|
||||||
|
|
||||||
use super::{Decoder, DecoderUpdate, UpdateSender};
|
use super::{Decoder, DecoderUpdate, UpdateSender};
|
||||||
use crate::i18n::*;
|
use crate::util::gettext::*;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum ImageFormat {
|
pub enum ImageFormat {
|
||||||
|
|
@ -52,9 +52,9 @@ impl std::fmt::Display for ImageFormat {
|
||||||
write!(f, "{}", debug)
|
write!(f, "{}", debug)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::AnimatedGif => write!(f, "{}", i18n("Animated GIF")),
|
Self::AnimatedGif => write!(f, "{}", gettext("Animated GIF")),
|
||||||
Self::AnimatedWebP => write!(f, "{}", i18n("Animated WebP")),
|
Self::AnimatedWebP => write!(f, "{}", gettext("Animated WebP")),
|
||||||
Self::AnimatedPng => write!(f, "{}", i18n("Animated PNG")),
|
Self::AnimatedPng => write!(f, "{}", gettext("Animated PNG")),
|
||||||
Self::Heif => write!(f, "HEIF Container"),
|
Self::Heif => write!(f, "HEIF Container"),
|
||||||
Self::Svg => write!(f, "SVG"),
|
Self::Svg => write!(f, "SVG"),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ pub mod tiling;
|
||||||
pub use formats::ImageDimensionDetails;
|
pub use formats::ImageDimensionDetails;
|
||||||
|
|
||||||
use crate::deps::*;
|
use crate::deps::*;
|
||||||
use crate::i18n::*;
|
|
||||||
use crate::image_metadata::ImageMetadata;
|
use crate::image_metadata::ImageMetadata;
|
||||||
|
use crate::util::gettext::*;
|
||||||
use formats::*;
|
use formats::*;
|
||||||
use tiling::FrameBufferExt;
|
use tiling::FrameBufferExt;
|
||||||
|
|
||||||
|
|
@ -116,10 +116,10 @@ impl Decoder {
|
||||||
update_sender.send(DecoderUpdate::Metadata(ImageMetadata::load(&path)));
|
update_sender.send(DecoderUpdate::Metadata(ImageMetadata::load(&path)));
|
||||||
|
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
let file = std::fs::File::open(&path).context(i18n("Could not open image"))?;
|
let file = std::fs::File::open(&path).context(gettext("Could not open image"))?;
|
||||||
file.take(64)
|
file.take(64)
|
||||||
.read_to_end(&mut buf)
|
.read_to_end(&mut buf)
|
||||||
.context(i18n("Could not read image"))?;
|
.context(gettext("Could not read image"))?;
|
||||||
|
|
||||||
// Try magic bytes first and than file name extension
|
// Try magic bytes first and than file name extension
|
||||||
let format =
|
let format =
|
||||||
|
|
@ -166,12 +166,15 @@ impl Decoder {
|
||||||
update_sender.send(DecoderUpdate::Format(ImageFormat::Heif));
|
update_sender.send(DecoderUpdate::Format(ImageFormat::Heif));
|
||||||
return Ok(FormatDecoder::Heif(Heif::new(path, update_sender, tiles)));
|
return Ok(FormatDecoder::Heif(Heif::new(path, update_sender, tiles)));
|
||||||
} else {
|
} else {
|
||||||
bail!(i18n_f("Unknown image format: {}", &[content_type.as_str()]));
|
bail!(gettext_f(
|
||||||
|
"Unknown image format: {}",
|
||||||
|
&[content_type.as_str()]
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bail!(i18n("Unknown image format"))
|
bail!(gettext("Unknown image format"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request missing tiles
|
/// Request missing tiles
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
use crate::deps::*;
|
use crate::deps::*;
|
||||||
use crate::i18n::*;
|
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
use crate::util::gettext::*;
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
|
@ -111,7 +111,7 @@ impl LpFileModel {
|
||||||
gio::FileQueryInfoFlags::NONE,
|
gio::FileQueryInfoFlags::NONE,
|
||||||
gio::Cancellable::NONE,
|
gio::Cancellable::NONE,
|
||||||
)
|
)
|
||||||
.context(i18n("Could not list other files in directory."))?;
|
.context(gettext("Could not list other files in directory."))?;
|
||||||
|
|
||||||
enumerator.for_each(|info| {
|
enumerator.for_each(|info| {
|
||||||
if let Ok(info) = info {
|
if let Ok(info) = info {
|
||||||
|
|
|
||||||
213
src/i18n.rs
213
src/i18n.rs
|
|
@ -1,213 +0,0 @@
|
||||||
// i18n.rs
|
|
||||||
//
|
|
||||||
// Copyright 2018 Daniel García Moreno <danigm@wadobo.com>
|
|
||||||
//
|
|
||||||
// Copied from https://gitlab.gnome.org/GNOME/fractal/-/blob/376248fd4a3bff05897ef39111a4e6d1a558f333/fractal-gtk/src/util/i18n.rs
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
use gettextrs::gettext;
|
|
||||||
use gettextrs::ngettext;
|
|
||||||
use gettextrs::npgettext;
|
|
||||||
use gettextrs::pgettext;
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn freplace(mut s: String, args: &[&str]) -> String {
|
|
||||||
for arg in args {
|
|
||||||
s = s.replacen("{}", arg, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
s
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn kreplace(mut s: String, kwargs: &[(&str, &str)]) -> String {
|
|
||||||
for (k, v) in kwargs {
|
|
||||||
s = s.replace(&format!("{{{k}}}"), v);
|
|
||||||
}
|
|
||||||
|
|
||||||
s
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple translations functions
|
|
||||||
|
|
||||||
#[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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Singular and plural translations functions
|
|
||||||
|
|
||||||
#[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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Translations with context functions
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn pi18n(ctx: &str, format: &str) -> String {
|
|
||||||
pgettext(ctx, format)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn pi18n_f(ctx: &str, format: &str, args: &[&str]) -> String {
|
|
||||||
let s = pgettext(ctx, format);
|
|
||||||
freplace(s, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn pi18n_k(ctx: &str, format: &str, kwargs: &[(&str, &str)]) -> String {
|
|
||||||
let s = pgettext(ctx, format);
|
|
||||||
kreplace(s, kwargs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Singular and plural with context
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn pni18n(ctx: &str, single: &str, multiple: &str, number: u32) -> String {
|
|
||||||
npgettext(ctx, single, multiple, number)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn pni18n_f(ctx: &str, single: &str, multiple: &str, number: u32, args: &[&str]) -> String {
|
|
||||||
let s = npgettext(ctx, single, multiple, number);
|
|
||||||
freplace(s, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn pni18n_k(
|
|
||||||
ctx: &str,
|
|
||||||
single: &str,
|
|
||||||
multiple: &str,
|
|
||||||
number: u32,
|
|
||||||
kwargs: &[(&str, &str)],
|
|
||||||
) -> String {
|
|
||||||
let s = npgettext(ctx, single, multiple, number);
|
|
||||||
kreplace(s, kwargs)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
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]
|
|
||||||
fn test_i18n_f() {
|
|
||||||
let out = i18n_f("{} param", &["one"]);
|
|
||||||
assert_eq!(out, "one param");
|
|
||||||
|
|
||||||
let out = i18n_f("middle {} param", &["one"]);
|
|
||||||
assert_eq!(out, "middle one param");
|
|
||||||
|
|
||||||
let out = i18n_f("end {}", &["one"]);
|
|
||||||
assert_eq!(out, "end one");
|
|
||||||
|
|
||||||
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]
|
|
||||||
fn test_i18n_k() {
|
|
||||||
let out = i18n_k("{one} param", &[("one", "one")]);
|
|
||||||
assert_eq!(out, "one param");
|
|
||||||
|
|
||||||
let out = i18n_k("middle {one} param", &[("one", "one")]);
|
|
||||||
assert_eq!(out, "middle one param");
|
|
||||||
|
|
||||||
let out = i18n_k("end {one}", &[("one", "one")]);
|
|
||||||
assert_eq!(out, "end one");
|
|
||||||
|
|
||||||
let out = i18n_k("multiple {one} and {two}", &[("one", "1"), ("two", "two")]);
|
|
||||||
assert_eq!(out, "multiple 1 and two");
|
|
||||||
|
|
||||||
let out = i18n_k("multiple {two} and {one}", &[("one", "1"), ("two", "two")]);
|
|
||||||
assert_eq!(out, "multiple two and 1");
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pi18n() {
|
|
||||||
let out = pi18n("This is the context", "translate1");
|
|
||||||
assert_eq!(out, "translate1");
|
|
||||||
|
|
||||||
let out = pni18n("context", "translate1", "translate multi", 1);
|
|
||||||
assert_eq!(out, "translate1");
|
|
||||||
let out = pni18n("The context string", "translate1", "translate multi", 2);
|
|
||||||
assert_eq!(out, "translate multi");
|
|
||||||
|
|
||||||
let out = pi18n_f("Context for translation", "{} param", &["one"]);
|
|
||||||
assert_eq!(out, "one param");
|
|
||||||
|
|
||||||
let out = pi18n_k("context", "{one} param", &[("one", "one")]);
|
|
||||||
assert_eq!(out, "one param");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::i18n::*;
|
use crate::util::gettext::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct GPSLocation {
|
pub struct GPSLocation {
|
||||||
|
|
@ -133,10 +133,10 @@ impl GPSLocation {
|
||||||
let coord = self.latitude;
|
let coord = self.latitude;
|
||||||
let reference = if coord.sing {
|
let reference = if coord.sing {
|
||||||
// Translators: short for "north" in GPS coordinate
|
// Translators: short for "north" in GPS coordinate
|
||||||
i18n("N")
|
gettext("N")
|
||||||
} else {
|
} else {
|
||||||
// Translators: short for "south" in GPS coordinate
|
// Translators: short for "south" in GPS coordinate
|
||||||
i18n("S")
|
gettext("S")
|
||||||
};
|
};
|
||||||
|
|
||||||
coord.display(&reference)
|
coord.display(&reference)
|
||||||
|
|
@ -146,10 +146,10 @@ impl GPSLocation {
|
||||||
let coord = self.longitude;
|
let coord = self.longitude;
|
||||||
let reference = if coord.sing {
|
let reference = if coord.sing {
|
||||||
// Translators: short for "east" in GPS coordinate
|
// Translators: short for "east" in GPS coordinate
|
||||||
i18n("E")
|
gettext("E")
|
||||||
} else {
|
} else {
|
||||||
// Translators: short for "west" in GPS coordinate
|
// Translators: short for "west" in GPS coordinate
|
||||||
i18n("W")
|
gettext("W")
|
||||||
};
|
};
|
||||||
|
|
||||||
coord.display(&reference)
|
coord.display(&reference)
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ mod obj;
|
||||||
pub use gps::GPSLocation;
|
pub use gps::GPSLocation;
|
||||||
pub use obj::LpImageMetadata;
|
pub use obj::LpImageMetadata;
|
||||||
|
|
||||||
use crate::i18n::*;
|
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
use crate::util::gettext::*;
|
||||||
|
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
|
|
||||||
|
|
@ -126,7 +126,7 @@ impl ImageMetadata {
|
||||||
let exposure = format!("{:.0}", 1. / rational.first()?.to_f32());
|
let exposure = format!("{:.0}", 1. / rational.first()?.to_f32());
|
||||||
|
|
||||||
// Translators: Unit for exposure time in seconds
|
// Translators: Unit for exposure time in seconds
|
||||||
return Some(i18n_f("1\u{2215}{}\u{202F}s", &[&exposure]));
|
return Some(gettext_f("1\u{2215}{}\u{202F}s", &[&exposure]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,7 +151,7 @@ impl ImageMetadata {
|
||||||
if let exif::Value::Rational(rational) = &field.value {
|
if let exif::Value::Rational(rational) = &field.value {
|
||||||
let length = format!("{:.0}", rational.first()?.to_f32());
|
let length = format!("{:.0}", rational.first()?.to_f32());
|
||||||
// Translators: Unit for focal length in millimeters
|
// Translators: Unit for focal length in millimeters
|
||||||
return Some(i18n_f("{}\u{202F}mm", &[&length]));
|
return Some(gettext_f("{}\u{202F}mm", &[&length]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,6 @@ mod application;
|
||||||
mod config;
|
mod config;
|
||||||
mod decoder;
|
mod decoder;
|
||||||
mod file_model;
|
mod file_model;
|
||||||
mod i18n;
|
|
||||||
mod image_metadata;
|
mod image_metadata;
|
||||||
mod util;
|
mod util;
|
||||||
mod widgets;
|
mod widgets;
|
||||||
|
|
|
||||||
14
src/util/gettext.rs
Normal file
14
src/util/gettext.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
pub use gettextrs::gettext;
|
||||||
|
|
||||||
|
fn freplace(mut s: String, args: &[&str]) -> String {
|
||||||
|
for arg in args {
|
||||||
|
s = s.replacen("{}", arg, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gettext_f(format: &str, args: &[&str]) -> String {
|
||||||
|
let s = gettextrs::gettext(format);
|
||||||
|
freplace(s, args)
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
|
pub mod gettext;
|
||||||
|
|
||||||
use crate::deps::*;
|
use crate::deps::*;
|
||||||
use crate::i18n::*;
|
use crate::util::gettext::*;
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Context};
|
use anyhow::{anyhow, bail, Context};
|
||||||
use gio::prelude::*;
|
use gio::prelude::*;
|
||||||
|
|
@ -13,7 +15,7 @@ pub fn datetime_fmt(datetime: &glib::DateTime) -> Option<String> {
|
||||||
// Translators: This is the date and time format we use in metadata output etc.
|
// Translators: This is the date and time format we use in metadata output etc.
|
||||||
// The format has to follow <https://docs.gtk.org/glib/method.DateTime.format.html>
|
// The format has to follow <https://docs.gtk.org/glib/method.DateTime.format.html>
|
||||||
// The default is already translated. Don't change if you are not sure what to use.
|
// The default is already translated. Don't change if you are not sure what to use.
|
||||||
let datetime_format = i18n("%x %X");
|
let datetime_format = gettext("%x %X");
|
||||||
|
|
||||||
let fmt = datetime.format(&datetime_format);
|
let fmt = datetime.format(&datetime_format);
|
||||||
|
|
||||||
|
|
@ -146,7 +148,7 @@ pub async fn untrash(path: &Path) -> anyhow::Result<()> {
|
||||||
)
|
)
|
||||||
.0
|
.0
|
||||||
.await
|
.await
|
||||||
.context(i18n("Failed to restore image from trash"));
|
.context(gettext("Failed to restore image from trash"));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -31,8 +31,8 @@ use crate::deps::*;
|
||||||
|
|
||||||
use crate::decoder::tiling::FrameBufferExt;
|
use crate::decoder::tiling::FrameBufferExt;
|
||||||
use crate::decoder::{self, tiling, Decoder, DecoderUpdate};
|
use crate::decoder::{self, tiling, Decoder, DecoderUpdate};
|
||||||
use crate::i18n::i18n;
|
|
||||||
use crate::image_metadata::LpImageMetadata;
|
use crate::image_metadata::LpImageMetadata;
|
||||||
|
use crate::util::gettext::*;
|
||||||
use crate::util::Gesture;
|
use crate::util::Gesture;
|
||||||
|
|
||||||
use crate::util::spawn;
|
use crate::util::spawn;
|
||||||
|
|
@ -748,7 +748,7 @@ impl LpImage {
|
||||||
self.set_file(&file);
|
self.set_file(&file);
|
||||||
|
|
||||||
if !path.is_file() {
|
if !path.is_file() {
|
||||||
self.set_error(anyhow::Error::msg(i18n("File does not exist")));
|
self.set_error(anyhow::Error::msg(gettext("File does not exist")));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
use crate::deps::*;
|
use crate::deps::*;
|
||||||
use crate::file_model::LpFileModel;
|
use crate::file_model::LpFileModel;
|
||||||
use crate::i18n::*;
|
use crate::util::gettext::*;
|
||||||
use crate::util::{Direction, Position};
|
use crate::util::{Direction, Position};
|
||||||
use crate::widgets::{LpImage, LpImagePage, LpSlidingView};
|
use crate::widgets::{LpImage, LpImagePage, LpSlidingView};
|
||||||
|
|
||||||
|
|
@ -555,7 +555,7 @@ impl LpImageView {
|
||||||
let background = self
|
let background = self
|
||||||
.current_path()
|
.current_path()
|
||||||
.and_then(|p| std::fs::File::open(p).ok())
|
.and_then(|p| std::fs::File::open(p).ok())
|
||||||
.context(i18n("Failed to open new background image"))?;
|
.context(gettext("Failed to open new background image"))?;
|
||||||
let native = self.native().expect("View should have a GtkNative");
|
let native = self.native().expect("View should have a GtkNative");
|
||||||
let id = WindowIdentifier::from_native(&native).await;
|
let id = WindowIdentifier::from_native(&native).await;
|
||||||
|
|
||||||
|
|
@ -572,14 +572,14 @@ impl LpImageView {
|
||||||
Ok(_) => self
|
Ok(_) => self
|
||||||
.activate_action(
|
.activate_action(
|
||||||
"win.show-toast",
|
"win.show-toast",
|
||||||
Some(&(i18n("Set as background."), 1).to_variant()),
|
Some(&(gettext("Set as background."), 1).to_variant()),
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if !matches!(err, Error::Response(ResponseError::Cancelled)) {
|
if !matches!(err, Error::Response(ResponseError::Cancelled)) {
|
||||||
self.activate_action(
|
self.activate_action(
|
||||||
"win.show-toast",
|
"win.show-toast",
|
||||||
Some(&(i18n("Could not set background."), 1).to_variant()),
|
Some(&(gettext("Could not set background."), 1).to_variant()),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
use crate::deps::*;
|
use crate::deps::*;
|
||||||
use crate::i18n::*;
|
use crate::util::gettext::*;
|
||||||
|
|
||||||
use crate::util::spawn;
|
use crate::util::spawn;
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
|
|
@ -352,7 +352,7 @@ mod imp {
|
||||||
obj.set_image_from_path(&file.path().unwrap());
|
obj.set_image_from_path(&file.path().unwrap());
|
||||||
} else {
|
} else {
|
||||||
obj.show_toast(
|
obj.show_toast(
|
||||||
i18n_f("“{}” is not a valid image.", &[&info.display_name()]),
|
gettext_f("“{}” is not a valid image.", &[&info.display_name()]),
|
||||||
adw::ToastPriority::High,
|
adw::ToastPriority::High,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -428,7 +428,7 @@ impl LpWindow {
|
||||||
filter_store.append(&filter);
|
filter_store.append(&filter);
|
||||||
|
|
||||||
let chooser = gtk::FileDialog::builder()
|
let chooser = gtk::FileDialog::builder()
|
||||||
.title(i18n("Open Image"))
|
.title(gettext("Open Image"))
|
||||||
.filters(&filter_store)
|
.filters(&filter_store)
|
||||||
.modal(true)
|
.modal(true)
|
||||||
.build();
|
.build();
|
||||||
|
|
@ -482,7 +482,10 @@ impl LpWindow {
|
||||||
if let Err(e) = imp.image_view.copy() {
|
if let Err(e) = imp.image_view.copy() {
|
||||||
log::error!("Failed to copy to clipboard: {}", e);
|
log::error!("Failed to copy to clipboard: {}", e);
|
||||||
} else {
|
} else {
|
||||||
self.show_toast(i18n("Image copied to clipboard"), adw::ToastPriority::High);
|
self.show_toast(
|
||||||
|
gettext("Image copied to clipboard"),
|
||||||
|
adw::ToastPriority::High,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -496,8 +499,8 @@ impl LpWindow {
|
||||||
match result {
|
match result {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
let toast = adw::Toast::builder()
|
let toast = adw::Toast::builder()
|
||||||
.title(i18n("Image moved to trash"))
|
.title(gettext("Image moved to trash"))
|
||||||
.button_label(i18n("Undo"))
|
.button_label(gettext("Undo"))
|
||||||
.build();
|
.build();
|
||||||
toast.connect_button_clicked(glib::clone!(@weak self as win => move |_| {
|
toast.connect_button_clicked(glib::clone!(@weak self as win => move |_| {
|
||||||
let path = path.clone();
|
let path = path.clone();
|
||||||
|
|
@ -508,7 +511,7 @@ impl LpWindow {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!("Failed to untrash {path:?}: {err}");
|
log::error!("Failed to untrash {path:?}: {err}");
|
||||||
win.show_toast(
|
win.show_toast(
|
||||||
i18n("Failed to restore image from trash"),
|
gettext("Failed to restore image from trash"),
|
||||||
adw::ToastPriority::High,
|
adw::ToastPriority::High,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -523,7 +526,7 @@ impl LpWindow {
|
||||||
} else {
|
} else {
|
||||||
log::error!("Failed to delete file {path:?}: {err}");
|
log::error!("Failed to delete file {path:?}: {err}");
|
||||||
self.show_toast(
|
self.show_toast(
|
||||||
i18n("Failed to move image to trash"),
|
gettext("Failed to move image to trash"),
|
||||||
adw::ToastPriority::Normal,
|
adw::ToastPriority::Normal,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -538,8 +541,8 @@ impl LpWindow {
|
||||||
let dialog = adw::MessageDialog::builder()
|
let dialog = adw::MessageDialog::builder()
|
||||||
.modal(true)
|
.modal(true)
|
||||||
.transient_for(self)
|
.transient_for(self)
|
||||||
.heading(i18n("Permanently Delete Image?"))
|
.heading(gettext("Permanently Delete Image?"))
|
||||||
.body(i18n_f(
|
.body(gettext_f(
|
||||||
"The image “{}” can only be deleted permanently.",
|
"The image “{}” can only be deleted permanently.",
|
||||||
&[&PathBuf::from(&path.file_name().unwrap_or_default())
|
&[&PathBuf::from(&path.file_name().unwrap_or_default())
|
||||||
.display()
|
.display()
|
||||||
|
|
@ -547,7 +550,10 @@ impl LpWindow {
|
||||||
))
|
))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
dialog.add_responses(&[("cancel", &i18n("Cancel")), ("delete", &i18n("Delete"))]);
|
dialog.add_responses(&[
|
||||||
|
("cancel", &gettext("Cancel")),
|
||||||
|
("delete", &gettext("Delete")),
|
||||||
|
]);
|
||||||
dialog.set_response_appearance("delete", adw::ResponseAppearance::Destructive);
|
dialog.set_response_appearance("delete", adw::ResponseAppearance::Destructive);
|
||||||
|
|
||||||
if "delete" == dialog.choose_future().await {
|
if "delete" == dialog.choose_future().await {
|
||||||
|
|
@ -556,7 +562,10 @@ impl LpWindow {
|
||||||
|
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
log::error!("Failed to delete file {path:?}: {err}");
|
log::error!("Failed to delete file {path:?}: {err}");
|
||||||
self.show_toast(i18n("Failed to delete image"), adw::ToastPriority::Normal);
|
self.show_toast(
|
||||||
|
gettext("Failed to delete image"),
|
||||||
|
adw::ToastPriority::Normal,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -673,13 +682,13 @@ impl LpWindow {
|
||||||
fn window_title(&self, path: glib::variant::Variant) -> String {
|
fn window_title(&self, path: glib::variant::Variant) -> String {
|
||||||
// ensure that templates are initialized
|
// ensure that templates are initialized
|
||||||
if path.as_maybe().is_none() {
|
if path.as_maybe().is_none() {
|
||||||
i18n("Loupe")
|
gettext("Loupe")
|
||||||
} else {
|
} else {
|
||||||
self.imp()
|
self.imp()
|
||||||
.image_view
|
.image_view
|
||||||
.current_file()
|
.current_file()
|
||||||
.and_then(|f| util::get_file_display_name(&f)) // If the file exists, get display name
|
.and_then(|f| util::get_file_display_name(&f)) // If the file exists, get display name
|
||||||
.unwrap_or_else(|| i18n("Loupe")) // Return that or the default if there's nothing
|
.unwrap_or_else(|| gettext("Loupe")) // Return that or the default if there's nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue