feat: add i18n support for libcosmic widgets
This commit is contained in:
parent
ea349aca82
commit
066999586b
9 changed files with 110 additions and 15 deletions
|
|
@ -107,6 +107,13 @@ cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-c
|
||||||
chrono = "0.4.41"
|
chrono = "0.4.41"
|
||||||
cosmic-config = { path = "cosmic-config" }
|
cosmic-config = { path = "cosmic-config" }
|
||||||
cosmic-settings-config = { git = "https://github.com/pop-os/cosmic-settings-daemon", optional = true }
|
cosmic-settings-config = { git = "https://github.com/pop-os/cosmic-settings-daemon", optional = true }
|
||||||
|
# Internationalization
|
||||||
|
i18n-embed = { version = "0.16.0", features = [
|
||||||
|
"fluent-system",
|
||||||
|
"desktop-requester",
|
||||||
|
] }
|
||||||
|
i18n-embed-fl = "0.10"
|
||||||
|
rust-embed = "8.7.2"
|
||||||
css-color = "0.2.8"
|
css-color = "0.2.8"
|
||||||
derive_setters = "0.1.8"
|
derive_setters = "0.1.8"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
|
|
|
||||||
4
i18n.toml
Normal file
4
i18n.toml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
fallback_language = "en"
|
||||||
|
|
||||||
|
[fluent]
|
||||||
|
assets_dir = "i18n"
|
||||||
11
i18n/en/libcosmic.ftl
Normal file
11
i18n/en/libcosmic.ftl
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Context Drawer
|
||||||
|
close = Close
|
||||||
|
|
||||||
|
# About
|
||||||
|
license = License
|
||||||
|
links = Links
|
||||||
|
developers = Developers
|
||||||
|
designers = Designers
|
||||||
|
artists = Artists
|
||||||
|
translators = Translators
|
||||||
|
documenters = Documenters
|
||||||
11
i18n/sr-Cyrl/libcosmic.ftl
Normal file
11
i18n/sr-Cyrl/libcosmic.ftl
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Context Drawer
|
||||||
|
close = Затвори
|
||||||
|
|
||||||
|
# About
|
||||||
|
license = Лиценца
|
||||||
|
links = Линкови
|
||||||
|
Developers = Програмери
|
||||||
|
Designers = Дизајнери
|
||||||
|
Artists = Уметници
|
||||||
|
Translators = Преводиоци
|
||||||
|
Documenters = Документатори
|
||||||
11
i18n/sr-Latn/libcosmic.ftl
Normal file
11
i18n/sr-Latn/libcosmic.ftl
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Context Drawer
|
||||||
|
close = Zatvori
|
||||||
|
|
||||||
|
# About
|
||||||
|
license = Licenca
|
||||||
|
links = Linkovi
|
||||||
|
developers = Programeri
|
||||||
|
designers = Dizajneri
|
||||||
|
artists = Umetnici
|
||||||
|
translators = Prevodioci
|
||||||
|
documenters = Dokumentatori
|
||||||
|
|
@ -90,6 +90,8 @@ pub use iced_wgpu;
|
||||||
pub mod icon_theme;
|
pub mod icon_theme;
|
||||||
pub mod keyboard_nav;
|
pub mod keyboard_nav;
|
||||||
|
|
||||||
|
mod localize;
|
||||||
|
|
||||||
#[cfg(all(target_env = "gnu", not(target_os = "windows")))]
|
#[cfg(all(target_env = "gnu", not(target_os = "windows")))]
|
||||||
pub(crate) mod malloc;
|
pub(crate) mod malloc;
|
||||||
|
|
||||||
|
|
|
||||||
51
src/localize.rs
Normal file
51
src/localize.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use i18n_embed::{
|
||||||
|
DefaultLocalizer, LanguageLoader, Localizer,
|
||||||
|
fluent::{FluentLanguageLoader, fluent_language_loader},
|
||||||
|
};
|
||||||
|
use rust_embed::RustEmbed;
|
||||||
|
use std::sync::{LazyLock, OnceLock};
|
||||||
|
|
||||||
|
#[derive(RustEmbed)]
|
||||||
|
#[folder = "i18n/"]
|
||||||
|
struct Localizations;
|
||||||
|
|
||||||
|
pub static LANGUAGE_LOADER: LazyLock<FluentLanguageLoader> = LazyLock::new(|| {
|
||||||
|
let loader: FluentLanguageLoader = fluent_language_loader!();
|
||||||
|
|
||||||
|
loader
|
||||||
|
.load_fallback_language(&Localizations)
|
||||||
|
.expect("Error while loading fallback language");
|
||||||
|
|
||||||
|
loader
|
||||||
|
});
|
||||||
|
|
||||||
|
static LOCALIZATION_INITIALIZED: OnceLock<()> = OnceLock::new();
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! fl {
|
||||||
|
($message_id:literal) => {{
|
||||||
|
$crate::localize::localize();
|
||||||
|
i18n_embed_fl::fl!($crate::localize::LANGUAGE_LOADER, $message_id)
|
||||||
|
}};
|
||||||
|
($message_id:literal, $($args:expr),*) => {{
|
||||||
|
$crate::localize::localize();
|
||||||
|
i18n_embed_fl::fl!($crate::localize::LANGUAGE_LOADER, $message_id, $($args), *)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the `Localizer` to be used for localizing this library.
|
||||||
|
pub fn localizer() -> Box<dyn Localizer> {
|
||||||
|
Box::from(DefaultLocalizer::new(&*LANGUAGE_LOADER, &Localizations))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn localize() {
|
||||||
|
LOCALIZATION_INITIALIZED.get_or_init(|| {
|
||||||
|
let localizer = localizer();
|
||||||
|
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
||||||
|
if let Err(error) = localizer.select(&requested_languages) {
|
||||||
|
eprintln!("Error while loading language for libcosmic {}", error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
Element,
|
Element, fl,
|
||||||
iced::{Alignment, Length},
|
iced::{Alignment, Length},
|
||||||
widget::{self, horizontal_space},
|
widget::{self, horizontal_space},
|
||||||
},
|
},
|
||||||
|
|
@ -116,7 +116,7 @@ pub fn about<'a, Message: Clone + 'static>(
|
||||||
space_xxs, space_m, ..
|
space_xxs, space_m, ..
|
||||||
} = crate::theme::spacing();
|
} = crate::theme::spacing();
|
||||||
|
|
||||||
let section = |list: &'a Vec<(String, String)>, title: &'a str| {
|
let section = |list: &'a Vec<(String, String)>, title: String| {
|
||||||
(!list.is_empty()).then_some({
|
(!list.is_empty()).then_some({
|
||||||
let items: Vec<Element<Message>> =
|
let items: Vec<Element<Message>> =
|
||||||
list.iter()
|
list.iter()
|
||||||
|
|
@ -150,15 +150,15 @@ pub fn about<'a, Message: Clone + 'static>(
|
||||||
});
|
});
|
||||||
let author = about.author.as_ref().map(widget::text::body);
|
let author = about.author.as_ref().map(widget::text::body);
|
||||||
let version = about.version.as_ref().map(widget::button::standard);
|
let version = about.version.as_ref().map(widget::button::standard);
|
||||||
let links_section = section(&about.links, "Links");
|
let links_section = section(&about.links, fl!("links"));
|
||||||
let developers_section = section(&about.developers, "Developers");
|
let developers_section = section(&about.developers, fl!("developers"));
|
||||||
let designers_section = section(&about.designers, "Designers");
|
let designers_section = section(&about.designers, fl!("designers"));
|
||||||
let artists_section = section(&about.artists, "Artists");
|
let artists_section = section(&about.artists, fl!("artists"));
|
||||||
let translators_section = section(&about.translators, "Translators");
|
let translators_section = section(&about.translators, fl!("translators"));
|
||||||
let documenters_section = section(&about.documenters, "Documenters");
|
let documenters_section = section(&about.documenters, fl!("documenters"));
|
||||||
let license = about.license.as_ref().map(|license| {
|
let license = about.license.as_ref().map(|license| {
|
||||||
let url = about.get_license_url();
|
let url = about.get_license_url();
|
||||||
widget::settings::section().title("License").add(
|
widget::settings::section().title(fl!("license")).add(
|
||||||
widget::button::custom(
|
widget::button::custom(
|
||||||
widget::row()
|
widget::row()
|
||||||
.push(widget::text(license))
|
.push(widget::text(license))
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
// Copyright 2023 System76 <info@system76.com>
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
use crate::widget::{LayerContainer, button, column, container, icon, row, scrollable, text};
|
|
||||||
use crate::{Apply, Element, Renderer, Theme};
|
|
||||||
|
|
||||||
use super::overlay::Overlay;
|
use super::overlay::Overlay;
|
||||||
|
use crate::widget::{LayerContainer, button, column, container, icon, row, scrollable, text};
|
||||||
|
use crate::{Apply, Element, Renderer, Theme, fl};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use iced_core::Alignment;
|
use iced_core::Alignment;
|
||||||
use iced_core::event::{self, Event};
|
use iced_core::event::{self, Event};
|
||||||
|
|
@ -86,7 +84,7 @@ impl<'a, Message: Clone + 'static> ContextDrawer<'a, Message> {
|
||||||
)
|
)
|
||||||
.push_maybe(title)
|
.push_maybe(title)
|
||||||
.push(
|
.push(
|
||||||
button::text("Close")
|
button::text(fl!("close"))
|
||||||
.trailing_icon(icon::from_name("go-next-symbolic"))
|
.trailing_icon(icon::from_name("go-next-symbolic"))
|
||||||
.on_press(on_close)
|
.on_press(on_close)
|
||||||
.apply(container)
|
.apply(container)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue