localization.rs (5744B)
1 use std::borrow::Cow; 2 3 use fluent_fallback::{ 4 env::LocalesProvider, 5 types::{L10nKey, ResourceId}, 6 Localization, 7 }; 8 use l10nregistry_tests::{ 9 FileSource, MockBundleAdapter, RegistrySetup, TestEnvironment, TestFileFetcher, 10 }; 11 use serial_test::serial; 12 use unic_langid::{langid, LanguageIdentifier}; 13 14 type L10nRegistry = l10nregistry::registry::L10nRegistry<TestEnvironment, MockBundleAdapter>; 15 16 static LOCALES: &[LanguageIdentifier] = &[langid!("pl"), langid!("en-US")]; 17 static mut FILE_FETCHER: Option<TestFileFetcher> = None; 18 static mut L10N_REGISTRY: Option<L10nRegistry> = None; 19 20 const FTL_RESOURCE: &str = "toolkit/updates/history.ftl"; 21 const L10N_ID_PL_EN: (&str, Option<&str>) = ("history-title", Some("Historia aktualizacji")); 22 const L10N_ID_MISSING: (&str, Option<&str>) = ("missing-id", None); 23 const L10N_ID_ONLY_EN: (&str, Option<&str>) = ( 24 "history-intro", 25 Some("The following updates have been installed"), 26 ); 27 28 fn get_file_fetcher() -> &'static TestFileFetcher { 29 let fetcher: &mut Option<TestFileFetcher> = unsafe { &mut FILE_FETCHER }; 30 31 fetcher.get_or_insert_with(|| TestFileFetcher::new()) 32 } 33 34 fn get_l10n_registry() -> &'static L10nRegistry { 35 let reg: &mut Option<L10nRegistry> = unsafe { &mut L10N_REGISTRY }; 36 37 reg.get_or_insert_with(|| { 38 let fetcher = get_file_fetcher(); 39 let setup = RegistrySetup::new( 40 "test", 41 vec![ 42 FileSource::new( 43 "toolkit", 44 None, 45 get_app_locales().to_vec(), 46 "toolkit/{locale}/", 47 ), 48 FileSource::new( 49 "browser", 50 None, 51 get_app_locales().to_vec(), 52 "browser/{locale}/", 53 ), 54 ], 55 get_app_locales().to_vec(), 56 ); 57 fetcher.get_registry_and_environment(setup).1 58 }) 59 } 60 61 fn get_app_locales() -> &'static [LanguageIdentifier] { 62 LOCALES 63 } 64 65 struct LocalesService; 66 67 impl LocalesProvider for LocalesService { 68 type Iter = std::vec::IntoIter<LanguageIdentifier>; 69 70 fn locales(&self) -> Self::Iter { 71 get_app_locales().to_vec().into_iter() 72 } 73 } 74 75 fn sync_localization( 76 reg: &'static L10nRegistry, 77 res_ids: Vec<ResourceId>, 78 ) -> Localization<L10nRegistry, LocalesService> { 79 Localization::with_env(res_ids, true, LocalesService, reg.clone()) 80 } 81 82 fn async_localization( 83 reg: &'static L10nRegistry, 84 res_ids: Vec<ResourceId>, 85 ) -> Localization<L10nRegistry, LocalesService> { 86 Localization::with_env(res_ids, false, LocalesService, reg.clone()) 87 } 88 89 fn setup_sync_test() -> Localization<L10nRegistry, LocalesService> { 90 sync_localization(get_l10n_registry(), vec![FTL_RESOURCE.into()]) 91 } 92 93 fn setup_async_test() -> Localization<L10nRegistry, LocalesService> { 94 async_localization(get_l10n_registry(), vec![FTL_RESOURCE.into()]) 95 } 96 97 #[test] 98 #[serial] 99 fn localization_format_value_sync() { 100 let loc = setup_sync_test(); 101 let bundles = loc.bundles(); 102 let mut errors = vec![]; 103 104 for query in &[L10N_ID_PL_EN, L10N_ID_MISSING, L10N_ID_ONLY_EN] { 105 let value = bundles 106 .format_value_sync(query.0, None, &mut errors) 107 .unwrap(); 108 assert_eq!(value, query.1.map(|s| Cow::Borrowed(s))); 109 } 110 111 assert_eq!(errors.len(), 4); 112 } 113 114 #[test] 115 #[serial] 116 fn localization_format_values_sync() { 117 let loc = setup_sync_test(); 118 let bundles = loc.bundles(); 119 let mut errors = vec![]; 120 121 let ids = &[L10N_ID_PL_EN, L10N_ID_MISSING, L10N_ID_ONLY_EN]; 122 let keys = ids 123 .iter() 124 .map(|query| L10nKey { 125 id: query.0.into(), 126 args: None, 127 }) 128 .collect::<Vec<_>>(); 129 130 let values = bundles.format_values_sync(&keys, &mut errors).unwrap(); 131 132 assert_eq!(values.len(), ids.len()); 133 134 for (value, query) in values.iter().zip(ids) { 135 if let Some(expected) = query.1 { 136 assert_eq!(*value, Some(Cow::Borrowed(expected))); 137 } 138 } 139 assert_eq!(errors.len(), 4); 140 } 141 142 #[tokio::test] 143 #[serial] 144 async fn localization_format_value_async() { 145 let loc = setup_async_test(); 146 let bundles = loc.bundles(); 147 let mut errors = vec![]; 148 149 for query in &[L10N_ID_PL_EN, L10N_ID_MISSING, L10N_ID_ONLY_EN] { 150 let value = bundles.format_value(query.0, None, &mut errors).await; 151 if let Some(expected) = query.1 { 152 assert_eq!(value, Some(Cow::Borrowed(expected))); 153 } 154 } 155 } 156 157 #[tokio::test] 158 #[serial] 159 async fn localization_format_values_async() { 160 let loc = setup_async_test(); 161 let bundles = loc.bundles(); 162 let mut errors = vec![]; 163 164 let ids = &[L10N_ID_PL_EN, L10N_ID_MISSING, L10N_ID_ONLY_EN]; 165 let keys = ids 166 .iter() 167 .map(|query| L10nKey { 168 id: query.0.into(), 169 args: None, 170 }) 171 .collect::<Vec<_>>(); 172 173 let values = bundles.format_values(&keys, &mut errors).await; 174 175 assert_eq!(values.len(), ids.len()); 176 177 for (value, query) in values.iter().zip(ids) { 178 if let Some(expected) = query.1 { 179 assert_eq!(*value, Some(Cow::Borrowed(expected))); 180 } 181 } 182 } 183 184 #[tokio::test] 185 #[serial] 186 async fn localization_upgrade() { 187 let mut loc = setup_sync_test(); 188 let bundles = loc.bundles(); 189 let mut errors = vec![]; 190 let value = bundles 191 .format_value_sync(L10N_ID_PL_EN.0, None, &mut errors) 192 .unwrap(); 193 assert_eq!(value, L10N_ID_PL_EN.1.map(|s| Cow::Borrowed(s))); 194 195 loc.set_async(); 196 let bundles = loc.bundles(); 197 let value = bundles 198 .format_value(L10N_ID_PL_EN.0, None, &mut errors) 199 .await; 200 assert_eq!(value, L10N_ID_PL_EN.1.map(|s| Cow::Borrowed(s))); 201 }