commonlibsse_ng\skse/translation.rs
1// use crate::sys::{root, RE};
2// use std::collections::HashMap;
3// use windows::core::HSTRING;
4
5// #[cfg(feature = "tracing")]
6// use tracing::{error, info, warn};
7
8// pub fn parse_translation(name: &str) {
9// let scaleform_manager = unsafe { RE::BSScaleformManager::GetSingleton() };
10// if scaleform_manager.is_null() {
11// error!("Scaleform manager is not available.");
12// return;
13// }
14// let loader = unsafe { scaleform_manager.as_ref() }.and_then(|m| unsafe { m.loader.as_ref() });
15// let translator = loader.and_then(|l| l.GetStateAddRef(RE::GFxState_StateType::kTranslator));
16
17// let scaleform_translator =
18// translator.and_then(|t| t.downcast_ref::<RE::BSScaleformTranslator>());
19
20// if scaleform_translator.is_none() {
21// #[cfg(feature = "tracing")]
22// warn!("Failed to import translation for {name}");
23// return;
24// }
25
26// let ini_setting_collection = unsafe { RE::INISettingCollection::GetSingleton() };
27
28// let sv = {
29// let s = "sLanguage:General";
30// let len = s.len() as u64;
31// let s_ptr = s.as_ptr() as u64;
32// let sv: root::std::string_view = [0; 2];
33// sv[0] = s_ptr;
34// sv[1] = len;
35// sv
36// };
37// let setting = unsafe { ini_setting_collection.as_ref().map(|c| c.GetSetting(sv)) };
38
39// let language = setting
40// .filter(|s| unsafe {
41// s.as_ref()
42// .map(|s| unsafe { s.GetType() } == RE::Setting_Type::kString)
43// .unwrap_or_default()
44// })
45// .map(|s| unsafe { s.as_ref() }.and_then(|s| s.c_str().to_string()))
46// .unwrap_or_else(|| "ENGLISH".to_string());
47
48// let path = format!("Interface\\Translations\\{}_{}.txt", name, language);
49// root::std::string;
50// let mut file_stream = RE::BSResourceNiBinaryStream::new2(&path);
51
52// if !file_stream.good() {
53// return;
54// }
55
56// info!("Reading translations from {}...", path);
57
58// let mut bom: u16 = 0;
59// if file_stream.read_exact(&mut bom).is_err() || bom != 0xFEFF {
60// error!("BOM Error, file must be encoded in UCS-2 LE.");
61// return;
62// }
63
64// let mut translation_map = HashMap::new();
65// while let Some(line) = file_stream.read_line_w('\n') {
66// if line.len() < 4 || !line.starts_with('$') {
67// continue;
68// }
69
70// let trimmed = line.trim_end_matches('\r');
71// if let Some(delim_idx) = trimmed.find('\t') {
72// let (key, value) = trimmed.split_at(delim_idx);
73// let key = key.trim();
74// let value = value[1..].trim();
75
76// if let (Some(cached_key), Some(cached_translation)) = (
77// RE::BSScaleformTranslator::GetCachedString(key),
78// RE::BSScaleformTranslator::GetCachedString(value),
79// ) {
80// translation_map.insert(cached_key, cached_translation);
81// }
82// }
83// }
84
85// if let Some(translator) = scaleform_translator {
86// translator.translation_map.extend(translation_map);
87// }
88// }
89
90// pub fn translate(key: &str) -> Option<String> {
91// if !key.starts_with('$') {
92// return None;
93// }
94
95// let scaleform_manager = unsafe { RE::BSScaleformManager::GetSingleton() };
96// let loader = unsafe { scaleform_manager.as_ref().and_then(|m| m.loader.as_ref()) };
97// let translator = loader.and_then(|l| l.getStateAddRef(RE::GFxState_StateType::kTranslator));
98
99// let translator = translator?;
100// let mut result = unsafe { RE::GFxWStringBuffer::new() };
101
102// let key_utf16 = HSTRING::from(key);
103// let translate_info = RE::GFxTranslator_TranslateInfo {
104// key: key_utf16.as_ptr(),
105// result: &mut result,
106// instanceName: ::core::ptr::null_mut(),
107// flags: 0,
108// pad19: 0,
109// pad1A: 0,
110// pad1C: 0,
111// };
112
113// translator.translate(&translate_info);
114// if unsafe { result.empty() } {
115// return None;
116// }
117
118// Some(HSTRING::from(unsafe { result.c_str() }).to_string())
119// }