batbox_i18n/lib.rs
1//! Internationalization
2//!
3//! Use `batbox_i18n::gen!(mod mod_name: "path/to.toml")`
4//!
5//! Example toml file:
6//!
7//! ```toml
8//! [en]
9//! hello = "Hello"
10//! world = "World"
11//!
12//! [ru]
13//! hello = "Привет"
14//! world = "Мир"
15//! ```
16//!
17//! Generated code with `batbox_i18n::gen!(mod i18n: "hello_world.toml")`:
18//!
19//! ```ignore
20//! mod i18n {
21//! struct Locale {
22//! ..
23//! }
24//!
25//! fn get(locale: &str) -> Option<&'static Locale> { .. }
26//! fn get_or_en(locale: &str) -> &'static Locale { .. }
27//!
28//! impl Locale {
29//! pub fn hello(&self) -> &str { .. }
30//! pub fn world(&self) -> &str { .. }
31//! }
32//! }
33//! ```
34#![warn(missing_docs)]
35
36pub use batbox_i18n_macro::gen;
37
38/// Detect user's locale
39///
40/// If detection failed, defaults to "en"
41pub fn detect_locale() -> &'static str {
42 static CELL: once_cell::sync::Lazy<String> = once_cell::sync::Lazy::new(|| {
43 #[cfg(target_arch = "wasm32")]
44 let locale = web_sys::window().unwrap().navigator().language();
45 #[cfg(not(target_arch = "wasm32"))]
46 let locale = unsafe {
47 let locale = libc::setlocale(
48 libc::LC_COLLATE,
49 std::ffi::CStr::from_bytes_with_nul_unchecked(b"\0").as_ptr(),
50 );
51 if locale.is_null() {
52 None
53 } else {
54 std::ffi::CStr::from_ptr(locale)
55 .to_str()
56 .ok()
57 .map(|s| s.to_owned())
58 }
59 };
60 log::trace!("Detected locale: {:?}", locale);
61 let mut locale = match locale {
62 Some(locale) => locale,
63 None => String::from("en"),
64 };
65 if locale.len() > 2 {
66 locale.truncate(2);
67 }
68 let locale = locale.to_lowercase();
69 log::trace!("Using locale: {:?}", locale);
70 locale
71 });
72 CELL.as_str()
73}