use crate::LOCALES; use askama::i18n::fluent_templates::Loader; use askama::i18n::FluentValue; use askama::i18n::{langid, LanguageIdentifier, Locale}; use serde::{Deserialize, Serialize}; use strum::IntoEnumIterator; use strum_macros::{AsRefStr, EnumCount, EnumIter, EnumVariantNames}; use derive_more::Display; #[derive( sqlx::Type, Serialize, Deserialize, Clone, Copy, Debug, Hash, Display, EnumIter, EnumCount, EnumVariantNames, AsRefStr, PartialEq, Eq, )] #[repr(i32)] pub enum SupportedLanguage { #[serde(rename = "en-ca")] #[display(fmt = "en-ca")] English = 1, #[serde(rename = "fr-ca")] #[display(fmt = "fr-ca")] French = 2, } impl From for i32 { fn from(lang: SupportedLanguage) -> Self { match lang { SupportedLanguage::English => 1, SupportedLanguage::French => 2, } } } impl From for FluentValue<'_> { fn from(n: SupportedLanguage) -> Self { n.to_string().into() } } impl From for LanguageIdentifier { fn from(lang: SupportedLanguage) -> LanguageIdentifier { match lang { SupportedLanguage::English => langid!("en-ca"), SupportedLanguage::French => langid!("fr-ca"), } } } impl<'a> From for Locale<'a> { fn from(lang: SupportedLanguage) -> Self { Locale::new(lang.into(), &LOCALES) } } impl SupportedLanguage { pub fn lookup(self, key: &str) -> String { LOCALES .lookup(&self.into(), key) .expect("Unable to find key {key} in locale {self}.") } pub fn other_langs(self) -> impl Iterator + 'static { Self::iter().filter(move |lang| lang != &self) } pub fn native_name(self) -> String { match self { Self::English => "English", Self::French => "Français", } .to_string() } pub fn id(self) -> i32 { match self { Self::English => 1, Self::French => 2, } } } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct LangLink { pub href: String, pub name: String, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct LocalizedName { pub localizations: std::collections::HashMap, } impl LocalizedName { fn localize(&self, lang: SupportedLanguage) -> Option { // first, try to find the proper match for a name self.localizations .iter() .find_map(|(translated_lang, string)| if translated_lang == &lang { Some(string.to_string()) } else { None }) // if not found, replace it with ANY localization of the word; this will help when, for example, there is no matching name for a French game, but the game has already been created with the English name. // if NO localization is found, then we can still return a None value; but hopefully through database, form, and web server restrictions, we can mostly stop that from happening .or_else(|| if self.localizations.is_empty() { Some(self.localizations.values().next().unwrap().to_string()) } else { None }) } }