forked from Floorp-Projects/Floorp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug 1761835 - Add a test for switching locales and string bundles; r=…
…platform-i18n-reviewers,dminor Differential Revision: https://phabricator.services.mozilla.com/D144032
- Loading branch information
Showing
5 changed files
with
298 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
var EXPORTED_SYMBOLS = ["setupFakeLangpacks"]; | ||
|
||
const { AddonTestUtils } = ChromeUtils.import( | ||
"resource://testing-common/AddonTestUtils.jsm" | ||
); | ||
const { AppConstants } = ChromeUtils.import( | ||
"resource://gre/modules/AppConstants.jsm" | ||
); | ||
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm"); | ||
|
||
/** | ||
* Allows the current app to install fake langpacks. This is useful for testing live | ||
* language switching where the browser can switch languages without a restart, as well | ||
* as testing novel message caching schemes. | ||
* | ||
* It's generally not recommended to assert against actual localized strings, as changing | ||
* these will break tests, and lock in the test suite to a single language. However, with | ||
* fake langpacks, the real strings can be tested against since they are defined in the | ||
* fake langpack inside of the test. | ||
* | ||
* Usage: | ||
* | ||
* add_task(async function test_stringBundleInvalidation() { | ||
* const fakeLangpacks = await setupFakeLangpacks(this, SpecialPowers); | ||
* | ||
* await fakeLangpacks.install({ | ||
* locale: "es-ES", | ||
* propertiesFiles: [ | ||
* { | ||
* rootURL: "chrome://branding/locale", | ||
* files: { | ||
* "brand.properties": "brandFullName=Zorro de Fuego", | ||
* "test-only.properties": "testOnly=Mensaje solo para pruebas" | ||
* }, | ||
* }, | ||
* ], | ||
* }); | ||
* | ||
* Services.locale.requestedLocales = ["es-ES"]; | ||
* const bundle1 = Services.strings.createBundle( | ||
* "chrome://branding/locale/branding.properties" | ||
* ); | ||
* const bundle2 = Services.strings.createBundle( | ||
* "chrome://branding/locale/test-only.properties" | ||
* ); | ||
* }); | ||
* | ||
* @param {object} testEnv - The `this` object from the test. | ||
* @param {SpecialPowers} SpecialPowers - Generally a property on `self` in the test. | ||
* | ||
* @return {Promise<{ | ||
* install: (options: FakeLangpackOptions) => Promise<nsIFile>, | ||
* create: (options: FakeLangpackOptions) => Promise<nsIFile>, | ||
* }>} | ||
*/ | ||
async function setupFakeLangpacks(testEnv, SpecialPowers) { | ||
/** | ||
* Create a test-only langpack, with actual content. | ||
* | ||
* @param {FakeLangpackOptions} options | ||
* @returns {Promise<nsIFile>} | ||
*/ | ||
function create(options) { | ||
const { locale, propertiesFiles } = options; | ||
const xpiFiles = { | ||
"manifest.json": getManifestData(locale, propertiesFiles), | ||
}; | ||
for (const { rootURL, files } of propertiesFiles || []) { | ||
const slug = getChromeUrlSlug(rootURL); | ||
const fakePath = getFakeXPIPath(slug); | ||
for (const [name, contents] of Object.entries(files)) { | ||
xpiFiles[OS.Path.join(fakePath, name)] = contents; | ||
} | ||
} | ||
return AddonTestUtils.createTempXPIFile(xpiFiles); | ||
} | ||
|
||
/** | ||
* Create and install a test-only langpack, with actual content. This XPI file will | ||
* be created in a temp directory, and actually installed in the app. | ||
* | ||
* @param {FakeLangpackOptions} options | ||
* @returns {Promise<nsIFile>} | ||
*/ | ||
function install(options) { | ||
testEnv.info(`Installing the ${options.locale} langpack`); | ||
return AddonTestUtils.promiseInstallFile(create(options)); | ||
} | ||
|
||
AddonTestUtils.initMochitest(testEnv); | ||
|
||
await SpecialPowers.pushPrefEnv({ | ||
set: [["extensions.langpacks.signatures.required", false]], | ||
}); | ||
|
||
return { | ||
install, | ||
create, | ||
}; | ||
} | ||
|
||
/** | ||
* Expect URLs to come in the form "chrome://slug/locale". | ||
* | ||
* @returns {string} | ||
*/ | ||
function getChromeUrlSlug(url) { | ||
const result = /^chrome:\/\/(\w+)\/locale\/?$/.exec(url); | ||
if (!result) { | ||
throw new Error( | ||
'Expected the properties file\'s chrome URL to take the form: "chrome://slug/locale":' + | ||
JSON.stringify(url) | ||
); | ||
} | ||
return result[1]; | ||
} | ||
|
||
function getManifestData(locale, propertiesFiles) { | ||
const chrome_resources = {}; | ||
for (const { rootURL } of propertiesFiles) { | ||
const slug = getChromeUrlSlug(rootURL); | ||
chrome_resources[slug] = getFakeXPIPath(slug) + "/"; | ||
} | ||
return { | ||
langpack_id: locale, | ||
name: `${locale} Language Pack`, | ||
description: `${locale} Language pack`, | ||
languages: { | ||
[locale]: { | ||
chrome_resources, | ||
version: "1", | ||
}, | ||
}, | ||
applications: { | ||
gecko: { | ||
strict_min_version: AppConstants.MOZ_APP_VERSION, | ||
id: `langpack-${locale}@firefox.mozilla.org`, | ||
strict_max_version: AppConstants.MOZ_APP_VERSION, | ||
}, | ||
}, | ||
version: "2.0", | ||
manifest_version: 2, | ||
sources: { | ||
browser: { | ||
base_path: "browser/", | ||
}, | ||
}, | ||
author: "Mozilla", | ||
}; | ||
} | ||
|
||
/** | ||
* @typedef {object} FakeProperties | ||
* @property {string} rootURL - The path that gets used for the chrome URL. It must take | ||
* the form "chrome://slug/locale". | ||
* @property {{[string]: string}} files - The list of files that will be placed in the | ||
* XPI. The key is the file name, and the value is the contents of the file. | ||
*/ | ||
|
||
/** | ||
* @typedef {object} FakeLangpackOptions | ||
* @property {string} locale - The BCP 47 identifier | ||
* @property {FakeProperties[]} propertiesFiles - This list of fake properties files | ||
* to be served from chrome URLs. These can either be invented files, or shadow | ||
* the underlying translation files. | ||
*/ | ||
|
||
/** | ||
* The real paths in XPI files are something like: | ||
* | ||
* - browser/chrome/es-ES/locale/branding/brand.properties | ||
* - browser/chrome/es-ES/locale/browser/browser.properties | ||
* - browser/chrome/es-ES/locale/es-ES/devtools/client/debugger.properties | ||
* - browser/features/[email protected]/es-ES/locale/es-ES/formautofill.properties | ||
* | ||
* However, in the manifest.json, the chrome URLs can point to arbitrary files via | ||
* the chrome_resources key. This function generates an arbitrary fake path to store | ||
* the files in. | ||
*/ | ||
function getFakeXPIPath(rootSlug) { | ||
return `fake-${rootSlug}`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
[DEFAULT] | ||
support-files = | ||
head.js | ||
|
||
[browser_stringBundleInvalidation.js] |
104 changes: 104 additions & 0 deletions
104
intl/locale/tests/browser/browser_stringBundleInvalidation.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
const { setupFakeLangpacks } = ChromeUtils.import( | ||
"resource://testing-common/LangPackTestUtils.jsm" | ||
); | ||
|
||
add_task(async function test_stringBundleInvalidation() { | ||
const fakeLangpacks = await setupFakeLangpacks(this, SpecialPowers); | ||
|
||
await fakeLangpacks.install({ | ||
locale: "es-ES", | ||
propertiesFiles: [ | ||
{ | ||
rootURL: "chrome://branding/locale", | ||
files: { | ||
// Localizers don't really translate the brand name this way, but it | ||
// makes for a useful test. | ||
"brand.properties": "brandFullName=Zorro de Fuego", | ||
"test-only.properties": "testOnly=Mensaje solo para pruebas", | ||
}, | ||
}, | ||
], | ||
}); | ||
|
||
await fakeLangpacks.install({ | ||
locale: "fr", | ||
propertiesFiles: [ | ||
{ | ||
rootURL: "chrome://branding/locale", | ||
files: { | ||
// Localizers don't really translate the brand name this way, but it | ||
// makes for a useful test. | ||
"brand.properties": "brandFullName=Renard de Feu", | ||
"test-only.properties": "testOnly=Message de test uniquement", | ||
}, | ||
}, | ||
], | ||
}); | ||
|
||
info(`Creating the bundle "chrome://branding/locale/brand.properties"`); | ||
const sharedStringBundle = Services.strings.createBundle( | ||
"chrome://branding/locale/brand.properties" | ||
); | ||
|
||
// Don't write an assertion directly off of the brand name, as it could change | ||
// depending on the build. | ||
const brandFullName = sharedStringBundle.GetStringFromName("brandFullName"); | ||
info("Reading the brand name: " + brandFullName); | ||
Assert.equal(typeof brandFullName, "string"); | ||
Assert.greater(brandFullName.length, 0); | ||
|
||
info("Changing the locale to es-ES."); | ||
Services.locale.requestedLocales = ["es-ES"]; | ||
await document.l10n.ready; | ||
|
||
info("Creating the test-only.properties bundle in Spanish."); | ||
const testOnlyBundle = Services.strings.createBundle( | ||
"chrome://branding/locale/test-only.properties" | ||
); | ||
|
||
Assert.equal( | ||
testOnlyBundle.GetStringFromName("testOnly"), | ||
"Mensaje solo para pruebas", | ||
"String bundles can load the new locale." | ||
); | ||
|
||
Assert.equal( | ||
sharedStringBundle.GetStringFromName("brandFullName"), | ||
brandFullName, | ||
"Shared string bundles are not invalidated." | ||
); | ||
|
||
info("Changing the locale to fr."); | ||
Services.locale.requestedLocales = ["fr"]; | ||
await document.l10n.ready; | ||
|
||
Assert.equal( | ||
sharedStringBundle.GetStringFromName("brandFullName"), | ||
brandFullName, | ||
"Shared string bundles are not invalidated." | ||
); | ||
Assert.equal( | ||
testOnlyBundle.GetStringFromName("testOnly"), | ||
"Mensaje solo para pruebas", | ||
"Existing string bundles are retained." | ||
); | ||
|
||
Assert.equal( | ||
Services.strings | ||
.createBundle("chrome://branding/locale/brand.properties") | ||
.GetStringFromName("brandFullName"), | ||
brandFullName, | ||
"Shared string bundles are not invalidated." | ||
); | ||
Assert.equal( | ||
Services.strings | ||
.createBundle("chrome://branding/locale/test-only.properties") | ||
.GetStringFromName("testOnly"), | ||
"Message de test uniquement", | ||
"The string bundle can be recreated." | ||
); | ||
}); |
Empty file.