Turn the the message types into an auto-generated build script

This commit is contained in:
Savanni D'Gerinel 2024-03-11 19:11:59 -04:00
parent 5c7f7766de
commit ff1d117e8c
8 changed files with 99 additions and 88 deletions

View File

@ -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";

View File

@ -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
]; ];
}; };

View File

@ -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());
} }

View File

@ -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.
} }

View File

@ -1,4 +1,6 @@
mod messages; mod messages {
include!(env!("KIFU_GTK_MESSAGES"));
}
pub mod ui; pub mod ui;

View File

@ -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
}
}

View File

@ -2,7 +2,7 @@ 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::messages;
@ -78,7 +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")); let mut l10n = L10N::new(PathBuf::from("resources"));
l10n.set_locales(NonEmptyList::from_iter(vec!["en-US", "eo"]).unwrap());
content.set_child(Some( content.set_child(Some(
&adw::StatusPage::builder().title(l10n.tr(messages::NothingHere)).build(), &adw::StatusPage::builder().title(l10n.tr(messages::NothingHere)).build(),
)); ));

View File

@ -26,7 +26,9 @@ impl<A> NonEmptyList<A> {
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))
@ -38,6 +40,10 @@ impl<A> NonEmptyList<A> {
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 +74,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 +162,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 +190,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 +218,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 {
let mut errors = vec![]; Some(msg) => {
self.message_bundles[0] let mut errors = vec![];
.format_pattern(msg, message.args().as_ref(), &mut errors) return self.message_bundles[0]
.to_string() .format_pattern(msg, message.args().as_ref(), &mut errors)
.to_string();
}
None => continue,
}
}
unreachable!("The message {} is missing", message.msgid());
} }
pub fn format_date_time_utc( pub fn format_date_time_utc(