test_localization.js (9128B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 const { AppConstants } = ChromeUtils.importESModule("resource://gre/modules/AppConstants.sys.mjs"); 5 6 // Disable `xpc::IsInAutomation()` so incomplete locales do not generate 7 // errors. 8 Services.prefs.setBoolPref( 9 "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer", 10 false 11 ); 12 13 add_task(function test_methods_presence() { 14 strictEqual(typeof Localization.prototype.formatValues, "function"); 15 strictEqual(typeof Localization.prototype.formatMessages, "function"); 16 strictEqual(typeof Localization.prototype.formatValue, "function"); 17 }); 18 19 add_task(async function test_methods_calling() { 20 const l10nReg = new L10nRegistry(); 21 const fs = [ 22 { path: "/localization/de/browser/menu.ftl", source: ` 23 key-value1 = [de] Value2 24 ` }, 25 { path: "/localization/en-US/browser/menu.ftl", source: ` 26 key-value1 = [en] Value2 27 key-value2 = [en] Value3 28 key-attr = 29 .label = [en] Label 3 30 ` }, 31 ]; 32 const originalRequested = Services.locale.requestedLocales; 33 34 const source = L10nFileSource.createMock("test", "app", ["de", "en-US"], "/localization/{locale}", fs); 35 l10nReg.registerSources([source]); 36 37 const l10n = new Localization([ 38 "/browser/menu.ftl", 39 ], false, l10nReg, ["de", "en-US"]); 40 41 { 42 let values = await l10n.formatValues([ 43 {id: "key-value1"}, 44 {id: "key-value2"}, 45 {id: "key-missing"}, 46 {id: "key-attr"} 47 ]); 48 49 strictEqual(values[0], "[de] Value2"); 50 strictEqual(values[1], "[en] Value3"); 51 strictEqual(values[2], null); 52 strictEqual(values[3], null); 53 } 54 55 { 56 let values = await l10n.formatValues([ 57 "key-value1", 58 "key-value2", 59 "key-missing", 60 "key-attr" 61 ]); 62 63 strictEqual(values[0], "[de] Value2"); 64 strictEqual(values[1], "[en] Value3"); 65 strictEqual(values[2], null); 66 strictEqual(values[3], null); 67 } 68 69 { 70 strictEqual(await l10n.formatValue("key-missing"), null); 71 strictEqual(await l10n.formatValue("key-value1"), "[de] Value2"); 72 strictEqual(await l10n.formatValue("key-value2"), "[en] Value3"); 73 strictEqual(await l10n.formatValue("key-attr"), null); 74 } 75 76 { 77 let messages = await l10n.formatMessages([ 78 {id: "key-value1"}, 79 {id: "key-missing"}, 80 {id: "key-value2"}, 81 {id: "key-attr"}, 82 ]); 83 84 strictEqual(messages[0].value, "[de] Value2"); 85 strictEqual(messages[1], null); 86 strictEqual(messages[2].value, "[en] Value3"); 87 strictEqual(messages[3].value, null); 88 } 89 }); 90 91 add_task(async function test_builtins() { 92 const l10nReg = new L10nRegistry(); 93 const known_platforms = { 94 "linux": "linux", 95 "win": "windows", 96 "macosx": "macos", 97 "android": "android", 98 }; 99 100 const fs = [ 101 { path: "/localization/en-US/test.ftl", source: ` 102 key = { PLATFORM() -> 103 ${ Object.values(known_platforms).map( 104 name => ` [${ name }] ${ name.toUpperCase() } Value\n`).join("") } 105 *[other] OTHER Value 106 }` }, 107 ]; 108 109 const source = L10nFileSource.createMock("test", "app", ["en-US"], "/localization/{locale}", fs); 110 l10nReg.registerSources([source]); 111 112 const l10n = new Localization([ 113 "/test.ftl", 114 ], false, l10nReg, ["en-US"]); 115 116 let values = await l10n.formatValues([{id: "key"}]); 117 118 ok(values[0].includes( 119 `${ known_platforms[AppConstants.platform].toUpperCase() } Value`)); 120 }); 121 122 add_task(async function test_add_remove_resourceIds() { 123 const l10nReg = new L10nRegistry(); 124 const fs = [ 125 { path: "/localization/en-US/browser/menu.ftl", source: "key1 = Value1" }, 126 { path: "/localization/en-US/toolkit/menu.ftl", source: "key2 = Value2" }, 127 ]; 128 129 130 const source = L10nFileSource.createMock("test", "app", ["en-US"], "/localization/{locale}", fs); 131 l10nReg.registerSources([source]); 132 133 const l10n = new Localization(["/browser/menu.ftl"], false, l10nReg, ["en-US"]); 134 135 let values = await l10n.formatValues([{id: "key1"}, {id: "key2"}]); 136 137 strictEqual(values[0], "Value1"); 138 strictEqual(values[1], null); 139 140 l10n.addResourceIds(["/toolkit/menu.ftl"]); 141 142 values = await l10n.formatValues([{id: "key1"}, {id: "key2"}]); 143 144 strictEqual(values[0], "Value1"); 145 strictEqual(values[1], "Value2"); 146 147 values = await l10n.formatValues(["key1", {id: "key2"}]); 148 149 strictEqual(values[0], "Value1"); 150 strictEqual(values[1], "Value2"); 151 152 values = await l10n.formatValues([{id: "key1"}, "key2"]); 153 154 strictEqual(values[0], "Value1"); 155 strictEqual(values[1], "Value2"); 156 157 l10n.removeResourceIds(["/browser/menu.ftl"]); 158 159 values = await l10n.formatValues([{id: "key1"}, {id: "key2"}]); 160 161 strictEqual(values[0], null); 162 strictEqual(values[1], "Value2"); 163 }); 164 165 add_task(async function test_switch_to_async() { 166 const l10nReg = new L10nRegistry(); 167 168 const fs = [ 169 { path: "/localization/en-US/browser/menu.ftl", source: "key1 = Value1" }, 170 { path: "/localization/en-US/toolkit/menu.ftl", source: "key2 = Value2" }, 171 ]; 172 173 const source = L10nFileSource.createMock("test", "app", ["en-US"], "/localization/{locale}", fs); 174 l10nReg.registerSources([source]); 175 176 const l10n = new Localization(["/browser/menu.ftl"], true, l10nReg, ["en-US"]); 177 178 let values = l10n.formatValuesSync([{id: "key1"}, {id: "key2"}]); 179 180 strictEqual(values[0], "Value1"); 181 strictEqual(values[1], null); 182 183 l10n.setAsync(); 184 185 Assert.throws(() => { 186 l10n.formatValuesSync([{ id: "key1" }, { id: "key2" }]); 187 }, /Can't use formatValuesSync when state is async./); 188 189 l10n.addResourceIds(["/toolkit/menu.ftl"]); 190 191 values = await l10n.formatValues([{id: "key1"}, {id: "key2"}]); 192 let values2 = await l10n.formatValues([{id: "key1"}, {id: "key2"}]); 193 194 deepEqual(values, values2); 195 strictEqual(values[0], "Value1"); 196 strictEqual(values[1], "Value2"); 197 198 l10n.removeResourceIds(["/browser/menu.ftl"]); 199 200 values = await l10n.formatValues([{id: "key1"}, {id: "key2"}]); 201 202 strictEqual(values[0], null); 203 strictEqual(values[1], "Value2"); 204 }); 205 206 /** 207 * This test verifies that when a required resource is missing, 208 * we fallback entirely to the next locale for all entries. 209 */ 210 add_task(async function test_format_from_missing_required_resource() { 211 const l10nReg = new L10nRegistry(); 212 213 const fs = [ 214 { path: "/localization/de/browser/menu.ftl", source: ` 215 key-value = [de] Value1 216 ` }, 217 { path: "/localization/de/browser/missing-in-en-US.ftl", source: ` 218 key-missing = [de] MissingValue 219 ` }, 220 { path: "/localization/en-US/browser/menu.ftl", source: ` 221 key-value = [en] Value1 222 ` }, 223 ]; 224 225 const source = L10nFileSource.createMock("test", "app", ["de", "en-US"], "/localization/{locale}", fs); 226 l10nReg.registerSources([source]); 227 228 // returns correct contexts for [en-US, de] 229 230 let l10n = new Localization([ 231 "/browser/menu.ftl", 232 "/browser/missing-in-en-US.ftl", 233 ], false, l10nReg, ["en-US", "de"]); 234 235 { 236 let values = await l10n.formatValues([ 237 {id: "key-value"}, 238 {id: "key-missing"}, 239 ]); 240 241 strictEqual(values[0], "[de] Value1"); 242 strictEqual(values[1], "[de] MissingValue"); 243 } 244 245 // returns correct contexts for [de, en-US] 246 247 l10n = new Localization([ 248 "/browser/menu.ftl", 249 {path: "/browser/missing-in-en-US.ftl", optional: false}, 250 ], false, l10nReg, ["de", "en-US"]); 251 252 { 253 let values = await l10n.formatValues([ 254 {id: "key-value"}, 255 {id: "key-missing"}, 256 ]); 257 258 strictEqual(values[0], "[de] Value1"); 259 strictEqual(values[1], "[de] MissingValue"); 260 } 261 }); 262 263 /** 264 * This test verifies that when an optional resource is missing, we continue 265 * to populate entires from other resources in the same locale, and we only 266 * fallback entries from the missing optional resource to the next locale. 267 */ 268 add_task(async function test_format_from_missing_optional_resource() { 269 const l10nReg = new L10nRegistry(); 270 271 const fs = [ 272 { path: "/localization/de/browser/menu.ftl", source: ` 273 key-value = [de] Value1 274 ` }, 275 { path: "/localization/de/browser/missing-in-en-US.ftl", source: ` 276 key-missing = [de] MissingValue 277 ` }, 278 { path: "/localization/en-US/browser/menu.ftl", source: ` 279 key-value = [en] Value1 280 ` }, 281 ]; 282 283 const source = L10nFileSource.createMock("test", "app", ["de", "en-US"], "/localization/{locale}", fs); 284 l10nReg.registerSources([source]); 285 286 // returns correct contexts for [en-US, de] 287 288 let l10n = new Localization([ 289 {path: "/browser/menu.ftl", optional: false}, 290 {path: "/browser/missing-in-en-US.ftl", optional: true}, 291 ], false, l10nReg, ["en-US", "de"]); 292 293 { 294 let values = await l10n.formatValues([ 295 {id: "key-value"}, 296 {id: "key-missing"}, 297 ]); 298 299 strictEqual(values[0], "[en] Value1"); 300 strictEqual(values[1], "[de] MissingValue"); 301 } 302 303 // returns correct contexts for [de, en-US] 304 305 l10n = new Localization([ 306 {path: "/browser/menu.ftl", optional: false}, 307 {path: "/browser/missing-in-en-US.ftl", optional: true}, 308 ], false, l10nReg, ["de", "en-US"]); 309 310 { 311 let values = await l10n.formatValues([ 312 {id: "key-value"}, 313 {id: "key-missing"}, 314 ]); 315 316 strictEqual(values[0], "[de] Value1"); 317 strictEqual(values[1], "[de] MissingValue"); 318 } 319 });