use std::string::ParseError;
use std::{fmt::Display, str::FromStr};
use std::{vec, vec::Vec};
use serde::{Deserialize, Serialize};
macro_rules! languages {
(
$(
$( #[$meta:meta] )*
$lang:ident => $code:literal,
)*
) => {
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Serialize)]
#[cfg_attr(feature = "non_exhaustive", non_exhaustive)]
#[cfg_attr(feature = "specta", derive(specta::Type))]
#[cfg_attr(feature = "async-graphql", derive(async_graphql::Enum))]
pub enum Language {
$(
$( #[$meta] )*
#[serde(rename = $code)]
$lang,
)*
#[serde(other)]
Unknown,
}
impl Language {
pub fn code2(&self) -> &str {
match self {
$(
Self::$lang => $code,
)*
Self::Unknown => "Unknown",
}
}
pub fn get_langs() -> Vec<Self> {
vec![
$(
Self::$lang,
)*
Self::Unknown,
]
}
}
impl From<&str> for Language {
fn from(value: &str) -> Self {
match value.to_lowercase().as_str() {
$(
$code => Self::$lang,
)*
_ => Self::Unknown,
}
}
}
impl FromStr for Language {
type Err = ParseError;
fn from_str(value: &str) -> Result<Self, ParseError> {
Ok(
match value.to_lowercase().as_str() {
$(
$code => Self::$lang,
)*
_ => Self::Unknown,
}
)
}
}
impl Default for Language {
fn default() -> Self{
Self::Unknown
}
}
};
}
languages! {
Arabic => "ar",
Azerbaijani => "az",
Afrikaans => "af",
Albanian => "sq",
Basque => "eu",
Belarusian => "be",
Bengali => "bn",
Bulgarian => "bg",
Burmese => "my",
Catalan => "ca",
ChineseRomanized => "zh-ro",
ChineseSimplified => "zh",
ChineseTraditional => "zh-hk",
Chuvash => "cv",
Croatian => "hr",
Czech => "cs",
Danish => "da",
Dutch => "nl",
English => "en",
Esperanto => "eo",
Estonian => "et",
Filipino => "tl",
Finnish => "fi",
French => "fr",
Georgian => "ka",
German => "de",
Greek => "el",
Hebrew => "he",
Hindi => "hi",
Hungarian => "hu",
Indonesian => "id",
Irish => "ga",
Italian => "it",
Japanese => "ja",
JapaneseRomanized => "ja-ro",
Javanese => "jv",
Jp => "jp",
Kazakh => "kk",
Korean => "ko",
KoreanRomanized => "ko-ro",
Latin => "la",
Lithuanian => "lt",
Malagasy => "mg",
Malay => "ms",
Mongolian => "mn",
Nepali => "ne",
NiloSaharan => "kr",
Norwegian => "no",
Persian => "fa",
Polish => "pl",
PortugueseBrazilian => "pt-br",
PortuguesePortugal => "pt",
Romansh => "rm",
Romanian => "ro",
Russian => "ru",
SerboCroatian => "sr",
Slovak => "sk",
Slovenian => "sl",
SpanishCastilian => "es",
SpanishLatinAmerican => "es-la",
Swedish => "sv",
Tamil => "ta",
Telugu => "te",
Thai => "th",
Turkish => "tr",
Ukrainian => "uk",
Urdu => "ur",
Uzbek => "uz",
Vietnamese => "vi",
}
impl Display for Language {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.code2())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn string_produces_english_from_en() {
let lang = Language::from("en");
assert_eq!(lang, Language::English);
}
#[test]
fn string_produces_japanese_from_capitalized_ja() {
let lang = Language::from("JA");
assert_eq!(lang, Language::Japanese);
}
#[test]
fn string_produces_unknown_from_unknown_string() {
let test_cases = ["foo", "bar", "baz"];
for test in test_cases {
let lang = Language::from(test);
assert_eq!(lang, Language::Unknown);
}
}
#[test]
fn serde_produces_unknown_from_unknown_string() {
#[derive(Deserialize)]
struct TestStruct {
lang: Language,
}
let value = serde_json::json!({
"lang" : "jp"
});
let out: TestStruct = serde_json::from_value(value).unwrap();
assert_eq!(out.lang, Language::Jp);
}
}