1use std::sync::Arc;
3
4use fluent::{FluentArgs, FluentBundle, FluentResource};
5use pslink_shared::datatypes::Lang;
6use unic_langid::LanguageIdentifier;
7
8#[derive(Clone)]
10pub struct I18n {
11 lang: Lang,
12 ftl_bundle: Arc<FluentBundle<FluentResource>>,
13}
14
15impl std::fmt::Debug for I18n {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 write!(f, "{:?}", self.lang)
19 }
20}
21
22impl I18n {
23 #[must_use]
25 pub fn new(lang: Lang) -> Self {
26 let ftl_bundle = Arc::new(Self::create_ftl_bundle(lang));
27 Self { lang, ftl_bundle }
28 }
29
30 #[must_use]
32 pub const fn lang(&self) -> &Lang {
33 &self.lang
34 }
35
36 pub fn set_lang(&mut self, lang: Lang) {
38 self.lang = lang;
39 self.ftl_bundle = Arc::new(Self::create_ftl_bundle(lang));
40 }
41
42 pub fn translate(&self, key: impl AsRef<str>, args: Option<&FluentArgs>) -> String {
44 let msg = self
46 .ftl_bundle
47 .get_message(key.as_ref())
48 .expect("Failed to get fluent message for key {}");
49
50 let pattern = msg.value().expect("Failed to parse pattern");
51
52 self.ftl_bundle
53 .format_pattern(pattern, args, &mut vec![])
54 .to_string()
55 }
56
57 #[must_use]
59 pub const fn label(&self) -> &'static str {
60 match self.lang {
61 Lang::EnUS => "English (US)",
62 Lang::DeDE => "Deutsch (Deutschland)",
63 }
64 }
65
66 #[must_use]
68 pub const fn ftl_messages(lang: Lang) -> &'static str {
69 macro_rules! include_ftl_messages {
70 ( $lang_id:literal ) => {
71 include_str!(concat!("../", $lang_id, "/main.ftl"))
72 };
73 }
74 match lang {
75 Lang::EnUS => include_ftl_messages!("en"),
76 Lang::DeDE => include_ftl_messages!("de"),
77 }
78 }
79
80 #[must_use]
81 pub fn language_identifier(lang: Lang) -> LanguageIdentifier {
82 lang.as_ref()
83 .parse()
84 .expect("parse Lang to LanguageIdentifier")
85 }
86
87 #[must_use]
89 pub fn create_ftl_bundle(lang: Lang) -> FluentBundle<FluentResource> {
90 let ftl_resource = FluentResource::try_new(Self::ftl_messages(lang).to_owned())
91 .expect("parse FTL messages");
92
93 let mut bundle = FluentBundle::new(vec![Self::language_identifier(lang)]);
94 bundle.add_resource(ftl_resource).expect("add FTL resource");
95 bundle
96 }
97}