@translation/angular
Advanced tools
Comparing version 1.2.0 to 1.3.0
# Changelog | ||
## [v1.3.0](https://github.com/translation/angular/releases/tag/v1.3.0) (2023-01-10) | ||
#### Fixes (bugs & defects): | ||
* Improve interpolation substitution to be more resilient to bad XLF formatting. | ||
## [v1.2.0](https://github.com/translation/angular/releases/tag/v1.2.0) (2022-10-13) | ||
@@ -4,0 +10,0 @@ |
{ | ||
"name": "@translation/angular", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"description": "Translation.io client for Angular applications", | ||
@@ -40,16 +40,16 @@ "repository": { | ||
"author": { | ||
"name" : "Michaël Hoste", | ||
"email" : "michael@translation.io", | ||
"url" : "https://translation.io" | ||
"name": "Michaël Hoste", | ||
"email": "michael@translation.io", | ||
"url": "https://translation.io" | ||
}, | ||
"contributors": [ | ||
{ | ||
"name" : "Didier Toussaint", | ||
"email" : "didier@translation.io", | ||
"url" : "https://translation.io" | ||
"name": "Didier Toussaint", | ||
"email": "didier@translation.io", | ||
"url": "https://translation.io" | ||
}, | ||
{ | ||
"name" : "Simon Cannuyer", | ||
"email" : "simon@corellia.be", | ||
"url" : "https://corellia.be" | ||
"name": "Simon Cannuyer", | ||
"email": "simon@corellia.be", | ||
"url": "https://corellia.be" | ||
} | ||
@@ -56,0 +56,0 @@ ], |
527
README.md
@@ -8,27 +8,46 @@ # [Translation.io](https://translation.io/angular) client for Angular | ||
Add this package to localize your Angular application (see [Installation](#installation)). | ||
Add this package to localize your **Angular** application. | ||
Use the [official Angular i18n syntax](#localization-syntax-overview) in your components. | ||
Use these [official](https://angular.io/guide/i18n-common-prepare) Angular localization syntaxes: | ||
Write only the source text in your Angular application, and keep it synchronized with your translators on [Translation.io](https://translation.io/angular). | ||
* <a href="#template--components">`<p i18n>source text</p>`</a> in templates. | ||
* <a href="#javascript">``$localize `source text` ``</a> in JavaScript. | ||
<a href="https://translation.io/laravel"> | ||
Write only the source text, and keep it synchronized with your translators | ||
on [Translation.io](https://translation.io/angular). | ||
<a href="https://translation.io/angular"> | ||
<img width="720px" alt="Translation.io interface" src="https://translation.io/gifs/translation.gif"> | ||
</a> | ||
Don't bother your translators with obscure `.XLF` files. Make them use our clean | ||
interface to translate complex singular and plurals strings: | ||
[![XLF files plural interface](https://github.com/translation/angular/raw/master/misc/angular-xlf-to-interface.png)](https://translation.io/angular) | ||
Need help? [contact@translation.io](mailto:contact@translation.io) | ||
Table of contents | ||
================= | ||
* [Localization syntax overview](#localization-syntax-overview) | ||
* [i18n attribute in templates](#i18n-attribute-in-templates) | ||
* [$localize in classes and functions](#$localize-in-classes-and-functions) | ||
## Table of contents | ||
* [Localization syntaxes](#localization-syntaxes) | ||
* [Template & Components](#template--components) | ||
* [JavaScript](#javascript) | ||
* [Installation](#installation) | ||
* [Usage](#usage) | ||
* [Sync](#sync) | ||
* [Read-only Sync](#read-only-sync) | ||
* [Sync & purge](#sync-&-purge) | ||
* [Manage locales](#manage-locales) | ||
* [Localization syntax in details](#localization-syntax-in-details) | ||
* [Advanced configuration options](#advanced-configuration-options) | ||
* [Sync and Purge](#sync-and-purge) | ||
* [Manage Languages](#manage-languages) | ||
* [Add or Remove Language](#add-or-remove-language) | ||
* [Edit Language](#edit-language) | ||
* [Custom Languages](#custom-languages) | ||
* [Continuous Integration](#continuous-integration) | ||
* [Advanced Configuration Options](#advanced-configuration-options) | ||
* [Source File Path](#source-file-path) | ||
* [Target Files Path](#target-files-path) | ||
* [Proxy](#proxy) | ||
* [Localization - Good Practices](#localization---good-practices) | ||
* [Testing](#testing) | ||
* [Contributing](#contributing) | ||
* [List of clients for Translation.io](#list-of-clients-for-translationio) | ||
@@ -41,45 +60,132 @@ * [Ruby on Rails (Ruby)](#ruby-on-rails-ruby) | ||
## Localization syntax overview | ||
## Localization syntaxes | ||
### i18n attribute in templates | ||
### Template & Components | ||
Mark the text in a HTML element as translatable by using the `i18n` attribute in your components' templates. | ||
Mark text as being translatable by using the `i18n` attribute in your templates. | ||
#### Singular | ||
~~~html | ||
<!-- Simple use of the i18n attribute --> | ||
<h1 i18n>Welcome to our Angular application!</h1> | ||
<!-- Regular --> | ||
<h1 i18n> | ||
Text to be translated | ||
</h1> | ||
<!-- Variable interpolation --> | ||
<!-- Translators will see "Hi {name}, welcome to your dashboard!" --> | ||
<p i18n>Hi {{ name }}, welcome to your dashboard!</p> | ||
<!-- Translators will see "Hi {name}" --> | ||
<p i18n> | ||
Hi {{ name }} | ||
</p> | ||
<!-- Simple HTML tags interpolation --> | ||
<!-- Translators will see "Text with <1>HTML</1> tags." --> | ||
<p i18n>Text with <em>HTML</em> tags.</p> | ||
<!-- Simple HTML tags --> | ||
<!-- Translators will see "Text with <1>HTML</1> tags" --> | ||
<p i18n> | ||
Text with <em>HTML</em> tags | ||
</p> | ||
<!-- Complex HTML Tags --> | ||
<!-- Translators will see "Text with a <1>link</1>" --> | ||
<p i18n> | ||
Text with a | ||
<a href="https://google.com" target="_blank">link</a> | ||
</p> | ||
<!-- Translatable attribute --> | ||
<img [src]="cat.png" i18n-alt alt="A fluffy cat" /> | ||
<img [src]="cat.png" i18n-alt alt="Text to be translated" /> | ||
<!-- ICU plural form --> | ||
<!-- Translators will see "There are no cats", "There is one cat", "There are {x} cats" --> | ||
<!-- Context --> | ||
<!-- Differentiate translations for the same source text --> | ||
<span i18n="meeting someone|"> | ||
Date | ||
</span> | ||
<span i18n="moment in time|"> | ||
Date | ||
</span> | ||
<!-- Comment --> | ||
<!-- Provide a plain-text description to the translators in the interface --> | ||
<span i18n="Big button at the bottom of the invoicing page"> | ||
Send the invoice | ||
</span> | ||
<!-- Context & Comment --> | ||
<span i18n="invoicing|Big button at the bottom of the invoicing page"> | ||
Send the invoice | ||
</span> | ||
~~~ | ||
#### Plural | ||
The plural syntax is supported using the [ICU MessageFormat](https://unicode-org.github.io/icu/userguide/format_parse/messages/). Multiple plural forms | ||
for each language are embedded into the same string, using a specific syntax with | ||
curly braces. | ||
These examples may seem easy for developers but are hard for translators to work with, | ||
without making any syntax mistake. | ||
That's why on Translation.io, we made sure that translators will only be able to see | ||
the sentences to translate, and only the correct existing plural forms for their | ||
target language. | ||
~~~html | ||
<!-- Regular --> | ||
<p i18n>{count, plural, | ||
=0 {There are no cats} | ||
=1 {There is one cat} | ||
other {There are {{count}} cats} | ||
}</p> | ||
one {You've got 1 message} | ||
other {You've got {{count}} messages}} | ||
</p> | ||
<!-- Custom plural forms --> | ||
<p i18n>{count, plural, | ||
=0 {Your inbox is empty!} | ||
=42 {You've found the ultimate answer} | ||
one {You've got 1 message} | ||
other {You've got {{count}} messages}} | ||
</p> | ||
<!-- Variable interpolation --> | ||
<p i18n>{count, plural, | ||
one {Hello {{name}}, you've got 1 message} | ||
other {Hello {{name}}, you've got {{count}} messages}} | ||
</p> | ||
<!-- HTML tags --> | ||
<p i18n>{count, plural, | ||
one {Hello {{name}}, you've got <strong>1</strong> message} | ||
other {Hello {{name}}, you've got <strong>{{count}}</strong> messages}} | ||
</p> | ||
~~~ | ||
### $localize in classes and functions | ||
**Note:** English has only 2 plural forms (`one` and `other`), but other languages | ||
have more of them, from this list: `zero`, `one`, `two`, `few`, `many`, | ||
`other`. | ||
Mark text (literal strings) as translatable in your component classes and functions using `$localize` and surrounding the text with backticks ( \` ). | ||
You can find the complete list of plural forms and plural rules here: | ||
https://translation.io/docs/languages_with_plural_cases | ||
### JavaScript | ||
Mark text as being translatable by using `$localize` and surrounding the text with backticks ( \` ). | ||
~~~javascript | ||
// Simple use of the $localize function | ||
let text = $localize `Welcome to our Angular application!`; | ||
~~~ | ||
// Regular | ||
$localize `Text to be translated`; | ||
To explore the syntax more in details (specifying metadata, using plurals and interpolations), please check out the "[Localization syntax in details](#localization-syntax-in-details)" section below. | ||
// Variable interpolation | ||
$localize `Hello ${name}`; | ||
// Context | ||
// Differentiate translations for the same source text | ||
$localize `:meeting someone|:Date`; | ||
$localize `:moment in time|:Date`; | ||
// Comment | ||
// Provide a plain-text description to the translators in the interface | ||
$localize `:Big button at the bottom of the invoicing page:Send the invoice`; | ||
// Context & Comment | ||
$localize `:invoicing|Big button at the bottom of the invoicing page:Send the invoice`; | ||
~~~ | ||
## Installation | ||
@@ -95,8 +201,6 @@ | ||
Configure the [i18n options](https://angular.io/guide/i18n-common-merge#define-locales-in-the-build-configuration) in the `angular.json` file at the root of your project. | ||
Configure the [i18n options](https://angular.io/guide/i18n-common-merge#define-locales-in-the-build-configuration) in your `angular.json` file. | ||
### 2. Install our `@translation/angular` package | ||
### 2. Install our package | ||
Run the following command at the root of your project to install our package: | ||
~~~bash | ||
@@ -110,37 +214,39 @@ # NPM | ||
### 3. Create a new translation project | ||
### 3. Add the following scripts | ||
Sign in to our platform and create your new project [from the UI](https://translation.io/angular), selecting the appropriate source and target locales. | ||
Add these lines to your `package.json` to make your life easier: | ||
### 4. Copy the generated `tio.config.json` file to the root of your application | ||
This configuration file should look like this: | ||
~~~json | ||
{ | ||
"api_key": "abcdefghijklmnopqrstuvwxyz123456", | ||
"source_locale": "en", | ||
"target_locales": ["fr", "it", "es"] | ||
"scripts": { | ||
"extract": "ng extract-i18n --output-path=src/locale", | ||
"translation:init": "npm run extract && tio init", | ||
"translation:sync": "npm run extract && tio sync" | ||
} | ||
} | ||
~~~ | ||
### 5. Add scripts to your package.json | ||
**Note:** If you are using Angular version 10 or lower, replace **extract-i18n** by **xi18n** in the "extract" command. | ||
To make your life easier, add these lines to the `package.json` at the root of your application: | ||
### 4. Create a new translation project | ||
Sign in to [Translation.io](https://translation.io/angular) and create a new project, selecting the appropriate source and target locales. | ||
### 5. Configure your project | ||
Copy the generated `tio.config.json` file to the root of your application. | ||
The configuration file looks like this: | ||
~~~json | ||
{ | ||
"scripts": { | ||
"extract": "ng extract-i18n --output-path=src/locale", | ||
"translation:init": "npm run extract && tio init", | ||
"translation:sync": "npm run extract && tio sync" | ||
} | ||
"api_key": "abcdefghijklmnopqrstuvwxyz123456", | ||
"source_locale": "en", | ||
"target_locales": ["fr", "it", "es"] | ||
} | ||
~~~ | ||
N.B. If you are using Angular version 10 or lower, replace **extract-i18n** by **xi18n** in the "extract" command. | ||
### 6. Initialize your project | ||
To push your source keys and existing translations (if any) to Translation.io, run the following command: | ||
Run the following command to push your source keys and existing translations to Translation.io | ||
@@ -159,3 +265,3 @@ ~~~bash | ||
To push new translatable source keys/strings and get translations from Translation.io, simply run: | ||
Push new translatable source keys/strings and get translations from Translation.io with: | ||
@@ -170,20 +276,8 @@ ~~~bash | ||
### Read-only Sync | ||
### Sync and Purge | ||
To retrieve translations without pushing new source keys, you can run: | ||
Remove unused source keys/strings from Translation.io, using your current local application as reference, with: | ||
~~~bash | ||
# NPM | ||
npm run translation:sync -- --readonly | ||
# YARN | ||
yarn translation:sync -- --readonly | ||
~~~ | ||
### Sync & Purge | ||
If you need to remove unused source keys/strings from Translation.io, using your current local application as reference, run the following command: | ||
~~~bash | ||
# NPM | ||
npm run translation:sync -- --purge | ||
@@ -197,5 +291,5 @@ | ||
## Manage locales | ||
## Manage Languages | ||
### Add or remove locales | ||
### Add or Remove Language | ||
@@ -207,5 +301,5 @@ You can add or remove a locale by updating `"target_locales": []` in your | ||
already have a translated XLF file in your project), you will need to create a | ||
new empty project on Translation.io and init your project for them to appear. | ||
new empty project on Translation.io and init it for the first time again. | ||
### Edit locales | ||
### Edit Language | ||
@@ -223,166 +317,42 @@ To edit existing locales while keeping their translations (e.g. changing from `en` to `en-US`): | ||
### Custom Languages | ||
## Localization syntax in details | ||
Custom languages are convenient if you want to customize translations for a specific customer | ||
or another instance of your application. | ||
### i18n attributes and $localize | ||
A custom language is always be derived from an [existing language](https://translation.io/docs/languages). | ||
Its structure should be like: | ||
The text in a HTML element can be marked as translatable by using the `i18n` attribute in the components' templates. | ||
~~~html | ||
<h1 i18n>Welcome to our Angular application!</h1> | ||
~~~ | ||
The attributes of HTML elements can also be marked as translatable by using `i18n-{attribute_name}` attributes. | ||
~~~html | ||
<img [src]="cat.png" i18n-alt alt="A fluffy cat" /> | ||
~~~ | ||
You can interpolate variables (component properties) into translatable strings. | ||
~~~html | ||
<!-- Translators will see "Hi {name}, welcome to your dashboard!" --> | ||
<p i18n>Hi {{ name }}, welcome to your dashboard!</p> | ||
~~~ | ||
And you can also interpolate **valid** HTML tags. | ||
~~~html | ||
<!-- Translators will see "Text with <1>HTML</1> tags." --> | ||
<p i18n>Text with <em>HTML</em> tags.</p> | ||
<!-- Translators will see "Text with a <1><2>partly-emphasized</2> link</1>." --> | ||
<p i18n>Text with a <a href="#"><em>partly-emphasized</em> link</a>.</p> | ||
~~~ | ||
Literal strings in your component classes and functions can also be marked as translatable using `$localize` and surrounding the source text with backticks ( \` ). | ||
~~~javascript | ||
let text = $localize `Hello, we hope you will enjoy this app.`; | ||
`${existingLanguageCode}-${customText}` | ||
~~~ | ||
This syntax also allows for variable interpolation. | ||
where `customText` can only contain alphabetic characters and `-`. | ||
~~~javascript | ||
// Translators will see "Hi {name}, welcome to your dashboard!" | ||
let text = $localize `Hi ${name}, welcome to your dashboard!`; | ||
~~~ | ||
Examples: `en-microsoft` or `fr-BE-custom`. | ||
The official Angular documentation for the syntax can be found [here](https://angular.io/guide/i18n-common-prepare). | ||
## Continuous Integration | ||
### Optional metadata for translation | ||
If you want fresh translations in your Continuous Integration workflow, you may | ||
find yourself calling `npm run translation:sync` very frequently. | ||
You can use metadata as the value of the i18n attribute to specify a custom ID, a meaning and a description. | ||
Since this task can't be concurrently executed | ||
(we have a [mutex](https://en.wikipedia.org/wiki/Mutual_exclusion) strategy with | ||
a queue but it returns an error under heavy load), we implemented this | ||
threadsafe readonly task: | ||
The syntax for the metadata, is the following: `{meaning}|{description}@@{custom_id}` | ||
~~~bash | ||
# NPM | ||
npm run translation:sync -- --readonly | ||
~~~html | ||
<!-- Specifying only the meaning (the pipe | is required) --> | ||
<h1 i18n="Welcome message|">Welcome to our app!</h1> | ||
<!-- Specifying only the description --> | ||
<h1 i18n="Message used on the homepage">Welcome to our app!</h1> | ||
<!-- Specifying only the indetifier --> | ||
<h1 i18n="@@home-welcome-message">Welcome to our app!</h1> | ||
<!-- Specifying a meaning, a description and an identifier --> | ||
<h1 i18n="Welcome message|Message used on the homepage@@home-welcome-message">Welcome to our app!</h1> | ||
# YARN | ||
yarn translation:sync -- --readonly | ||
~~~ | ||
Metadata can also be used with `$localize`, but it must then be formatted as follows: `:{meaning}|{description}@@{custom_id}:{source_text}`. | ||
This task will prevent your CI from failing and still provide new translations. But | ||
be aware that it won't send new keys from your code to Translation.io so you | ||
still need to sync at some point during development. | ||
~~~javascript | ||
// Specifying only the meaning (the pipe | is required) | ||
let text = $localize `:Welcome message|:Welcome to our Angular app!`; | ||
## Advanced Configuration Options | ||
// Specifying only the description | ||
let text = $localize `:Message used on the homepage:Welcome to our Angular app!`; | ||
// Specifying only the identifier | ||
let text = $localize `:@@home-welcome-message:Welcome to our Angular app!`; | ||
// Specifying a meaning, a description and an identifier | ||
let text = $localize `:Welcome message|Message used on the homepage@@home-welcome-message:Welcome to our Angular app!`; | ||
~~~ | ||
The official Angular documentation for optional metadata can be found [here](https://angular.io/guide/i18n-optional-manage-marked-text). | ||
#### Our recommendations for metadata | ||
The "unicity" of a source key is determined by its source text, its custom ID (if any) and its meaning (if any). The description plays no role in this unicity. | ||
If you choose to use custom IDs, make sure that your IDs are unique (or that you always use the same source text with the same ID), otherwise only the first source text will be associated with the ID ([see official documentation](https://angular.io/guide/i18n-optional-manage-marked-text#define-unique-custom-ids)). | ||
To avoid any problems, we strongly recommend that you opt for the use of "meanings" instead of IDs. | ||
**Note:** If you use a meaning without a description, make sure to add a pipe (`|`) after the meaning, otherwise it will be considered as a description. | ||
~~~html | ||
<!-- Good use cases: --> | ||
<!-- Example 1 | ||
The meaning helps distinguish between two keys with the same source text | ||
=> This will result in two distinct source keys | ||
--> | ||
<span i18n="Numbered day in a calendar|">Date</span> | ||
<span i18n="Social meeting with someone|">Date</span> | ||
<!-- Example 2 | ||
Adding a description after the meaning will be useful to translators | ||
=> This will result in two distinct source keys | ||
--> | ||
<span i18n="Verb|Text on a button used to report a problem">Report</span> | ||
<span i18n="Noun|Title of the Report section in the app">Report</span> | ||
<!-- Bad use cases: --> | ||
<!-- Example 1 | ||
Using only descriptions, without meanings (note the missing pipe | ) | ||
-> This will result in only one source key | ||
--> | ||
<label i18n="Label for the datepicker">Date</label> | ||
... | ||
<option i18n="Type of event in a dropdown">Date</option> | ||
<!-- Example 2 | ||
Using the same ID with two different source texts | ||
-> This will result in only one source key (the first one) | ||
--> | ||
<h2 i18n="@@section-title">First section</h2> | ||
<h2 i18n="@@section-title">Second section</h2> | ||
~~~ | ||
### ICU expressions (plural and select) | ||
#### Pluralization | ||
Pluralization rules may vary from one locale to another, and it is recommended to use the plural syntax in your code to facilitate translation. This syntax is expressed as follows: `{ component_property, plural, pluralization_categories }`. | ||
~~~html | ||
<!-- Translators will see "There are no cats", "There is one cat", "There are {x} cats" --> | ||
<p i18n>{count, plural, | ||
=0 {There are no cats} | ||
=1 {There is one cat} | ||
other {There are {{count}} cats} | ||
}</p> | ||
~~~ | ||
The official Angular documentation for plurals can be found [here](https://angular.io/guide/i18n-common-prepare#mark-plurals). | ||
#### Select clause | ||
The select clause allows to display alternate text depending on the value of a variable. This syntax is expressed as follows: `{ component_property, select, selection_categories }`. | ||
~~~html | ||
<span i18n>The user is {gender, select, male {a man} female {a woman} other { other }}.</span> | ||
~~~ | ||
The official Angular documentation for select clauses can be found [here](https://angular.io/guide/i18n-common-prepare#mark-alternates-and-nested-expressions). | ||
#### Our recommendations for plural and select expressions | ||
To facilitate the work of translators, try to avoid complicated or nested expressions. | ||
## Advanced configuration options | ||
The `tio.config.json` file, at the root of your application, can take other optional configuration options. | ||
@@ -392,15 +362,18 @@ | ||
### Custom path for the source locale file | ||
### Source File Path | ||
If your source locale file (XLF) is not located in the default `src/locale` directory and/or is not named `messages.xlf` (default name), you may specify a custom source locale path in your `tio.config.json` file: | ||
You may specify a custom source locale path in your `tio.config.json` file | ||
if your source locale file (XLF) is not located in the default `src/locale` | ||
directory and/or is not named `messages.xlf` (default name): | ||
```json | ||
~~~json | ||
{ | ||
"source_file_path" : "src/translations/sources.xlf" | ||
} | ||
``` | ||
~~~ | ||
**Warning!** The name of your source file should match the one generated by the `extract` script. Make sure to stay consistent in your `package.json`: | ||
**Warning!** The name of your source file should match the one generated by the `extract` script. | ||
Make sure to stay consistent in your `package.json`: | ||
```json | ||
~~~json | ||
{ | ||
@@ -411,24 +384,27 @@ "scripts": { | ||
} | ||
``` | ||
~~~ | ||
### Custom path for target locale files | ||
### Target Files Path | ||
You may also specify a custom path for the target locale files (XLF) if you need them to have a name other than the defaut `messages.{lang}.xlf` or to be located in a directory other than the default `src/locale` directory. Simply add the following line to your `tio.config.json`, but make sure that it contains the `{lang}` placeholder as such: | ||
You may specify a custom path for the target locale files (XLF) if you need them | ||
to have a name other than the defaut `messages.{lang}.xlf` or to be located in | ||
a directory other than the default `src/locale` directory. | ||
```json | ||
Simply add the following line to your `tio.config.json`, but make sure that it | ||
contains the `{lang}` placeholder as such: | ||
~~~json | ||
{ | ||
"target_files_path": "src/translations/translations.{lang}.xlf" | ||
} | ||
``` | ||
~~~ | ||
or | ||
```json | ||
~~~json | ||
{ | ||
"target_files_path": "src/locale/{lang}/translations.xlf" | ||
} | ||
``` | ||
~~~ | ||
Note: our package will attempt to create any missing directories. If it fails (for example, if permissions are strict on your side), please make sure to create the required directories manually. | ||
### Proxy | ||
@@ -444,8 +420,67 @@ | ||
## Localization - Good Practices | ||
The "unicity" of a source key is determined by its source text and its context | ||
(if any). The comment plays no role in this unicity. | ||
If you use a meaning without a comment, make sure to add a | ||
pipe (`|`) after the meaning, otherwise it will be considered as a comment. | ||
### Good use cases | ||
~~~html | ||
<!-- | ||
The context helps distinguish between two keys with the same source text | ||
=> This will result in two distinct source keys | ||
--> | ||
<span i18n="Numbered day in a calendar|">Date</span> | ||
<span i18n="Social meeting with someone|">Date</span> | ||
<!-- | ||
Adding a comment after the context will be useful to translators | ||
=> This will result in two distinct source keys | ||
--> | ||
<span i18n="Verb|Text on a button used to report a problem">Report</span> | ||
<span i18n="Noun|Title of the Report section in the app">Report</span> | ||
~~~ | ||
### Bad use case | ||
~~~html | ||
<!-- | ||
Using only comments, without context (note the missing pipe | ) | ||
=> This will result in only one source key | ||
--> | ||
<span i18n="Label for the datepicker">Date</span> | ||
<span i18n="Type of event in a dropdown">Date</span> | ||
~~~ | ||
## Testing | ||
Run the specs with: | ||
~~~bash | ||
jest | ||
~~~ | ||
or | ||
~~~bash | ||
npm run test | ||
~~~ | ||
Please note that [GitHub Actions](.github/workflows/test.yml) contains more specs including real synchronization | ||
tests between different versions of Angular projects and Translation.io. | ||
## Contributing | ||
Please read the [CONTRIBUTING](CONTRIBUTING.md) file. | ||
## List of clients for Translation.io | ||
Implementations were usually started by contributors for their own projects. | ||
The following are officially supported by [Translation.io](https://translation.io) | ||
The following clients are officially supported by [Translation.io](https://translation.io) | ||
and are well documented. | ||
Some of these implementations (and other non-officially supported ones) | ||
were started by contributors for their own translation projects. | ||
We are thankful to all contributors for their hard work! | ||
@@ -487,2 +522,4 @@ | ||
* NPM: https://www.npmjs.com/package/@translation/angular | ||
Credits: [@SimonCorellia](https://github.com/SimonCorellia), [@didier-84](https://github.com/didier-84), [@michaelhoste](https://github.com/michaelhoste) | ||
@@ -502,4 +539,4 @@ ### Others | ||
## Licence | ||
## License | ||
The MIT License (MIT). Please see [License File](LICENSE) for more information. |
@@ -59,3 +59,3 @@ const HtmlTagExtraction = require('./html-tag-extraction') | ||
substitution = `{x1}` | ||
} else if (extraction.includes('id="INTERPOLATION') && extraction.includes('equiv-text=')) { // {name}, {variable}, {count} | ||
} else if (extraction.includes('id="INTERPOLATION') && extraction.includes('equiv-text="{{') && extraction.includes('}}"')) { // {name}, {variable}, {count} | ||
name = extraction.split('equiv-text="{{', 2)[1].split('}}"', 2)[0].trim() | ||
@@ -66,13 +66,14 @@ substitution = `{${name}}` | ||
substitution = `{icu${number}}` | ||
} else if (HtmlTagExtraction.isOpeningTag(extraction)) { // <tag> | ||
} else if (HtmlTagExtraction.isOpeningTag(extraction)) { // <tag> | ||
number = HtmlTagExtraction.addToStackAndGetNumber(extraction) | ||
substitution = `<${number}>` | ||
} else if (HtmlTagExtraction.isClosingTag(extraction)) { // </tag> | ||
} else if (HtmlTagExtraction.isClosingTag(extraction)) { // </tag> | ||
number = HtmlTagExtraction.removeFromStackAndGetNumber(extraction) | ||
substitution = `</${number}>` | ||
} else if (HtmlTagExtraction.isSelfClosingTag(extraction)) { // <tag/> | ||
} else if (HtmlTagExtraction.isSelfClosingTag(extraction)) { // <tag/> | ||
number = HtmlTagExtraction.addToStackAndGetNumber(extraction) | ||
substitution = `<${number}/>` | ||
} else { | ||
console.error(`No substitution found for this extraction: ${extraction}`) | ||
substitution = `{parsingError}`; | ||
console.error(`\n⚠️ No substitution found for this extraction: ${extraction}\nPlease check the validity of your XLF formatting.`); | ||
} | ||
@@ -79,0 +80,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
676
529
49010