Skip to content

Commit 7a3a453

Browse files
devversionalxhub
authored andcommitted
build: convert CLDR locale extraction from Gulp to Bazel tool (angular#42230)
Converts the CLDR locale extraction script to a Bazel tool. This allows us to generate locale files within Bazel, so that locales don't need to live as sources within the repo. Also it allows us to get rid of the legacy Gulp tooling. The migration of the Gulp script to a Bazel tool involved the following things: 1. Basic conversion of the `extract.js` script to TypeScript. This mostly was about adding explicit types. e.g. adding `locale: string` or `localeData: CldrStatic`. 2. Split-up into separate files. Instead of keeping the large `extract.js` file, the tool has been split into separate files. The logic remains the same, just that code is more readable and maintainable. 3. Introduction of a new `index.ts` file that is the entry-point for the Bazel tool. Previously the Gulp tool just generated all locale files, the default locale and base currency files at once. The new entry-point accepts a mode to be passed as first process argument. based on that argument, either locales are generated into a specified directory, or the default locale, base currencies or closure file is generated. This allows us to generate files with a Bazel genrule where we simply run the tool and specify the outputs. Note: It's necessary to have multiple modes because files live in separate locations. e.g. the default locale in `@angular/core`, but the rest in `@angular/common`. 4. Removal of the `cldr-data-downloader` and custom CLDR resolution logic. Within Bazel we cannot run a downloader using network. We switch this to something more Bazel idiomatic with better caching. For this a new repository rule is introduced that downloads the CLDR JSON repository and extracts it. Within that rule we determine the supported locales so that they can be used to pre-declare outputs (for the locales) within Bazel analysis phase. This allows us to add the generated locale files to a `ts_library` (which we want to have for better testing, and consistent JS transpilation). Note that the removal of `cldr-data-downloader` also requires us to add logic for detecting locales without data. The CLDR data downloader overwrote the `availableLocales.json` file with a file that only lists locales that CLDR provides data for. We use the official `availableLocales` file CLDR provides, but filter out locales for which no data is available. This is needed until we update to CLDR 39 where data is available for all such locales listed in `availableLocales.json`. PR Close angular#42230
1 parent f2cd6de commit 7a3a453

31 files changed

+1278
-1294
lines changed

.gitignore

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,5 @@ baseline.json
5050
# Ignore .history for the xyz.local-history VSCode extension
5151
.history
5252

53-
# CLDR data
54-
tools/gulp-tasks/cldr/cldr-data/
55-
5653
# Husky
5754
.husky/_

WORKSPACE

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,18 @@ web_test_repositories()
4747
load("//dev-infra/bazel/browsers:browser_repositories.bzl", "browser_repositories")
4848

4949
browser_repositories()
50+
51+
load("//packages/common/locales/generate-locales-tool:cldr-data.bzl", "cldr_data_repository")
52+
53+
cldr_data_repository(
54+
name = "cldr_data",
55+
# Since we use the Github archives for CLDR 37, we need to specify a path
56+
# to the available locales. This wouldn't be needed with CLDR 39 as that
57+
# comes with an official JSON archive not containing a version suffix.
58+
available_locales_path = "cldr-core-37.0.0/availableLocales.json",
59+
urls = {
60+
"https://github.com/unicode-cldr/cldr-core/archive/37.0.0.zip": "32b5c49c3874aa342b90412c207b42e7aefb2435295891fb714c34ce58b3c706",
61+
"https://github.com/unicode-cldr/cldr-dates-full/archive/37.0.0.zip": "e1c410dd8ad7d75df4a5393efaf5d28f0d56c0fa126c5d66e171a3f21a988a1e",
62+
"https://github.com/unicode-cldr/cldr-numbers-full/archive/37.0.0.zip": "a921b90cf7f436e63fbdd55880f96e39a203acd9e174b0ceafa20a02c242a12e",
63+
},
64+
)

gulpfile.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,3 @@ function loadTask(fileName, taskName) {
2020

2121
gulp.task('source-map-test', loadTask('source-map-test'));
2222
gulp.task('changelog:zonejs', loadTask('changelog-zonejs'));
23-
gulp.task('cldr:extract', loadTask('cldr', 'extract'));
24-
gulp.task('cldr:download', loadTask('cldr', 'download'));
25-
gulp.task('cldr:gen-closure-locale', loadTask('cldr', 'closure'));

package.json

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@
167167
"@bazel/buildifier": "^4.0.1",
168168
"@bazel/ibazel": "^0.15.8",
169169
"@octokit/graphql": "^4.6.1",
170+
"@types/cldrjs": "^0.4.22",
170171
"@types/cli-progress": "^3.4.2",
171172
"@types/conventional-commits-parser": "^3.0.1",
172173
"@types/ejs": "^3.0.6",
@@ -176,8 +177,7 @@
176177
"browserstacktunnel-wrapper": "^2.0.4",
177178
"check-side-effects": "0.0.23",
178179
"clang-format": "^1.4.0",
179-
"cldr": "7.0.0",
180-
"cldr-data-downloader": "^0.3.5",
180+
"cldr": "5.7.0",
181181
"cldrjs": "0.5.5",
182182
"cli-progress": "^3.7.0",
183183
"conventional-changelog": "^3.1.24",
@@ -220,6 +220,5 @@
220220
"@babel/template": "7.8.6",
221221
"@babel/traverse": "7.8.6",
222222
"@babel/types": "7.8.6"
223-
},
224-
"cldr-data-coverage": "full"
223+
}
225224
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
load("//tools:defaults.bzl", "ts_library")
2+
3+
package(default_visibility = ["//visibility:public"])
4+
5+
ts_library(
6+
name = "generate-locales-tool",
7+
srcs = glob(["*.ts"]),
8+
deps = [
9+
"@npm//@bazel/runfiles",
10+
"@npm//@types/cldrjs",
11+
"@npm//@types/glob",
12+
"@npm//@types/node",
13+
"@npm//cldr",
14+
"@npm//cldrjs",
15+
"@npm//glob",
16+
],
17+
)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
/**
10+
* To create smaller locale files, we remove duplicated data.
11+
* To make this work we store the data in arrays, where `undefined` indicates that the
12+
* value is a duplicate of the previous value in the array.
13+
* e.g. consider an array like: [x, y, undefined, z, undefined, undefined]
14+
* The first `undefined` is equivalent to y, the second and third are equivalent to z
15+
* Note that the first value in an array is always defined.
16+
*
17+
* Also since we need to know which data is assumed similar, it is important that we store those
18+
* similar data in arrays to mark the delimitation between values that have different meanings
19+
* (e.g. months and days).
20+
*
21+
* For further size improvements, "undefined" values will be replaced by a constant in the arrays
22+
* as the last step of the file generation (in generateLocale and generateLocaleExtra).
23+
* e.g.: [x, y, undefined, z, undefined, undefined] will be [x, y, u, z, u, u]
24+
*/
25+
export function removeDuplicates(data: unknown[]) {
26+
const dedup = [data[0]];
27+
for (let i = 1; i < data.length; i++) {
28+
if (JSON.stringify(data[i]) !== JSON.stringify(data[i - 1])) {
29+
dedup.push(data[i]);
30+
} else {
31+
dedup.push(undefined);
32+
}
33+
}
34+
return dedup;
35+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
2+
load("//tools:defaults.bzl", "ts_library")
3+
4+
package(default_visibility = ["//visibility:public"])
5+
6+
BIN_ENTRYPOINTS = [
7+
"get-base-currencies-file",
8+
"get-base-locale-file",
9+
"get-closure-locale-file",
10+
"write-locale-files-to-dist",
11+
]
12+
13+
ts_library(
14+
name = "bin",
15+
srcs = glob(["*.ts"]),
16+
deps = [
17+
"//packages/common/locales/generate-locales-tool",
18+
"@npm//@types/node",
19+
],
20+
)
21+
22+
[nodejs_binary(
23+
name = entrypoint,
24+
data = [
25+
":bin",
26+
"@cldr_data//:all_json",
27+
],
28+
entry_point = ":%s.ts" % entrypoint,
29+
# We need to patch the NodeJS module resolution as this binary runs as
30+
# part of a genrule where the linker does not work as expected.
31+
# See: https://github.com/bazelbuild/rules_nodejs/issues/2600.
32+
templated_args = ["--bazel_patch_module_resolver"],
33+
) for entrypoint in BIN_ENTRYPOINTS]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
10+
/**
11+
* Base locale used as foundation for other locales. For example: A base locale allows
12+
* generation of a file containing all currencies with their corresponding symbols. If we
13+
* generate other locales, they can override currency symbols which are different in the base
14+
* locale. This means that we do not need re-generate all currencies w/ symbols multiple times,
15+
* and allows us to reduce the locale data payload as the base locale is always included.
16+
* */
17+
export const BASE_LOCALE = 'en';
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
import {CldrData} from '../cldr-data';
9+
import {generateBaseCurrenciesFile} from '../locale-base-currencies';
10+
11+
import {BASE_LOCALE} from './base-locale';
12+
13+
/** Generates the base currencies file and prints it to the stdout. */
14+
function main() {
15+
const cldrData = new CldrData();
16+
const baseLocaleData = cldrData.getLocaleData(BASE_LOCALE)!;
17+
18+
process.stdout.write(generateBaseCurrenciesFile(baseLocaleData));
19+
}
20+
21+
if (require.main === module) {
22+
main();
23+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
import {CldrData} from '../cldr-data';
9+
import {generateBaseCurrencies} from '../locale-base-currencies';
10+
import {generateLocale} from '../locale-file';
11+
12+
import {BASE_LOCALE} from './base-locale';
13+
14+
/** Generates the base locale file and prints it to the stdout. */
15+
function main() {
16+
const cldrData = new CldrData();
17+
const baseLocaleData = cldrData.getLocaleData(BASE_LOCALE)!;
18+
const baseCurrencies = generateBaseCurrencies(baseLocaleData);
19+
20+
process.stdout.write(generateLocale(BASE_LOCALE, baseLocaleData, baseCurrencies));
21+
}
22+
23+
if (require.main === module) {
24+
main();
25+
}

0 commit comments

Comments
 (0)