dioxus_std/i18n/
use_i18n.rs1use dioxus::prelude::*;
2use serde::{Deserialize, Serialize};
3use std::{collections::HashMap, str::FromStr};
4use unic_langid::LanguageIdentifier;
5
6use super::use_init_i18n::UseInitI18Data;
7
8#[derive(Debug, Clone, Default, Deserialize, Serialize)]
9pub struct Language {
10 id: LanguageIdentifier,
11 texts: Text,
12}
13
14#[derive(Debug, Clone, Deserialize, Serialize)]
15#[serde(untagged)]
16pub enum Text {
17 Value(String),
18 Texts(HashMap<String, Text>),
19}
20
21impl Default for Text {
22 fn default() -> Self {
23 Self::Texts(HashMap::default())
24 }
25}
26
27impl Text {
28 fn query(&self, steps: &mut Vec<&str>) -> Option<String> {
29 match self {
30 Text::Texts(texts) => {
31 if steps.is_empty() {
32 return None;
33 }
34
35 let current_path = steps.join(".");
36
37 let this_step = steps.remove(0);
39 let deep = texts.get(this_step)?;
40 let res = deep.query(steps);
41
42 if res.is_none() {
44 let res_text = texts.get(¤t_path);
45 if let Some(res_text) = res_text {
46 return res_text.query(steps);
47 }
48 }
49 res
50 }
51 Text::Value(value) => Some(value.to_owned()),
52 }
53 }
54}
55
56impl FromStr for Language {
57 type Err = ();
58
59 fn from_str(s: &str) -> Result<Self, Self::Err> {
60 serde_json::from_str(s).map_err(|_| ())
61 }
62}
63
64impl Language {
65 pub fn get_text(&self, path: &str, params: HashMap<&str, String>) -> Option<String> {
66 let mut steps = path.split('.').collect::<Vec<&str>>();
67
68 let mut text = self.texts.query(&mut steps).unwrap_or_default();
69
70 for (name, value) in params {
71 text = text.replacen(&format!("{{{name}}}"), &value.to_string(), 1);
72 }
73 Some(text)
74 }
75}
76
77#[derive(Clone, PartialEq, Copy)]
78pub struct UseI18 {
79 pub selected_language: Signal<LanguageIdentifier>,
80 pub data: Signal<UseInitI18Data>,
81}
82
83impl UseI18 {
84 pub fn translate_with_params(&self, id: &str, params: HashMap<&str, String>) -> String {
85 let i18n_data = self.data.read();
86
87 for language in i18n_data.languages.iter() {
89 if language.id == *self.selected_language.read() {
90 return language.get_text(id, params).unwrap_or_default();
91 }
92 }
93
94 for language in i18n_data.languages.iter() {
96 if language.id == i18n_data.fallback_language {
97 return language.get_text(id, params).unwrap_or_default();
98 }
99 }
100
101 id.to_string()
103 }
104
105 pub fn translate(&self, id: &str) -> String {
106 self.translate_with_params(id, HashMap::default())
107 }
108
109 pub fn set_language(&mut self, id: LanguageIdentifier) {
110 *self.selected_language.write() = id;
111 }
112}
113
114pub fn use_i18() -> UseI18 {
115 use_hook(|| {
116 let selected_language = consume_context::<Signal<LanguageIdentifier>>();
117 let data = consume_context::<Signal<UseInitI18Data>>();
118
119 UseI18 {
120 selected_language,
121 data,
122 }
123 })
124}