Revert "build: convert CLDR locale extraction from Gulp to Bazel tool" (#42521)
This reverts commit b9759522260cd57392e44fe63c5b17a9f102c101. PR Close #42521
This commit is contained in:
parent
cb59bdfebd
commit
e3b709314f
|
@ -50,5 +50,8 @@ baseline.json
|
|||
# Ignore .history for the xyz.local-history VSCode extension
|
||||
.history
|
||||
|
||||
# CLDR data
|
||||
tools/gulp-tasks/cldr/cldr-data/
|
||||
|
||||
# Husky
|
||||
.husky/_
|
||||
|
|
15
WORKSPACE
15
WORKSPACE
|
@ -62,18 +62,3 @@ sass_repositories()
|
|||
load("@io_bazel_skydoc//skylark:skylark.bzl", "skydoc_repositories")
|
||||
|
||||
skydoc_repositories()
|
||||
|
||||
load("//packages/common/locales/generate-locales-tool:cldr-data.bzl", "cldr_data_repository")
|
||||
|
||||
cldr_data_repository(
|
||||
name = "cldr_data",
|
||||
# Since we use the Github archives for CLDR 37, we need to specify a path
|
||||
# to the available locales. This wouldn't be needed with CLDR 39 as that
|
||||
# comes with an official JSON archive not containing a version suffix.
|
||||
available_locales_path = "cldr-core-37.0.0/availableLocales.json",
|
||||
urls = {
|
||||
"https://github.com/unicode-cldr/cldr-core/archive/37.0.0.zip": "32b5c49c3874aa342b90412c207b42e7aefb2435295891fb714c34ce58b3c706",
|
||||
"https://github.com/unicode-cldr/cldr-dates-full/archive/37.0.0.zip": "e1c410dd8ad7d75df4a5393efaf5d28f0d56c0fa126c5d66e171a3f21a988a1e",
|
||||
"https://github.com/unicode-cldr/cldr-numbers-full/archive/37.0.0.zip": "a921b90cf7f436e63fbdd55880f96e39a203acd9e174b0ceafa20a02c242a12e",
|
||||
},
|
||||
)
|
||||
|
|
|
@ -20,3 +20,6 @@ function loadTask(fileName, taskName) {
|
|||
|
||||
gulp.task('source-map-test', loadTask('source-map-test'));
|
||||
gulp.task('changelog:zonejs', loadTask('changelog-zonejs'));
|
||||
gulp.task('cldr:extract', loadTask('cldr', 'extract'));
|
||||
gulp.task('cldr:download', loadTask('cldr', 'download'));
|
||||
gulp.task('cldr:gen-closure-locale', loadTask('cldr', 'closure'));
|
||||
|
|
|
@ -164,7 +164,6 @@
|
|||
"@bazel/buildifier": "^4.0.1",
|
||||
"@bazel/ibazel": "^0.15.8",
|
||||
"@octokit/graphql": "^4.6.1",
|
||||
"@types/cldrjs": "^0.4.22",
|
||||
"@types/cli-progress": "^3.4.2",
|
||||
"@types/conventional-commits-parser": "^3.0.1",
|
||||
"@types/ejs": "^3.0.6",
|
||||
|
@ -174,7 +173,8 @@
|
|||
"browserstacktunnel-wrapper": "^2.0.4",
|
||||
"check-side-effects": "0.0.23",
|
||||
"clang-format": "^1.4.0",
|
||||
"cldr": "5.7.0",
|
||||
"cldr": "7.0.0",
|
||||
"cldr-data-downloader": "^0.3.5",
|
||||
"cldrjs": "0.5.5",
|
||||
"cli-progress": "^3.7.0",
|
||||
"conventional-changelog": "^3.1.24",
|
||||
|
@ -218,5 +218,6 @@
|
|||
"@babel/template": "7.8.6",
|
||||
"@babel/traverse": "7.8.6",
|
||||
"@babel/types": "7.8.6"
|
||||
}
|
||||
},
|
||||
"cldr-data-coverage": "full"
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
load("//tools:defaults.bzl", "ts_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
ts_library(
|
||||
name = "generate-locales-tool",
|
||||
srcs = glob(["*.ts"]),
|
||||
deps = [
|
||||
"@npm//@bazel/runfiles",
|
||||
"@npm//@types/cldrjs",
|
||||
"@npm//@types/glob",
|
||||
"@npm//@types/node",
|
||||
"@npm//cldr",
|
||||
"@npm//cldrjs",
|
||||
"@npm//glob",
|
||||
],
|
||||
)
|
|
@ -1,35 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
/**
|
||||
* To create smaller locale files, we remove duplicated data.
|
||||
* To make this work we store the data in arrays, where `undefined` indicates that the
|
||||
* value is a duplicate of the previous value in the array.
|
||||
* e.g. consider an array like: [x, y, undefined, z, undefined, undefined]
|
||||
* The first `undefined` is equivalent to y, the second and third are equivalent to z
|
||||
* Note that the first value in an array is always defined.
|
||||
*
|
||||
* Also since we need to know which data is assumed similar, it is important that we store those
|
||||
* similar data in arrays to mark the delimitation between values that have different meanings
|
||||
* (e.g. months and days).
|
||||
*
|
||||
* For further size improvements, "undefined" values will be replaced by a constant in the arrays
|
||||
* as the last step of the file generation (in generateLocale and generateLocaleExtra).
|
||||
* e.g.: [x, y, undefined, z, undefined, undefined] will be [x, y, u, z, u, u]
|
||||
*/
|
||||
export function removeDuplicates(data: unknown[]) {
|
||||
const dedup = [data[0]];
|
||||
for (let i = 1; i < data.length; i++) {
|
||||
if (JSON.stringify(data[i]) !== JSON.stringify(data[i - 1])) {
|
||||
dedup.push(data[i]);
|
||||
} else {
|
||||
dedup.push(undefined);
|
||||
}
|
||||
}
|
||||
return dedup;
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
|
||||
load("//tools:defaults.bzl", "ts_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
BIN_ENTRYPOINTS = [
|
||||
"get-base-currencies-file",
|
||||
"get-base-locale-file",
|
||||
"get-closure-locale-file",
|
||||
"write-locale-files-to-dist",
|
||||
]
|
||||
|
||||
ts_library(
|
||||
name = "bin",
|
||||
srcs = glob(["*.ts"]),
|
||||
deps = [
|
||||
"//packages/common/locales/generate-locales-tool",
|
||||
"@npm//@types/node",
|
||||
],
|
||||
)
|
||||
|
||||
[nodejs_binary(
|
||||
name = entrypoint,
|
||||
data = [
|
||||
":bin",
|
||||
"@cldr_data//:all_json",
|
||||
],
|
||||
entry_point = ":%s.ts" % entrypoint,
|
||||
# We need to patch the NodeJS module resolution as this binary runs as
|
||||
# part of a genrule where the linker does not work as expected.
|
||||
# See: https://github.com/bazelbuild/rules_nodejs/issues/2600.
|
||||
templated_args = ["--bazel_patch_module_resolver"],
|
||||
) for entrypoint in BIN_ENTRYPOINTS]
|
|
@ -1,17 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Base locale used as foundation for other locales. For example: A base locale allows
|
||||
* generation of a file containing all currencies with their corresponding symbols. If we
|
||||
* generate other locales, they can override currency symbols which are different in the base
|
||||
* locale. This means that we do not need re-generate all currencies w/ symbols multiple times,
|
||||
* and allows us to reduce the locale data payload as the base locale is always included.
|
||||
* */
|
||||
export const BASE_LOCALE = 'en';
|
|
@ -1,23 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {CldrData} from '../cldr-data';
|
||||
import {generateBaseCurrenciesFile} from '../locale-base-currencies';
|
||||
|
||||
import {BASE_LOCALE} from './base-locale';
|
||||
|
||||
/** Generates the base currencies file and prints it to the stdout. */
|
||||
function main() {
|
||||
const cldrData = new CldrData();
|
||||
const baseLocaleData = cldrData.getLocaleData(BASE_LOCALE);
|
||||
|
||||
process.stdout.write(generateBaseCurrenciesFile(baseLocaleData));
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {CldrData} from '../cldr-data';
|
||||
import {generateBaseCurrencies} from '../locale-base-currencies';
|
||||
import {generateLocale} from '../locale-file';
|
||||
|
||||
import {BASE_LOCALE} from './base-locale';
|
||||
|
||||
/** Generates the base locale file and prints it to the stdout. */
|
||||
function main() {
|
||||
const cldrData = new CldrData();
|
||||
const baseLocaleData = cldrData.getLocaleData(BASE_LOCALE);
|
||||
const baseCurrencies = generateBaseCurrencies(baseLocaleData);
|
||||
|
||||
process.stdout.write(generateLocale(BASE_LOCALE, baseLocaleData, baseCurrencies));
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {CldrData} from '../cldr-data';
|
||||
import {generateClosureLocaleFile} from '../closure-locale-file';
|
||||
import {generateBaseCurrencies} from '../locale-base-currencies';
|
||||
|
||||
import {BASE_LOCALE} from './base-locale';
|
||||
|
||||
/** Generates the Google3 closure-locale file and prints it to the stdout. */
|
||||
function main() {
|
||||
const cldrData = new CldrData();
|
||||
const baseLocaleData = cldrData.getLocaleData(BASE_LOCALE);
|
||||
const baseCurrencies = generateBaseCurrencies(baseLocaleData);
|
||||
|
||||
process.stdout.write(generateClosureLocaleFile(cldrData, baseCurrencies));
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {writeFileSync} from 'fs';
|
||||
import {join} from 'path';
|
||||
|
||||
import {CldrData} from '../cldr-data';
|
||||
import {generateBaseCurrencies} from '../locale-base-currencies';
|
||||
import {generateLocaleExtra} from '../locale-extra-file';
|
||||
import {generateLocale} from '../locale-file';
|
||||
import {generateLocaleGlobalFile} from '../locale-global-file';
|
||||
|
||||
import {BASE_LOCALE} from './base-locale';
|
||||
|
||||
/**
|
||||
* Generates locale files for each available CLDR locale and writes it to the
|
||||
* specified directory.
|
||||
*/
|
||||
function main(outputDir: string) {
|
||||
const cldrData = new CldrData();
|
||||
const baseLocaleData = cldrData.getLocaleData(BASE_LOCALE);
|
||||
const baseCurrencies = generateBaseCurrencies(baseLocaleData);
|
||||
const extraLocaleDir = join(outputDir, 'extra');
|
||||
const globalLocaleDir = join(outputDir, 'global');
|
||||
|
||||
console.info(`Writing locales to: ${outputDir}`);
|
||||
|
||||
// Generate locale files for all locales we have data for.
|
||||
cldrData.availableLocales.forEach((locale: string) => {
|
||||
const localeData = cldrData.getLocaleData(locale);
|
||||
|
||||
// If `cldrjs` is unable to resolve a `bundle` for the current locale, then there is no data
|
||||
// for this locale, and it should not be generated. This can happen as with older versions of
|
||||
// CLDR where `availableLocales.json` specifies locales for which no data is available
|
||||
// (even within the `full` tier packages). See:
|
||||
// http://cldr.unicode.org/development/development-process/design-proposals/json-packaging.
|
||||
// TODO(devversion): Remove if we update to CLDR v39 where this seems fixed. Note that this
|
||||
// worked before in the Gulp tooling without such a check because the `cldr-data-downloader`
|
||||
// overwrote the `availableLocales` to only capture locales with data.
|
||||
if (localeData && !(localeData.attributes as any).bundle) {
|
||||
console.info(`Skipping generation of ${locale} as there is no data.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const localeFile = generateLocale(locale, localeData, baseCurrencies);
|
||||
const localeExtraFile = generateLocaleExtra(locale, localeData);
|
||||
const localeGlobalFile = generateLocaleGlobalFile(locale, localeData, baseCurrencies);
|
||||
|
||||
writeFileSync(join(outputDir, `${locale}.ts`), localeFile);
|
||||
writeFileSync(join(extraLocaleDir, `${locale}.ts`), localeExtraFile);
|
||||
writeFileSync(join(globalLocaleDir, `${locale}.js`), localeGlobalFile);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (require.main === module) {
|
||||
// The first argument is expected to be a path resolving to a directory
|
||||
// where all locales should be generated into.
|
||||
const outputDir = process.argv[2];
|
||||
|
||||
if (outputDir === undefined) {
|
||||
throw Error('No output directory specified.');
|
||||
}
|
||||
|
||||
main(outputDir);
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
def _cldr_data_repository_impl(ctx):
|
||||
for url, sha256 in ctx.attr.urls.items():
|
||||
ctx.report_progress("Downloading CLDR data from: %s" % url)
|
||||
ctx.download_and_extract(
|
||||
url = url,
|
||||
sha256 = sha256,
|
||||
)
|
||||
|
||||
ctx.report_progress("Extracting available locales from: %s" % ctx.attr.available_locales_path)
|
||||
locales_json = ctx.read(ctx.attr.available_locales_path)
|
||||
locales = json.decode(locales_json)["availableLocales"]["full"]
|
||||
ctx.report_progress("Extracted %s locales from CLDR" % len(locales))
|
||||
|
||||
ctx.file("index.bzl", content = """
|
||||
LOCALES=%s
|
||||
""" % locales)
|
||||
|
||||
ctx.file("BUILD.bazel", content = """
|
||||
filegroup(
|
||||
name = "all_json",
|
||||
srcs = glob(["**/*.json"]),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""")
|
||||
|
||||
"""
|
||||
Repository rule that downloads CLDR data from the specified repository and generates a
|
||||
`BUILD.bazel` file that exposes all data files. Additionally, an `index.bzl` file is generated
|
||||
that exposes a constant for all locales the repository contains data for. This can be used to
|
||||
generate pre-declared outputs.
|
||||
"""
|
||||
cldr_data_repository = repository_rule(
|
||||
implementation = _cldr_data_repository_impl,
|
||||
attrs = {
|
||||
"urls": attr.string_dict(doc = """
|
||||
Dictionary of URLs that resolve to archives containing CLDR JSON data. These archives
|
||||
will be downloaded and extracted at root of the repository. Each key can specify
|
||||
a SHA256 checksum for hermetic builds.
|
||||
""", mandatory = True),
|
||||
"available_locales_path": attr.string(
|
||||
doc = """
|
||||
Relative path to the JSON data file describing all available locales.
|
||||
This file usually resides within the `cldr-core` package
|
||||
""",
|
||||
default = "cldr-core/availableLocales.json",
|
||||
),
|
||||
},
|
||||
)
|
|
@ -1,95 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {runfiles} from '@bazel/runfiles';
|
||||
import {CldrStatic} from 'cldrjs';
|
||||
import {sync as globSync} from 'glob';
|
||||
|
||||
// TypeScript doesn't allow us to import the default export without the `esModuleInterop`. We use
|
||||
// the NodeJS require function instead as specifying a custom tsconfig complicates the setup
|
||||
// unnecessarily.
|
||||
// TODO: See if we can improve this by having better types for `cldrjs`.
|
||||
const cldrjs: typeof import('cldrjs') = require('cldrjs');
|
||||
|
||||
/**
|
||||
* Globs that match CLDR JSON data files that should be fetched. We limit these intentionally
|
||||
* as loading unused data results in significant slow-down of the generation
|
||||
* (noticeable in local development if locale data is re-generated).
|
||||
*/
|
||||
const CLDR_DATA_GLOBS = [
|
||||
'cldr-core-37.0.0/scriptMetadata.json',
|
||||
'cldr-core-37.0.0/supplemental/**/*.json',
|
||||
'cldr-dates-full-37.0.0/main/**/*.json',
|
||||
'cldr-numbers-full-37.0.0/main/**/*.json',
|
||||
];
|
||||
|
||||
/** Path to the CLDR available locales file. */
|
||||
const CLDR_AVAILABLE_LOCALES_PATH = 'cldr-core-37.0.0/availableLocales.json';
|
||||
|
||||
/**
|
||||
* Class that provides access to the CLDR data downloaded as part of
|
||||
* the `@cldr_data` Bazel repository.
|
||||
*/
|
||||
export class CldrData {
|
||||
/** Path to the CLDR data Bazel repository. i.e. `@cldr_data//`. */
|
||||
cldrDataDir = runfiles.resolve('cldr_data');
|
||||
|
||||
/** List of all available locales CLDR provides data for. */
|
||||
availableLocales: string[];
|
||||
|
||||
constructor() {
|
||||
this._loadAndPopulateCldrData();
|
||||
this.availableLocales = this._getAvailableLocales();
|
||||
}
|
||||
|
||||
/** Gets the CLDR data for the specified locale. */
|
||||
getLocaleData(localeName: string): CldrStatic {
|
||||
return new cldrjs(localeName);
|
||||
}
|
||||
|
||||
/** Gets a list of all locales CLDR provides data for. */
|
||||
private _getAvailableLocales(): string[] {
|
||||
return require(`${this.cldrDataDir}/${CLDR_AVAILABLE_LOCALES_PATH}`).availableLocales.full;
|
||||
}
|
||||
|
||||
/** Loads the CLDR data and populates the `cldrjs` library with it. */
|
||||
private _loadAndPopulateCldrData() {
|
||||
const localeData = this._readCldrDataFromRepository();
|
||||
|
||||
if (localeData.length === 0) {
|
||||
throw Error('No CLDR data could be found.');
|
||||
}
|
||||
|
||||
// Populate the `cldrjs` library with the locale data. Note that we need this type cast
|
||||
// to satisfy the first `cldrjs.load` parameter which cannot be undefined.
|
||||
cldrjs.load(...localeData as [object, ...object[]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the CLDR JSON data from the Bazel repository.
|
||||
* @returns a list of read JSON objects representing the CLDR data.
|
||||
*/
|
||||
private _readCldrDataFromRepository(): object[] {
|
||||
const jsonFiles =
|
||||
CLDR_DATA_GLOBS.map(pattern => globSync(pattern, {cwd: this.cldrDataDir, absolute: true}))
|
||||
.reduce((acc, dataFiles) => [...acc, ...dataFiles], []);
|
||||
|
||||
// Read the JSON for all determined CLDR json files.
|
||||
return jsonFiles.map(filePath => {
|
||||
const parsed = require(filePath);
|
||||
|
||||
// Guards against cases where non-CLDR data files are accidentally picked up
|
||||
// by the glob above and would throw-off the bundle lookup in `cldrjs`.
|
||||
if (parsed.main !== undefined && typeof parsed.main !== 'object') {
|
||||
throw Error('Unexpected CLDR json file with "main" field which is not an object.');
|
||||
}
|
||||
|
||||
return parsed;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,153 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CldrData} from './cldr-data';
|
||||
import {fileHeader} from './file-header';
|
||||
import {BaseCurrencies} from './locale-base-currencies';
|
||||
import {generateLocale} from './locale-file';
|
||||
|
||||
/**
|
||||
* List of locales used by Closure. These locales will be incorporated in the generated
|
||||
* closure locale file. See:
|
||||
* https://github.com/google/closure-library/blob/master/closure/goog/i18n/datetimepatterns.js#L2450
|
||||
*/
|
||||
const GOOG_LOCALES = [
|
||||
'af', 'am', 'ar', 'ar-DZ', 'az', 'be', 'bg', 'bn', 'br', 'bs',
|
||||
'ca', 'chr', 'cs', 'cy', 'da', 'de', 'de-AT', 'de-CH', 'el', 'en-AU',
|
||||
'en-CA', 'en-GB', 'en-IE', 'en-IN', 'en-SG', 'en-ZA', 'es', 'es-419', 'es-MX', 'es-US',
|
||||
'et', 'eu', 'fa', 'fi', 'fr', 'fr-CA', 'ga', 'gl', 'gsw', 'gu',
|
||||
'haw', 'hi', 'hr', 'hu', 'hy', 'in', 'is', 'it', 'iw', 'ja',
|
||||
'ka', 'kk', 'km', 'kn', 'ko', 'ky', 'ln', 'lo', 'lt', 'lv',
|
||||
'mk', 'ml', 'mn', 'mo', 'mr', 'ms', 'mt', 'my', 'ne', 'nl',
|
||||
'no', 'or', 'pa', 'pl', 'pt', 'pt-PT', 'ro', 'ru', 'sh', 'si',
|
||||
'sk', 'sl', 'sq', 'sr', 'sv', 'sw', 'ta', 'te', 'th', 'tl',
|
||||
'tr', 'uk', 'ur', 'uz', 'vi', 'zh', 'zh-CN', 'zh-HK', 'zh-TW', 'zu'
|
||||
];
|
||||
|
||||
export function generateClosureLocaleFile(
|
||||
cldrData: CldrData, baseCurrencies: BaseCurrencies): string {
|
||||
// locale id aliases to support deprecated locale ids used by closure
|
||||
// it maps deprecated ids --> new ids
|
||||
// manually extracted from ./cldr-data/supplemental/aliases.json
|
||||
// TODO: Consider extracting directly from the CLDR data instead.
|
||||
const aliases = {
|
||||
'in': 'id',
|
||||
'iw': 'he',
|
||||
'mo': 'ro-MD',
|
||||
'no': 'nb',
|
||||
'nb': 'no-NO',
|
||||
'sh': 'sr-Latn',
|
||||
'tl': 'fil',
|
||||
'pt': 'pt-BR',
|
||||
'zh-CN': 'zh-Hans-CN',
|
||||
'zh-Hans-CN': 'zh-Hans',
|
||||
'zh-HK': 'zh-Hant-HK',
|
||||
'zh-TW': 'zh-Hant-TW',
|
||||
'zh-Hant-TW': 'zh-Hant',
|
||||
};
|
||||
|
||||
return generateAllLocalesFile(cldrData, GOOG_LOCALES, aliases, baseCurrencies);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a file that contains all locale to import for closure.
|
||||
* Tree shaking will only keep the data for the `goog.LOCALE` locale.
|
||||
*/
|
||||
function generateAllLocalesFile(
|
||||
cldrData: CldrData, locales: string[], aliases: {[name: string]: string},
|
||||
baseCurrencies: BaseCurrencies) {
|
||||
const existingLocalesAliases: {[locale: string]: Set<string>} = {};
|
||||
const existingLocalesData: {[locale: string]: string} = {};
|
||||
|
||||
// for each locale, get the data and the list of equivalent locales
|
||||
locales.forEach(locale => {
|
||||
const eqLocales = new Set<string>();
|
||||
eqLocales.add(locale);
|
||||
if (locale.match(/-/)) {
|
||||
eqLocales.add(locale.replace(/-/g, '_'));
|
||||
}
|
||||
|
||||
// check for aliases
|
||||
const alias = aliases[locale];
|
||||
if (alias) {
|
||||
eqLocales.add(alias);
|
||||
|
||||
if (alias.match(/-/)) {
|
||||
eqLocales.add(alias.replace(/-/g, '_'));
|
||||
}
|
||||
|
||||
// to avoid duplicated "case" we regroup all locales in the same "case"
|
||||
// the simplest way to do that is to have alias aliases
|
||||
// e.g. 'no' --> 'nb', 'nb' --> 'no-NO'
|
||||
// which means that we'll have 'no', 'nb' and 'no-NO' in the same "case"
|
||||
const aliasKeys = Object.keys(aliases);
|
||||
for (let i = 0; i < aliasKeys.length; i++) {
|
||||
const aliasValue = aliases[alias];
|
||||
if (aliasKeys.indexOf(alias) !== -1 && !eqLocales.has(aliasValue)) {
|
||||
eqLocales.add(aliasValue);
|
||||
|
||||
if (aliasValue.match(/-/)) {
|
||||
eqLocales.add(aliasValue.replace(/-/g, '_'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const localeNameForData = aliases[locale] ?? locale;
|
||||
const localeData = cldrData.getLocaleData(localeNameForData);
|
||||
const localeName = formatLocale(locale);
|
||||
existingLocalesData[locale] =
|
||||
generateLocale(localeNameForData, localeData, baseCurrencies)
|
||||
.replace(`${fileHeader}\n`, '')
|
||||
.replace('export default ', `export const locale_${localeName} = `)
|
||||
.replace('function plural', `function plural_${localeName}`)
|
||||
.replace(/,\s+plural/, `, plural_${localeName}`)
|
||||
.replace(/\s*const u = undefined;\s*/, '');
|
||||
|
||||
existingLocalesAliases[locale] = eqLocales;
|
||||
});
|
||||
|
||||
function generateCases(locale: string) {
|
||||
let str = '';
|
||||
let locales: string[] = [];
|
||||
const eqLocales = existingLocalesAliases[locale];
|
||||
eqLocales.forEach(l => {
|
||||
str += `case '${l}':\n`;
|
||||
locales.push(`'${l}'`);
|
||||
});
|
||||
let localesStr = '[' + locales.join(',') + ']';
|
||||
|
||||
str += ` l = locale_${formatLocale(locale)};
|
||||
locales = ${localesStr};
|
||||
break;\n`;
|
||||
return str;
|
||||
}
|
||||
|
||||
return `${fileHeader}
|
||||
|
||||
import {registerLocaleData} from '../src/i18n/locale_data';
|
||||
|
||||
const u = undefined;
|
||||
|
||||
${locales.map(locale => `${existingLocalesData[locale]}`).join('\n')}
|
||||
|
||||
let l: any;
|
||||
let locales: string[] = [];
|
||||
|
||||
switch (goog.LOCALE) {
|
||||
${locales.map(locale => generateCases(locale)).join('')}}
|
||||
|
||||
if(l) {
|
||||
locales.forEach(locale => registerLocaleData(l, locale));
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
function formatLocale(locale: string): string {
|
||||
return locale.replace(/-/g, '_');
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CldrStatic} from 'cldrjs';
|
||||
|
||||
/**
|
||||
* Returns data for the chosen day periods
|
||||
*/
|
||||
export function getDayPeriods(localeData: CldrStatic, dayPeriodsList: string[]): {
|
||||
format: {narrow: string[], abbreviated: string[], wide: string[]},
|
||||
'stand-alone': {narrow: string[], abbreviated: string[], wide: string[]}
|
||||
} {
|
||||
const dayPeriods = localeData.main(`dates/calendars/gregorian/dayPeriods`);
|
||||
const result: any = {};
|
||||
// cleaning up unused keys
|
||||
Object.keys(dayPeriods).forEach(key1 => { // format / stand-alone
|
||||
result[key1] = {};
|
||||
Object.keys(dayPeriods[key1]).forEach(key2 => { // narrow / abbreviated / wide
|
||||
result[key1][key2] = {};
|
||||
Object.keys(dayPeriods[key1][key2]).forEach(key3 => {
|
||||
if (dayPeriodsList.indexOf(key3) !== -1) {
|
||||
result[key1][key2][key3] = dayPeriods[key1][key2][key3];
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return result as any;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns day period rules for a locale
|
||||
* @returns string[]
|
||||
*/
|
||||
export function getDayPeriodRules(
|
||||
localeData: CldrStatic, language = localeData.attributes.language): {[key: string]: []} {
|
||||
const dayPeriodRules = localeData.get(`supplemental/dayPeriodRuleSet/${language}`);
|
||||
const rules: any = {};
|
||||
if (dayPeriodRules) {
|
||||
Object.keys(dayPeriodRules).forEach(key => {
|
||||
if (dayPeriodRules[key]._at) {
|
||||
rules[key] = dayPeriodRules[key]._at;
|
||||
} else {
|
||||
rules[key] = [dayPeriodRules[key]._from, dayPeriodRules[key]._before];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Implements inheritance for the day periods. As of CLDR v39, the `nn` locale
|
||||
// for example fully inherits from `no`.
|
||||
// http://cldr.unicode.org/index/downloads/cldr-39?pli=1#TOC-Migration.
|
||||
if (dayPeriodRules === undefined) {
|
||||
const parentLocale = localeData.get(`supplemental/parentLocales/parentLocale/${language}`);
|
||||
|
||||
if (parentLocale !== undefined) {
|
||||
return getDayPeriodRules(localeData, parentLocale);
|
||||
}
|
||||
}
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the basic day periods (am/pm)
|
||||
*/
|
||||
export function getDayPeriodsAmPm(localeData: CldrStatic) {
|
||||
return getDayPeriods(localeData, ['am', 'pm']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extra day periods (without am/pm)
|
||||
*/
|
||||
export function getDayPeriodsNoAmPm(localeData: CldrStatic) {
|
||||
return getDayPeriods(localeData, [
|
||||
'noon', 'midnight', 'morning1', 'morning2', 'afternoon1', 'afternoon2', 'evening1', 'evening2',
|
||||
'night1', 'night2'
|
||||
]);
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
export const fileHeader = `/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// THIS CODE IS GENERATED - DO NOT MODIFY.`;
|
|
@ -1,75 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CldrStatic} from 'cldrjs';
|
||||
|
||||
import {fileHeader} from './file-header';
|
||||
import {stringify} from './object-stringify';
|
||||
|
||||
export type BaseCurrencySymbols = [
|
||||
string
|
||||
]|[string | undefined, string]|[string, undefined, number]|[string | undefined, string, number];
|
||||
|
||||
export type BaseCurrencies = {
|
||||
[code: string]: BaseCurrencySymbols|undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate a file that contains the list of currencies, their symbols and digits.
|
||||
*/
|
||||
export function generateBaseCurrenciesFile(baseLocaleData: CldrStatic) {
|
||||
const baseCurrencies = generateBaseCurrencies(baseLocaleData);
|
||||
|
||||
return `${fileHeader}
|
||||
export type CurrenciesSymbols = [string] | [string | undefined, string];
|
||||
|
||||
/** @internal */
|
||||
export const CURRENCIES_EN: {[code: string]: CurrenciesSymbols | [string | undefined, string | undefined, number]} = ${
|
||||
stringify(baseCurrencies)};
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a list of currencies to be used as a base for other currencies
|
||||
* e.g.: {'ARS': [, '$'], 'AUD': ['A$', '$'], ...}
|
||||
*/
|
||||
export function generateBaseCurrencies(localeData: CldrStatic) {
|
||||
const currenciesData = localeData.main('numbers/currencies');
|
||||
const fractions = localeData.get(`supplemental/currencyData/fractions`);
|
||||
const currencies: BaseCurrencies = {};
|
||||
|
||||
Object.keys(currenciesData).forEach(key => {
|
||||
let symbolsArray = [];
|
||||
const symbol = currenciesData[key].symbol;
|
||||
const symbolNarrow = currenciesData[key]['symbol-alt-narrow'];
|
||||
if (symbol && symbol !== key) {
|
||||
symbolsArray.push(symbol);
|
||||
}
|
||||
if (symbolNarrow && symbolNarrow !== symbol) {
|
||||
if (symbolsArray.length > 0) {
|
||||
symbolsArray.push(symbolNarrow);
|
||||
} else {
|
||||
symbolsArray = [undefined, symbolNarrow];
|
||||
}
|
||||
}
|
||||
if (fractions[key] && fractions[key]['_digits']) {
|
||||
const digits = parseInt(fractions[key]['_digits'], 10);
|
||||
if (symbolsArray.length === 2) {
|
||||
symbolsArray.push(digits);
|
||||
} else if (symbolsArray.length === 1) {
|
||||
symbolsArray = [...symbolsArray, undefined, digits];
|
||||
} else {
|
||||
symbolsArray = [undefined, undefined, digits];
|
||||
}
|
||||
}
|
||||
if (symbolsArray.length > 0) {
|
||||
currencies[key] = symbolsArray as BaseCurrencySymbols;
|
||||
}
|
||||
});
|
||||
return currencies;
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CldrStatic} from 'cldrjs';
|
||||
import {BaseCurrencies} from './locale-base-currencies';
|
||||
|
||||
/**
|
||||
* To minimize the file even more, we only output the differences compared to the base currency
|
||||
*/
|
||||
export function generateLocaleCurrencies(localeData: CldrStatic, baseCurrencies: BaseCurrencies) {
|
||||
const currenciesData = localeData.main('numbers/currencies');
|
||||
const currencies: any = {};
|
||||
|
||||
Object.keys(currenciesData).forEach(code => {
|
||||
let symbolsArray = [];
|
||||
const symbol = currenciesData[code].symbol;
|
||||
const symbolNarrow = currenciesData[code]['symbol-alt-narrow'];
|
||||
if (symbol && symbol !== code) {
|
||||
symbolsArray.push(symbol);
|
||||
}
|
||||
if (symbolNarrow && symbolNarrow !== symbol) {
|
||||
if (symbolsArray.length > 0) {
|
||||
symbolsArray.push(symbolNarrow);
|
||||
} else {
|
||||
symbolsArray = [undefined, symbolNarrow];
|
||||
}
|
||||
}
|
||||
|
||||
const baseCurrencySymbols = baseCurrencies[code] || [];
|
||||
|
||||
// Jf locale data is equal to the one in the base currencies, skip this currency to
|
||||
// avoid unnecessary locale data that could be inferred from the base currency.
|
||||
if (baseCurrencySymbols && baseCurrencySymbols[0] === symbolsArray[0] &&
|
||||
baseCurrencySymbols[1] === symbolsArray[1]) {
|
||||
return;
|
||||
}
|
||||
|
||||
currencies[code] = symbolsArray;
|
||||
});
|
||||
return currencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currency code, symbol and name for a locale
|
||||
*/
|
||||
export function getCurrencySettings(localeName: string, localeData: CldrStatic) {
|
||||
const currencyInfo = localeData.main(`numbers/currencies`);
|
||||
let currentCurrency = '';
|
||||
|
||||
// find the currency currently used in this country
|
||||
const currencies: any[] =
|
||||
localeData.get(`supplemental/currencyData/region/${localeData.attributes.territory}`) ||
|
||||
localeData.get(
|
||||
`supplemental/currencyData/region/${localeData.attributes.language.toUpperCase()}`);
|
||||
|
||||
if (currencies) {
|
||||
currencies.some(currency => {
|
||||
const keys = Object.keys(currency);
|
||||
return keys.some(key => {
|
||||
if (currency[key]._from && !currency[key]._to) {
|
||||
return currentCurrency = key;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!currentCurrency) {
|
||||
throw new Error(`Unable to find currency for locale "${localeName}"`);
|
||||
}
|
||||
}
|
||||
|
||||
let currencySettings = [undefined, undefined, undefined];
|
||||
|
||||
if (currentCurrency) {
|
||||
currencySettings = [
|
||||
currentCurrency, currencyInfo[currentCurrency].symbol,
|
||||
currencyInfo[currentCurrency].displayName
|
||||
];
|
||||
}
|
||||
|
||||
return currencySettings;
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CldrStatic} from 'cldrjs';
|
||||
|
||||
import {removeDuplicates} from './array-deduplication';
|
||||
import {getDayPeriodRules, getDayPeriodsNoAmPm} from './day-periods';
|
||||
import {fileHeader} from './file-header';
|
||||
import {stringify} from './object-stringify';
|
||||
|
||||
/**
|
||||
* Generate the contents for the extra data file
|
||||
*/
|
||||
export function generateLocaleExtra(locale: string, localeData: CldrStatic) {
|
||||
return `${fileHeader}
|
||||
const u = undefined;
|
||||
|
||||
export default ${generateDayPeriodsSupplementalString(locale, localeData)};
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Collect up the day period rules, and extended day period data.
|
||||
*/
|
||||
export function generateDayPeriodsSupplementalString(locale: string, localeData: CldrStatic) {
|
||||
const dayPeriods = getDayPeriodsNoAmPm(localeData);
|
||||
const dayPeriodRules = getDayPeriodRules(localeData);
|
||||
|
||||
let dayPeriodsSupplemental: any[] = [];
|
||||
if (Object.keys(dayPeriods.format.narrow).length) {
|
||||
const keys = Object.keys(dayPeriods.format.narrow);
|
||||
|
||||
if (keys.length !== Object.keys(dayPeriodRules).length) {
|
||||
throw new Error(`Error: locale ${locale} has not the correct number of day period rules`);
|
||||
}
|
||||
|
||||
const dayPeriodsFormat = removeDuplicates([
|
||||
Object.values(dayPeriods.format.narrow), Object.values(dayPeriods.format.abbreviated),
|
||||
Object.values(dayPeriods.format.wide)
|
||||
]);
|
||||
|
||||
const dayPeriodsStandalone = removeDuplicates([
|
||||
Object.values(dayPeriods['stand-alone'].narrow),
|
||||
Object.values(dayPeriods['stand-alone'].abbreviated),
|
||||
Object.values(dayPeriods['stand-alone'].wide)
|
||||
]);
|
||||
|
||||
const rules = keys.map(key => dayPeriodRules[key]);
|
||||
dayPeriodsSupplemental = [...removeDuplicates([dayPeriodsFormat, dayPeriodsStandalone]), rules];
|
||||
}
|
||||
return stringify(dayPeriodsSupplemental).replace(/undefined/g, 'u');
|
||||
}
|
|
@ -1,226 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CldrStatic} from 'cldrjs';
|
||||
|
||||
import {removeDuplicates} from './array-deduplication';
|
||||
import {getDayPeriodsAmPm} from './day-periods';
|
||||
import {fileHeader} from './file-header';
|
||||
import {BaseCurrencies} from './locale-base-currencies';
|
||||
import {generateLocaleCurrencies, getCurrencySettings} from './locale-currencies';
|
||||
import {stringify} from './object-stringify';
|
||||
import {getPluralFunction} from './plural-function';
|
||||
|
||||
const WEEK_DAYS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
|
||||
|
||||
/** Generate contents for the basic locale data file */
|
||||
export function generateLocale(
|
||||
locale: string, localeData: CldrStatic, baseCurrencies: BaseCurrencies) {
|
||||
return `${fileHeader}
|
||||
const u = undefined;
|
||||
|
||||
${getPluralFunction(locale)}
|
||||
|
||||
export default ${generateBasicLocaleString(locale, localeData, baseCurrencies)};
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Collect up the basic locale data [ localeId, dateTime, number, currency, directionality,
|
||||
* pluralCase ].
|
||||
*/
|
||||
export function generateBasicLocaleString(
|
||||
locale: string, localeData: CldrStatic, baseCurrencies: BaseCurrencies) {
|
||||
let data = stringify([
|
||||
locale,
|
||||
...getDateTimeTranslations(localeData),
|
||||
...getDateTimeSettings(localeData),
|
||||
...getNumberSettings(localeData),
|
||||
...getCurrencySettings(locale, localeData),
|
||||
generateLocaleCurrencies(localeData, baseCurrencies),
|
||||
getDirectionality(localeData),
|
||||
])
|
||||
// We remove "undefined" added by spreading arrays when there is no value
|
||||
.replace(/undefined/g, 'u');
|
||||
|
||||
// adding plural function after, because we don't want it as a string. The function named `plural`
|
||||
// is expected to be available in the file. See `generateLocale` above.
|
||||
data = data.replace(/\]$/, ', plural]');
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the writing direction for a locale
|
||||
* @returns 'rtl' | 'ltr'
|
||||
*/
|
||||
function getDirectionality(localeData: CldrStatic): 'rtl'|'ltr' {
|
||||
const rtl = localeData.get('scriptMetadata/{script}/rtl');
|
||||
return rtl === 'YES' ? 'rtl' : 'ltr';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns dateTime data for a locale
|
||||
* @returns [ firstDayOfWeek, weekendRange, formats ]
|
||||
*/
|
||||
function getDateTimeSettings(localeData: CldrStatic) {
|
||||
return [
|
||||
getFirstDayOfWeek(localeData), getWeekendRange(localeData), ...getDateTimeFormats(localeData)
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number symbols and formats for a locale
|
||||
* @returns [ symbols, formats ]
|
||||
* symbols: [ decimal, group, list, percentSign, plusSign, minusSign, exponential,
|
||||
* superscriptingExponent, perMille, infinity, nan, timeSeparator, currencyDecimal?, currencyGroup?
|
||||
* ]
|
||||
* formats: [ currency, decimal, percent, scientific ]
|
||||
*/
|
||||
function getNumberSettings(localeData: CldrStatic) {
|
||||
const decimalFormat = localeData.main('numbers/decimalFormats-numberSystem-latn/standard');
|
||||
const percentFormat = localeData.main('numbers/percentFormats-numberSystem-latn/standard');
|
||||
const scientificFormat = localeData.main('numbers/scientificFormats-numberSystem-latn/standard');
|
||||
const currencyFormat = localeData.main('numbers/currencyFormats-numberSystem-latn/standard');
|
||||
const symbols = localeData.main('numbers/symbols-numberSystem-latn');
|
||||
const symbolValues = [
|
||||
symbols.decimal,
|
||||
symbols.group,
|
||||
symbols.list,
|
||||
symbols.percentSign,
|
||||
symbols.plusSign,
|
||||
symbols.minusSign,
|
||||
symbols.exponential,
|
||||
symbols.superscriptingExponent,
|
||||
symbols.perMille,
|
||||
symbols.infinity,
|
||||
symbols.nan,
|
||||
symbols.timeSeparator,
|
||||
];
|
||||
|
||||
if (symbols.currencyDecimal || symbols.currencyGroup) {
|
||||
symbolValues.push(symbols.currencyDecimal);
|
||||
}
|
||||
|
||||
if (symbols.currencyGroup) {
|
||||
symbolValues.push(symbols.currencyGroup);
|
||||
}
|
||||
|
||||
return [symbolValues, [decimalFormat, percentFormat, currencyFormat, scientificFormat]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns week-end range for a locale, based on US week days
|
||||
* @returns [number, number]
|
||||
*/
|
||||
function getWeekendRange(localeData: CldrStatic) {
|
||||
const startDay =
|
||||
localeData.get(`supplemental/weekData/weekendStart/${localeData.attributes.territory}`) ||
|
||||
localeData.get('supplemental/weekData/weekendStart/001');
|
||||
const endDay =
|
||||
localeData.get(`supplemental/weekData/weekendEnd/${localeData.attributes.territory}`) ||
|
||||
localeData.get('supplemental/weekData/weekendEnd/001');
|
||||
return [WEEK_DAYS.indexOf(startDay), WEEK_DAYS.indexOf(endDay)];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns date-related translations for a locale
|
||||
* @returns [ dayPeriodsFormat, dayPeriodsStandalone, daysFormat, dayStandalone, monthsFormat,
|
||||
* monthsStandalone, eras ]
|
||||
* each value: [ narrow, abbreviated, wide, short? ]
|
||||
*/
|
||||
function getDateTimeTranslations(localeData: CldrStatic) {
|
||||
const dayNames = localeData.main(`dates/calendars/gregorian/days`);
|
||||
const monthNames = localeData.main(`dates/calendars/gregorian/months`);
|
||||
const erasNames = localeData.main(`dates/calendars/gregorian/eras`);
|
||||
const dayPeriods = getDayPeriodsAmPm(localeData);
|
||||
|
||||
const dayPeriodsFormat = removeDuplicates([
|
||||
Object.values(dayPeriods.format.narrow), Object.values(dayPeriods.format.abbreviated),
|
||||
Object.values(dayPeriods.format.wide)
|
||||
]);
|
||||
|
||||
const dayPeriodsStandalone = removeDuplicates([
|
||||
Object.values(dayPeriods['stand-alone'].narrow),
|
||||
Object.values(dayPeriods['stand-alone'].abbreviated),
|
||||
Object.values(dayPeriods['stand-alone'].wide)
|
||||
]);
|
||||
|
||||
const daysFormat = removeDuplicates([
|
||||
Object.values(dayNames.format.narrow), Object.values(dayNames.format.abbreviated),
|
||||
Object.values(dayNames.format.wide), Object.values(dayNames.format.short)
|
||||
]);
|
||||
|
||||
const daysStandalone = removeDuplicates([
|
||||
Object.values(dayNames['stand-alone'].narrow),
|
||||
Object.values(dayNames['stand-alone'].abbreviated), Object.values(dayNames['stand-alone'].wide),
|
||||
Object.values(dayNames['stand-alone'].short)
|
||||
]);
|
||||
|
||||
const monthsFormat = removeDuplicates([
|
||||
Object.values(monthNames.format.narrow), Object.values(monthNames.format.abbreviated),
|
||||
Object.values(monthNames.format.wide)
|
||||
]);
|
||||
|
||||
const monthsStandalone = removeDuplicates([
|
||||
Object.values(monthNames['stand-alone'].narrow),
|
||||
Object.values(monthNames['stand-alone'].abbreviated),
|
||||
Object.values(monthNames['stand-alone'].wide)
|
||||
]);
|
||||
|
||||
const eras = removeDuplicates([
|
||||
[erasNames.eraNarrow['0'], erasNames.eraNarrow['1']],
|
||||
[erasNames.eraAbbr['0'], erasNames.eraAbbr['1']],
|
||||
[erasNames.eraNames['0'], erasNames.eraNames['1']]
|
||||
]);
|
||||
|
||||
const dateTimeTranslations = [
|
||||
...removeDuplicates([dayPeriodsFormat, dayPeriodsStandalone]),
|
||||
...removeDuplicates([daysFormat, daysStandalone]),
|
||||
...removeDuplicates([monthsFormat, monthsStandalone]), eras
|
||||
];
|
||||
|
||||
return dateTimeTranslations;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns date, time and dateTime formats for a locale
|
||||
* @returns [dateFormats, timeFormats, dateTimeFormats]
|
||||
* each format: [ short, medium, long, full ]
|
||||
*/
|
||||
function getDateTimeFormats(localeData: CldrStatic) {
|
||||
function getFormats(data: any) {
|
||||
return removeDuplicates([
|
||||
data.short._value || data.short, data.medium._value || data.medium,
|
||||
data.long._value || data.long, data.full._value || data.full
|
||||
]);
|
||||
}
|
||||
|
||||
const dateFormats = localeData.main('dates/calendars/gregorian/dateFormats');
|
||||
const timeFormats = localeData.main('dates/calendars/gregorian/timeFormats');
|
||||
const dateTimeFormats = localeData.main('dates/calendars/gregorian/dateTimeFormats');
|
||||
|
||||
return [getFormats(dateFormats), getFormats(timeFormats), getFormats(dateTimeFormats)];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the first day of the week, based on US week days
|
||||
* @returns number
|
||||
*/
|
||||
function getFirstDayOfWeek(localeData: CldrStatic) {
|
||||
// The `cldrjs` package does not provide proper types for `supplemental`. The
|
||||
// types are part of the package but embedded incorrectly and not usable.
|
||||
return WEEK_DAYS.indexOf((localeData as any).supplemental.weekData.firstDay());
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CldrStatic} from 'cldrjs';
|
||||
|
||||
import {fileHeader} from './file-header';
|
||||
import {BaseCurrencies} from './locale-base-currencies';
|
||||
import {generateDayPeriodsSupplementalString} from './locale-extra-file';
|
||||
import {generateBasicLocaleString} from './locale-file';
|
||||
import {getPluralFunction} from './plural-function';
|
||||
|
||||
/**
|
||||
* Generated the contents for the global locale file
|
||||
*/
|
||||
export function generateLocaleGlobalFile(
|
||||
locale: string, localeData: CldrStatic, baseCurrencies: BaseCurrencies) {
|
||||
const basicLocaleData = generateBasicLocaleString(locale, localeData, baseCurrencies);
|
||||
const extraLocaleData = generateDayPeriodsSupplementalString(locale, localeData);
|
||||
const data = basicLocaleData.replace(/\]$/, `, ${extraLocaleData}]`);
|
||||
return `${fileHeader}
|
||||
(function(global) {
|
||||
global.ng = global.ng || {};
|
||||
global.ng.common = global.ng.common || {};
|
||||
global.ng.common.locales = global.ng.common.locales || {};
|
||||
const u = undefined;
|
||||
${getPluralFunction(locale, false)}
|
||||
global.ng.common.locales['${normalizeLocale(locale)}'] = ${data};
|
||||
})(typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window);
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* In Angular the locale is referenced by a "normalized" form.
|
||||
*/
|
||||
function normalizeLocale(locale: string): string {
|
||||
return locale.toLowerCase().replace(/_/g, '-');
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
const UNDEFINED_PLACEHOLDER = `ɵɵUNDEFINED_PLACEHOLDER_JSON`;
|
||||
const UNDEFINED_PLACEHOLDER_REGEX = new RegExp(`["']${UNDEFINED_PLACEHOLDER}["']`, 'g');
|
||||
|
||||
/**
|
||||
* Stringifies the given object while preserving `undefined` values which would usually
|
||||
* be transformed into `null` with JSON5. We want to preserve `undefined` because in generated
|
||||
* JavaScript, the `undefined` values are separate from `null`, and `undefined` can be minified
|
||||
* more efficiently. For example in arrays: `[, , someValue]`.
|
||||
*
|
||||
* Note that we do not use `JSON5` or similar formats where properties are not explicitly
|
||||
* wrapped in quotes. Quotes are necessary so that Closure compiler does not accidentally
|
||||
* rename properties. See an example where the currency symbols will be incorrect:
|
||||
* https://closure-compiler.appspot.com/home#code%3D%252F%252F%2520%253D%253DClosureCompiler%253D%253D%250A%252F%252F%2520%2540output_file_name%2520default.js%250A%252F%252F%2520%2540compilation_level%2520ADVANCED_OPTIMIZATIONS%250A%252F%252F%2520%253D%253D%252FClosureCompiler%253D%253D%250A%250Aconst%2520base_currencies%2520%253D%2520%257B%250A%2520%2520ABC%253A%2520'd'%252C%250A%2509USD%253A%2520'x'%252C%250A%257D%253B%250A%250Aconst%2520current_locale_currencies%2520%253D%2520%257B%257D%250A%250Afunction%2520getCurrencySymbol(l)%2520%257B%250A%2520%2520return%2520current_locale_currencies%255Bl%255D%2520%257C%257C%2520base_currencies%255Bl%255D%2520%257C%257C%2520l%250A%257D%250A%250Aconsole.log(getCurrencySymbol('de'))%253B
|
||||
*/
|
||||
export function stringify(value: any) {
|
||||
const result =
|
||||
JSON.stringify(value, ((_, value) => value === undefined ? UNDEFINED_PLACEHOLDER : value));
|
||||
|
||||
UNDEFINED_PLACEHOLDER_REGEX.lastIndex = 0;
|
||||
|
||||
return result.replace(UNDEFINED_PLACEHOLDER_REGEX, 'undefined');
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// There are no types available for `cldr`.
|
||||
const cldr = require('cldr');
|
||||
|
||||
/**
|
||||
* Returns the plural function for a locale
|
||||
* TODO(ocombe): replace "cldr" extractPluralRuleFunction with our own extraction using "CldrJS"
|
||||
* because the 2 libs can become out of sync if they use different versions of the cldr database
|
||||
*/
|
||||
export function getPluralFunction(locale: string, withTypes = true) {
|
||||
let fn = cldr.extractPluralRuleFunction(locale).toString();
|
||||
|
||||
const numberType = withTypes ? ': number' : '';
|
||||
fn =
|
||||
fn.replace(/function anonymous\(n[^}]+{/g, `function plural(n${numberType})${numberType} {`)
|
||||
// Since our generated plural functions only take numbers, we can eliminate some of
|
||||
// the logic generated by the `cldr` package (to reduce payload size).
|
||||
.replace(/var/g, /let/)
|
||||
.replace(/if\s+\(typeof\s+n\s+===\s+["']string["']\)\s+n\s+=\s+parseInt\(n,\s+10\);/, '');
|
||||
|
||||
// The replacement values must match the `Plural` enum from common.
|
||||
// We do not use the enum directly to avoid depending on that package.
|
||||
return fn.replace(/["']zero["']/, '0')
|
||||
.replace(/["']one["']/, '1')
|
||||
.replace(/["']two["']/, '2')
|
||||
.replace(/["']few["']/, '3')
|
||||
.replace(/["']many["']/, '4')
|
||||
.replace(/["']other["']/, '5');
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
module.exports = {
|
||||
extract: gulp => done => {
|
||||
if (!fs.existsSync(path.join(__dirname, 'cldr/cldr-data'))) {
|
||||
throw new Error(`You must run "gulp cldr:download" before you can extract the data`);
|
||||
}
|
||||
const extract = require('./cldr/extract');
|
||||
return extract(gulp, done);
|
||||
},
|
||||
|
||||
download: gulp => done => {
|
||||
const cldrDownloader = require('cldr-data-downloader');
|
||||
const cldrDataFolder = path.join(__dirname, 'cldr/cldr-data');
|
||||
if (fs.existsSync(cldrDataFolder)) {
|
||||
fs.rmdirSync(cldrDataFolder, {recursive: true});
|
||||
} else {
|
||||
fs.mkdirSync(cldrDataFolder);
|
||||
}
|
||||
cldrDownloader(path.join(__dirname, 'cldr/cldr-urls.json'), cldrDataFolder, {}, done);
|
||||
},
|
||||
|
||||
closure: gulp => done => {
|
||||
const {RELATIVE_I18N_DATA_FOLDER} = require('./cldr/extract');
|
||||
// tslint:disable-next-line:no-console
|
||||
console.log(RELATIVE_I18N_DATA_FOLDER, fs.existsSync(RELATIVE_I18N_DATA_FOLDER));
|
||||
if (!fs.existsSync(RELATIVE_I18N_DATA_FOLDER)) {
|
||||
throw new Error(
|
||||
`You must run "gulp cldr:extract" before you can create the closure-locale.ts file`);
|
||||
}
|
||||
const localeAll = require('./cldr/closure');
|
||||
return localeAll(gulp, done);
|
||||
},
|
||||
};
|
|
@ -0,0 +1,86 @@
|
|||
// tslint:disable:file-header
|
||||
|
||||
/**
|
||||
* Npm module for Unicode CLDR JSON data
|
||||
*
|
||||
* @license
|
||||
* Copyright 2013 Rafael Xavier de Souza
|
||||
* Released under the MIT license
|
||||
* https://github.com/rxaviers/cldr-data-npm/blob/master/LICENSE-MIT
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const JSON_EXTENSION = /^(.*)\.json$/;
|
||||
|
||||
const assert = require('assert');
|
||||
const _fs = require('fs');
|
||||
const _path = require('path');
|
||||
|
||||
function argsToArray(arg) {
|
||||
return [].slice.call(arg, 0);
|
||||
}
|
||||
|
||||
function jsonFiles(dirName) {
|
||||
const fileList = _fs.readdirSync(_path.join(__dirname, 'cldr-data', dirName));
|
||||
|
||||
return fileList.reduce(function(sum, file) {
|
||||
if (JSON_EXTENSION.test(file)) {
|
||||
return sum.concat(file.match(JSON_EXTENSION)[1]);
|
||||
}
|
||||
}, []);
|
||||
}
|
||||
|
||||
function cldrData(path /*, ...*/) {
|
||||
assert(
|
||||
typeof path === 'string',
|
||||
'must include path (e.g., "main/en/numbers" or "supplemental/likelySubtags")');
|
||||
|
||||
if (arguments.length > 1) {
|
||||
return argsToArray(arguments).reduce(function(sum, path) {
|
||||
sum.push(cldrData(path));
|
||||
return sum;
|
||||
}, []);
|
||||
}
|
||||
return require('./cldr-data/' + path);
|
||||
}
|
||||
|
||||
function mainPathsFor(locales) {
|
||||
return locales.reduce(function(sum, locale) {
|
||||
const mainFiles = jsonFiles(_path.join('main', locale));
|
||||
mainFiles.forEach(function(mainFile) {
|
||||
sum.push(_path.join('main', locale, mainFile));
|
||||
});
|
||||
return sum;
|
||||
}, []);
|
||||
}
|
||||
|
||||
function supplementalPaths() {
|
||||
const supplementalFiles = jsonFiles('supplemental');
|
||||
|
||||
return supplementalFiles.map(function(supplementalFile) {
|
||||
return _path.join('supplemental', supplementalFile);
|
||||
});
|
||||
}
|
||||
|
||||
Object.defineProperty(cldrData, 'availableLocales', {
|
||||
get: function() {
|
||||
return cldrData('availableLocales').availableLocales;
|
||||
}
|
||||
});
|
||||
|
||||
cldrData.all = function() {
|
||||
const paths = supplementalPaths().concat(mainPathsFor(this.availableLocales));
|
||||
return cldrData.apply({}, paths);
|
||||
};
|
||||
|
||||
cldrData.entireMainFor = function(locale /*, ...*/) {
|
||||
assert(typeof locale === 'string', 'must include locale (e.g., "en")');
|
||||
return cldrData.apply({}, mainPathsFor(argsToArray(arguments)));
|
||||
};
|
||||
|
||||
cldrData.entireSupplemental = function() {
|
||||
return cldrData.apply({}, supplementalPaths());
|
||||
};
|
||||
|
||||
module.exports = cldrData;
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"core": [
|
||||
"https://github.com/unicode-cldr/cldr-core/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-segments-modern/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-dates-full/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-cal-buddhist-full/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-cal-chinese-full/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-cal-coptic-full/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-cal-dangi-full/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-cal-ethiopic-full/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-cal-hebrew-full/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-cal-indian-full/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-cal-islamic-full/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-cal-japanese-full/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-cal-persian-full/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-cal-roc-full/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-localenames-full/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-misc-full/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-numbers-full/archive/37.0.0.zip",
|
||||
"https://github.com/unicode-cldr/cldr-units-full/archive/37.0.0.zip"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const yargs = require('yargs').argv;
|
||||
const shelljs = require('shelljs');
|
||||
const {I18N_DATA_FOLDER, RELATIVE_I18N_DATA_FOLDER, HEADER} = require('./extract');
|
||||
const OUTPUT_NAME = `closure-locale.ts`;
|
||||
|
||||
// tslint:disable:no-console
|
||||
module.exports = (gulp, done) => {
|
||||
// the locales used by closure that will be used to generate the closure-locale file
|
||||
// extracted from:
|
||||
// https://github.com/google/closure-library/blob/master/closure/goog/i18n/datetimepatterns.js#L2136
|
||||
let GOOG_LOCALES = [
|
||||
'af', 'am', 'ar', 'ar-DZ', 'az', 'be', 'bg', 'bn', 'br', 'bs',
|
||||
'ca', 'chr', 'cs', 'cy', 'da', 'de', 'de-AT', 'de-CH', 'el', 'en-AU',
|
||||
'en-CA', 'en-GB', 'en-IE', 'en-IN', 'en-SG', 'en-ZA', 'es', 'es-419', 'es-MX', 'es-US',
|
||||
'et', 'eu', 'fa', 'fi', 'fr', 'fr-CA', 'ga', 'gl', 'gsw', 'gu',
|
||||
'haw', 'hi', 'hr', 'hu', 'hy', 'in', 'is', 'it', 'iw', 'ja',
|
||||
'ka', 'kk', 'km', 'kn', 'ko', 'ky', 'ln', 'lo', 'lt', 'lv',
|
||||
'mk', 'ml', 'mn', 'mo', 'mr', 'ms', 'mt', 'my', 'ne', 'nl',
|
||||
'no', 'or', 'pa', 'pl', 'pt', 'pt-PT', 'ro', 'ru', 'sh', 'si',
|
||||
'sk', 'sl', 'sq', 'sr', 'sv', 'sw', 'ta', 'te', 'th', 'tl',
|
||||
'tr', 'uk', 'ur', 'uz', 'vi', 'zh', 'zh-CN', 'zh-HK', 'zh-TW', 'zu'
|
||||
];
|
||||
|
||||
// locale id aliases to support deprecated locale ids used by closure
|
||||
// it maps deprecated ids --> new ids
|
||||
// manually extracted from ./cldr-data/supplemental/aliases.json
|
||||
const ALIASES = {
|
||||
'in': 'id',
|
||||
'iw': 'he',
|
||||
'mo': 'ro-MD',
|
||||
'no': 'nb',
|
||||
'nb': 'no-NO',
|
||||
'sh': 'sr-Latn',
|
||||
'tl': 'fil',
|
||||
'pt': 'pt-BR',
|
||||
'zh-CN': 'zh-Hans-CN',
|
||||
'zh-Hans-CN': 'zh-Hans',
|
||||
'zh-HK': 'zh-Hant-HK',
|
||||
'zh-TW': 'zh-Hant-TW',
|
||||
'zh-Hant-TW': 'zh-Hant',
|
||||
};
|
||||
|
||||
if (yargs.locales) {
|
||||
GOOG_LOCALES = yargs.locales.split(',');
|
||||
}
|
||||
|
||||
console.log(`Writing file ${I18N_DATA_FOLDER}/${OUTPUT_NAME}`);
|
||||
fs.writeFileSync(
|
||||
`${RELATIVE_I18N_DATA_FOLDER}/${OUTPUT_NAME}`, generateAllLocalesFile(GOOG_LOCALES, ALIASES));
|
||||
|
||||
console.log(`Formatting ${I18N_DATA_FOLDER}/${OUTPUT_NAME}..."`);
|
||||
shelljs.exec(`yarn clang-format -i ${I18N_DATA_FOLDER}/${OUTPUT_NAME}`, {silent: true});
|
||||
done();
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate a file that contains all locale to import for closure.
|
||||
* Tree shaking will only keep the data for the `goog.LOCALE` locale.
|
||||
*/
|
||||
function generateAllLocalesFile(LOCALES, ALIASES) {
|
||||
const existingLocalesAliases = {};
|
||||
const existingLocalesData = {};
|
||||
|
||||
// for each locale, get the data and the list of equivalent locales
|
||||
LOCALES.forEach(locale => {
|
||||
const eqLocales = new Set();
|
||||
eqLocales.add(locale);
|
||||
if (locale.match(/-/)) {
|
||||
eqLocales.add(locale.replace(/-/g, '_'));
|
||||
}
|
||||
|
||||
// check for aliases
|
||||
const alias = ALIASES[locale];
|
||||
if (alias) {
|
||||
eqLocales.add(alias);
|
||||
|
||||
if (alias.match(/-/)) {
|
||||
eqLocales.add(alias.replace(/-/g, '_'));
|
||||
}
|
||||
|
||||
// to avoid duplicated "case" we regroup all locales in the same "case"
|
||||
// the simplest way to do that is to have alias aliases
|
||||
// e.g. 'no' --> 'nb', 'nb' --> 'no-NO'
|
||||
// which means that we'll have 'no', 'nb' and 'no-NO' in the same "case"
|
||||
const aliasKeys = Object.keys(ALIASES);
|
||||
for (let i = 0; i < aliasKeys.length; i++) {
|
||||
const aliasValue = ALIASES[alias];
|
||||
if (aliasKeys.indexOf(alias) !== -1 && !eqLocales.has(aliasValue)) {
|
||||
eqLocales.add(aliasValue);
|
||||
|
||||
if (aliasValue.match(/-/)) {
|
||||
eqLocales.add(aliasValue.replace(/-/g, '_'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let l of eqLocales) {
|
||||
// find the existing content file
|
||||
const path = `${RELATIVE_I18N_DATA_FOLDER}/${l}.ts`;
|
||||
if (fs.existsSync(`${RELATIVE_I18N_DATA_FOLDER}/${l}.ts`)) {
|
||||
const localeName = formatLocale(locale);
|
||||
existingLocalesData[locale] =
|
||||
fs.readFileSync(path, 'utf8')
|
||||
.replace(`${HEADER}\n`, '')
|
||||
.replace('export default ', `export const locale_${localeName} = `)
|
||||
.replace('function plural', `function plural_${localeName}`)
|
||||
.replace(/,(\n | )plural/, `, plural_${localeName}`)
|
||||
.replace('const u = undefined;\n\n', '');
|
||||
}
|
||||
}
|
||||
|
||||
existingLocalesAliases[locale] = eqLocales;
|
||||
});
|
||||
|
||||
function generateCases(locale) {
|
||||
let str = '';
|
||||
let locales = [];
|
||||
const eqLocales = existingLocalesAliases[locale];
|
||||
for (let l of eqLocales) {
|
||||
str += `case '${l}':\n`;
|
||||
locales.push(`'${l}'`);
|
||||
}
|
||||
let localesStr = '[' + locales.join(',') + ']';
|
||||
|
||||
str += ` l = locale_${formatLocale(locale)};
|
||||
locales = ${localesStr};
|
||||
break;\n`;
|
||||
return str;
|
||||
}
|
||||
|
||||
function formatLocale(locale) {
|
||||
return locale.replace(/-/g, '_');
|
||||
}
|
||||
// clang-format off
|
||||
return `${HEADER}
|
||||
import {registerLocaleData} from '../src/i18n/locale_data';
|
||||
|
||||
const u = undefined;
|
||||
|
||||
${LOCALES.map(locale => `${existingLocalesData[locale]}`).join('\n')}
|
||||
|
||||
let l: any;
|
||||
let locales: string[] = [];
|
||||
|
||||
switch (goog.LOCALE) {
|
||||
${LOCALES.map(locale => generateCases(locale)).join('')}}
|
||||
|
||||
if(l) {
|
||||
locales.forEach(locale => registerLocaleData(l, locale));
|
||||
}
|
||||
`;
|
||||
// clang-format on
|
||||
}
|
|
@ -0,0 +1,632 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const stringify = require('./util').stringify;
|
||||
// used to extract plural rules
|
||||
const cldr = require('cldr');
|
||||
// used to extract all other cldr data
|
||||
const cldrJs = require('cldrjs');
|
||||
// used to call to clang-format
|
||||
const shelljs = require('shelljs');
|
||||
|
||||
const COMMON_PACKAGE = 'packages/common';
|
||||
const CORE_PACKAGE = 'packages/core';
|
||||
const I18N_FOLDER = `${COMMON_PACKAGE}/src/i18n`;
|
||||
const I18N_CORE_FOLDER = `${CORE_PACKAGE}/src/i18n`;
|
||||
const I18N_DATA_FOLDER = `${COMMON_PACKAGE}/locales`;
|
||||
const I18N_DATA_EXTRA_FOLDER = `${I18N_DATA_FOLDER}/extra`;
|
||||
const I18N_GLOBAL_FOLDER = `${I18N_DATA_FOLDER}/global`;
|
||||
const RELATIVE_I18N_FOLDER = path.resolve(__dirname, `../../../${I18N_FOLDER}`);
|
||||
const RELATIVE_I18N_CORE_FOLDER = path.resolve(__dirname, `../../../${I18N_CORE_FOLDER}`);
|
||||
const RELATIVE_I18N_DATA_FOLDER = path.resolve(__dirname, `../../../${I18N_DATA_FOLDER}`);
|
||||
const RELATIVE_I18N_DATA_EXTRA_FOLDER =
|
||||
path.resolve(__dirname, `../../../${I18N_DATA_EXTRA_FOLDER}`);
|
||||
const RELATIVE_I18N_GLOBAL_FOLDER = path.resolve(__dirname, `../../../${I18N_GLOBAL_FOLDER}`);
|
||||
const DEFAULT_RULE = 'function anonymous(n) {\nreturn"other"\n}';
|
||||
const EMPTY_RULE = 'function anonymous(n) {\n\n}';
|
||||
const WEEK_DAYS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
|
||||
const HEADER = `/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// THIS CODE IS GENERATED - DO NOT MODIFY
|
||||
// See angular/tools/gulp-tasks/cldr/extract.js
|
||||
`;
|
||||
|
||||
// tslint:disable:no-console
|
||||
module.exports = (gulp, done) => {
|
||||
const cldrData = require('./cldr-data');
|
||||
const LOCALES = cldrData.availableLocales;
|
||||
|
||||
console.log(`Loading CLDR data...`);
|
||||
cldrJs.load(cldrData.all().concat(cldrData('scriptMetadata')));
|
||||
|
||||
console.log(`Writing locale files`);
|
||||
if (!fs.existsSync(RELATIVE_I18N_FOLDER)) {
|
||||
fs.mkdirSync(RELATIVE_I18N_FOLDER);
|
||||
}
|
||||
if (!fs.existsSync(RELATIVE_I18N_DATA_FOLDER)) {
|
||||
fs.mkdirSync(RELATIVE_I18N_DATA_FOLDER);
|
||||
}
|
||||
if (!fs.existsSync(RELATIVE_I18N_DATA_EXTRA_FOLDER)) {
|
||||
fs.mkdirSync(RELATIVE_I18N_DATA_EXTRA_FOLDER);
|
||||
}
|
||||
if (!fs.existsSync(RELATIVE_I18N_GLOBAL_FOLDER)) {
|
||||
fs.mkdirSync(RELATIVE_I18N_GLOBAL_FOLDER);
|
||||
}
|
||||
|
||||
console.log(`Writing file ${I18N_FOLDER}/currencies.ts`);
|
||||
fs.writeFileSync(`${RELATIVE_I18N_FOLDER}/currencies.ts`, generateCurrenciesFile());
|
||||
|
||||
const baseCurrencies = generateBaseCurrencies(new cldrJs('en'));
|
||||
// additional "en" file that will be included in common
|
||||
console.log(`Writing file ${I18N_CORE_FOLDER}/locale_en.ts`);
|
||||
const localeEnFile = generateLocale('en', new cldrJs('en'), baseCurrencies);
|
||||
fs.writeFileSync(`${RELATIVE_I18N_CORE_FOLDER}/locale_en.ts`, localeEnFile);
|
||||
|
||||
LOCALES.forEach((locale, index) => {
|
||||
const localeData = new cldrJs(locale);
|
||||
|
||||
console.log(`${index + 1}/${LOCALES.length}`);
|
||||
console.log(`\t${I18N_DATA_FOLDER}/${locale}.ts`);
|
||||
fs.writeFileSync(
|
||||
`${RELATIVE_I18N_DATA_FOLDER}/${locale}.ts`,
|
||||
locale === 'en' ? localeEnFile : generateLocale(locale, localeData, baseCurrencies));
|
||||
console.log(`\t${I18N_DATA_EXTRA_FOLDER}/${locale}.ts`);
|
||||
fs.writeFileSync(
|
||||
`${RELATIVE_I18N_DATA_EXTRA_FOLDER}/${locale}.ts`, generateLocaleExtra(locale, localeData));
|
||||
console.log(`\t${I18N_GLOBAL_FOLDER}/${locale}.js`);
|
||||
fs.writeFileSync(
|
||||
`${RELATIVE_I18N_GLOBAL_FOLDER}/${locale}.js`,
|
||||
generateGlobalLocale(
|
||||
locale, locale === 'en' ? new cldrJs('en') : localeData, baseCurrencies));
|
||||
});
|
||||
console.log(`${LOCALES.length} locale files generated.`);
|
||||
|
||||
console.log(`All i18n cldr files have been generated, formatting files..."`);
|
||||
shelljs.exec(
|
||||
`yarn clang-format -i ${I18N_DATA_FOLDER}/**/*.ts ${I18N_DATA_FOLDER}/*.ts ${
|
||||
I18N_FOLDER}/currencies.ts ${I18N_CORE_FOLDER}/locale_en.ts ${I18N_GLOBAL_FOLDER}/*.js`,
|
||||
{silent: true});
|
||||
done();
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate contents for the basic locale data file
|
||||
*/
|
||||
function generateLocale(locale, localeData, baseCurrencies) {
|
||||
return `${HEADER}
|
||||
const u = undefined;
|
||||
|
||||
${getPluralFunction(locale)}
|
||||
|
||||
export default ${generateBasicLocaleString(locale, localeData, baseCurrencies)};
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the contents for the extra data file
|
||||
*/
|
||||
function generateLocaleExtra(locale, localeData) {
|
||||
return `${HEADER}
|
||||
const u = undefined;
|
||||
|
||||
export default ${generateDayPeriodsSupplementalString(locale, localeData)};
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated the contents for the global locale file
|
||||
*/
|
||||
function generateGlobalLocale(locale, localeData, baseCurrencies) {
|
||||
const basicLocaleData = generateBasicLocaleString(locale, localeData, baseCurrencies);
|
||||
const extraLocaleData = generateDayPeriodsSupplementalString(locale, localeData);
|
||||
const data = basicLocaleData.replace(/\]$/, `, ${extraLocaleData}]`);
|
||||
return `${HEADER}
|
||||
(function(global) {
|
||||
global.ng = global.ng || {};
|
||||
global.ng.common = global.ng.common || {};
|
||||
global.ng.common.locales = global.ng.common.locales || {};
|
||||
const u = undefined;
|
||||
${getPluralFunction(locale, false)}
|
||||
global.ng.common.locales['${normalizeLocale(locale)}'] = ${data};
|
||||
})(typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window);
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect up the basic locale data [ localeId, dateTime, number, currency, pluralCase ].
|
||||
*/
|
||||
function generateBasicLocaleString(locale, localeData, baseCurrencies) {
|
||||
let data = stringify(
|
||||
[
|
||||
locale,
|
||||
...getDateTimeTranslations(localeData),
|
||||
...getDateTimeSettings(localeData),
|
||||
...getNumberSettings(localeData),
|
||||
...getCurrencySettings(locale, localeData),
|
||||
generateLocaleCurrencies(localeData, baseCurrencies),
|
||||
getDirectionality(localeData),
|
||||
],
|
||||
true)
|
||||
// We remove "undefined" added by spreading arrays when there is no value
|
||||
.replace(/undefined/g, 'u');
|
||||
|
||||
// adding plural function after, because we don't want it as a string
|
||||
data = data.replace(/\]$/, ', plural]');
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect up the day period rules, and extended day period data.
|
||||
*/
|
||||
function generateDayPeriodsSupplementalString(locale, localeData) {
|
||||
const dayPeriods = getDayPeriodsNoAmPm(localeData);
|
||||
const dayPeriodRules = getDayPeriodRules(localeData);
|
||||
|
||||
let dayPeriodsSupplemental = [];
|
||||
if (Object.keys(dayPeriods.format.narrow).length) {
|
||||
const keys = Object.keys(dayPeriods.format.narrow);
|
||||
|
||||
if (keys.length !== Object.keys(dayPeriodRules).length) {
|
||||
throw new Error(`Error: locale ${locale} has not the correct number of day period rules`);
|
||||
}
|
||||
|
||||
const dayPeriodsFormat = removeDuplicates([
|
||||
objectValues(dayPeriods.format.narrow), objectValues(dayPeriods.format.abbreviated),
|
||||
objectValues(dayPeriods.format.wide)
|
||||
]);
|
||||
|
||||
const dayPeriodsStandalone = removeDuplicates([
|
||||
objectValues(dayPeriods['stand-alone'].narrow),
|
||||
objectValues(dayPeriods['stand-alone'].abbreviated),
|
||||
objectValues(dayPeriods['stand-alone'].wide)
|
||||
]);
|
||||
|
||||
const rules = keys.map(key => dayPeriodRules[key]);
|
||||
dayPeriodsSupplemental = [...removeDuplicates([dayPeriodsFormat, dayPeriodsStandalone]), rules];
|
||||
}
|
||||
return stringify(dayPeriodsSupplemental).replace(/undefined/g, 'u');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a list of currencies to be used as a based for other currencies
|
||||
* e.g.: {'ARS': [, '$'], 'AUD': ['A$', '$'], ...}
|
||||
*/
|
||||
function generateBaseCurrencies(localeData, addDigits) {
|
||||
const currenciesData = localeData.main('numbers/currencies');
|
||||
const fractions = new cldrJs('en').get(`supplemental/currencyData/fractions`);
|
||||
const currencies = {};
|
||||
Object.keys(currenciesData).forEach(key => {
|
||||
let symbolsArray = [];
|
||||
const symbol = currenciesData[key].symbol;
|
||||
const symbolNarrow = currenciesData[key]['symbol-alt-narrow'];
|
||||
if (symbol && symbol !== key) {
|
||||
symbolsArray.push(symbol);
|
||||
}
|
||||
if (symbolNarrow && symbolNarrow !== symbol) {
|
||||
if (symbolsArray.length > 0) {
|
||||
symbolsArray.push(symbolNarrow);
|
||||
} else {
|
||||
symbolsArray = [undefined, symbolNarrow];
|
||||
}
|
||||
}
|
||||
if (addDigits && fractions[key] && fractions[key]['_digits']) {
|
||||
const digits = parseInt(fractions[key]['_digits'], 10);
|
||||
if (symbolsArray.length === 2) {
|
||||
symbolsArray.push(digits);
|
||||
} else if (symbolsArray.length === 1) {
|
||||
symbolsArray = [...symbolsArray, undefined, digits];
|
||||
} else {
|
||||
symbolsArray = [undefined, undefined, digits];
|
||||
}
|
||||
}
|
||||
if (symbolsArray.length > 0) {
|
||||
currencies[key] = symbolsArray;
|
||||
}
|
||||
});
|
||||
return currencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* To minimize the file even more, we only output the differences compared to the base currency
|
||||
*/
|
||||
function generateLocaleCurrencies(localeData, baseCurrencies) {
|
||||
const currenciesData = localeData.main('numbers/currencies');
|
||||
const currencies = {};
|
||||
Object.keys(currenciesData).forEach(code => {
|
||||
let symbolsArray = [];
|
||||
const symbol = currenciesData[code].symbol;
|
||||
const symbolNarrow = currenciesData[code]['symbol-alt-narrow'];
|
||||
if (symbol && symbol !== code) {
|
||||
symbolsArray.push(symbol);
|
||||
}
|
||||
if (symbolNarrow && symbolNarrow !== symbol) {
|
||||
if (symbolsArray.length > 0) {
|
||||
symbolsArray.push(symbolNarrow);
|
||||
} else {
|
||||
symbolsArray = [undefined, symbolNarrow];
|
||||
}
|
||||
}
|
||||
|
||||
// if locale data are different, set the value
|
||||
if ((baseCurrencies[code] || []).toString() !== symbolsArray.toString()) {
|
||||
currencies[code] = symbolsArray;
|
||||
}
|
||||
});
|
||||
return currencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a file that contains the list of currencies and their symbols
|
||||
*/
|
||||
function generateCurrenciesFile() {
|
||||
const baseCurrencies = generateBaseCurrencies(new cldrJs('en'), true);
|
||||
|
||||
return `${HEADER}
|
||||
export type CurrenciesSymbols = [string] | [string | undefined, string];
|
||||
|
||||
/** @internal */
|
||||
export const CURRENCIES_EN: {[code: string]: CurrenciesSymbols | [string | undefined, string | undefined, number]} = ${
|
||||
stringify(baseCurrencies, true)};
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns data for the chosen day periods
|
||||
* @returns {
|
||||
* format: {narrow / abbreviated / wide: [...]},
|
||||
* stand-alone: {narrow / abbreviated / wide: [...]}
|
||||
* }
|
||||
*/
|
||||
function getDayPeriods(localeData, dayPeriodsList) {
|
||||
const dayPeriods = localeData.main(`dates/calendars/gregorian/dayPeriods`);
|
||||
const result = {};
|
||||
// cleaning up unused keys
|
||||
Object.keys(dayPeriods).forEach(key1 => { // format / stand-alone
|
||||
result[key1] = {};
|
||||
Object.keys(dayPeriods[key1]).forEach(key2 => { // narrow / abbreviated / wide
|
||||
result[key1][key2] = {};
|
||||
Object.keys(dayPeriods[key1][key2]).forEach(key3 => {
|
||||
if (dayPeriodsList.indexOf(key3) !== -1) {
|
||||
result[key1][key2][key3] = dayPeriods[key1][key2][key3];
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the basic day periods (am/pm)
|
||||
*/
|
||||
function getDayPeriodsAmPm(localeData) {
|
||||
return getDayPeriods(localeData, ['am', 'pm']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extra day periods (without am/pm)
|
||||
*/
|
||||
function getDayPeriodsNoAmPm(localeData) {
|
||||
return getDayPeriods(localeData, [
|
||||
'noon', 'midnight', 'morning1', 'morning2', 'afternoon1', 'afternoon2', 'evening1', 'evening2',
|
||||
'night1', 'night2'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns date-related translations for a locale
|
||||
* @returns [ dayPeriodsFormat, dayPeriodsStandalone, daysFormat, dayStandalone, monthsFormat,
|
||||
* monthsStandalone, eras ]
|
||||
* each value: [ narrow, abbreviated, wide, short? ]
|
||||
*/
|
||||
function getDateTimeTranslations(localeData) {
|
||||
const dayNames = localeData.main(`dates/calendars/gregorian/days`);
|
||||
const monthNames = localeData.main(`dates/calendars/gregorian/months`);
|
||||
const erasNames = localeData.main(`dates/calendars/gregorian/eras`);
|
||||
const dayPeriods = getDayPeriodsAmPm(localeData);
|
||||
|
||||
const dayPeriodsFormat = removeDuplicates([
|
||||
objectValues(dayPeriods.format.narrow), objectValues(dayPeriods.format.abbreviated),
|
||||
objectValues(dayPeriods.format.wide)
|
||||
]);
|
||||
|
||||
const dayPeriodsStandalone = removeDuplicates([
|
||||
objectValues(dayPeriods['stand-alone'].narrow),
|
||||
objectValues(dayPeriods['stand-alone'].abbreviated),
|
||||
objectValues(dayPeriods['stand-alone'].wide)
|
||||
]);
|
||||
|
||||
const daysFormat = removeDuplicates([
|
||||
objectValues(dayNames.format.narrow), objectValues(dayNames.format.abbreviated),
|
||||
objectValues(dayNames.format.wide), objectValues(dayNames.format.short)
|
||||
]);
|
||||
|
||||
const daysStandalone = removeDuplicates([
|
||||
objectValues(dayNames['stand-alone'].narrow), objectValues(dayNames['stand-alone'].abbreviated),
|
||||
objectValues(dayNames['stand-alone'].wide), objectValues(dayNames['stand-alone'].short)
|
||||
]);
|
||||
|
||||
const monthsFormat = removeDuplicates([
|
||||
objectValues(monthNames.format.narrow), objectValues(monthNames.format.abbreviated),
|
||||
objectValues(monthNames.format.wide)
|
||||
]);
|
||||
|
||||
const monthsStandalone = removeDuplicates([
|
||||
objectValues(monthNames['stand-alone'].narrow),
|
||||
objectValues(monthNames['stand-alone'].abbreviated),
|
||||
objectValues(monthNames['stand-alone'].wide)
|
||||
]);
|
||||
|
||||
const eras = removeDuplicates([
|
||||
[erasNames.eraNarrow['0'], erasNames.eraNarrow['1']],
|
||||
[erasNames.eraAbbr['0'], erasNames.eraAbbr['1']],
|
||||
[erasNames.eraNames['0'], erasNames.eraNames['1']]
|
||||
]);
|
||||
|
||||
const dateTimeTranslations = [
|
||||
...removeDuplicates([dayPeriodsFormat, dayPeriodsStandalone]),
|
||||
...removeDuplicates([daysFormat, daysStandalone]),
|
||||
...removeDuplicates([monthsFormat, monthsStandalone]), eras
|
||||
];
|
||||
|
||||
return dateTimeTranslations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns date, time and dateTime formats for a locale
|
||||
* @returns [dateFormats, timeFormats, dateTimeFormats]
|
||||
* each format: [ short, medium, long, full ]
|
||||
*/
|
||||
function getDateTimeFormats(localeData) {
|
||||
function getFormats(data) {
|
||||
return removeDuplicates([
|
||||
data.short._value || data.short, data.medium._value || data.medium,
|
||||
data.long._value || data.long, data.full._value || data.full
|
||||
]);
|
||||
}
|
||||
|
||||
const dateFormats = localeData.main('dates/calendars/gregorian/dateFormats');
|
||||
const timeFormats = localeData.main('dates/calendars/gregorian/timeFormats');
|
||||
const dateTimeFormats = localeData.main('dates/calendars/gregorian/dateTimeFormats');
|
||||
|
||||
return [getFormats(dateFormats), getFormats(timeFormats), getFormats(dateTimeFormats)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns day period rules for a locale
|
||||
* @returns string[]
|
||||
*/
|
||||
function getDayPeriodRules(localeData) {
|
||||
const dayPeriodRules =
|
||||
localeData.get(`supplemental/dayPeriodRuleSet/${localeData.attributes.language}`);
|
||||
const rules = {};
|
||||
if (dayPeriodRules) {
|
||||
Object.keys(dayPeriodRules).forEach(key => {
|
||||
if (dayPeriodRules[key]._at) {
|
||||
rules[key] = dayPeriodRules[key]._at;
|
||||
} else {
|
||||
rules[key] = [dayPeriodRules[key]._from, dayPeriodRules[key]._before];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first day of the week, based on US week days
|
||||
* @returns number
|
||||
*/
|
||||
function getFirstDayOfWeek(localeData) {
|
||||
return WEEK_DAYS.indexOf(localeData.supplemental.weekData.firstDay());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns week-end range for a locale, based on US week days
|
||||
* @returns [number, number]
|
||||
*/
|
||||
function getWeekendRange(localeData) {
|
||||
const startDay =
|
||||
localeData.get(`supplemental/weekData/weekendStart/${localeData.attributes.territory}`) ||
|
||||
localeData.get('supplemental/weekData/weekendStart/001');
|
||||
const endDay =
|
||||
localeData.get(`supplemental/weekData/weekendEnd/${localeData.attributes.territory}`) ||
|
||||
localeData.get('supplemental/weekData/weekendEnd/001');
|
||||
return [WEEK_DAYS.indexOf(startDay), WEEK_DAYS.indexOf(endDay)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns dateTime data for a locale
|
||||
* @returns [ firstDayOfWeek, weekendRange, formats ]
|
||||
*/
|
||||
function getDateTimeSettings(localeData) {
|
||||
return [
|
||||
getFirstDayOfWeek(localeData), getWeekendRange(localeData), ...getDateTimeFormats(localeData)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number symbols and formats for a locale
|
||||
* @returns [ symbols, formats ]
|
||||
* symbols: [ decimal, group, list, percentSign, plusSign, minusSign, exponential,
|
||||
* superscriptingExponent, perMille, infinity, nan, timeSeparator, currencyDecimal?, currencyGroup?
|
||||
* ]
|
||||
* formats: [ currency, decimal, percent, scientific ]
|
||||
*/
|
||||
function getNumberSettings(localeData) {
|
||||
const decimalFormat = localeData.main('numbers/decimalFormats-numberSystem-latn/standard');
|
||||
const percentFormat = localeData.main('numbers/percentFormats-numberSystem-latn/standard');
|
||||
const scientificFormat = localeData.main('numbers/scientificFormats-numberSystem-latn/standard');
|
||||
const currencyFormat = localeData.main('numbers/currencyFormats-numberSystem-latn/standard');
|
||||
const symbols = localeData.main('numbers/symbols-numberSystem-latn');
|
||||
const symbolValues = [
|
||||
symbols.decimal,
|
||||
symbols.group,
|
||||
symbols.list,
|
||||
symbols.percentSign,
|
||||
symbols.plusSign,
|
||||
symbols.minusSign,
|
||||
symbols.exponential,
|
||||
symbols.superscriptingExponent,
|
||||
symbols.perMille,
|
||||
symbols.infinity,
|
||||
symbols.nan,
|
||||
symbols.timeSeparator,
|
||||
];
|
||||
|
||||
if (symbols.currencyDecimal || symbols.currencyGroup) {
|
||||
symbolValues.push(symbols.currencyDecimal);
|
||||
}
|
||||
|
||||
if (symbols.currencyGroup) {
|
||||
symbolValues.push(symbols.currencyGroup);
|
||||
}
|
||||
|
||||
return [symbolValues, [decimalFormat, percentFormat, currencyFormat, scientificFormat]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currency code, symbol and name for a locale
|
||||
* @returns [ code, symbol, name ]
|
||||
*/
|
||||
function getCurrencySettings(locale, localeData) {
|
||||
const currencyInfo = localeData.main(`numbers/currencies`);
|
||||
let currentCurrency = '';
|
||||
|
||||
// find the currency currently used in this country
|
||||
const currencies =
|
||||
localeData.get(`supplemental/currencyData/region/${localeData.attributes.territory}`) ||
|
||||
localeData.get(
|
||||
`supplemental/currencyData/region/${localeData.attributes.language.toUpperCase()}`);
|
||||
|
||||
if (currencies) {
|
||||
currencies.some(currency => {
|
||||
const keys = Object.keys(currency);
|
||||
return keys.some(key => {
|
||||
if (currency[key]._from && !currency[key]._to) {
|
||||
return currentCurrency = key;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!currentCurrency) {
|
||||
throw new Error(`Unable to find currency for locale "${locale}"`);
|
||||
}
|
||||
}
|
||||
|
||||
let currencySettings = [undefined, undefined, undefined];
|
||||
|
||||
if (currentCurrency) {
|
||||
currencySettings = [
|
||||
currentCurrency, currencyInfo[currentCurrency].symbol,
|
||||
currencyInfo[currentCurrency].displayName
|
||||
];
|
||||
}
|
||||
|
||||
return currencySettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the writing direction for a locale
|
||||
* @returns 'rtl' | 'ltr'
|
||||
*/
|
||||
function getDirectionality(localeData) {
|
||||
const rtl = localeData.get('scriptMetadata/{script}/rtl');
|
||||
return rtl === 'YES' ? 'rtl' : 'ltr';
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a string into a regexp
|
||||
*/
|
||||
function toRegExp(s) {
|
||||
return new RegExp(s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'), 'g');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plural function for a locale
|
||||
* todo(ocombe): replace "cldr" extractPluralRuleFunction with our own extraction using "CldrJS"
|
||||
* because the 2 libs can become out of sync if they use different versions of the cldr database
|
||||
*/
|
||||
function getPluralFunction(locale, withTypes = true) {
|
||||
let fn = cldr.extractPluralRuleFunction(locale).toString();
|
||||
|
||||
if (fn === EMPTY_RULE) {
|
||||
fn = DEFAULT_RULE;
|
||||
}
|
||||
|
||||
const numberType = withTypes ? ': number' : '';
|
||||
fn = fn.replace(/function anonymous\(n[^}]+{/g, `function plural(n${numberType})${numberType} {`)
|
||||
.replace(toRegExp('var'), 'let')
|
||||
.replace(toRegExp('if(typeof n==="string")n=parseInt(n,10);'), '')
|
||||
.replace(toRegExp('\n}'), ';\n}');
|
||||
|
||||
// The replacement values must match the `Plural` enum from common.
|
||||
// We do not use the enum directly to avoid depending on that package.
|
||||
return fn.replace(toRegExp('"zero"'), ' 0')
|
||||
.replace(toRegExp('"one"'), ' 1')
|
||||
.replace(toRegExp('"two"'), ' 2')
|
||||
.replace(toRegExp('"few"'), ' 3')
|
||||
.replace(toRegExp('"many"'), ' 4')
|
||||
.replace(toRegExp('"other"'), ' 5');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of values from an object
|
||||
*/
|
||||
function objectValues(obj) {
|
||||
return Object.keys(obj).map(key => obj[key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* To create smaller locale files, we remove duplicated data.
|
||||
* To be make this work we need to store similar data in arrays, if some value in an array
|
||||
* is undefined, we can take the previous defined value instead, because it means that it has
|
||||
* been deduplicated.
|
||||
* e.g.: [x, y, undefined, z, undefined, undefined]
|
||||
* The first undefined is equivalent to y, the second and third are equivalent to z
|
||||
* Note that the first value in an array is always defined.
|
||||
*
|
||||
* Also since we need to know which data is assumed similar, it is important that we store those
|
||||
* similar data in arrays to mark the delimitation between values that have different meanings
|
||||
* (e.g. months and days).
|
||||
*
|
||||
* For further size improvements, "undefined" values will be replaced by a constant in the arrays
|
||||
* as the last step of the file generation (in generateLocale and generateLocaleExtra).
|
||||
* e.g.: [x, y, undefined, z, undefined, undefined] will be [x, y, u, z, u, u]
|
||||
*/
|
||||
function removeDuplicates(data) {
|
||||
const dedup = [data[0]];
|
||||
for (let i = 1; i < data.length; i++) {
|
||||
if (stringify(data[i]) !== stringify(data[i - 1])) {
|
||||
dedup.push(data[i]);
|
||||
} else {
|
||||
dedup.push(undefined);
|
||||
}
|
||||
}
|
||||
return dedup;
|
||||
}
|
||||
|
||||
/**
|
||||
* In Angular the locale is referenced by a "normalized" form.
|
||||
*/
|
||||
function normalizeLocale(locale) {
|
||||
return locale.toLowerCase().replace(/_/g, '-');
|
||||
}
|
||||
|
||||
module.exports.I18N_FOLDER = I18N_FOLDER;
|
||||
module.exports.I18N_DATA_FOLDER = I18N_DATA_FOLDER;
|
||||
module.exports.RELATIVE_I18N_DATA_FOLDER = RELATIVE_I18N_DATA_FOLDER;
|
||||
module.exports.HEADER = HEADER;
|
|
@ -0,0 +1,182 @@
|
|||
// tslint:disable:file-header
|
||||
|
||||
/**
|
||||
* Like JSON.stringify, but without double quotes around keys, and without null instead of undefined
|
||||
* values
|
||||
* Based on https://github.com/json5/json5/blob/master/lib/json5.js
|
||||
* Use option "quoteKeys" to preserve quotes for keys
|
||||
*/
|
||||
module.exports.stringify = function(obj, quoteKeys) {
|
||||
var getReplacedValueOrUndefined = function(holder, key) {
|
||||
var value = holder[key];
|
||||
|
||||
// Replace the value with its toJSON value first, if possible
|
||||
if (value && value.toJSON && typeof value.toJSON === 'function') {
|
||||
value = value.toJSON();
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
function isWordChar(c) {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') ||
|
||||
c === '_' || c === '$';
|
||||
}
|
||||
|
||||
function isWordStart(c) {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c === '_' || c === '$';
|
||||
}
|
||||
|
||||
function isWord(key) {
|
||||
if (typeof key !== 'string') {
|
||||
return false;
|
||||
}
|
||||
if (!isWordStart(key[0])) {
|
||||
return false;
|
||||
}
|
||||
var i = 1, length = key.length;
|
||||
while (i < length) {
|
||||
if (!isWordChar(key[i])) {
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// polyfills
|
||||
function isArray(obj) {
|
||||
if (Array.isArray) {
|
||||
return Array.isArray(obj);
|
||||
} else {
|
||||
return Object.prototype.toString.call(obj) === '[object Array]';
|
||||
}
|
||||
}
|
||||
|
||||
function isDate(obj) {
|
||||
return Object.prototype.toString.call(obj) === '[object Date]';
|
||||
}
|
||||
|
||||
var objStack = [];
|
||||
function checkForCircular(obj) {
|
||||
for (var i = 0; i < objStack.length; i++) {
|
||||
if (objStack[i] === obj) {
|
||||
throw new TypeError('Converting circular structure to JSON');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from Crokford's implementation of JSON
|
||||
// See
|
||||
// https://github.com/douglascrockford/JSON-js/blob/e39db4b7e6249f04a195e7dd0840e610cc9e941e/json2.js#L195
|
||||
// Begin
|
||||
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
meta = { // table of character substitutions
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
};
|
||||
function escapeString(str, keepQuotes) {
|
||||
// If the string contains no control characters, no quote characters, and no
|
||||
// backslash characters, then we can safely slap some quotes around it.
|
||||
// Otherwise we must also replace the offending characters with safe escape
|
||||
// sequences.
|
||||
escapable.lastIndex = 0;
|
||||
return escapable.test(str) && !keepQuotes ? '"' + str.replace(escapable, function(a) {
|
||||
var c = meta[a];
|
||||
return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||
}) + '"' : '"' + str + '"';
|
||||
}
|
||||
// End
|
||||
|
||||
function internalStringify(holder, key) {
|
||||
var buffer, res;
|
||||
|
||||
// Replace the value, if necessary
|
||||
var obj_part = getReplacedValueOrUndefined(holder, key);
|
||||
|
||||
if (obj_part && !isDate(obj_part)) {
|
||||
// unbox objects
|
||||
// don't unbox dates, since will turn it into number
|
||||
obj_part = obj_part.valueOf();
|
||||
}
|
||||
switch (typeof obj_part) {
|
||||
case 'boolean':
|
||||
return obj_part.toString();
|
||||
|
||||
case 'number':
|
||||
if (isNaN(obj_part) || !isFinite(obj_part)) {
|
||||
return 'null';
|
||||
}
|
||||
return obj_part.toString();
|
||||
|
||||
case 'string':
|
||||
return escapeString(obj_part.toString());
|
||||
|
||||
case 'object':
|
||||
if (obj_part === null) {
|
||||
return 'null';
|
||||
} else if (isArray(obj_part)) {
|
||||
checkForCircular(obj_part);
|
||||
buffer = '[';
|
||||
objStack.push(obj_part);
|
||||
|
||||
for (var i = 0; i < obj_part.length; i++) {
|
||||
res = internalStringify(obj_part, i);
|
||||
if (res === null) {
|
||||
buffer += 'null';
|
||||
} /* else if (typeof res === 'undefined') { // modified to support empty array values
|
||||
buffer += '';
|
||||
}*/
|
||||
else {
|
||||
buffer += res;
|
||||
}
|
||||
if (i < obj_part.length - 1) {
|
||||
buffer += ',';
|
||||
}
|
||||
}
|
||||
objStack.pop();
|
||||
buffer += ']';
|
||||
} else {
|
||||
checkForCircular(obj_part);
|
||||
buffer = '{';
|
||||
var nonEmpty = false;
|
||||
objStack.push(obj_part);
|
||||
for (var prop in obj_part) {
|
||||
if (obj_part.hasOwnProperty(prop)) {
|
||||
var value = internalStringify(obj_part, prop);
|
||||
if (typeof value !== 'undefined' && value !== null) {
|
||||
nonEmpty = true;
|
||||
key = isWord(prop) && !quoteKeys ? prop : escapeString(prop, quoteKeys);
|
||||
buffer += key + ':' + value + ',';
|
||||
}
|
||||
}
|
||||
}
|
||||
objStack.pop();
|
||||
if (nonEmpty) {
|
||||
buffer = buffer.substring(0, buffer.length - 1) + '}';
|
||||
} else {
|
||||
buffer = '{}';
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
default:
|
||||
// functions and undefined should be ignored
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// special case...when undefined is used inside of
|
||||
// a compound object/array, return null.
|
||||
// but when top-level, return undefined
|
||||
var topLevelHolder = {'': obj};
|
||||
if (obj === undefined) {
|
||||
return getReplacedValueOrUndefined(topLevelHolder, '');
|
||||
}
|
||||
return internalStringify(topLevelHolder, '');
|
||||
};
|
186
yarn.lock
186
yarn.lock
|
@ -1620,11 +1620,6 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.35.tgz#3964c48372bf62d60616d8673dd77a9719ebac9b"
|
||||
integrity sha512-2WeeXK7BuQo7yPI4WGOBum90SzF/f8rqlvpaXx4rjeTmNssGRDHWf7fgDUH90xMB3sUOu716fUK5d+OVx0+ncQ==
|
||||
|
||||
"@types/cldrjs@^0.4.22":
|
||||
version "0.4.22"
|
||||
resolved "https://registry.yarnpkg.com/@types/cldrjs/-/cldrjs-0.4.22.tgz#24e31cdf15a4ea806ca0a774b024150d1066fea1"
|
||||
integrity sha512-YyzxXZ5s9xwPWznXnI3++X14JGnomDdDAlin7kWZvxX/MzirC9BNFcDSQ0yR8YG2M/xNMn0nXsCGkgbFVyXjGw==
|
||||
|
||||
"@types/cli-progress@^3.4.2":
|
||||
version "3.9.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/cli-progress/-/cli-progress-3.9.1.tgz#285e7fbdad6e7baf072d163ae1c3b23b7b219130"
|
||||
|
@ -2132,6 +2127,11 @@ adjust-sourcemap-loader@^4.0.0:
|
|||
loader-utils "^2.0.0"
|
||||
regex-parser "^2.2.11"
|
||||
|
||||
adm-zip@0.4.11:
|
||||
version "0.4.11"
|
||||
resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.11.tgz#2aa54c84c4b01a9d0fb89bb11982a51f13e3d62a"
|
||||
integrity sha512-L8vcjDTCOIJk7wFvmlEUN7AsSb8T+2JrdP7KINBjzr24TJ5Mwj590sLu3BC7zNZowvJWa/JtPmD8eJCzdtDWjA==
|
||||
|
||||
adm-zip@^0.4.9, adm-zip@~0.4.3:
|
||||
version "0.4.16"
|
||||
resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365"
|
||||
|
@ -2205,6 +2205,16 @@ ajv@8.2.0:
|
|||
require-from-string "^2.0.2"
|
||||
uri-js "^4.2.2"
|
||||
|
||||
ajv@^5.1.0:
|
||||
version "5.5.2"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
|
||||
integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=
|
||||
dependencies:
|
||||
co "^4.6.0"
|
||||
fast-deep-equal "^1.0.0"
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
json-schema-traverse "^0.3.0"
|
||||
|
||||
ajv@^6.1.0, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5:
|
||||
version "6.12.6"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
||||
|
@ -2709,7 +2719,7 @@ aws-sign2@~0.7.0:
|
|||
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
|
||||
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
|
||||
|
||||
aws4@^1.8.0:
|
||||
aws4@^1.6.0, aws4@^1.8.0:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
|
||||
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
|
||||
|
@ -3496,20 +3506,33 @@ class-utils@^0.3.5:
|
|||
isobject "^3.0.0"
|
||||
static-extend "^0.1.1"
|
||||
|
||||
cldr@5.7.0:
|
||||
version "5.7.0"
|
||||
resolved "https://registry.yarnpkg.com/cldr/-/cldr-5.7.0.tgz#8c466bdc2500fd293462029631011adcd55bc5ae"
|
||||
integrity sha512-Pyoh0kwXJIUvbAvQoQqKIr0pKWwWfkcYCIDKWmVIxJ9HftSsg57AqyfW1EzWRcP4nJj40WX4vB/lXQ+Uw4NbNA==
|
||||
cldr-data-downloader@^0.3.5:
|
||||
version "0.3.5"
|
||||
resolved "https://registry.yarnpkg.com/cldr-data-downloader/-/cldr-data-downloader-0.3.5.tgz#f5445cb9d222bf7fa8426c62e0ae9d7d4897b243"
|
||||
integrity sha512-uyIMa1K98DAp/PE7dYpq2COIrkWn681Atjng1GgEzeJzYb1jANtugtp9wre6+voE+qzVC8jtWv6E/xZ1GTJdlw==
|
||||
dependencies:
|
||||
escodegen "^1.12.0"
|
||||
adm-zip "0.4.11"
|
||||
mkdirp "0.5.0"
|
||||
nopt "3.0.x"
|
||||
progress "1.1.8"
|
||||
q "1.0.1"
|
||||
request "~2.87.0"
|
||||
request-progress "0.3.1"
|
||||
|
||||
cldr@7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cldr/-/cldr-7.0.0.tgz#8e0f42acc21b5762842cf23a747120be898447fe"
|
||||
integrity sha512-BmD93+RhHGkdVRO9LYL6kd7IA9ANxnpH1A+OM6FdhKVYXqRgBaDmt9P83VaQB6gMBaFvOl4IozW/g3ViLn9LeQ==
|
||||
dependencies:
|
||||
escodegen "^2.0.0"
|
||||
esprima "^4.0.1"
|
||||
memoizeasync "^1.1.0"
|
||||
passerror "^1.1.1"
|
||||
pegjs "^0.10.0"
|
||||
seq "^0.3.5"
|
||||
unicoderegexp "^0.4.1"
|
||||
xmldom "^0.3.0"
|
||||
xpath "^0.0.27"
|
||||
xmldom "^0.6.0"
|
||||
xpath "^0.0.32"
|
||||
|
||||
cldrjs@0.5.5:
|
||||
version "0.5.5"
|
||||
|
@ -3663,6 +3686,11 @@ cloneable-readable@^1.0.0:
|
|||
process-nextick-args "^2.0.0"
|
||||
readable-stream "^2.3.5"
|
||||
|
||||
co@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
|
||||
integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=
|
||||
|
||||
code-point-at@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
||||
|
@ -3763,7 +3791,7 @@ colorspace@1.1.x:
|
|||
color "3.0.x"
|
||||
text-hex "1.0.x"
|
||||
|
||||
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
|
||||
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.5, combined-stream@~1.0.6:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
|
@ -5230,7 +5258,7 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
|
|||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
|
||||
escodegen@^1.12.0, escodegen@^1.8.1:
|
||||
escodegen@^1.8.1:
|
||||
version "1.14.3"
|
||||
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503"
|
||||
integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==
|
||||
|
@ -5497,7 +5525,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
|
|||
assign-symbols "^1.0.0"
|
||||
is-extendable "^1.0.1"
|
||||
|
||||
extend@^3.0.0, extend@^3.0.2, extend@~3.0.2:
|
||||
extend@^3.0.0, extend@^3.0.2, extend@~3.0.1, extend@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||
|
@ -5556,6 +5584,11 @@ fancy-log@^1.3.2:
|
|||
parse-node-version "^1.0.0"
|
||||
time-stamp "^1.0.0"
|
||||
|
||||
fast-deep-equal@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
|
||||
integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=
|
||||
|
||||
fast-deep-equal@^3.1.1:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
|
@ -5934,7 +5967,7 @@ form-data@^3.0.0:
|
|||
combined-stream "^1.0.8"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
form-data@~2.3.2:
|
||||
form-data@~2.3.1, form-data@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
|
||||
integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
|
||||
|
@ -6613,6 +6646,14 @@ har-schema@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
|
||||
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
|
||||
|
||||
har-validator@~5.0.3:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd"
|
||||
integrity sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=
|
||||
dependencies:
|
||||
ajv "^5.1.0"
|
||||
har-schema "^2.0.0"
|
||||
|
||||
har-validator@~5.1.3:
|
||||
version "5.1.5"
|
||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
|
||||
|
@ -7856,6 +7897,11 @@ json-ptr@^2.2.0:
|
|||
dependencies:
|
||||
tslib "^2.2.0"
|
||||
|
||||
json-schema-traverse@^0.3.0:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
|
||||
integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=
|
||||
|
||||
json-schema-traverse@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
||||
|
@ -8982,6 +9028,11 @@ minimist-options@4.1.0:
|
|||
is-plain-obj "^1.1.0"
|
||||
kind-of "^6.0.3"
|
||||
|
||||
minimist@0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
||||
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
|
||||
|
||||
minimist@1.x, minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
|
@ -9082,6 +9133,13 @@ mkdirp-classic@^0.5.2:
|
|||
resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
|
||||
integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
|
||||
|
||||
mkdirp@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12"
|
||||
integrity sha1-HXMHam35hs2TROFecfzAWkyavxI=
|
||||
dependencies:
|
||||
minimist "0.0.8"
|
||||
|
||||
"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5:
|
||||
version "0.5.5"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
|
||||
|
@ -9350,6 +9408,13 @@ nodejs-websocket@^1.7.2:
|
|||
resolved "https://registry.yarnpkg.com/nodejs-websocket/-/nodejs-websocket-1.7.2.tgz#94abd1e248f57d4d1c663dec3831015c6dad98a6"
|
||||
integrity sha512-PFX6ypJcCNDs7obRellR0DGTebfUhw1SXGKe2zpB+Ng1DQJhdzbzx1ob+AvJCLzy2TJF4r8cCDqMQqei1CZdPQ==
|
||||
|
||||
nopt@3.0.x:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
|
||||
integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k=
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
nopt@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"
|
||||
|
@ -9501,6 +9566,11 @@ number-is-nan@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
|
||||
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
|
||||
|
||||
oauth-sign@~0.8.2:
|
||||
version "0.8.2"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
|
||||
integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=
|
||||
|
||||
oauth-sign@~0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||
|
@ -10867,6 +10937,11 @@ process-nextick-args@~1.0.6:
|
|||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
|
||||
integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=
|
||||
|
||||
progress@1.1.8:
|
||||
version "1.1.8"
|
||||
resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
|
||||
integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=
|
||||
|
||||
progress@^2.0.1, progress@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
|
||||
|
@ -11033,7 +11108,7 @@ punycode@1.3.2:
|
|||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
|
||||
integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=
|
||||
|
||||
punycode@^1.3.2:
|
||||
punycode@^1.3.2, punycode@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
|
||||
|
@ -11068,6 +11143,11 @@ puppeteer@5.4.1:
|
|||
unbzip2-stream "^1.3.3"
|
||||
ws "^7.2.3"
|
||||
|
||||
q@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/q/-/q-1.0.1.tgz#11872aeedee89268110b10a718448ffb10112a14"
|
||||
integrity sha1-EYcq7t7okmgRCxCnGESP+xARKhQ=
|
||||
|
||||
q@1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e"
|
||||
|
@ -11095,7 +11175,7 @@ qs@^6.4.0, qs@^6.6.0:
|
|||
dependencies:
|
||||
side-channel "^1.0.4"
|
||||
|
||||
qs@~6.5.2:
|
||||
qs@~6.5.1, qs@~6.5.2:
|
||||
version "6.5.2"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
|
||||
|
@ -11485,6 +11565,13 @@ replace-homedir@^1.0.0:
|
|||
is-absolute "^1.0.0"
|
||||
remove-trailing-separator "^1.1.0"
|
||||
|
||||
request-progress@0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-0.3.1.tgz#0721c105d8a96ac6b2ce8b2c89ae2d5ecfcf6b3a"
|
||||
integrity sha1-ByHBBdipasayzossia4tXs/Pazo=
|
||||
dependencies:
|
||||
throttleit "~0.0.2"
|
||||
|
||||
request@^2.87.0, request@^2.88.2:
|
||||
version "2.88.2"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
|
||||
|
@ -11511,6 +11598,32 @@ request@^2.87.0, request@^2.88.2:
|
|||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
request@~2.87.0:
|
||||
version "2.87.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e"
|
||||
integrity sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.6.0"
|
||||
caseless "~0.12.0"
|
||||
combined-stream "~1.0.5"
|
||||
extend "~3.0.1"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.3.1"
|
||||
har-validator "~5.0.3"
|
||||
http-signature "~1.2.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.17"
|
||||
oauth-sign "~0.8.2"
|
||||
performance-now "^2.1.0"
|
||||
qs "~6.5.1"
|
||||
safe-buffer "^5.1.1"
|
||||
tough-cookie "~2.3.3"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.1.0"
|
||||
|
||||
require-directory@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
|
||||
|
@ -11820,7 +11933,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
|||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
|
||||
safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
@ -11872,6 +11985,7 @@ sauce-connect-launcher@^1.2.4:
|
|||
|
||||
"sauce-connect@https://saucelabs.com/downloads/sc-4.6.2-linux.tar.gz":
|
||||
version "0.0.0"
|
||||
uid "7b7f35433af9c3380758e048894d7b9aecf3754e"
|
||||
resolved "https://saucelabs.com/downloads/sc-4.6.2-linux.tar.gz#7b7f35433af9c3380758e048894d7b9aecf3754e"
|
||||
|
||||
saucelabs@^1.5.0:
|
||||
|
@ -12981,6 +13095,11 @@ text-table@0.2.0:
|
|||
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
|
||||
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
|
||||
|
||||
throttleit@~0.0.2:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf"
|
||||
integrity sha1-z+34jmDADdlpe2H90qg0OptoDq8=
|
||||
|
||||
through2-filter@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254"
|
||||
|
@ -13128,6 +13247,13 @@ toidentifier@1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
||||
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
|
||||
|
||||
tough-cookie@~2.3.3:
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655"
|
||||
integrity sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==
|
||||
dependencies:
|
||||
punycode "^1.4.1"
|
||||
|
||||
tough-cookie@~2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
||||
|
@ -13700,7 +13826,7 @@ uuid@8.3.2:
|
|||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
uuid@^3.0.0, uuid@^3.3.2, uuid@^3.4.0:
|
||||
uuid@^3.0.0, uuid@^3.1.0, uuid@^3.3.2, uuid@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
@ -14236,25 +14362,25 @@ xmlbuilder@~11.0.0:
|
|||
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
|
||||
integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==
|
||||
|
||||
xmldom@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.3.0.tgz#e625457f4300b5df9c2e1ecb776147ece47f3e5a"
|
||||
integrity sha512-z9s6k3wxE+aZHgXYxSTpGDo7BYOUfJsIRyoZiX6HTjwpwfS2wpQBQKa2fD+ShLyPkqDYo5ud7KitmLZ2Cd6r0g==
|
||||
|
||||
xmldom@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.5.0.tgz#193cb96b84aa3486127ea6272c4596354cb4962e"
|
||||
integrity sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA==
|
||||
|
||||
xmldom@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.6.0.tgz#43a96ecb8beece991cef382c08397d82d4d0c46f"
|
||||
integrity sha512-iAcin401y58LckRZ0TkI4k0VSM1Qg0KGSc3i8rU+xrxe19A/BN1zHyVSJY7uoutVlaTSzYyk/v5AmkewAP7jtg==
|
||||
|
||||
xmlhttprequest-ssl@~1.5.4:
|
||||
version "1.5.5"
|
||||
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
|
||||
integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
|
||||
|
||||
xpath@^0.0.27:
|
||||
version "0.0.27"
|
||||
resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.27.tgz#dd3421fbdcc5646ac32c48531b4d7e9d0c2cfa92"
|
||||
integrity sha512-fg03WRxtkCV6ohClePNAECYsmpKKTv5L8y/X3Dn1hQrec3POx2jHZ/0P2qQ6HvsrU1BmeqXcof3NGGueG6LxwQ==
|
||||
xpath@^0.0.32:
|
||||
version "0.0.32"
|
||||
resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.32.tgz#1b73d3351af736e17ec078d6da4b8175405c48af"
|
||||
integrity sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==
|
||||
|
||||
xregexp@2.0.0:
|
||||
version "2.0.0"
|
||||
|
|
Loading…
Reference in New Issue