168 lines
5.2 KiB
JavaScript
168 lines
5.2 KiB
JavaScript
/* 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 lazy = {};
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
AddressMetaData: "resource://gre/modules/shared/AddressMetaData.sys.mjs",
|
|
AddressMetaDataExtension:
|
|
"resource://gre/modules/shared/AddressMetaDataExtension.sys.mjs",
|
|
});
|
|
|
|
export class AddressMetaDataLoader {
|
|
// Status of address data loading. We'll load all the countries with basic level 1
|
|
// information while requesting conutry information, and set country to true.
|
|
// Level 1 Set is for recording which country's level 1/level 2 data is loaded,
|
|
// since we only load this when getCountryAddressData called with level 1 parameter.
|
|
static dataLoaded = {
|
|
country: false,
|
|
level1: new Set(),
|
|
};
|
|
|
|
static addressData = {};
|
|
|
|
static DATA_PREFIX = "data/";
|
|
|
|
/**
|
|
* Load address meta data and extension into one object.
|
|
*
|
|
* @returns {object}
|
|
* An object containing address data object with properties from extension.
|
|
*/
|
|
static loadAddressMetaData() {
|
|
const addressMetaData = lazy.AddressMetaData;
|
|
|
|
for (const key in lazy.AddressMetaDataExtension) {
|
|
let addressDataForKey = addressMetaData[key];
|
|
if (!addressDataForKey) {
|
|
addressDataForKey = addressMetaData[key] = {};
|
|
}
|
|
|
|
Object.assign(addressDataForKey, lazy.AddressMetaDataExtension[key]);
|
|
}
|
|
return addressMetaData;
|
|
}
|
|
|
|
/**
|
|
* Convert certain properties' string value into array. We should make sure
|
|
* the cached data is parsed.
|
|
*
|
|
* @param {object} data Original metadata from addressReferences.
|
|
* @returns {object} parsed metadata with property value that converts to array.
|
|
*/
|
|
static #parse(data) {
|
|
if (!data) {
|
|
return null;
|
|
}
|
|
|
|
const properties = [
|
|
"languages",
|
|
"sub_keys",
|
|
"sub_isoids",
|
|
"sub_names",
|
|
"sub_lnames",
|
|
];
|
|
for (const key of properties) {
|
|
if (!data[key]) {
|
|
continue;
|
|
}
|
|
// No need to normalize data if the value is array already.
|
|
if (Array.isArray(data[key])) {
|
|
return data;
|
|
}
|
|
|
|
data[key] = data[key].split("~");
|
|
}
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* We'll cache addressData in the loader once the data loaded from scripts.
|
|
* It'll become the example below after loading addressReferences with extension:
|
|
* addressData: {
|
|
* "data/US": {"lang": ["en"], ...// Data defined in libaddressinput metadata
|
|
* "alternative_names": ... // Data defined in extension }
|
|
* "data/CA": {} // Other supported country metadata
|
|
* "data/TW": {} // Other supported country metadata
|
|
* "data/TW/台北市": {} // Other supported country level 1 metadata
|
|
* }
|
|
*
|
|
* @param {string} country
|
|
* @param {string?} level1
|
|
* @returns {object} Default locale metadata
|
|
*/
|
|
static #loadData(country, level1 = null) {
|
|
// Load the addressData if needed
|
|
if (!this.dataLoaded.country) {
|
|
this.addressData = this.loadAddressMetaData();
|
|
this.dataLoaded.country = true;
|
|
}
|
|
if (!level1) {
|
|
return this.#parse(this.addressData[`${this.DATA_PREFIX}${country}`]);
|
|
}
|
|
// If level1 is set, load addressReferences under country folder with specific
|
|
// country/level 1 for level 2 information.
|
|
if (!this.dataLoaded.level1.has(country)) {
|
|
Object.assign(this.addressData, this.loadAddressMetaData());
|
|
this.dataLoaded.level1.add(country);
|
|
}
|
|
return this.#parse(
|
|
this.addressData[`${this.DATA_PREFIX}${country}/${level1}`]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Return the region metadata with default locale and other locales (if exists).
|
|
*
|
|
* @param {string} country
|
|
* @param {string?} level1
|
|
* @returns {object} Return default locale and other locales metadata.
|
|
*/
|
|
static getData(country, level1 = null) {
|
|
const defaultLocale = this.#loadData(country, level1);
|
|
if (!defaultLocale) {
|
|
return null;
|
|
}
|
|
|
|
const countryData = this.#parse(
|
|
this.addressData[`${this.DATA_PREFIX}${country}`]
|
|
);
|
|
let locales = [];
|
|
// TODO: Should be able to support multi-locale level 1/ level 2 metadata query
|
|
// in Bug 1421886
|
|
if (countryData.languages) {
|
|
const list = countryData.languages.filter(
|
|
key => key !== countryData.lang
|
|
);
|
|
locales = list.map(key =>
|
|
this.#parse(this.addressData[`${defaultLocale.id}--${key}`])
|
|
);
|
|
}
|
|
return { defaultLocale, locales };
|
|
}
|
|
|
|
/**
|
|
* Return an array containing countries alpha2 codes.
|
|
*
|
|
* @returns {Array} Return an array containing countries alpha2 codes.
|
|
*/
|
|
static get #countryCodes() {
|
|
return Object.keys(lazy.AddressMetaDataExtension).map(dataKey =>
|
|
dataKey.replace(this.DATA_PREFIX, "")
|
|
);
|
|
}
|
|
|
|
static getCountries(locales = []) {
|
|
const displayNames = new Intl.DisplayNames(locales, {
|
|
type: "region",
|
|
fallback: "none",
|
|
});
|
|
const countriesMap = new Map();
|
|
for (const countryCode of this.#countryCodes) {
|
|
countriesMap.set(countryCode, displayNames.of(countryCode));
|
|
}
|
|
return countriesMap;
|
|
}
|
|
}
|
|
|
|
export default AddressMetaDataLoader;
|