Compare commits
2 Commits
5c7f7766de
...
4114e64b8e
Author | SHA1 | Date |
---|---|---|
Savanni D'Gerinel | 4114e64b8e | |
Savanni D'Gerinel | ff1d117e8c |
|
@ -2709,6 +2709,8 @@ dependencies = [
|
||||||
"libadwaita",
|
"libadwaita",
|
||||||
"pango",
|
"pango",
|
||||||
"sgf",
|
"sgf",
|
||||||
|
"sys-locale",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
16
Cargo.nix
16
Cargo.nix
|
@ -8735,6 +8735,14 @@ rec {
|
||||||
name = "cairo-rs";
|
name = "cairo-rs";
|
||||||
packageId = "cairo-rs";
|
packageId = "cairo-rs";
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
name = "fluent";
|
||||||
|
packageId = "fluent";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "fluent-ergonomics";
|
||||||
|
packageId = "fluent-ergonomics";
|
||||||
|
}
|
||||||
{
|
{
|
||||||
name = "gio";
|
name = "gio";
|
||||||
packageId = "gio";
|
packageId = "gio";
|
||||||
|
@ -8867,6 +8875,10 @@ rec {
|
||||||
name = "icu_provider";
|
name = "icu_provider";
|
||||||
packageId = "icu_provider";
|
packageId = "icu_provider";
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
name = "intl-memoizer";
|
||||||
|
packageId = "intl-memoizer";
|
||||||
|
}
|
||||||
{
|
{
|
||||||
name = "serde";
|
name = "serde";
|
||||||
packageId = "serde 1.0.193";
|
packageId = "serde 1.0.193";
|
||||||
|
@ -8880,6 +8892,10 @@ rec {
|
||||||
name = "sys-locale";
|
name = "sys-locale";
|
||||||
packageId = "sys-locale";
|
packageId = "sys-locale";
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
name = "thiserror";
|
||||||
|
packageId = "thiserror";
|
||||||
|
}
|
||||||
{
|
{
|
||||||
name = "unic-langid";
|
name = "unic-langid";
|
||||||
packageId = "unic-langid";
|
packageId = "unic-langid";
|
||||||
|
|
30
flake.nix
30
flake.nix
|
@ -17,6 +17,21 @@
|
||||||
let
|
let
|
||||||
pkgs = import nixpkgs { system = "x86_64-linux"; };
|
pkgs = import nixpkgs { system = "x86_64-linux"; };
|
||||||
pkgs-unstable = import unstable { system = "x86_64-linux"; };
|
pkgs-unstable = import unstable { system = "x86_64-linux"; };
|
||||||
|
|
||||||
|
cargo_nix = pkgs.callPackage ./Cargo.nix {
|
||||||
|
nixpkgs = pkgs;
|
||||||
|
};
|
||||||
|
|
||||||
|
l10n-codegen-rust = pkgs.stdenv.mkDerivation {
|
||||||
|
name = "l10n-codegen-rust";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
cp ${cargo_nix.workspaceMembers.l10n.build}/bin/codegen-rust $out/bin/l10n-codegen-rust
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
in
|
in
|
||||||
pkgs.mkShell {
|
pkgs.mkShell {
|
||||||
name = "ld-tools-devshell";
|
name = "ld-tools-devshell";
|
||||||
|
@ -45,6 +60,8 @@
|
||||||
pkgs.udev
|
pkgs.udev
|
||||||
pkgs.wasm-pack
|
pkgs.wasm-pack
|
||||||
typeshare.packages."x86_64-linux".default
|
typeshare.packages."x86_64-linux".default
|
||||||
|
|
||||||
|
l10n-codegen-rust
|
||||||
];
|
];
|
||||||
LIBCLANG_PATH="${pkgs.llvmPackages.libclang.lib}/lib";
|
LIBCLANG_PATH="${pkgs.llvmPackages.libclang.lib}/lib";
|
||||||
ENV = "dev";
|
ENV = "dev";
|
||||||
|
@ -86,17 +103,6 @@
|
||||||
file-service = cargo_nix.workspaceMembers.file-service.build;
|
file-service = cargo_nix.workspaceMembers.file-service.build;
|
||||||
fitnesstrax = cargo_nix.workspaceMembers.fitnesstrax.build;
|
fitnesstrax = cargo_nix.workspaceMembers.fitnesstrax.build;
|
||||||
kifu-gtk = cargo_nix.workspaceMembers.kifu-gtk.build;
|
kifu-gtk = cargo_nix.workspaceMembers.kifu-gtk.build;
|
||||||
l10n = cargo_nix.workspaceMembers.l10n.build;
|
|
||||||
l10n-codegen-rust = pkgs.stdenv.mkDerivation {
|
|
||||||
name = "l10n-codegen-rust";
|
|
||||||
src = ./.;
|
|
||||||
buildInputs = [ l10n ];
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
mkdir -p $out/bin
|
|
||||||
cp ${l10n}/bin/codegen-rust $out/bin/l10n-codegen-rust
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
xdg-test = cargo_nix.workspaceMembers.xdg-test.build;
|
xdg-test = cargo_nix.workspaceMembers.xdg-test.build;
|
||||||
|
|
||||||
all = pkgs.symlinkJoin {
|
all = pkgs.symlinkJoin {
|
||||||
|
@ -107,8 +113,6 @@
|
||||||
file-service
|
file-service
|
||||||
fitnesstrax
|
fitnesstrax
|
||||||
# kifu-gtk
|
# kifu-gtk
|
||||||
l10n
|
|
||||||
l10n-codegen-rust
|
|
||||||
xdg-test
|
xdg-test
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,8 +13,8 @@ adw = { version = "0.5", package = "libadwaita", features = [ "v1_2"
|
||||||
async-channel = { version = "2" }
|
async-channel = { version = "2" }
|
||||||
async-std = { version = "1" }
|
async-std = { version = "1" }
|
||||||
cairo-rs = { version = "0.18" }
|
cairo-rs = { version = "0.18" }
|
||||||
fluent = { version = "0.16" }
|
|
||||||
fluent-ergonomics = { path = "../../fluent-ergonomics" }
|
fluent-ergonomics = { path = "../../fluent-ergonomics" }
|
||||||
|
fluent = { version = "0.16" }
|
||||||
gio = { version = "0.18" }
|
gio = { version = "0.18" }
|
||||||
glib = { version = "0.18" }
|
glib = { version = "0.18" }
|
||||||
gtk = { version = "0.7", package = "gtk4", features = [ "v4_8" ] }
|
gtk = { version = "0.7", package = "gtk4", features = [ "v4_8" ] }
|
||||||
|
@ -23,6 +23,8 @@ kifu-core = { path = "../core" }
|
||||||
l10n = { path = "../../l10n" }
|
l10n = { path = "../../l10n" }
|
||||||
pango = { version = "*" }
|
pango = { version = "*" }
|
||||||
sgf = { path = "../../sgf" }
|
sgf = { path = "../../sgf" }
|
||||||
|
sys-locale = { version = "0.3" }
|
||||||
|
thiserror = { version = "1" }
|
||||||
tokio = { version = "1.26", features = [ "full" ] }
|
tokio = { version = "1.26", features = [ "full" ] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|
|
@ -1,7 +1,29 @@
|
||||||
|
use std::{path::PathBuf, env, process, fs::File, io::Write};
|
||||||
|
|
||||||
|
fn generate_message_types(dest: &PathBuf) {
|
||||||
|
println!("message types");
|
||||||
|
let output: Vec<u8> = process::Command::new("l10n-codegen-rust")
|
||||||
|
.arg("messages/en.yaml")
|
||||||
|
.output()
|
||||||
|
.unwrap()
|
||||||
|
.stdout;
|
||||||
|
|
||||||
|
let mut file = File::create(dest).unwrap();
|
||||||
|
file.write(&output).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
glib_build_tools::compile_resources(
|
glib_build_tools::compile_resources(
|
||||||
&["resources"],
|
&["resources"],
|
||||||
"gresources.xml",
|
"gresources.xml",
|
||||||
"com.luminescent-dreams.kifu-gtk.gresource",
|
"com.luminescent-dreams.kifu-gtk.gresource",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// println!("OUT_DIR={}", env::var("OUT_DIR").unwrap());
|
||||||
|
let mut message_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||||
|
message_path.push("messages.rs");
|
||||||
|
|
||||||
|
generate_message_types(&message_path);
|
||||||
|
|
||||||
|
println!("cargo:rustc-env=KIFU_GTK_MESSAGES={}", message_path.to_string_lossy());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
nothing-here = Nenio estas ĉi tie
|
nothing-here = Nenio estas ĉi tie
|
||||||
hello = Saluton, ${name}
|
hello = Saluton, ${name}
|
||||||
welcome = Bonvenon
|
welcome = Bonvenon
|
||||||
games-in-database = {count ->
|
games-in-database = {$count ->
|
||||||
[one] Estas unu ludon en la datumbazo.
|
[one] Estas unu ludon en la datumbazo.
|
||||||
[other] Estas {count} ludojn en la datumbazo.
|
*[other] Estas ${count} ludojn en la datumbazo.
|
||||||
}
|
}
|
|
@ -1,15 +1,18 @@
|
||||||
mod messages;
|
use async_std::task::yield_now;
|
||||||
|
use kifu_core::{Core, CoreRequest, Observable};
|
||||||
|
use l10n::{NonEmptyList, L10N};
|
||||||
|
use std::{rc::Rc, sync::Arc};
|
||||||
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
|
mod messages {
|
||||||
|
include!(env!("KIFU_GTK_MESSAGES"));
|
||||||
|
}
|
||||||
|
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
|
||||||
mod view_models;
|
mod view_models;
|
||||||
mod views;
|
mod views;
|
||||||
|
|
||||||
use async_std::task::yield_now;
|
|
||||||
use kifu_core::{Core, CoreRequest, CoreResponse, Observable};
|
|
||||||
use std::{rc::Rc, sync::Arc};
|
|
||||||
use tokio::runtime::Runtime;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CoreApi {
|
pub struct CoreApi {
|
||||||
pub rt: Arc<Runtime>,
|
pub rt: Arc<Runtime>,
|
||||||
|
@ -41,6 +44,45 @@ where
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// AppContext is our global store for things that need to be available everywhere. Developers
|
||||||
|
/// should never pass this around directly, but should instead pass it around by traits. This is to
|
||||||
|
/// provide systems such as:
|
||||||
|
///
|
||||||
|
/// - Feature Flags
|
||||||
|
/// - L10N
|
||||||
|
pub struct AppContext {
|
||||||
|
pub l10n: L10N,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AppContextInitError {}
|
||||||
|
|
||||||
|
impl AppContext {
|
||||||
|
pub fn new() -> Result<Self, AppContextInitError> {
|
||||||
|
let mut locale_list = NonEmptyList::new("en-US");
|
||||||
|
|
||||||
|
let user_locale = sys_locale::get_locale().unwrap();
|
||||||
|
println!("user locale: {}", user_locale);
|
||||||
|
if locale_list.find(|l| *l == user_locale).is_none() {
|
||||||
|
locale_list.push(&user_locale);
|
||||||
|
}
|
||||||
|
let mut l10n = l10n::L10N::new("messages".into());
|
||||||
|
l10n.set_locales(locale_list);
|
||||||
|
|
||||||
|
Ok(Self { l10n })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ProvidesL10N {
|
||||||
|
fn l10n(&self) -> &L10N;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProvidesL10N for AppContext {
|
||||||
|
fn l10n(&self) -> &L10N {
|
||||||
|
&self.l10n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// LocalObserver creates a task on the current thread which watches the specified observer for notifications and calls the handler function with each one.
|
/// LocalObserver creates a task on the current thread which watches the specified observer for notifications and calls the handler function with each one.
|
||||||
///
|
///
|
||||||
/// The LocalObserver starts a task which listens for notifications during the constructor. When the observer goes out of scope, it will make a point of aborting the task. This combination means that anything which uses the observer can create it, hold on to a reference of it, and then drop it when done, and not have to do anything else with the observer object.
|
/// The LocalObserver starts a task which listens for notifications during the constructor. When the observer goes out of scope, it will make a point of aborting the task. This combination means that anything which uses the observer can create it, hold on to a reference of it, and then drop it when done, and not have to do anything else with the observer object.
|
||||||
|
|
|
@ -3,8 +3,9 @@ use kifu_core::{Config, ConfigOption, Core, CoreRequest, CoreResponse, DatabaseP
|
||||||
use kifu_gtk::{
|
use kifu_gtk::{
|
||||||
perftrace,
|
perftrace,
|
||||||
ui::{AppWindow, ConfigurationPage, Home, PlayingField},
|
ui::{AppWindow, ConfigurationPage, Home, PlayingField},
|
||||||
CoreApi,
|
AppContext, CoreApi,
|
||||||
};
|
};
|
||||||
|
use l10n::NonEmptyList;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
const APP_ID_DEV: &str = "com.luminescent-dreams.kifu-gtk.dev";
|
const APP_ID_DEV: &str = "com.luminescent-dreams.kifu-gtk.dev";
|
||||||
|
@ -104,7 +105,9 @@ fn main() {
|
||||||
app.connect_activate({
|
app.connect_activate({
|
||||||
let runtime = runtime.clone();
|
let runtime = runtime.clone();
|
||||||
move |app| {
|
move |app| {
|
||||||
let app_window = AppWindow::new(app);
|
|
||||||
|
let ctx = AppContext::new().unwrap();
|
||||||
|
let app_window = AppWindow::new(app, &ctx);
|
||||||
|
|
||||||
let api = CoreApi {
|
let api = CoreApi {
|
||||||
rt: runtime.clone(),
|
rt: runtime.clone(),
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
// This file was autogenerated from l10n-codegen-rust. Edits will be lost
|
|
||||||
// on next generation.
|
|
||||||
use l10n::Message;
|
|
||||||
use fluent::FluentArgs;
|
|
||||||
|
|
||||||
pub struct Hello {
|
|
||||||
name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Message for Hello {
|
|
||||||
fn msgid(&self) -> &str {
|
|
||||||
"hello"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn args(&self) -> Option<FluentArgs> {
|
|
||||||
let mut args = FluentArgs::new();
|
|
||||||
args.set("name", self.name.clone());
|
|
||||||
Some(args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Welcome;
|
|
||||||
impl Message for Welcome {
|
|
||||||
fn msgid(&self) -> &str {
|
|
||||||
"welcome"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn args(&self) -> Option<FluentArgs> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct GamesInDatabase {
|
|
||||||
count: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Message for GamesInDatabase {
|
|
||||||
fn msgid(&self) -> &str {
|
|
||||||
"games-in-database"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn args(&self) -> Option<FluentArgs> {
|
|
||||||
let mut args = FluentArgs::new();
|
|
||||||
args.set("count", self.count.clone());
|
|
||||||
Some(args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NothingHere;
|
|
||||||
impl Message for NothingHere {
|
|
||||||
fn msgid(&self) -> &str {
|
|
||||||
"nothing-here"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn args(&self) -> Option<FluentArgs> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,9 +2,9 @@ use adw::prelude::*;
|
||||||
use gio::resources_lookup_data;
|
use gio::resources_lookup_data;
|
||||||
use glib::IsA;
|
use glib::IsA;
|
||||||
use gtk::STYLE_PROVIDER_PRIORITY_USER;
|
use gtk::STYLE_PROVIDER_PRIORITY_USER;
|
||||||
use l10n::L10N;
|
use l10n::{L10N, NonEmptyList};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use crate::messages;
|
use crate::{ProvidesL10N, messages};
|
||||||
|
|
||||||
mod chat;
|
mod chat;
|
||||||
pub use chat::Chat;
|
pub use chat::Chat;
|
||||||
|
@ -40,7 +40,7 @@ pub struct AppWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppWindow {
|
impl AppWindow {
|
||||||
pub fn new(app: &adw::Application) -> Self {
|
pub fn new(app: &adw::Application, ctx: &impl ProvidesL10N) -> Self {
|
||||||
let window = adw::ApplicationWindow::builder()
|
let window = adw::ApplicationWindow::builder()
|
||||||
.application(app)
|
.application(app)
|
||||||
.width_request(800)
|
.width_request(800)
|
||||||
|
@ -78,9 +78,8 @@ impl AppWindow {
|
||||||
header.pack_end(&hamburger);
|
header.pack_end(&hamburger);
|
||||||
|
|
||||||
let content = adw::Bin::builder().css_classes(vec!["content"]).build();
|
let content = adw::Bin::builder().css_classes(vec!["content"]).build();
|
||||||
let l10n = L10N::new(PathBuf::from("resources"));
|
|
||||||
content.set_child(Some(
|
content.set_child(Some(
|
||||||
&adw::StatusPage::builder().title(l10n.tr(messages::NothingHere)).build(),
|
&adw::StatusPage::builder().title(ctx.l10n().tr(messages::NothingHere)).build(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let layout = gtk::Box::builder()
|
let layout = gtk::Box::builder()
|
||||||
|
|
|
@ -22,11 +22,13 @@ pub enum NonEmptyListError {
|
||||||
pub struct NonEmptyList<A>(Vec<A>);
|
pub struct NonEmptyList<A>(Vec<A>);
|
||||||
|
|
||||||
impl<A> NonEmptyList<A> {
|
impl<A> NonEmptyList<A> {
|
||||||
fn new(elem: A) -> Self {
|
pub fn new(elem: A) -> Self {
|
||||||
Self(vec![elem])
|
Self(vec![elem])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_iter(iter: impl IntoIterator<Item = A>) -> Result<NonEmptyList<A>, NonEmptyListError> {
|
pub fn from_iter(
|
||||||
|
iter: impl IntoIterator<Item = A>,
|
||||||
|
) -> Result<NonEmptyList<A>, NonEmptyListError> {
|
||||||
let lst = iter.into_iter().collect::<Vec<A>>();
|
let lst = iter.into_iter().collect::<Vec<A>>();
|
||||||
if lst.len() > 0 {
|
if lst.len() > 0 {
|
||||||
Ok(NonEmptyList(lst))
|
Ok(NonEmptyList(lst))
|
||||||
|
@ -35,9 +37,21 @@ impl<A> NonEmptyList<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, item: A) {
|
||||||
|
self.0.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find(&self, f: impl Fn(&A) -> bool) -> Option<&A> {
|
||||||
|
self.0.iter().find(|item| f(*item))
|
||||||
|
}
|
||||||
|
|
||||||
fn first(&self) -> &A {
|
fn first(&self) -> &A {
|
||||||
&self.0[0]
|
&self.0[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn iter<'a>(&'a self) -> impl Iterator<Item = &'a A> {
|
||||||
|
self.0.iter()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> Deref for NonEmptyList<A> {
|
impl<A> Deref for NonEmptyList<A> {
|
||||||
|
@ -68,7 +82,7 @@ pub enum FileLoadError {
|
||||||
FileNotFound,
|
FileNotFound,
|
||||||
|
|
||||||
#[error("The Fluent file is malformed")]
|
#[error("The Fluent file is malformed")]
|
||||||
FluentParseError,
|
FluentParseError(String),
|
||||||
|
|
||||||
#[error("An unknown IO error was found")]
|
#[error("An unknown IO error was found")]
|
||||||
IOError(std::io::Error),
|
IOError(std::io::Error),
|
||||||
|
@ -156,7 +170,13 @@ impl L10N {
|
||||||
self.message_bundles.push(bundle);
|
self.message_bundles.push(bundle);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err((_, _error)) => Err(FileLoadError::FluentParseError),
|
Err((_, errors)) => Err(FileLoadError::FluentParseError(
|
||||||
|
errors
|
||||||
|
.into_iter()
|
||||||
|
.map(|err| err.to_string())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join("\n"),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +198,13 @@ impl L10N {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|locale| Locale::try_from_bytes(locale.as_bytes()))
|
.map(|locale| Locale::try_from_bytes(locale.as_bytes()))
|
||||||
.collect::<Result<Vec<Locale>, icu::locid::Error>>()?;
|
.collect::<Result<Vec<Locale>, icu::locid::Error>>()?;
|
||||||
|
|
||||||
|
for locale in locales.iter() {
|
||||||
|
self.load_messages_from_file(locale.to_string()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
self.locales = NonEmptyList(locales);
|
self.locales = NonEmptyList(locales);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,15 +226,21 @@ impl L10N {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
pub fn tr(&self, message: impl Message) -> String {
|
pub fn tr(&self, message: impl Message) -> String {
|
||||||
println!("message: {}", message.msgid());
|
for bundle in self.message_bundles.iter().rev() {
|
||||||
let msg = self.message_bundles[0]
|
let msg = bundle
|
||||||
.get_message(message.msgid())
|
.get_message(message.msgid())
|
||||||
.and_then(|msg| msg.value())
|
.and_then(|msg| msg.value());
|
||||||
.unwrap();
|
match msg {
|
||||||
|
Some(msg) => {
|
||||||
let mut errors = vec![];
|
let mut errors = vec![];
|
||||||
self.message_bundles[0]
|
return self.message_bundles[0]
|
||||||
.format_pattern(msg, message.args().as_ref(), &mut errors)
|
.format_pattern(msg, message.args().as_ref(), &mut errors)
|
||||||
.to_string()
|
.to_string();
|
||||||
|
}
|
||||||
|
None => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unreachable!("The message {} is missing", message.msgid());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_date_time_utc(
|
pub fn format_date_time_utc(
|
||||||
|
|
Loading…
Reference in New Issue