From 7e0eccc4efa0fb1fcf25a9830ae2977d0fa1e0ac Mon Sep 17 00:00:00 2001 From: Tony Bove Date: Mon, 4 May 2020 13:27:39 -1000 Subject: [PATCH] docs: Refactor-i18n (#36924) Rewrite headings to focus on tasks and separate reference info and best practices from tasks. Add missing steps or procedures, and links to important information. Make the example open in StackBlitz. See i18n Documentation Plan at https://docs.google.com/document/d/1aV2TKsIqry7JnNiHEfhmheu5rNAbNl1IRYVhYErc7Ks/edit?usp=sharing PR Close #36924 --- aio/content/examples/i18n/stackblitz.json | 10 + aio/content/guide/i18n.md | 1066 +++++++++-------- aio/tools/examples/run-example-e2e.js | 101 +- .../shared/boilerplate/i18n/angular.json | 39 +- .../shared/boilerplate/i18n/package.json | 1 + .../shared/boilerplate/i18n/polyfills.ts | 68 ++ aio/tools/examples/shared/package.json | 1 + aio/tools/examples/shared/yarn.lock | 146 ++- 8 files changed, 889 insertions(+), 543 deletions(-) create mode 100644 aio/content/examples/i18n/stackblitz.json create mode 100644 aio/tools/examples/shared/boilerplate/i18n/polyfills.ts diff --git a/aio/content/examples/i18n/stackblitz.json b/aio/content/examples/i18n/stackblitz.json new file mode 100644 index 0000000000..31759ca104 --- /dev/null +++ b/aio/content/examples/i18n/stackblitz.json @@ -0,0 +1,10 @@ +{ + "description": "i18n", + "files":[ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[0-9].*" + ], + "file": "src/app/app.component.ts", + "tags": ["Angular", "i18n", "internationalization"] +} diff --git a/aio/content/guide/i18n.md b/aio/content/guide/i18n.md index f238b766e5..20d083398e 100644 --- a/aio/content/guide/i18n.md +++ b/aio/content/guide/i18n.md @@ -1,156 +1,160 @@ -# Internationalization (i18n) - -Application internationalization is a many-faceted area of development, focused on making -applications available and user-friendly to a worldwide audience. This page describes Angular's -internationalization (i18n) tools, which can help you make your app available in multiple languages. - -See the i18n Example for a simple example of -an AOT-compiled app, translated into French. +# Localizing your app +{@searchKeywords i18n} {@a angular-i18n} -## Angular and i18n -*Internationalization* is the process of designing and preparing your app to be usable in different languages. -*Localization* is the process of translating your internationalized app into specific languages for particular locales. +*Internationalization* (i18n) is the process of designing and preparing your app to be usable in different locales around the world. +*Localization* is the process of building versions of your app for different locales, including extracting text for translation into different languages, and formatting data for particular locales. -Angular simplifies the following aspects of internationalization: -* Displaying dates, number, percentages, and currencies in a local format. -* Preparing text in component templates for translation. -* Handling plural forms of words. -* Handling alternative text. +A *locale* identifies a region (such as a country) in which people speak a particular language or language variant. The locale determines the formatting and parsing of dates, times, numbers, and currencies as well as measurement units and the translated names for time zones, languages, and countries. -For localization, you can use the [Angular CLI](cli) to generate most of the boilerplate necessary to create files for translators, and to publish your app in multiple languages. -After you have set up your app to use i18n, the CLI can help you with the following steps: -* Extracting localizable text into a file that you can send out to be translated. -* Building and serving the app for a given locale, using the translated text. -* Creating multiple language versions of your app. +
+ +Create an adaptable user interface for all of your target locales that takes into consideration the differences in spacing for different languages. For details, see [How to approach internationalization](https://marketfinder.thinkwithgoogle.com/intl/en_us/guide/how-to-approach-i18n/#overview "How to approach internationalization"). + +
+ +Use Angular to internationalize your app: + +* Use built-in pipes to display dates, numbers, percentages, and currencies in a local format. +* Mark text in component templates for translation. +* Mark plural forms of expressions for translation. +* Mark alternate text for translation. + +After preparing your app for an international audience, use the [Angular CLI](cli) to localize your app by performing the following tasks: + +* Use the CLI to extract marked text to a _source language_ file. +* Make a copy of this file for each language, and send these _translation files_ to a translator or service. +* Use the CLI to merge the finished translation files when building your app for one or more locales. + +
+ + To explore the sample app with French translations used in this guide, see the . + +
+ +## Prerequisites + +To prepare your app for translations, you should have a basic understanding of the following: + +* [Templates](guide/glossary#template "Definition of a template") +* [Components](guide/glossary#component "Definition of a component") +* [Angular CLI](guide/glossary#command-line-interface-cli "Definition of CLI") command-line tool for managing the Angular development cycle +* [Extensible Markup Language (XML)](https://www.w3.org/XML/ "W3C: Extensible Markup Language (XML)") used for translation files + +## Steps to localize your app + +To localize your app, follow these general steps: + +1. [Add the localize package](#setting-up-cli). +2. [Refer to locales by ID](#setting-up-locale). +3. [Format data based on locale](#i18n-pipes). +4. [Prepare templates for translations](#Template-translations). +5. [Work with translation files](#ng-xi18n). +6. [Merge translations into the app](#merge). +7. [Deploy multiple locales](#deploy-locales). + +While following these steps, you can [explore the translated example app](#app-pre-translation). + +The following are optional practices that may be required in special cases: + +* [Set the source locale manually](#set-source-manually) if you need to set the [LOCALE_ID](https://angular.io/api/core/LOCALE_ID "API reference for LOCALE_ID") token. +* [Import global variants of the locale data](#import-locale) for extra locale data. +* [Manage marked text with custom IDs](#custom-id) if you require more control over matching translations. {@a setting-up-cli} -## Setting up localization with the Angular CLI +{@a add-localize} -The first step to setting up localization when using the Angular CLI is to add the `@angular/localize` package to the project. This will install the package within your project as well as -initialize the project to take advantage of Angular's localization features. +## Add the localize package + +To take advantage of Angular's localization features, use the Angular CLI to add the `@angular/localize` package to your project: ng add @angular/localize +This command updates your project's `package.json` and `polyfills.ts` files to import the `@angular/localize` package. + +
+ +For more information about `package.json` and polyfill packages, see [Workspace npm dependencies](https://angular.io/guide/npm-packages). + +
+ +If `@angular/localize` is not installed, the Angular CLI may generate an error when you try to build a localized version of your app. {@a setting-up-locale} -## Setting up the locale of your app -A locale is an identifier (id) that refers to a set of user preferences that tend to be shared -within a region of the world, such as country. This document refers to a locale identifier as a -"locale" or "locale id". +{@a setting-up-the-locale-of-your-app} -A Unicode locale identifier is composed of a Unicode language identifier and (optionally) the -character `-` followed by a locale extension. (For historical reasons the character `_` is supported -as an alternative to `-`.) For example, in the locale id `fr-CA` the `fr` refers to the French -language identifier, and the `CA` refers to the locale extension Canada. +## Refer to locales by ID -
+Refer to a locale using the Unicode *locale identifier* (ID), which specifies the language, country, and an optional code for further variants or subdivisions. -Angular follows the Unicode LDML convention that uses stable identifiers (Unicode locale identifiers) -based on the norm [BCP47](http://www.rfc-editor.org/rfc/bcp/bcp47.txt). It is very important that -you follow this convention when you define your locale, because the Angular i18n tools use this -locale id to find the correct corresponding locale data. +
+
Unicode locale identifiers
+ +* For a list of language codes, see [ISO 639-2](https://www.loc.gov/standards/iso639-2/ "ISO 639-2 Registration Authority"). +* IDs conform to the Unicode Common Locale Data Repository (CLDR). +For more information about Unicode locale identifiers, see the [CLDR core specification](http://cldr.unicode.org/core-spec#Unicode_Language_and_Locale_Identifiers "CLDR - Unicode Common Locale Data Repository"). +* CLDR and Angular base their identifiers on [BCP47 tags](http://www.rfc-editor.org/rfc/bcp/bcp47.txt "BCP47 Tags for Identifying Languages").
-By default, Angular uses the locale `en-US`, which is English as spoken in the United States of America. - -For more information about Unicode locale identifiers, see the -[CLDR core spec](http://cldr.unicode.org/core-spec#Unicode_Language_and_Locale_Identifiers). - -For a complete list of locales supported by Angular, see -[the Angular repository](https://github.com/angular/angular/tree/master/packages/common/locales). - -The locale identifiers used by CLDR and Angular are based on [BCP47](http://www.rfc-editor.org/rfc/bcp/bcp47.txt). -These specifications change over time; the following table maps previous identifiers to current ones at -time of writing: - -| Locale name | Old locale id | New locale id | -|-------------------------------|-------------------|---------------| -| Indonesian | in | id | -| Hebrew | iw | he | -| Romanian Moldova | mo | ro-MD | -| Norwegian Bokmål | no, no-NO | nb | -| Serbian Latin | sh | sr-Latn | -| Filipino | tl | fil | -| Portuguese Brazil | pt-BR | pt | -| Chinese Simplified | zh-cn, zh-Hans-CN | zh-Hans | -| Chinese Traditional | zh-tw, zh-Hant-TW | zh-Hant | -| Chinese Traditional Hong Kong | zh-hk | zh-Hant-HK | - - -## i18n pipes - -Angular pipes can help you with internationalization: the `DatePipe`, `CurrencyPipe`, `DecimalPipe` -and `PercentPipe` use locale data to format data based on the `LOCALE_ID` dependency injection token. - -By default, Angular only contains locale data for `en-US`. -The CLI automatically includes the locale data and sets the `LOCALE_ID` value for you when you use the -parameter `--i18nLocale` or option `i18nLocale` with `ng serve` and `ng build`. -However, if you manually set the value of `LOCALE_ID` to another locale, you must import locale data for that new locale. - -If you want to import locale data for other languages, you can do it manually: - - - -The first parameter is an object containing the locale data imported from `@angular/common/locales`. -By default, the imported locale data is registered with the locale id that is defined in the Angular -locale data itself. -If you want to register the imported locale data with another locale id, use the second parameter to -specify a custom locale id. For example, Angular's locale data defines the locale id for French as -"fr". You can use the second parameter to associate the imported French locale data with the custom -locale id "fr-FR" instead of "fr". - -The files in `@angular/common/locales` contain most of the locale data that you -need, but some advanced formatting options might only be available in the extra dataset that you can -import from `@angular/common/locales/extra`. An error message informs you when this is the case. -Ivy will automatically include the extra locale data if the locale was configured via `i18nLocale`. - - +The ID consists of a language identifier, such as `en` for English or `fr` for French, followed by a dash (`-`) and a locale extension, such as `US` for the United States or `CA` for Canada. +For example, `en-US` refers to English in the United States, and `fr-CA` refers to French in Canada. +Angular uses this ID to find the correct corresponding locale data.
- All locale data used by Angular are extracted from the Unicode Consortium's - Common Locale Data Repository (CLDR). +Many countries, such as France and Canada, use the same language (French, identified as `fr`) but differ in grammar, punctuation, and formats for currency, decimal numbers, and dates. +Use a more specific locale ID, such as French for Canada (`fr-CA`), when localizing your app.
+Angular by default uses `en-US` (English in the United States) as your app's source locale. -## Template translations +The [Angular repository](https://github.com/angular/angular/tree/master/packages/common/locales "Common locales in the Angular repository") includes common locales. +You can change your app's source locale for the build by setting the source locale in the `sourceLocale` field of your app's [workspace configuration](guide/workspace-config "Angular workspace configuration") file (`angular.json`). +The build process (described in [Merge translations into the app](#merge) in this guide) uses your app's `angular.json` file to automatically set the [`LOCALE_ID`](api/core/LOCALE_ID "API reference for LOCALE_ID") token and load the locale data. -
+{@a i18n-pipes} - This document refers to a unit of translatable text as "text," a "message", or a - "text message." +## Format data based on locale -
+Angular provides the following built-in data transformation [pipes](guide/glossary#pipe "Definition of a pipe") that use the [`LOCALE_ID`](api/core/LOCALE_ID "API reference for LOCALE_ID") token to format data according to the locale's rules: -The i18n template translation process has four phases: +* [`DatePipe`](api/common/DatePipe): Formats a date value. +* [`CurrencyPipe`](api/common/CurrencyPipe): Transforms a number to a currency string. +* [`DecimalPipe`](/api/common/DecimalPipe): Transforms a number into a decimal number string. +* [`PercentPipe`](api/common/PercentPipe): Transforms a number to a percentage string. -1. Mark static text messages in your component templates for translation. +For example, `{{today | date}}` uses `DatePipe` to display the current date in the format for the locale in `LOCALE_ID`. -2. Create a translation file: Use the Angular CLI `xi18n` command to extract the marked text into an industry-standard translation source file. +To override the value of `LOCALE_ID`, add the `locale` parameter. +For example, to force the currency to use `en-US` no matter which language-locale you set for `LOCALE_ID`, use this form: `{{amount | currency : 'en-US'}}`. -3. Edit the generated translation file: Translate the extracted text into the target language. +{@a Template-translations} -4. Add the target locale and language translation to the application's configuration. +## Prepare templates for translations -5. Merge the completed translation file into the application. To do this, use the Angular CLI `build` command to compile the app, choosing a [locale-specific configuration](#merge), or specifying the `--localize` [option](#localize-config). The command replaces the original messages with translated text, and generates a new version of the app in the target language. - * When using individual configurations per locale, you need to build and deploy a separate version of the app for each supported language. - * When using the `--localize` option, the CLI will automatically build a separate version of the application -for each supported language. This option shortens the build process by removing the requirement to perform a full application build for each supported language. You still need to deploy each language-specific version separately. +To translate your app's templates, you need to prepare the text for a translator or translation service by marking text, attributes, and other elements with the Angular `i18n` attribute. +Follow these general steps: + +1. [Mark text for translations](#i18n-attribute). +2. [Add helpful descriptions and meanings](#help-translator) to help the translator with additional information or context. +3. [Translate text not for display](#no-element). +4. [Mark element attributes for translations](#translate-attributes), such as an image's `title` attribute. +5. [Mark plurals and alternates for translation](#plurals-alternates) in order to comply with the pluralization rules and grammatical constructions of different languages. {@a i18n-attribute} -### Mark text with the i18n attribute -The Angular `i18n` attribute marks translatable content. Place it on every element tag whose fixed -text is to be translated. +### Mark text for translations -In the example below, an `

` tag displays a simple English language greeting, "Hello i18n!" +Mark the static text messages in your component templates for translation using the `i18n` attribute. +Place it on every element tag with fixed text to be translated. + +For example, the following `

` tag displays a simple English language greeting, "Hello i18n!" @@ -158,259 +162,227 @@ To mark the greeting for translation, add the `i18n` attribute to the `

` tag -
- `i18n` is a custom attribute, recognized by Angular tools and compilers. - After translation, the compiler removes it. It is not an Angular directive. +`i18n` is a custom attribute, recognized by Angular tools and compilers. +After translation, the compiler removes it. It is not an Angular directive.
- {@a help-translator} -### Help the translator with a description and meaning + +### Add helpful descriptions and meanings To translate a text message accurately, the translator may need additional information or context. - -You can add a description of the text message as the value of the `i18n` attribute, as shown in the -example below: +Add a _description_ of the text message as the value of the `i18n` attribute, as shown in the following example: -The translator may also need to know the meaning or intent of the text message within this particular -app context. +The translator may also need to know the meaning or intent of the text message within this particular app context, in order to translate it the same way as other text with the same meaning. +Start the `i18n` attribute value with the _meaning_ and +separate it from the _description_ with the `|` character: `|`. -You add context by beginning the `i18n` attribute value with the _meaning_ and -separating it from the _description_ with the `|` character: `|` +For example, you can add the meaning that this `

` tag is a site header that needs to be translated the same way not only when used as a header, but also when referred to from another section of text: -All occurrences of a text message that have the same meaning will have the same translation. -A text message that is associated with different meanings can have different translations. +As a result, any text marked with `site header` as the _meaning_ is translated exactly the same way. -The Angular extraction tool preserves both the meaning and the description in the translation -source file to facilitate contextually-specific translations, but only the combination of meaning -and text message are used to generate the specific id of a translation. If you have two -similar text messages with different meanings, they are extracted separately. If you have two similar -text messages with different descriptions (not different meanings), then they are extracted only once. +{@a transaction-unit-ids} +
+
How meanings control text extraction and merging
-{@a custom-id} -### Set a custom id for persistence and maintenance +The Angular extraction tool (described in [Work with translation files](#ng-xi18n) in this guide) generates a translation unit entry for each `i18n` +attribute in a template. +It assigns each translation unit a unique ID based on the _meaning_ and _description_. -The angular i18n extractor tool generates a file with a translation unit entry for each `i18n` -attribute in a template. By default, it assigns each translation unit a unique id such as this one: +The same text elements with different _meanings_ are extracted with separate IDs. +For example, if the word "right" appears with the meaning `correct` (as in "You are right") in one place, and with the meaning `direction` (as in "Turn right") in another place, the word is translated differently and merged back into the app as different translation entries. - - -When you change the translatable text, the extractor tool generates a new id for that translation unit. -You must then update the translation file with the new id. - -Alternatively, you can specify a custom id in the `i18n` attribute by using the prefix `@@`. -The example below defines the custom id `introductionHeader`: - - - -When you specify a custom id, the extractor tool and compiler generate a translation unit with that -custom id. - - - -The custom id is persistent. The extractor tool does not change it when the translatable text changes. -Therefore, you do not need to update the translation. This approach makes maintenance easier. - -#### Use a custom id with a description - -You can use a custom id in combination with a description by including both in the value of the -`i18n` attribute. In the example below, the `i18n` attribute value includes a description, followed -by the custom `id`: - - - -You also can add a meaning, as shown in this example: - - - -#### Define unique custom ids - -Be sure to define custom ids that are unique. If you use the same id for two different text messages, -only the first one is extracted, and its translation is used in place of both original text messages. - -In the example below the custom id `myId` is used for two different messages: - - ```html -

Hello

- -

Good bye

- ``` - -Consider this translation to French: - - ```xml - - Hello - Bonjour - - ``` - -Because the custom id is the same, both of the elements in the resulting translation contain -the same text, `Bonjour`: - - ```html -

Bonjour

- -

Bonjour

- ``` - - - -{@a no-element} -### Translate text without creating an element - -If there is a section of text that you would like to translate, you can wrap it in a `` tag. -However, if you don't want to create a new DOM element merely to facilitate translation, -you can wrap the text in an `` element. -The `` is transformed into an html comment: - - - -{@a translate-attributes} -### Translate attributes - -Displayed text is sometimes supplied as the value of an attribute, rather than the content of tag. -For example, if your template has an image with a `title` attribute, the text value of the `title` attribute needs to be translated. - - - -To mark an attribute for translation, add an attribute in the form of `i18n-x`, -where `x` is the name of the attribute to translate. The following example shows how to mark the -`title` attribute for translation by adding the `i18n-title` attribute on the `img` tag: - - - -This technique works for any attribute of any element. - -You also can assign a meaning, description, and id with the `i18n-x="|@@"` -syntax. - -## Regular expressions for plurals and selections - -Different languages have different pluralization rules and grammatical constructions that add -complexity to the translation task. -You can use regular expressions with the `plural` and `select` clauses to provide patterns that aid translation in these cases. - -{@a plural-ICU} -### Pluralization - -Suppose that you want to say that something was "updated x minutes ago". -In English, depending upon the number of minutes, you could display "just now", "one minute ago", -or "x minutes ago" (with x being the actual number). -Other languages might express the cardinality differently. - -The example below shows how to use a `plural` ICU expression to display one of those three options -based on when the update occurred: - - - -* The first parameter is the key. It is bound to the component property (`minutes`), which determines -the number of minutes. -* The second parameter identifies this as a `plural` translation type. -* The third parameter defines a pluralization pattern consisting of pluralization categories and their matching values. - - -
- - This syntax conforms to the - ICU Message Format - as specified in the - CLDR pluralization rules. +If the same text elements have different _descriptions_ but the same _meaning_, they are extracted only once, with only one ID. That one translation entry is merged back into the app wherever the same text elements appear.
-Pluralization categories include (depending on the language): +{@a no-element} -* =0 (or any other number) -* zero -* one -* two -* few -* many -* other +### Translate text not for display -After the pluralization category, put the default English text in braces (`{}`). +While you can translate non-displayed text using a `` tag, you are creating a new DOM element. To avoid doing so, wrap the text in an `` element, which is transformed into a non-displayed HTML comment as shown in this example: -In the example above, the three options are specified according to that pluralization pattern. For -talking about zero minutes, you use `=0 {just now}`. For one minute, you use `=1 {one minute}`. -Any unmatched cardinality uses `other {{{minutes}} minutes ago}`. You could choose to add patterns -for two, three, or any other number if the pluralization rules were different. For the example of -"minute", only these three patterns are necessary in English. + + +{@a translate-attributes} + +### Mark element attributes for translations + +HTML attributes such as `title` include text that should be translated along with the rest of the displayed text in the template. +The following example shows an image with a `title` attribute: + + + +To mark an attribute for translation, add `i18n-`*attribute* in which *attribute* is the attribute to translate. +The following example shows how to mark the +`title` attribute on the `img` tag by adding `i18n-title`: + + + +You can use `i18n-`*attribute* with any attribute of any element. +You also can assign a meaning, description, and custom ID with the `i18n-`*attribute*`="|@@"` syntax. + +{@a plurals-alternates} + +### Mark plurals and alternates for translation + +Different languages have different pluralization rules and grammatical constructions that can make translation difficult. +To simplify translation, use International Components for Unicode (ICU) clauses with regular expressions, such as `plural` to mark the uses of plural numbers, and `select` to mark alternate text choices.
- You can use interpolations and html markup inside of your translations. +The ICU clauses adhere to the [ICU Message Format](http://userguide.icu-project.org/formatparse/messages "ICU Message Format") specified in the [CLDR pluralization rules](http://cldr.unicode.org/index/cldr-spec/plural-rules "Pluralization Rules"). + +
+ +{@a plural-ICU} + +#### Mark plurals + +Use the `plural` clause to mark expressions that may not be meaningful if translated word-for-word. + +For example, if you want to display "updated x minutes ago" in English, you may want to display "just now", "one minute ago", or "_x_ minutes ago" (with _x_ as the actual number). +Other languages might express this cardinality differently. +The following example shows how to use a `plural` clause to express these three options: + + + +In the above example: + +* The first parameter, `minutes`, is bound to the component property (`minutes`), which determines the number of minutes. + +* The second parameter identifies this as a `plural` translation type. + +* The third parameter defines a pattern of pluralization categories and their matching values: + * For zero minutes, use `=0 {just now}`. + * For one minute, use `=1 {one minute}`. + * For any unmatched cardinality, use `other {{{minutes}} minutes ago}`. + You can use HTML markup and [interpolations](guide/glossary#interpolation "Definition of interpolation") such as `{{{minutes}}` with the `plural` clause in expressions. + * After the pluralization category, put the default text (English) within braces (`{}`). + +Pluralization categories include (depending on the language): + +* `=0` (or any other number) +* `zero` +* `one` +* `two` +* `few` +* `many` +* `other` + +
+
Locales may not support some pluralization categories
+ +Many locales don't support some of the pluralization categories. +For example, the default locale (`en-US`) and other locales (such as `es`) have very simple `plural()` functions that don't support the `few` category. +The following shows the [en-US](https://github.com/angular/angular/blob/ecffc3557fe1bff9718c01277498e877ca44588d/packages/core/src/i18n/locale_en.ts#L15-L18) `plural()` function: + +``` +function plural(n: number): number { + let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + if (i === 1 && v === 0) return 1; + return 5; +} +``` + +The function will only ever return 1 (`one`) or 5 (`other`). +The `few` category will never match. +If none of the pluralization categories match, Angular will try to match `other`. +Use `other` as the standard fallback for a missing category. + +For more information about pluralization categories, see [Choosing plural category names](http://cldr.unicode.org/index/cldr-spec/plural-rules#TOC-Choosing-Plural-Category-Names) in the CLDR - Unicode Common Locale Data Repository.
{@a select-ICU} -### Select among alternative text messages +{@a nesting-ICUS} -If your template needs to display different text messages depending on the value of a variable, you -need to translate all of those alternative text messages. +### Mark alternates and nested expressions -You can handle this with a `select` ICU expression. It is similar to the `plural` expressions -except that you choose among alternative translations based on a string value instead of a number, -and you define those string values. +If you need to display alternate text depending on the value of a variable, you +need to translate all of the alternates. -The following format message in the component template binds to the component's `gender` property, -which outputs one of the following string values: "male", "female" or "other". -The message maps those values to the appropriate translations: +The `select` clause, similar to the `plural` clause, marks choices for alternate text based on your defined string values. +For example, the following clause in the component template binds to the component's `gender` property, which outputs one of the following string values: "male", "female" or "other". +The clause maps those values to the appropriate translations: -{@a nesting-ICUS} -### Nesting plural and select ICU expressions - -You can also nest different ICU expressions together, as shown in this example: +You can also nest different clauses together, such as the `plural` and `select` clauses in the following example: {@a ng-xi18n} {@a ng-xi18n-options} +{@a translate} -## Create a translation source file +## Work with translation files -When your app is ready, you can use the Angular CLI to extract the text messages marked with `i18n` and attributes marked with `i18n-x` into a translation source file. -Open a terminal window at the root of the app project and run the CLI command `xi18n`. +After preparing a template for translation, use the Angular CLI `xi18n` command to extract the marked text in the template into a _source language_ file. +The marked text includes text marked with `i18n` and attributes marked with `i18n-`*attribute* as described in the previous section. +Follow these steps: + +1. [Extract the source language file](#create-source). +You can optionally change the location, format, and name. +2. [Create a translation file for each language](#localization-folder) by copying the source language file. +3. [Translate each translation file](#translate-text-nodes). +4. [Translate plurals and alternate expressions](#translate-plural-select) separately. + +{@a create-source} + +### Extract the source language file + +To extract the source language file, open a terminal window, change to the root directory of your app project, and run the following CLI command: ng xi18n -By default, the command creates a file named `messages.xlf` in your project's root directory. +The `xi18n` command creates a source language file named `messages.xlf` in your project's root directory using the [XML Localization Interchange File Format (XLIFF, version 1.2)](https://en.wikipedia.org/wiki/XLIFF "Wikipedia page about XLIFF"). -{@a other-formats} -### Output options +Use the following `xi18n` command options to change the source language file location, format, and file name: -You can supply command options to change the format, the name, the location, and the source locale of the extracted file. -For example, to create a file in the `src/locale` folder, specify the output path: +* `--output-path`: Change the location. +* `--format`: Change the format. +* `--outFile`: Change the file name. + +Note: The `--i18n-locale` option is deprecated. +Angular 9 uses the source locale configured in your app's [workspace configuration](guide/workspace-config "Angular workspace configuration") file (`angular.json`). + +
+ +The ng xi18n extraction mechanism uses the ViewEngine compiler, which is not able to cope with some code syntax that the Ivy compiler can handle. A fix for this issue is currently under development. To follow or contribute to this fix see [PR 32912](https://github.com/angular/angular/pull/32912). + +
+ +#### Change the source language file location + +To create a file in the `src/locale` directory, specify the output path as an option, as shown in the following example: ng xi18n --output-path src/locale -By default, the `xi18n` command generates a translation file named `messages.xlf` in the -XML Localization Interchange File Format -(XLIFF, version 1.2). +{@a other-formats} + +#### Change the source language file format + +The `xi18n` command can read and write files in three translation formats: -The command can read and write files in three translation formats: * XLIFF 1.2 (default) * XLIFF 2 -* XML Message -Bundle (XMB) +* [XML Message Bundle (XMB)](http://cldr.unicode.org/development/development-process/design-proposals/xmb) -You can specify the translation format explicitly with the `--format` command option, as illustrated in -these example commands: +Specify the translation format explicitly with the `--format` command option, as shown in the following examples: ng xi18n --format=xlf @@ -418,235 +390,200 @@ ng xi18n --format=xlf2 ng xi18n --format=xmb -The sample in this guide uses the default XLIFF 1.2 format. -
- XLIFF files have the extension .xlf. The XMB format generates .xmb source files but uses - .xtb (XML Translation Bundle: XTB) translation files. + XLIFF files use the extension `.xlf`. + The XMB format generates `.xmb` source language files but uses`.xtb` (XML Translation Bundle: XTB) translation files.
-You can change the name of the translation source file that is generated by the extraction tool with +#### Change the source language file name + +To change the name of the source language file generated by the extraction tool, use the `--outFile` command option: - ng xi18n --out-file source.xlf - -You can specify the base locale of your app with the`--i18n-locale` command option: - - - - ng xi18n --i18n-locale fr - - - -The extraction tool uses the locale to add the app locale information into your translation source -file. This information is not used by Angular, but external translation tools may need it. - - -{@a translate} -## Translate the source text - -By default, the `ng xi18n` command generates a translation source file named `messages.xlf` in the project `src` folder. -The next step is to translate the display strings in this source file into language-specific -translation files. The example in this guide creates a French translation file. - {@a localization-folder} -### Create a localization folder -Most apps are translated into more than one other language. For this reason, it is standard practice -for the project structure to reflect the entire internationalization effort. +### Create a translation file for each language -One approach is to dedicate a folder to localization and store related assets, such as -internationalization files, there. +The `ng xi18n` command (with no options) generates a source language file named `messages.xlf` in the project `src` folder. +Create *translation* files for each language by copying the source language file. +To avoid confusion with multiple translations, you should organize the language translation files by locale in a dedicated `locale` folder under `src/`. +Use a filename extension that matches the associated locale, such as `messages.fr.xlf`. -
+For example, to create a French translation file, follow these steps: - Localization and internationalization are - different but - closely related terms. +1. Make a copy of the `messages.xlf` source language file. +2. Put the copy in the `src/locale` folder. +3. Rename the copy to `messages.fr.xlf` for the French language (`fr`) translation. +Send this translation file to the translator. -
- -This guide follows that approach. It has a `locale` folder under `src/`. -Assets within that folder have a filename extension that matches their associated locale. - -### Create the translation files - -For each translation source file, there must be at least one language translation file for the -resulting translation. - -For this example: - -1. Make a copy of the `messages.xlf` file. -2. Put the copy in the `locale` folder. -3. Rename the copy to `messages.fr.xlf` for the French language translation. - -If you were translating to other languages, you would repeat these steps for each target language. +Repeat the above steps for each language you want to add to your app. {@a translate-text-nodes} -### Translate text nodes -In a large translation project, you would send the `messages.fr.xlf` file to a French translator who -would enter the translations using an XLIFF file editor. +### Translate each translation file -This sample file is easy to translate without a special editor or knowledge of French. +Unless you are fluent in the language and have the time to edit translations, you would likely send each translation file to a translator, who would then use an XLIFF file editor to create and edit the translation. -1. Open `messages.fr.xlf` and find the first `` section: +To demonstrate this process, see the `messages.fr.xlf` file in the , which includes a French translation you can edit without a special XLIFF editor or knowledge of French. +Follow these steps: + +1. Open `messages.fr.xlf` and find the first `` element. This is a *translation unit*, also known as a *text node*, representing the translation of the `

` greeting tag that was previously marked with the `i18n` attribute: > -> This XML element represents the translation of the `

` greeting tag that you marked with the - `i18n` attribute earlier in this guide. +> The `id="introductionHeader""` is a [custom ID](#custom-id "Manage marked text with custom IDs"), but without the `@@` prefix required in the source HTML. -> Note that the translation unit `id=introductionHeader` is derived from the - [custom `id`](#custom-id "Set a custom id") that you set earlier, but - without the `@@` prefix required in the source HTML. - - -2. Duplicate the `` tag, rename it `target`, and then replace its content with the French - greeting. If you were working with a more complex translation, you could use the information - and context provided by the source, description, and meaning elements to guide your selection of - the appropriate French translation. +2. Duplicate the `...` element in the text node, rename it `target`, and then replace its content with the French text: > -3. Translate the other text nodes the same way: +> In a more complex translation, the information and context in the [description and meaning elements](#help-translator "Add helpful descriptions and meanings") described previously would help you choose the right words for translation. + +3. Translate the other text nodes the same way as shown in the following example: >
- **The Angular i18n tools generated the ids for these translation units. Don't change them.** - Each `id` depends upon the content of the template text and its assigned meaning. + Don't change the IDs for translation units. + Each `id` is generated by Angular and depends on the content of the template text and its assigned meaning. If you change either the text or the meaning, then the `id` changes. - For more information, see the **[translation file maintenance discussion](#custom-id)**. + For more about managing text updates and IDs, see the previous section on [custom IDs](#custom-id "Manage marked text with custom IDs").
{@a translate-plural-select} -## Translating plural and select expressions -The _plural_ and _select_ ICU expressions are extracted separately, so they require special attention -when preparing for translation. +### Translate plurals and alternate expressions -Look for these expressions in relation to other translation units that you recognize from -elsewhere in the source template. In this example, you know the translation unit for the `select` -must be just below the translation unit for the logo. +The [`plural` and `select` ICU expressions](#plurals-alternates "Mark plurals and alternates for translation") are extracted as additional messages, so you must translate them separately. {@a translate-plural} -### Translate _plural_ -To translate a `plural`, translate its ICU format match values: +#### Translate plurals + +To translate a `plural`, translate its ICU format match values as shown in the following example: + +* `just now` +* `one minute ago` +* ` minutes ago` -You can add or remove plural cases, with each language having its own cardinality. (See -[CLDR plural rules](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html).) +You can add or remove plural cases as needed for each language. + +
+ +For language plural rules, see +[CLDR plural rules](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html "CLDR Charts to view the Common Locale Data Repository data"). + +
{@a translate-select} -### Translate _select_ -Below is the content of our example `select` ICU expression in the component template: +#### Translate alternate expressions + +Angular also extracts alternate `select` ICU expressions as separate translation units. +The following shows a `select` ICU expression in the component template: -The extraction tool broke that into two translation units because ICU expressions are extracted -separately. - -The first unit contains the text that was outside of the `select`. -In place of the `select` is a placeholder, ``, that represents the `select` message. -Translate the text and move around the placeholder if necessary, but don't remove it. If you remove -the placeholder, the ICU expression will not be present in your translated app. +In this example, Angular extracts the expression into two translation units. The first contains the text outside of the `select` clause, and uses a placeholder for `select` (``): -The second translation unit, immediately below the first one, contains the `select` message. -Translate that as well. +
+ +When translating the text, you can move the placeholder if necessary, but don't remove it. +If you remove the placeholder, the ICU expression will not appear in your translated app. + +
+ +The second translation unit contains the `select` clause: -Here they are together, after translation: +The following example shows both translation units after translating: {@a translate-nested} -### Translate a nested expression -A nested expression is similar to the previous examples. As in the previous example, there are -two translation units. The first one contains the text outside of the nested expression: +#### Translate nested expressions + +Angular treats a nested expression in the same manner as an alternate expression, extracting it into two translation units. The first contains the text outside of the nested expression: -The second unit contains the complete nested expression: +The second translation unit contains the complete nested expression: -And both together: +The following example shows both translation units after translating: -The entire template translation is complete. The next section describes how to load that translation -into the app. - -{@a app-pre-translation} -### The app and its translation file - -The sample app and its translation file are now as follows: - - - - - - - - - - - - - - {@a merge} -## Merge the completed translation file into the app - -To merge the translated text into component templates, compile the app with the completed -translation file. You will need to provide the path to the translation file, and the supported locale or locales for which you have provided translations. You can do this on the command line, or through a build configuration in the project's `angular.json` file. - -The compilation process is the same whether the translation file is in `.xlf` format or in another -format that Angular understands, such as `.xtb`. - {@a merge-aot} -The [AOT compiler](guide/glossary#aot) is part of a build process that produces a small, fast, -ready-to-run application package. With Ivy in Angular version 9, AOT is used by default for both -development and production builds. + +## Merge translations into the app + +To merge the completed translations into the app, use the [Angular CLI](guide/glossary#command-line-interface-cli "Definition of CLI") to build a copy of the app's distributable files for each locale. +The build process replaces the original text with translated text, and sets the `LOCALE_ID` token for each distributable copy of the app. +It also loads and registers the locale data. + +After merging, you can serve each distributable copy of the app using server-side language detection or different subdirectories, as described in the next section about [deploying multiple locales](#deploy-locales). + +The build process uses [ahead-of-time (AOT) compilation](guide/glossary#ahead-of-time-aot-compilation) to produce a small, fast, +ready-to-run app. With Ivy in Angular version 9, AOT is used by default for both +development and production builds, and AOT is required to localize component templates. + +
+ +For a detailed explanation the build process, see [Building and serving Angular apps](guide/build "Building and serving Angular apps"). +This build process works for translation files in the `.xlf` format or in another format that Angular understands, such as `.xtb`. + +
Ivy does not support merging i18n translations when using JIT mode. -If you [disable Ivy](guide/ivy#opting-out-of-ivy-in-version-9) and are using JIT mode, -additional information regarding translation merging can be found [here](https://v8.angular.io/guide/i18n#merge-with-the-jit-compiler). +If you [disable Ivy](guide/ivy#opting-out-of-ivy-in-version-9) and are using JIT mode, see [merging with the JIT compiler](https://v8.angular.io/guide/i18n#merge-with-the-jit-compiler "Merge with the JIT compiler").
-When you internationalize with the AOT compiler, you must build a separate application -package for each language and serve the appropriate package based on either server-side language -detection or URL parameters. The CLI can be configured to automatically build separate locale-specific versions -for each defined locale. +To build a separate distributable copy of the app for each locale, [define the locales in the build configuration](#localize-config) in your project's workspace configuration file [`angular.json`](guide/workspace-config "Angular workspace configuration"). +This method shortens the build process by removing the requirement to perform a full app build for each locale. + +You can then [generate app versions for each locale](#localize-generate) using the `"localize"` option in `angular.json`. You can also [build from the command line](#localize-build-command) using the Angular CLI [`build`](/cli/build "CLI reference for ng build") command with the `--localize` option. + +
+ +You can optionally [apply specific build options for just one locale](#localize-build-one-locale) for a custom locale configuration. + +
{@a localize-config} -The `i18n` project option in your CLI configuration file is used to define locales for a project. The sub-options identify the source language and tell the compiler where to find supported translations for the project. - * `sourceLocale` - The locale used within the source code for the application. Defaults to `en-US`. - * `locales` - A map of locale identifiers to translation files +### Define locales in the build configuration + +Use the `i18n` project option in your app's build configuration file ([`angular.json`](guide/workspace-config "Angular workspace configuration")) to define locales for a project. +The following sub-options identify the source language and tell the compiler where to find supported translations for the project: + +* `sourceLocale`: The locale you use within the app source code (`en-US` by default) +* `locales`: A map of locale identifiers to translation files + +For example, the following excerpt of an `angular.json` file sets the source locale to `en-US` and provides the path to the `fr` (French) locale translation file: +... "projects": { - ... "angular.io-example": { ... "i18n": { @@ -654,32 +591,71 @@ The `i18n` project option in your CLI configuration file is used to define local "locales": { "fr": "src/locale/messages.fr.xlf" } - } + }, + "architect": { ... - "targets": { - ... } - } } -To instruct the AOT compiler to use your translation configuration, set the `localize` build configuration option in your CLI configuration file, `angular.json`. The option supports the following values: +{@a localize-generate} - * `true` - Build and generate locale-specific versions for all defined locales including the source locale. - * `false` - (default) Disable localization and do not generate locale-specific versions. - * Array of locale identifiers - Build and generate locale-specific versions for one or more specified locales. +### Generate app versions for each locale -When using the `localize` option, the CLI places the output in a locale-specific directory to keep it separate from other locale versions of your application. The directories are placed within the configured `outputPath` for the project. -The CLI also adjusts the HTML base HREF for each version of the application by adding the locale to the configured `baseHref`. +To use your locale definition in the build configuration, use the `"localize"` option in `angular.json` to tell the CLI which locales to generate for the build configuration: -You can also provide the `--localize` option to the `ng build` command with your existing `production` configuration. -In this case, the CLI builds all locales defined under i18n in the project configuration. +* Set `"localize"` to `true` for *all* the locales previously defined in the build configuration. +* Set `"localize"` to an array of a subset of the previously-defined locale identifiers to build only those locale versions. +* Set `"localize"` to `false` to disable localization and not generate any locale-specific versions. + +
+ +Note: [Ahead-of-time (AOT) compilation](guide/glossary#ahead-of-time-aot-compilation) is required to localize component templates. +If you changed this setting, set `"aot"` to `true` in order to use AOT. + +
+ +The following example shows the `"localize"` option set to `true` in `angular.json` so that all locales defined in the build configuration are built: + + +"build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "localize": true, + "aot": true, + ... + + +
+ +Due to the deployment complexities of i18n and the need to minimize rebuild time, the development server only supports localizing a single locale at a time. +Setting the `"localize"` option to `true` will cause an error when using `ng serve` if more than one locale is defined. +Setting the option to a specific locale, such as `"localize": ["fr"]`, can work if you want to develop against a specific locale (such as `fr`). + +
+ +The CLI loads and registers the locale data, places each generated version in a locale-specific directory to keep it separate from other locale versions, and puts the directories within the configured `outputPath` for the project. +For each application variant the `lang` attribute of the `html` element is set to the locale. +The CLI also adjusts the HTML base HREF for each version of the app by adding the locale to the configured `baseHref`. + +You can set the `"localize"` property as a shared configuration that all the configurations effectively inherit (or can override). + +{@a localize-build-command} + +### Build from the command line + +You can also use the `--localize` option with the [`ng build`](/cli/build "CLI reference for ng build") command and your existing `production` configuration. +The CLI builds all locales defined in the build configuration, which is similar to setting the `"localize"` option to `true` as described in the previous section. ng build --prod --localize -To apply specific build options to only one locale, you can create a custom locale-specific configuration. In this case, the localize option specifies the single locale, as shown here. +{@a localize-build-one-locale} + +### Apply specific build options for just one locale + +To apply specific build options to only one locale, you can create a custom locale-specific configuration by specifying a single locale as shown in the following example: "build": { @@ -705,8 +681,7 @@ To apply specific build options to only one locale, you can create a custom loca You can then pass this configuration to the `ng serve` or `ng build` commands. -The example below shows how to serve the French language file created in previous -sections of this guide: +The following shows how to serve the French language file created in the example for this guide: ng serve --configuration=fr @@ -714,7 +689,7 @@ sections of this guide:
-The CLI development server (`ng serve`) can only be used with a single locale. +You can use the CLI development server (`ng serve`), but only with a single locale.
@@ -755,18 +730,18 @@ For production builds, you can use configuration composition to execute both con
{@a missing-translation} + ### Report missing translations -By default, when a translation is missing, the build succeeds but generates a warning such as -`Missing translation for message "foo"`. You can configure the level of warning that is generated by -the Angular compiler: +When a translation is missing, the build succeeds but generates a warning such as +`Missing translation for message "foo"`. You can configure the level of warning that is generated by the Angular compiler: -* Error: throw an error. If you are using AOT compilation, the build will fail. If you are using JIT -compilation, the app will fail to load. -* Warning (default): show a 'Missing translation' warning in the console or shell. -* Ignore: do nothing. +* `error`: Throw an error. If you are using AOT compilation, the build will fail. +If you are using JIT compilation, the app will fail to load. +* `warning` (default): Show a `Missing translation` warning in the console or shell. +* `ignore`: Do nothing. -You specify the warning level in the `options` section for the `build` target of your Angular CLI configuration file, `angular.json`. The example below shows how to set the warning level to error. +Specify the warning level in the `options` section for the `build` target of your Angular CLI configuration file (`angular.json`). The following example shows how to set the warning level to `error`: "options": { @@ -775,6 +750,161 @@ You specify the warning level in the `options` section for the `build` target of } -### Deployment for multiple locales +{@a deploy-locales} -For more details about how to create scripts to generate an app in multiple languages and how to set up Apache 2 and NGINX to serve them from different subdirectories, read [this tutorial by Philippe Martin](https://dev.to/angular/deploying-an-i18n-angular-app-with-angular-cli-2fb9). +## Deploy multiple locales + +If `myapp` is the directory containing your app's distributable files, you would typically make available different versions for different locales in locale directories such as `myapp/fr` for the French version and `myapp.com/es` for the Spanish version. + +The HTML `base` tag with the `href` attribute specifies the base URI, or URL, for relative links. If you set the `"localize"` option in `angular.json` to `true` or to an array of locale IDs, the CLI adjusts the base `href` for each version of the app by adding the locale to the configured `"baseHref"`. You can specify the `"baseHref"` for each locale in your workspace configuration file (`angular.json`), as shown in the following example, which sets `"baseHref"` to an empty string: + + +... +"projects": { + "angular.io-example": { + ... + "i18n": { + "sourceLocale": "en-US", + "locales": { + "fr": "src/locale/messages.fr.xlf" + "baseHref": "" + } + }, + "architect": { + ... + } +} + + +You can also use the CLI `--baseHref` option with [`ng build`](cli/build "CLI reference for ng build") to declare the base `href` at compile time. + +Configuring servers for hosting multiple locales is outside the scope of this guide. +For details on how to deploy apps to a remote server, see [Deployment](guide/deployment "Deployment guide"). + +{@a app-pre-translation} + +## Explore the translated example app + +The following tabs show the example app and its translation files: + + + + + + + + + + + + + + +## Optional practices + +The following are optional practices that may be required in special cases: + +* [Set the source locale manually](#set-source-manually) by setting the [LOCALE_ID](https://angular.io/api/core/LOCALE_ID "API reference for LOCALE_ID") token. +* [Import global variants of the locale data](#import-locale) for extra locale data. +* [Manage marked text with custom IDs](#custom-id) if you require more control over matching translations. + +{@a set-source-manually} + +### Set the source locale manually + +Angular already contains locale data for `en-US`. +The Angular CLI automatically includes the locale data and sets the `LOCALE_ID` value when you use the `--localize` option with [`ng build`](cli/build "ng build description"). + +To manually set an app's source locale to one other than the automatic value, follow these steps: + +1. Look up the ID for the language-locale combination in [the Angular repository](https://github.com/angular/angular/tree/master/packages/common/locales "Common locales in the Angular repository"). +2. Set the [`LOCALE_ID`](api/core/LOCALE_ID "API reference for LOCALE_ID") token. +The following example sets the value of `LOCALE_ID` to `fr` (French): + + + +{@a import-locale} + +### Import global variants of the locale data + +Angular will automatically include locale data if you configure the locale using the `--localize` option with [`ng build`](cli/build "ng build description") CLI command. + +The [Angular repository](https://github.com/angular/angular/tree/master/packages/common/locales "Common locales in the Angular repository") files (`@angular/common/locales`) contain most of the locale data that you need, but some advanced formatting options require additional locale data. +Global variants of the locale data are available in [`@angular/common/locales/global`](https://github.com/angular/angular/tree/master/packages/common/locales/global "Global locale variants in the Angular repository"). +The following example imports the global variants for French (`fr`): + + +import '@angular/common/locales/global/fr; + + +{@a custom-id} + +### Manage marked text with custom IDs + +The Angular extractor generates a file with a translation unit entry for each `i18n` +attribute in a template. +As described previously (in [How meanings control text extraction and merging](#transaction-unit-ids)), Angular assigns each translation unit a unique ID such as the following: + + + +When you change the translatable text, the extractor generates a new ID for that translation unit. +In most cases a text change would also require a change to the translation. +Therefore, using a new ID keeps the text change in sync with translations. + +However, some translation systems require a specific form or syntax for the ID. +To address this requirement, you can mark text with _custom_ IDs. +While most developers don't need to use custom IDs, some may want to use IDs that have a unique syntax to convey additional metadata (such as the library, component, or area of the app in which the text appears). + +Specify a custom ID in the `i18n` attribute by using the prefix `@@`. +The following example defines the custom ID `introductionHeader`: + + + +When you specify a custom ID, the extractor generates a translation unit with the custom ID: + + + +If you change the text, the extractor does *not* change the ID. +As a result, you don't have to take the extra step of updating the translation. +The drawback of using custom IDs is that if you change the text, your translation may be out-of-sync with the newly changed source text. + +#### Use a custom ID with a description + +Use a custom ID in combination with a description and a meaning to further help the translator. +The following example includes a description, followed by the custom `id`: + + + +The following example adds a meaning: + + + +#### Define unique custom IDs + +Be sure to define custom IDs that are unique. +If you use the same ID for two different text elements, the extraction tool extracts only the first one, and Angular uses its translation in place of both original text elements. + +For example, in the following code the same custom ID `myId` is defined for two different text elements: + + ```html +

Hello

+ +

Good bye

+ ``` + +The following shows the translation to French: + + ```xml + + Hello + Bonjour + + ``` + +Both elements now use the same translation (`Bonjour`) because they were defined with the same custom ID: + + ```html +

Bonjour

+ +

Bonjour

+ ``` diff --git a/aio/tools/examples/run-example-e2e.js b/aio/tools/examples/run-example-e2e.js index 6470cbd4b3..d5798fecfe 100644 --- a/aio/tools/examples/run-example-e2e.js +++ b/aio/tools/examples/run-example-e2e.js @@ -23,10 +23,7 @@ const DEFAULT_CLI_EXAMPLE_PORT = 4200; const DEFAULT_CLI_SPECS_CONCURRENCY = 1; const IGNORED_EXAMPLES = []; -const fixmeIvyExamples = [ - // fixmeIvy('unknown') app fails at runtime due to missing external service (goog is undefined) - 'i18n', -]; +const fixmeIvyExamples = []; if (!argv.viewengine) { IGNORED_EXAMPLES.push(...fixmeIvyExamples); @@ -72,8 +69,10 @@ function runE2e() { const outputFile = path.join(AIO_PATH, './protractor-results.txt'); return Promise.resolve() - .then(() => findAndRunE2eTests(argv.filter, outputFile, argv.shard, - argv.cliSpecsConcurrency || DEFAULT_CLI_SPECS_CONCURRENCY, argv.retry || 1)) + .then( + () => findAndRunE2eTests( + argv.filter, outputFile, argv.shard, + argv.cliSpecsConcurrency || DEFAULT_CLI_SPECS_CONCURRENCY, argv.retry || 1)) .then((status) => { reportStatus(status, outputFile); if (status.failed.length > 0) { @@ -226,8 +225,12 @@ function runProtractorSystemJS(prepPromise, appDir, appRunSpawnInfo, outputFile) }); }) .then( - function() { return finish(appRunSpawnInfo.proc.pid, true); }, - function() { return finish(appRunSpawnInfo.proc.pid, false); }); + function() { + return finish(appRunSpawnInfo.proc.pid, true); + }, + function() { + return finish(appRunSpawnInfo.proc.pid, false); + }); } function finish(spawnProcId, ok) { @@ -263,15 +266,15 @@ function runE2eTestsCLI(appDir, outputFile, bufferOutput, port) { // `--no-webdriver-update` is needed to preserve the ChromeDriver version already installed. const config = loadExampleConfig(appDir); const testCommands = config.tests || [{ - cmd: 'yarn', - args: [ - 'e2e', - '--prod', - '--protractor-config=e2e/protractor-puppeteer.conf.js', - '--no-webdriver-update', - '--port={PORT}', - ], - }]; + cmd: 'yarn', + args: [ + 'e2e', + '--prod', + '--protractor-config=e2e/protractor-puppeteer.conf.js', + '--no-webdriver-update', + '--port={PORT}', + ], + }]; let bufferedOutput = `\n\n============== AIO example output for: ${appDir}\n\n`; const e2eSpawnPromise = testCommands.reduce((prevSpawnPromise, {cmd, args}) => { @@ -281,26 +284,30 @@ function runE2eTestsCLI(appDir, outputFile, bufferOutput, port) { args = args.map(a => a.replace('{PORT}', port || DEFAULT_CLI_EXAMPLE_PORT)); return prevSpawnPromise.then(() => { - const currSpawn = spawnExt(cmd, args, {cwd: appDir}, false, - bufferOutput ? msg => bufferedOutput += msg : undefined); + const currSpawn = spawnExt( + cmd, args, {cwd: appDir}, false, bufferOutput ? msg => bufferedOutput += msg : undefined); return currSpawn.promise.then( () => Promise.resolve(finish(currSpawn.proc.pid, true)), () => Promise.reject(finish(currSpawn.proc.pid, false))); }); }, Promise.resolve()); - return e2eSpawnPromise.then(() => { - fs.appendFileSync(outputFile, `Passed: ${appDir}\n\n`); - return true; - }, () => { - fs.appendFileSync(outputFile, `Failed: ${appDir}\n\n`); - return false; - }).then(passed => { - if (bufferOutput) { - process.stdout.write(bufferedOutput); - } - return passed; - }); + return e2eSpawnPromise + .then( + () => { + fs.appendFileSync(outputFile, `Passed: ${appDir}\n\n`); + return true; + }, + () => { + fs.appendFileSync(outputFile, `Failed: ${appDir}\n\n`); + return false; + }) + .then(passed => { + if (bufferOutput) { + process.stdout.write(bufferedOutput); + } + return passed; + }); } // Report final status. @@ -309,23 +316,31 @@ function reportStatus(status, outputFile) { log.push('Suites ignored due to legacy guides:'); IGNORED_EXAMPLES.filter(example => !fixmeIvyExamples.find(ex => ex.startsWith(example))) - .forEach(function(val) { log.push(' ' + val); }); + .forEach(function(val) { + log.push(' ' + val); + }); if (!argv.viewengine) { log.push(''); log.push('Suites ignored due to breakage with Ivy:'); - fixmeIvyExamples.forEach(function(val) { log.push(' ' + val); }); + fixmeIvyExamples.forEach(function(val) { + log.push(' ' + val); + }); } log.push(''); log.push('Suites passed:'); - status.passed.forEach(function(val) { log.push(' ' + val); }); + status.passed.forEach(function(val) { + log.push(' ' + val); + }); if (status.failed.length == 0) { log.push('All tests passed'); } else { log.push('Suites failed:'); - status.failed.forEach(function(val) { log.push(' ' + val); }); + status.failed.forEach(function(val) { + log.push(' ' + val); + }); } log.push('\nElapsed time: ' + status.elapsedTime + ' seconds'); log = log.join('\n'); @@ -334,8 +349,8 @@ function reportStatus(status, outputFile) { } // Returns both a promise and the spawned process so that it can be killed if needed. -function spawnExt(command, args, options, ignoreClose = false, - printMessage = msg => process.stdout.write(msg)) { +function spawnExt( + command, args, options, ignoreClose = false, printMessage = msg => process.stdout.write(msg)) { let proc; const promise = new Promise((resolve, reject) => { let descr = command + ' ' + args.join(' '); @@ -370,13 +385,19 @@ function getE2eSpecs(basePath, filter) { let specs = {}; return getE2eSpecsFor(basePath, SJS_SPEC_FILENAME, filter) - .then(sjsPaths => { specs.systemjs = sjsPaths; }) + .then(sjsPaths => { + specs.systemjs = sjsPaths; + }) .then(() => { return getE2eSpecsFor(basePath, CLI_SPEC_FILENAME, filter).then(cliPaths => { - return cliPaths.map(p => { return p.replace(`${CLI_SPEC_FILENAME}`, ''); }); + return cliPaths.map(p => { + return p.replace(`${CLI_SPEC_FILENAME}`, ''); + }); }); }) - .then(cliPaths => { specs.cli = cliPaths; }) + .then(cliPaths => { + specs.cli = cliPaths; + }) .then(() => specs); } diff --git a/aio/tools/examples/shared/boilerplate/i18n/angular.json b/aio/tools/examples/shared/boilerplate/i18n/angular.json index 11c01b2604..8934ab45e6 100644 --- a/aio/tools/examples/shared/boilerplate/i18n/angular.json +++ b/aio/tools/examples/shared/boilerplate/i18n/angular.json @@ -9,10 +9,18 @@ "root": "", "sourceRoot": "src", "prefix": "app", + "i18n": { + "sourceLocale": "en-US", + "locales": { + "fr": "src/locale/messages.fr.xlf" + } + }, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { + "localize": true, + "aot": true, "outputPath": "dist", "index": "src/index.html", "main": "src/main.ts", @@ -57,35 +65,10 @@ } ] }, - "production-fr": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "extractCss": true, - "namedChunks": false, - "aot": true, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, - "outputPath": "dist/my-project-fr/", - "i18nFile": "src/locale/messages.fr.xlf", - "i18nFormat": "xlf", - "i18nLocale": "fr", - "i18nMissingTranslation": "error" - }, "fr": { - "aot": true, - "outputPath": "dist/my-project-fr/", - "i18nFile": "src/locale/messages.fr.xlf", - "i18nFormat": "xlf", - "i18nLocale": "fr", - "i18nMissingTranslation": "error" + "localize": [ + "fr" + ] } } }, diff --git a/aio/tools/examples/shared/boilerplate/i18n/package.json b/aio/tools/examples/shared/boilerplate/i18n/package.json index 97778a60e6..6d10e0759b 100644 --- a/aio/tools/examples/shared/boilerplate/i18n/package.json +++ b/aio/tools/examples/shared/boilerplate/i18n/package.json @@ -20,6 +20,7 @@ "@angular/compiler": "~9.1.4", "@angular/core": "~9.1.4", "@angular/forms": "~9.1.4", + "@angular/localize": "^9.1.4", "@angular/platform-browser": "~9.1.4", "@angular/platform-browser-dynamic": "~9.1.4", "@angular/router": "~9.1.4", diff --git a/aio/tools/examples/shared/boilerplate/i18n/polyfills.ts b/aio/tools/examples/shared/boilerplate/i18n/polyfills.ts new file mode 100644 index 0000000000..d06dbf69c5 --- /dev/null +++ b/aio/tools/examples/shared/boilerplate/i18n/polyfills.ts @@ -0,0 +1,68 @@ +/*************************************************************************************************** + * Load `$localize` onto the global scope - used if i18n tags appear in Angular templates. + */ +import '@angular/localize/init'; +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + */ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch + * requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch + * specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/aio/tools/examples/shared/package.json b/aio/tools/examples/shared/package.json index 1323822ff3..4c64be04aa 100644 --- a/aio/tools/examples/shared/package.json +++ b/aio/tools/examples/shared/package.json @@ -26,6 +26,7 @@ "@angular/core": "~9.1.4", "@angular/elements": "~9.1.4", "@angular/forms": "~9.1.4", + "@angular/localize": "~9.1.4", "@angular/platform-browser": "~9.1.4", "@angular/platform-browser-dynamic": "~9.1.4", "@angular/platform-server": "~9.1.4", diff --git a/aio/tools/examples/shared/yarn.lock b/aio/tools/examples/shared/yarn.lock index 519caf9e2d..714f688230 100644 --- a/aio/tools/examples/shared/yarn.lock +++ b/aio/tools/examples/shared/yarn.lock @@ -215,6 +215,15 @@ resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-9.1.4.tgz#2fa2c444e5a5a6036d5ca43d2887826df17d0553" integrity sha512-eyVxxiegdb4ESdFGfkuDN+YfUbOVHRQLjIl6ACFJQDNHzVXzbmuqpyr5hIJANIVady103/7+dqRxxJo1DdIdTQ== +"@angular/localize@~9.1.4": + version "9.1.11" + resolved "https://registry.yarnpkg.com/@angular/localize/-/localize-9.1.11.tgz#25921d794836fb7a07d284c1ac0ed06c10e77d50" + integrity sha512-CrR7RniwJIK3+QKH8nHl35KDAHZn1mp1QAd5vujTWKw6YRLfio7SjM9qIfzw5y4WZuUitTsqKlQT/m/NK146Ag== + dependencies: + "@babel/core" "7.8.3" + glob "7.1.2" + yargs "15.3.0" + "@angular/platform-browser-dynamic@~9.1.4": version "9.1.4" resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.1.4.tgz#bf1cde9156bd29eeeef932b683b0c993614f75d5" @@ -254,6 +263,13 @@ dependencies: "@babel/highlight" "^7.0.0" +"@babel/code-frame@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.1.tgz#d5481c5095daa1c57e16e54c6f9198443afb49ff" + integrity sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw== + dependencies: + "@babel/highlight" "^7.10.1" + "@babel/code-frame@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" @@ -277,6 +293,27 @@ invariant "^2.2.4" semver "^5.5.0" +"@babel/core@7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.3.tgz#30b0ebb4dd1585de6923a0b4d179e0b9f5d82941" + integrity sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.3" + "@babel/helpers" "^7.8.3" + "@babel/parser" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.0" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + "@babel/core@7.9.0": version "7.9.0" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e" @@ -330,6 +367,16 @@ lodash "^4.17.13" source-map "^0.5.0" +"@babel/generator@^7.10.1", "@babel/generator@^7.8.3": + version "7.10.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.2.tgz#0fa5b5b2389db8bfdfcc3492b551ee20f5dd69a9" + integrity sha512-AxfBNHNu99DTMvlUPlt1h2+Hn7knPpH5ayJ8OqDWSeLld+Fi2AYBTC/IejWDM9Edcii4UzZRCsbUt0WlSDsDsA== + dependencies: + "@babel/types" "^7.10.2" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + "@babel/generator@^7.4.0", "@babel/generator@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.4.tgz#db651e2840ca9aa66f327dcec1dc5f5fa9611369" @@ -420,6 +467,15 @@ "@babel/traverse" "^7.8.3" "@babel/types" "^7.8.3" +"@babel/helper-function-name@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz#92bd63829bfc9215aca9d9defa85f56b539454f4" + integrity sha512-fcpumwhs3YyZ/ttd5Rz0xn0TpIwVkN7X0V38B9TWNfVF42KEkhkAAuPCQ3oXmtTRtiPJrmZ0TrfS0GKF0eMaRQ== + dependencies: + "@babel/helper-get-function-arity" "^7.10.1" + "@babel/template" "^7.10.1" + "@babel/types" "^7.10.1" + "@babel/helper-function-name@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz#ab6e041e7135d436d8f0a3eca15de5b67a341a2e" @@ -447,6 +503,13 @@ "@babel/template" "^7.8.3" "@babel/types" "^7.9.5" +"@babel/helper-get-function-arity@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz#7303390a81ba7cb59613895a192b93850e373f7d" + integrity sha512-F5qdXkYGOQUb0hpRaPoetF9AnsXknKjWMZ+wmsIRsp5ge5sFh4c3h1eH2pRTTuy9KKAA2+TTYomGXAtEL2fQEw== + dependencies: + "@babel/types" "^7.10.1" + "@babel/helper-get-function-arity@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz#cb46348d2f8808e632f0ab048172130e636005f0" @@ -558,6 +621,13 @@ "@babel/template" "^7.8.3" "@babel/types" "^7.8.3" +"@babel/helper-split-export-declaration@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz#c6f4be1cbc15e3a868e4c64a17d5d31d754da35f" + integrity sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g== + dependencies: + "@babel/types" "^7.10.1" + "@babel/helper-split-export-declaration@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz#57292af60443c4a3622cf74040ddc28e68336fd8" @@ -572,6 +642,11 @@ dependencies: "@babel/types" "^7.8.3" +"@babel/helper-validator-identifier@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz#5770b0c1a826c4f53f5ede5e153163e0318e94b5" + integrity sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw== + "@babel/helper-validator-identifier@^7.9.5": version "7.9.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80" @@ -587,6 +662,15 @@ "@babel/traverse" "^7.8.3" "@babel/types" "^7.8.3" +"@babel/helpers@^7.8.3": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.1.tgz#a6827b7cb975c9d9cef5fd61d919f60d8844a973" + integrity sha512-muQNHF+IdU6wGgkaJyhhEmI54MOZBKsFfsXFhboz1ybwJ1Kl7IHlbm2a++4jwrmY5UYsgitt5lfqo1wMFcHmyw== + dependencies: + "@babel/template" "^7.10.1" + "@babel/traverse" "^7.10.1" + "@babel/types" "^7.10.1" + "@babel/helpers@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.4.tgz#754eb3ee727c165e0a240d6c207de7c455f36f73" @@ -613,6 +697,15 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/highlight@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.1.tgz#841d098ba613ba1a427a2b383d79e35552c38ae0" + integrity sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg== + dependencies: + "@babel/helper-validator-identifier" "^7.10.1" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/highlight@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" @@ -622,6 +715,11 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/parser@^7.10.1": + version "7.10.2" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.2.tgz#871807f10442b92ff97e4783b9b54f6a0ca812d0" + integrity sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ== + "@babel/parser@^7.4.3", "@babel/parser@^7.7.4": version "7.7.5" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.5.tgz#cbf45321619ac12d83363fcf9c94bb67fa646d71" @@ -1126,6 +1224,15 @@ "@babel/parser" "^7.8.6" "@babel/types" "^7.8.6" +"@babel/template@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811" + integrity sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig== + dependencies: + "@babel/code-frame" "^7.10.1" + "@babel/parser" "^7.10.1" + "@babel/types" "^7.10.1" + "@babel/template@^7.4.0", "@babel/template@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.4.tgz#428a7d9eecffe27deac0a98e23bf8e3675d2a77b" @@ -1144,6 +1251,21 @@ "@babel/parser" "^7.8.3" "@babel/types" "^7.8.3" +"@babel/traverse@^7.10.1": + version "7.10.1" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.1.tgz#bbcef3031e4152a6c0b50147f4958df54ca0dd27" + integrity sha512-C/cTuXeKt85K+p08jN6vMDz8vSV0vZcI0wmQ36o6mjbuo++kPMdpOYw23W2XH04dbRt9/nMEfA4W3eR21CD+TQ== + dependencies: + "@babel/code-frame" "^7.10.1" + "@babel/generator" "^7.10.1" + "@babel/helper-function-name" "^7.10.1" + "@babel/helper-split-export-declaration" "^7.10.1" + "@babel/parser" "^7.10.1" + "@babel/types" "^7.10.1" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.4.tgz#9c1e7c60fb679fe4fcfaa42500833333c2058558" @@ -1189,6 +1311,15 @@ globals "^11.1.0" lodash "^4.17.13" +"@babel/types@^7.10.1", "@babel/types@^7.10.2": + version "7.10.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.2.tgz#30283be31cad0dbf6fb00bd40641ca0ea675172d" + integrity sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng== + dependencies: + "@babel/helper-validator-identifier" "^7.10.1" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + "@babel/types@^7.4.0", "@babel/types@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.4.tgz#516570d539e44ddf308c07569c258ff94fde9193" @@ -5265,10 +5396,10 @@ glob-parent@~5.1.0: dependencies: is-glob "^4.0.1" -glob@7.1.6, glob@^7.1.4: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== +glob@7.1.2, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -5277,9 +5408,10 @@ glob@7.1.6, glob@^7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" +glob@7.1.6, glob@^7.1.4: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4"