assembly_xml/
localization.rs1use std::{
7 collections::BTreeMap,
8 fs::File,
9 io::{self, BufReader},
10 path::Path,
11};
12
13use displaydoc::Display;
14use quick_xml::{events::Event as XmlEvent, Error as XmlError, Reader as XmlReader};
15use thiserror::Error;
16
17use super::common::exact::{expect_attribute, expect_end, expect_start, expect_text, Error};
18
19#[derive(Debug, Display, Error)]
20pub enum LocaleError {
22 Io(#[from] io::Error),
24 Xml(#[from] Error),
26}
27
28impl From<XmlError> for LocaleError {
29 fn from(e: XmlError) -> Self {
30 Self::Xml(Error::Xml(e))
31 }
32}
33#[derive(Debug, Default)]
34pub struct LocaleNode {
36 pub value: Option<String>,
38 pub int_children: BTreeMap<u32, LocaleNode>,
40 pub str_children: BTreeMap<String, LocaleNode>,
42}
43
44impl LocaleNode {
45 pub fn get_keys(&self) -> BTreeMap<String, String> {
49 let mut keys = BTreeMap::new();
50 for (key, value) in &self.str_children {
51 value.add_keys(&mut keys, key.clone());
52 }
53 for (key, value) in &self.int_children {
54 value.add_keys(&mut keys, key.to_string());
55 }
56 keys
57 }
58
59 fn add_keys(&self, keys: &mut BTreeMap<String, String>, prefix: String) {
60 for (key, value) in &self.str_children {
61 let inner = format!("{}_{}", prefix, key);
62 value.add_keys(keys, inner);
63 }
64 for (key, value) in &self.int_children {
65 let inner = format!("{}_{}", prefix, key);
66 value.add_keys(keys, inner);
67 }
68 if let Some(v) = &self.value {
69 keys.insert(prefix, v.clone());
70 }
71 }
72}
73
74pub fn load_locale(path: &Path) -> Result<LocaleNode, LocaleError> {
76 let file = File::open(path)?;
77 let file = BufReader::new(file);
78
79 let mut root = LocaleNode {
80 value: None,
81 int_children: BTreeMap::new(),
82 str_children: BTreeMap::new(),
83 };
84
85 let mut reader = XmlReader::from_reader(file);
86 reader.trim_text(true);
87
88 let mut buf = Vec::new();
89
90 if let Ok(XmlEvent::Decl(_)) = reader.read_event(&mut buf) {}
92 buf.clear();
93
94 let _ = expect_start("localization", &mut reader, &mut buf)?;
95 buf.clear();
97
98 let e_locales = expect_start("locales", &mut reader, &mut buf)?;
99 let locale_count = expect_attribute("count", &reader, &e_locales)?;
101 buf.clear();
102
103 for _ in 0..locale_count {
104 let _ = expect_start("locale", &mut reader, &mut buf)?;
105 buf.clear();
107
108 let _locale = expect_text(&mut reader, &mut buf)?;
109 buf.clear();
111
112 let _ = expect_end("locale", &mut reader, &mut buf)?;
113 buf.clear();
115 }
116
117 let _ = expect_end("locales", &mut reader, &mut buf)?;
118 buf.clear();
119 let e_locales = expect_start("phrases", &mut reader, &mut buf)?;
122 let phrase_count = expect_attribute("count", &reader, &e_locales)?;
124 buf.clear();
125
126 for _ in 0..phrase_count {
127 let e_phrase = expect_start("phrase", &mut reader, &mut buf)?;
128 let id: String = expect_attribute("id", &reader, &e_phrase)?;
129
130 buf.clear();
132
133 let mut translation = None;
134
135 loop {
136 let event = reader.read_event(&mut buf)?;
137 let e_translation = match event {
138 XmlEvent::End(e) => {
139 if e.name() == b"phrase" {
140 break;
141 } else {
142 let name_str = reader.decode(e.name());
143 return Err(LocaleError::Xml(Error::ExpectedEndTag(
144 String::from("phrase"),
145 name_str.into_owned(),
146 )));
147 }
148 }
149 XmlEvent::Start(e) => {
150 if e.name() == b"translation" {
151 e
152 } else {
153 let name_str = reader.decode(e.name());
154 return Err(LocaleError::Xml(Error::ExpectedEndTag(
155 String::from("translation"),
156 name_str.into_owned(),
157 )));
158 }
159 }
160 _ => panic!(),
161 };
162 let locale: String = expect_attribute("locale", &reader, &e_translation)?;
163 buf.clear();
164
165 let trans = expect_text(&mut reader, &mut buf)?;
166 if &locale == "en_US" {
167 translation = Some(trans);
168 }
169 buf.clear();
170
171 let _ = expect_end("translation", &mut reader, &mut buf)?;
172 buf.clear();
173 }
174
175 let mut node = &mut root;
176 for comp in id.split('_') {
177 if let Ok(num) = comp.parse::<u32>() {
178 node = node.int_children.entry(num).or_default();
179 } else {
180 node = node.str_children.entry(comp.to_owned()).or_default();
181 }
182 }
183 if let Some(translation) = translation {
184 node.value = Some(translation);
185 }
186 }
187
188 let _ = expect_end("phrases", &mut reader, &mut buf)?;
189 buf.clear();
191
192 Ok(root)
193}