Create a little application which manages an l10n messages database #290
@ -1,22 +1,22 @@
|
|||||||
key = "SaveSettings"
|
key = "SaveSettings"
|
||||||
description = "This is a label on a button which will save the settings when clicked"
|
description = "This is a label on a button which will save the settings when clicked"
|
||||||
|
|
||||||
[variants.en]
|
|
||||||
locale = "en"
|
|
||||||
content = "Save Settings"
|
|
||||||
modified = "2025-02-22T23:44:18.874218939Z"
|
|
||||||
|
|
||||||
[variants.eo]
|
[variants.eo]
|
||||||
locale = "eo"
|
locale = "eo"
|
||||||
content = "Konservi Agordojn"
|
content = "Konservi Agordojn"
|
||||||
modified = "2025-02-24T19:32:11.246639077Z"
|
modified = "2025-02-24T19:32:11.246639077Z"
|
||||||
|
|
||||||
[variants.de]
|
|
||||||
locale = "de"
|
|
||||||
content = "Einstellungen Speichern"
|
|
||||||
modified = "2025-02-24T19:33:19.516005843Z"
|
|
||||||
|
|
||||||
[variants.es]
|
[variants.es]
|
||||||
locale = "es"
|
locale = "es"
|
||||||
content = "Guardar Configuraciones"
|
content = "Guardar Configuraciones"
|
||||||
modified = "2025-02-24T19:33:23.861329923Z"
|
modified = "2025-02-24T19:33:23.861329923Z"
|
||||||
|
|
||||||
|
[variants.en]
|
||||||
|
locale = "en"
|
||||||
|
content = "Save Settings"
|
||||||
|
modified = "2025-02-22T23:44:18.874218939Z"
|
||||||
|
|
||||||
|
[variants.de]
|
||||||
|
locale = "de"
|
||||||
|
content = "Einstellungen Speichern"
|
||||||
|
modified = "2025-02-24T19:33:19.516005843Z"
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
key = "TimeDistance"
|
key = "TimeDistance"
|
||||||
description = "A summary of a workout or many workouts that involve a time and a distance"
|
description = "A summary of a workout or many workouts that involve a time and a distance"
|
||||||
|
|
||||||
[variants.en]
|
[variants.es]
|
||||||
locale = "en"
|
locale = "es"
|
||||||
content = "{distance} of {activity} in {hours, plural, =1 {{hours} hour} other {{hours} hours}} and {minutes, plural, =1 {{minutes} minute} other {{minutes} minutes}}"
|
content = "{distance} de {activity} en {hours, plural, one {}=1 {{hours} hora} other {{hours} horas}} y {minutes, plural, one {}=1 {{minutes} minuto} other {{minutes} minutos}}"
|
||||||
modified = "2025-02-24T14:09:17.361641899Z"
|
modified = "2025-02-24T19:33:23.861604738Z"
|
||||||
|
|
||||||
[variants.eo]
|
[variants.eo]
|
||||||
locale = "eo"
|
locale = "eo"
|
||||||
content = "{distance} de {activity} en {hours, plural, =1 {{hours} horo} other {{hours} horoj}} {minutes, plural, =1 {{minutes} minuto} other {{minutes} minutoj}}"
|
content = "{distance} de {activity} en {hours, plural, =1 {{hours} horo} other {{hours} horoj}} {minutes, plural, =1 {{minutes} minuto} other {{minutes} minutoj}}"
|
||||||
modified = "2025-02-24T19:32:11.246943602Z"
|
modified = "2025-02-24T19:32:11.246943602Z"
|
||||||
|
|
||||||
|
[variants.en]
|
||||||
|
locale = "en"
|
||||||
|
content = "{distance} of {activity} in {hours, plural, =1 {{hours} hour} other {{hours} hours}} and {minutes, plural, =1 {{minutes} minute} other {{minutes} minutes}}"
|
||||||
|
modified = "2025-02-24T14:09:17.361641899Z"
|
||||||
|
|
||||||
[variants.de]
|
[variants.de]
|
||||||
locale = "de"
|
locale = "de"
|
||||||
content = "{distance} von {activity} in {hours, plural, one {}=1 {{hours} Stunde} other {{hours} Stunden}} und {minutes, plural, one {}=1 {{minutes} Minute} other {{minutes} Minuten}}"
|
content = "{distance} von {activity} in {hours, plural, one {}=1 {{hours} Stunde} other {{hours} Stunden}} und {minutes, plural, one {}=1 {{minutes} Minute} other {{minutes} Minuten}}"
|
||||||
modified = "2025-02-24T19:33:19.516210807Z"
|
modified = "2025-02-24T19:33:19.516210807Z"
|
||||||
|
|
||||||
[variants.es]
|
|
||||||
locale = "es"
|
|
||||||
content = "{distance} de {activity} en {hours, plural, one {}=1 {{hours} hora} other {{hours} horas}} y {minutes, plural, one {}=1 {{minutes} minuto} other {{minutes} minutos}}"
|
|
||||||
modified = "2025-02-24T19:33:23.861604738Z"
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
key = "Welcome"
|
key = "Welcome"
|
||||||
description = "This is a welcome content that will be shown on first app opening, before configuration."
|
description = "This is a welcome content that will be shown on first app opening, before configuration."
|
||||||
|
|
||||||
|
[variants.en]
|
||||||
|
locale = "en"
|
||||||
|
content = "Welcome to FitnessTrax, the privacy-centered fitness tracker"
|
||||||
|
modified = "2025-02-25T02:12:25.757240004Z"
|
||||||
|
|
||||||
[variants.eo]
|
[variants.eo]
|
||||||
locale = "eo"
|
locale = "eo"
|
||||||
content = "Bonvenon al FitnessTrax"
|
content = "Bonvenon al FitnessTrax"
|
||||||
modified = "2025-02-24T19:32:11.246407627Z"
|
modified = "2025-02-24T19:32:11.246407627Z"
|
||||||
|
|
||||||
[variants.en]
|
|
||||||
locale = "en"
|
|
||||||
content = "Welcome to FitnessTrax"
|
|
||||||
modified = "2025-02-22T23:43:24.786544124Z"
|
|
||||||
|
|
||||||
[variants.es]
|
[variants.es]
|
||||||
locale = "es"
|
locale = "es"
|
||||||
content = "Bienvenido a FitnessTrax"
|
content = "Bienvenido a FitnessTrax"
|
||||||
|
@ -7,7 +7,11 @@ use std::{
|
|||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
use icu_locid::{langid, LanguageIdentifier};
|
use icu_locid::{langid, LanguageIdentifier};
|
||||||
use l10n_db::{self, js, read_file, xliff::{self, import_file}, Bundle, Editor, ReadError};
|
use l10n_db::{
|
||||||
|
self, js, read_file,
|
||||||
|
xliff::{self, import_file},
|
||||||
|
Bundle, Editor, ReadError,
|
||||||
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
@ -41,6 +45,7 @@ enum Commands {
|
|||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
locale: Option<String>,
|
locale: Option<String>,
|
||||||
},
|
},
|
||||||
|
Report,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@ -56,6 +61,44 @@ fn edit_key(bundle: &mut Bundle, key: String, locale: LanguageIdentifier, editor
|
|||||||
bundle.save();
|
bundle.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
struct Report {
|
||||||
|
keys: Vec<String>,
|
||||||
|
source_deleted: Vec<String>,
|
||||||
|
out_of_date: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_report(
|
||||||
|
bundle: &Bundle,
|
||||||
|
base_locale: &LanguageIdentifier,
|
||||||
|
locales: Vec<LanguageIdentifier>,
|
||||||
|
) -> Report {
|
||||||
|
let mut report: Report = Default::default();
|
||||||
|
let locales: Vec<LanguageIdentifier> =
|
||||||
|
locales.into_iter().filter(|a| a != base_locale).collect();
|
||||||
|
for (key, message) in bundle.message_iter() {
|
||||||
|
match message.variant(base_locale) {
|
||||||
|
Some(ref base_variant) => {
|
||||||
|
for locale in locales.iter() {
|
||||||
|
match message.variant(locale) {
|
||||||
|
Some(v) if v.modified() < base_variant.modified() => {
|
||||||
|
report.out_of_date.push(key.to_owned())
|
||||||
|
}
|
||||||
|
Some(_) => {}
|
||||||
|
None => report.out_of_date.push(key.to_owned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
report.source_deleted.push(key.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let base_variant = message.variant(base_locale).clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
report
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let editor = std::env::var("EDITOR").expect("Set EDITOR to the path to your favorite editor");
|
let editor = std::env::var("EDITOR").expect("Set EDITOR to the path to your favorite editor");
|
||||||
|
|
||||||
@ -83,14 +126,23 @@ fn main() {
|
|||||||
bundle.save();
|
bundle.save();
|
||||||
}
|
}
|
||||||
Some(Commands::Export { format, locale }) => {
|
Some(Commands::Export { format, locale }) => {
|
||||||
let locale = locale.as_ref().map(|l| l.clone().parse::<LanguageIdentifier>().unwrap()).unwrap_or(langid!("en"));
|
let locale = locale
|
||||||
|
.as_ref()
|
||||||
|
.map(|l| l.clone().parse::<LanguageIdentifier>().unwrap())
|
||||||
|
.unwrap_or(langid!("en"));
|
||||||
|
|
||||||
match format.as_ref() {
|
match format.as_ref() {
|
||||||
"js" => js::export_file(&bundle, locale, &PathBuf::from("output.json")).unwrap(),
|
"js" => js::export_file(&bundle, locale, &PathBuf::from("output.json")).unwrap(),
|
||||||
"xliff" => xliff::export_file(&bundle, locale, &PathBuf::from("output.xliff")).unwrap(),
|
"xliff" => {
|
||||||
|
xliff::export_file(&bundle, locale, &PathBuf::from("output.xliff")).unwrap()
|
||||||
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
Some(Commands::Report) => {
|
||||||
|
let report = generate_report(&bundle, &config.base_locale, config.locales);
|
||||||
|
println!("{:?}", report);
|
||||||
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,10 @@ impl Variant {
|
|||||||
self.content = content;
|
self.content = content;
|
||||||
self.modified = Utc::now();
|
self.modified = Utc::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn modified(&self) -> DateTime<Utc> {
|
||||||
|
self.modified
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user