1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
pub use tr::tr;
use crate::locale::Locale;
use rust_embed::RustEmbed;
use std::path::PathBuf;
mod locale;
#[macro_export]
macro_rules! tr_init {
($path:expr, $embedded:ty) => {
$crate::internal::tr_init::<$embedded>(module_path!(), $path)
};
}
pub mod internal {
use crate::{locale, try_read_locale, RustEmbed};
pub fn tr_init<E: RustEmbed>(module: &'static str, local_folder: &str) {
if let Some(locale) = locale::Locale::current() {
if let Some(content) = try_read_locale::<E>(module, &locale, local_folder) {
if let Some(catalog) = gettext::Catalog::parse(&content[..]).ok() {
tr::internal::set_translator(module, catalog);
}
}
}
}
}
fn try_read_locale<E: RustEmbed>(module: &str, locale: &Locale, local_folder: &str) -> Option<Vec<u8>> {
if let Some(content) = try_read_from_file(module, locale, local_folder) {
Some(content)
} else {
try_read_from_embedded::<E>(module, locale)
}
}
fn try_read_from_file(module: &str, locale: &Locale, local_folder: &str) -> Option<Vec<u8>> {
let exe_path = std::env::current_exe().unwrap();
let exe_folder = exe_path.parent().unwrap();
let locale_paths = locale_to_paths(module, locale);
for locale_path in locale_paths {
let full_path = exe_folder.join(local_folder).join(locale_path);
if let Some(content) = try_read_from_filepath(full_path) {
return Some(content)
}
}
None
}
fn try_read_from_embedded<E: RustEmbed>(module: &str, locale: &Locale) -> Option<Vec<u8>> {
let locale_paths = locale_to_paths(module, locale);
for locale_path in locale_paths {
if let Some(content) = E::get(&locale_path.to_string_lossy().into_owned()) {
return Some(content.to_vec())
}
}
None
}
fn try_read_from_filepath(filepath: PathBuf) -> Option<Vec<u8>> {
if let Ok(content) = std::fs::read(filepath) {
Some(content)
} else {
None
}
}
fn locale_to_paths(module: &str, locale: &Locale) -> Vec<PathBuf> {
let mut possible_paths = Vec::new();
if let Some(region) = &locale.region {
possible_paths.push(PathBuf::from(&format!("{}_{}/LC_MESSAGES/{}.mo", locale.language, region, module)));
possible_paths.push(PathBuf::from(&format!("{}_{}/{}.mo", locale.language, region, module)));
}
possible_paths.push(PathBuf::from(&format!("{}/LC_MESSAGES/{}.mo", locale.language, module)));
possible_paths.push(PathBuf::from(&format!("{}/{}.mo", locale.language, module)));
possible_paths
}