You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
3.2 KiB
115 lines
3.2 KiB
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<SupportedLanguage> for i32 {
|
|
fn from(lang: SupportedLanguage) -> Self {
|
|
match lang {
|
|
SupportedLanguage::English => 1,
|
|
SupportedLanguage::French => 2,
|
|
}
|
|
}
|
|
}
|
|
impl From<SupportedLanguage> for FluentValue<'_> {
|
|
fn from(n: SupportedLanguage) -> Self {
|
|
n.to_string().into()
|
|
}
|
|
}
|
|
impl From<SupportedLanguage> for LanguageIdentifier {
|
|
fn from(lang: SupportedLanguage) -> LanguageIdentifier {
|
|
match lang {
|
|
SupportedLanguage::English => langid!("en-ca"),
|
|
SupportedLanguage::French => langid!("fr-ca"),
|
|
}
|
|
}
|
|
}
|
|
impl<'a> From<SupportedLanguage> 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<Item = Self> + '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<SupportedLanguage, String>,
|
|
}
|
|
impl LocalizedName {
|
|
fn localize(&self, lang: SupportedLanguage) -> Option<String> {
|
|
// 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
|
|
})
|
|
}
|
|
}
|