Translation (WIP)

This commit is contained in:
Greg Burri 2025-01-05 22:38:46 +01:00
parent 9b0fcec5e2
commit e9873c1943
29 changed files with 586 additions and 285 deletions

142
backend/src/translation.rs Normal file
View file

@ -0,0 +1,142 @@
use std::{fs::File, sync::LazyLock};
use ron::de::from_reader;
use rustc_hash::FxHashMap;
use serde::Deserialize;
use tracing::{event, Level};
use crate::consts;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Clone)]
pub enum Sentence {
ProfileTitle,
MainTitle,
CreateNewRecipe,
UnpublishedRecipes,
UntitledRecipe,
EmailAddress,
Password,
// Sign in page.
SignInMenu,
SignInTitle,
SignInButton,
WrongEmailOrPassword,
// Sign up page.
SignUpMenu,
SignUpTitle,
SignUpButton,
ChooseAPassword,
ReEnterPassword,
AccountMustBeValidatedFirst,
InvalidEmail,
PasswordDontMatch,
InvalidPassword,
EmailAlreadyTaken,
UnableToSendEmail,
// Reset password page.
LostPassword,
AskResetButton,
}
#[derive(Clone)]
pub struct Tr {
lang: &'static Language,
}
impl Tr {
pub fn new(code: &str) -> Self {
for lang in TRANSLATIONS.iter() {
if lang.code == code {
return Self { lang };
}
}
event!(
Level::WARN,
"Unable to find translation for language {}",
code
);
Tr::new("en")
}
pub fn t(&self, sentence: Sentence) -> String {
match self.lang.translation.get(&sentence) {
Some(str) => str.clone(),
None => format!(
"Translation missing, lang: {}/{}, element: {:?}",
self.lang.name, self.lang.code, sentence
),
}
}
pub fn tp(&self, sentence: Sentence, params: &[Box<dyn ToString>]) -> String {
match self.lang.translation.get(&sentence) {
Some(str) => {
let mut result = str.clone();
for p in params {
result = result.replacen("{}", &p.to_string(), 1);
}
result
}
None => format!(
"Translation missing, lang: {}/{}, element: {:?}",
self.lang.name, self.lang.code, sentence
),
}
}
pub fn available_languages() -> Vec<(&'static str, &'static str)> {
TRANSLATIONS
.iter()
.map(|tr| (tr.code.as_ref(), tr.name.as_ref()))
.collect()
}
pub fn available_codes() -> Vec<&'static str> {
TRANSLATIONS.iter().map(|tr| tr.code.as_ref()).collect()
}
}
// #[macro_export]
// macro_rules! t {
// ($self:expr, $str:expr) => {
// $self.t($str)
// };
// ($self:expr, $str:expr, $( $x:expr ),+ ) => {
// {
// let mut result = $self.t($str);
// $( result = result.replacen("{}", &$x.to_string(), 1); )+
// result
// }
// };
// }
#[derive(Debug, Deserialize, Clone)]
struct Language {
code: String,
name: String,
translation: FxHashMap<Sentence, String>,
}
static TRANSLATIONS: LazyLock<Vec<Language>> =
LazyLock::new(|| match File::open(consts::TRANSLATION_FILE) {
Ok(file) => from_reader(file).unwrap_or_else(|error| {
panic!(
"Failed to read translation file {}: {}",
consts::TRANSLATION_FILE,
error
)
}),
Err(error) => {
panic!(
"Failed to open translation file {}: {}",
consts::TRANSLATION_FILE,
error
)
}
});