i18n.rs
1 /* This file is part of DarkFi (https://dark.fi) 2 * 3 * Copyright (C) 2020-2025 Dyne.org foundation 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU Affero General Public License as 7 * published by the Free Software Foundation, either version 3 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Affero General Public License for more details. 14 * 15 * You should have received a copy of the GNU Affero General Public License 16 * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 */ 18 19 use fluent::{concurrent::FluentBundle, FluentResource}; 20 use parking_lot::RwLock; 21 use std::sync::Arc; 22 use unic_langid::langid; 23 24 pub type I18nResource = Arc<FluentResource>; 25 26 pub struct I18nBabelFish { 27 bundle: RwLock<Arc<FluentBundle<I18nResource>>>, 28 } 29 30 impl I18nBabelFish { 31 pub fn new(src: String, lang: &str) -> Self { 32 let mut langs = vec![lang.parse().unwrap()]; 33 if lang != "en-US" { 34 langs.push(langid!("en-US")); 35 } 36 37 let res = Arc::new(FluentResource::try_new(src).unwrap()); 38 let mut bundle = FluentBundle::new_concurrent(langs); 39 bundle.add_resource(res).unwrap(); 40 Self { bundle: RwLock::new(Arc::new(bundle)) } 41 } 42 43 pub fn set(&self, other: &Self) { 44 let bundle = other.bundle.read(); 45 *self.bundle.write() = Arc::clone(&*bundle); 46 } 47 48 pub fn tr(&self, id: &str) -> Option<String> { 49 let bundle = self.bundle.read(); 50 let msg = bundle.get_message(id)?; 51 let patt = msg.value()?; 52 // See FluentBundle::format_pattern() 53 // this is where we can also pass args into the ftl str 54 let mut errs = vec![]; 55 let res = bundle.format_pattern(&patt, None, &mut errs); 56 Some(res.into_owned()) 57 } 58 } 59 60 impl Clone for I18nBabelFish { 61 fn clone(&self) -> Self { 62 let bundle = self.bundle.read(); 63 Self { bundle: RwLock::new(Arc::clone(&*bundle)) } 64 } 65 }