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"
|
||||
cosmic-config = { path = "cosmic-config" }
|
||||
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"
|
||||
derive_setters = "0.1.8"
|
||||
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 keyboard_nav;
|
||||
|
||||
mod localize;
|
||||
|
||||
#[cfg(all(target_env = "gnu", not(target_os = "windows")))]
|
||||
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 {
|
||||
crate::{
|
||||
Element,
|
||||
Element, fl,
|
||||
iced::{Alignment, Length},
|
||||
widget::{self, horizontal_space},
|
||||
},
|
||||
|
|
@ -116,7 +116,7 @@ pub fn about<'a, Message: Clone + 'static>(
|
|||
space_xxs, space_m, ..
|
||||
} = 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({
|
||||
let items: Vec<Element<Message>> =
|
||||
list.iter()
|
||||
|
|
@ -150,15 +150,15 @@ pub fn about<'a, Message: Clone + 'static>(
|
|||
});
|
||||
let author = about.author.as_ref().map(widget::text::body);
|
||||
let version = about.version.as_ref().map(widget::button::standard);
|
||||
let links_section = section(&about.links, "Links");
|
||||
let developers_section = section(&about.developers, "Developers");
|
||||
let designers_section = section(&about.designers, "Designers");
|
||||
let artists_section = section(&about.artists, "Artists");
|
||||
let translators_section = section(&about.translators, "Translators");
|
||||
let documenters_section = section(&about.documenters, "Documenters");
|
||||
let links_section = section(&about.links, fl!("links"));
|
||||
let developers_section = section(&about.developers, fl!("developers"));
|
||||
let designers_section = section(&about.designers, fl!("designers"));
|
||||
let artists_section = section(&about.artists, fl!("artists"));
|
||||
let translators_section = section(&about.translators, fl!("translators"));
|
||||
let documenters_section = section(&about.documenters, fl!("documenters"));
|
||||
let license = about.license.as_ref().map(|license| {
|
||||
let url = about.get_license_url();
|
||||
widget::settings::section().title("License").add(
|
||||
widget::settings::section().title(fl!("license")).add(
|
||||
widget::button::custom(
|
||||
widget::row()
|
||||
.push(widget::text(license))
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
// Copyright 2023 System76 <info@system76.com>
|
||||
// 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 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::event::{self, Event};
|
||||
|
|
@ -86,7 +84,7 @@ impl<'a, Message: Clone + 'static> ContextDrawer<'a, Message> {
|
|||
)
|
||||
.push_maybe(title)
|
||||
.push(
|
||||
button::text("Close")
|
||||
button::text(fl!("close"))
|
||||
.trailing_icon(icon::from_name("go-next-symbolic"))
|
||||
.on_press(on_close)
|
||||
.apply(container)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue