1use serde::{Deserialize, Serialize};
2
3use std::borrow::Borrow;
4use std::collections::BTreeMap;
5use std::fmt;
6
7#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
8#[serde(transparent)]
9pub struct Locale(pub(crate) String);
10
11impl Locale {
12 pub fn as_str(&self) -> &str {
13 &self.0
14 }
15}
16
17#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
18#[serde(transparent)]
19pub struct Map<T = String>(BTreeMap<Locale, T>);
20
21impl<T> Map<T> {
22 pub fn new() -> Self
23 where
24 T: Default,
25 {
26 Self::default()
27 }
28
29 pub fn insert(&mut self, locale: Locale, value: T) -> Option<T> {
30 self.0.insert(locale, value)
31 }
32
33 pub fn get<Q>(&self, locale: &Q) -> Option<&T>
34 where
35 Locale: Borrow<Q> + Ord,
36 Q: Ord + ?Sized,
37 {
38 self.0.get(locale)
39 }
40
41 pub fn contains(&self, query: &str) -> bool
42 where
43 T: AsRef<str>,
44 {
45 self.0
46 .values()
47 .any(|name| name.as_ref().to_lowercase().contains(query))
48 }
49
50 pub fn is_supported(&self) -> bool {
51 self.has_english() || self.has_japanese()
52 }
53
54 pub fn has_english(&self) -> bool {
55 self.0.contains_key("en")
56 }
57
58 pub fn has_japanese(&self) -> bool {
59 self.0.contains_key("ja")
60 }
61
62 pub fn locales(&self) -> impl Iterator<Item = &Locale> {
63 self.0.keys()
64 }
65
66 pub fn as_str(&self) -> &str
67 where
68 T: AsRef<str>,
69 {
70 self.get("en")
71 .or_else(|| self.get("ja"))
72 .or_else(|| self.0.values().next())
73 .map(AsRef::as_ref)
74 .unwrap_or("Unknown")
75 }
76}
77
78impl Borrow<str> for Locale {
79 fn borrow(&self) -> &str {
80 &self.0
81 }
82}
83
84impl fmt::Display for Locale {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 f.write_str(&self.0)
87 }
88}
89
90impl<T> FromIterator<(Locale, T)> for Map<T> {
91 fn from_iter<I: IntoIterator<Item = (Locale, T)>>(iter: I) -> Self {
92 Self(BTreeMap::from_iter(iter))
93 }
94}