{"id":19722963,"url":"https://github.com/translation/angular","last_synced_at":"2025-04-29T22:30:51.389Z","repository":{"id":59757687,"uuid":"532928186","full_name":"translation/angular","owner":"translation","description":"Angular translation made simple","archived":false,"fork":false,"pushed_at":"2023-07-07T09:26:03.000Z","size":2464,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-21T17:58:58.689Z","etag":null,"topics":["angular","i18n","javascript","localization","translation"],"latest_commit_sha":null,"homepage":"https://translation.io/angular","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/translation.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-05T14:07:46.000Z","updated_at":"2023-07-06T11:52:35.000Z","dependencies_parsed_at":"2024-09-25T08:48:38.909Z","dependency_job_id":"7c209163-1f54-430b-9da2-266619ff3a25","html_url":"https://github.com/translation/angular","commit_stats":{"total_commits":326,"total_committers":4,"mean_commits":81.5,"dds":0.5828220858895705,"last_synced_commit":"3818ec5d079dc2f405a6e01de4372357618a001c"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/translation%2Fangular","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/translation%2Fangular/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/translation%2Fangular/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/translation%2Fangular/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/translation","download_url":"https://codeload.github.com/translation/angular/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251592936,"owners_count":21614445,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","i18n","javascript","localization","translation"],"created_at":"2024-11-11T23:19:06.734Z","updated_at":"2025-04-29T22:30:49.593Z","avatar_url":"https://github.com/translation.png","language":"JavaScript","readme":"# [Translation.io](https://translation.io/angular) client for Angular\n\n[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)\n[![Build Status](https://github.com/translation/angular/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/translation/angular/actions/workflows/test.yml)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/52c0801558cd21fa31dd/test_coverage)](https://codeclimate.com/github/translation/angular/test_coverage)\n[![npm version)](https://img.shields.io/npm/v/@translation/angular)](https://www.npmjs.com/package/@translation/angular)\n\nAdd this package to localize your **Angular** application.\n\nUse these [official](https://angular.io/guide/i18n-common-prepare) Angular localization syntaxes:\n\n* \u003ca href=\"#template--components\"\u003e`\u003cp i18n\u003esource text\u003c/p\u003e`\u003c/a\u003e in templates.\n* \u003ca href=\"#javascript\"\u003e``$localize `source text` ``\u003c/a\u003e  in JavaScript.\n\nWrite only the source text, and keep it synchronized with your translators \non [Translation.io](https://translation.io/angular).\n\n\u003ca href=\"https://translation.io/angular\"\u003e\n  \u003cimg width=\"720px\" alt=\"Translation.io interface\" src=\"https://translation.io/gifs/translation.gif\"\u003e\n\u003c/a\u003e\n\n \n\nDon't bother your translators with obscure `.XLF` files. Make them use our clean\ninterface to translate complex singular and plurals strings:\n\n[![XLF files plural interface](https://github.com/translation/angular/raw/master/misc/angular-xlf-to-interface.png)](https://translation.io/angular)\n\nNeed help? [contact@translation.io](mailto:contact@translation.io)\n\n## Table of contents\n\n* [Localization syntaxes](#localization-syntaxes)\n  * [Template \u0026 Components](#template--components)\n  * [JavaScript](#javascript)\n* [Installation](#installation)\n* [Usage](#usage)\n  * [Sync](#sync)\n  * [Sync and Purge](#sync-and-purge)\n* [Manage Languages](#manage-languages)\n  * [Add or Remove Language](#add-or-remove-language)\n  * [Edit Language](#edit-language)\n  * [Custom Languages](#custom-languages)\n* [Continuous Integration](#continuous-integration)\n* [Advanced Configuration Options](#advanced-configuration-options)\n   * [Source File Path](#source-file-path)\n   * [Target Files Path](#target-files-path)\n   * [Proxy](#proxy)\n* [Localization - Good Practices](#localization---good-practices)\n* [Testing](#testing)\n* [Contributing](#contributing)\n* [List of clients for Translation.io](#list-of-clients-for-translationio)\n  * [Ruby on Rails (Ruby)](#ruby-on-rails-ruby)\n  * [Laravel (PHP)](#laravel-php)\n  * [React, React Native and JavaScript](#react-react-native-and-javascript)\n  * [Others](#others)\n* [License](#license)\n\n## Localization syntaxes\n\n### Template \u0026 Components\n\nMark text as being translatable by using the `i18n` attribute in your templates.\n\n#### Singular\n\n~~~html\n\u003c!-- Regular --\u003e\n\u003ch1 i18n\u003e\n  Text to be translated\n\u003c/h1\u003e\n\n\u003c!-- Variable interpolation --\u003e\n\u003c!-- Translators will see \"Hi {name}\" --\u003e\n\u003cp i18n\u003e\n  Hi {{ name }}\n\u003c/p\u003e\n\n\u003c!-- Simple HTML tags --\u003e\n\u003c!-- Translators will see \"Text with \u003c1\u003eHTML\u003c/1\u003e tags\" --\u003e\n\u003cp i18n\u003e\n  Text with \u003cem\u003eHTML\u003c/em\u003e tags\n\u003c/p\u003e\n\n\u003c!-- Complex HTML Tags --\u003e\n\u003c!-- Translators will see \"Text with a \u003c1\u003elink\u003c/1\u003e\" --\u003e\n\u003cp i18n\u003e\n  Text with a\n  \u003ca href=\"https://google.com\" target=\"_blank\"\u003elink\u003c/a\u003e\n\u003c/p\u003e\n\n\u003c!-- Translatable attribute --\u003e\n\u003cimg [src]=\"cat.png\" i18n-alt alt=\"Text to be translated\" /\u003e\n\n\u003c!-- Context --\u003e\n\u003c!-- Differentiate translations for the same source text --\u003e\n\u003cspan i18n=\"meeting someone|\"\u003e\n  Date\n\u003c/span\u003e\n\n\u003cspan i18n=\"moment in time|\"\u003e\n  Date\n\u003c/span\u003e\n\n\u003c!-- Comment --\u003e\n\u003c!-- Provide a plain-text description to the translators in the interface --\u003e\n\u003cspan i18n=\"Big button at the bottom of the invoicing page\"\u003e\n  Send the invoice\n\u003c/span\u003e\n\n\u003c!-- Context \u0026 Comment --\u003e\n\u003cspan i18n=\"invoicing|Big button at the bottom of the invoicing page\"\u003e\n  Send the invoice\n\u003c/span\u003e\n~~~\n\n#### Plural\n\nThe plural syntax is supported using the [ICU MessageFormat](https://unicode-org.github.io/icu/userguide/format_parse/messages/). Multiple plural forms\nfor each language are embedded into the same string, using a specific syntax with \ncurly braces.\n\nThese examples may seem easy for developers but are hard for translators to work with, \nwithout making any syntax mistake.\n\nThat's why on Translation.io, we made sure that translators will only be able to see \nthe sentences to translate, and only the correct existing plural forms for their \ntarget language.\n\n~~~html\n\u003c!-- Regular --\u003e\n\u003cp i18n\u003e{count, plural,\n  one   {You've got 1 message}\n  other {You've got {{count}} messages}}\n\u003c/p\u003e\n\n\u003c!-- Custom plural forms --\u003e\n\u003cp i18n\u003e{count, plural,\n  =0    {Your inbox is empty!}\n  =42   {You've found the ultimate answer}\n  one   {You've got 1 message}\n  other {You've got {{count}} messages}}\n\u003c/p\u003e\n\n\u003c!-- Variable interpolation --\u003e\n\u003cp i18n\u003e{count, plural,\n  one   {Hello {{name}}, you've got 1 message}\n  other {Hello {{name}}, you've got {{count}} messages}}\n\u003c/p\u003e\n\n\u003c!-- HTML tags --\u003e\n\u003cp i18n\u003e{count, plural,\n  one   {Hello {{name}}, you've got \u003cstrong\u003e1\u003c/strong\u003e message}\n  other {Hello {{name}}, you've got \u003cstrong\u003e{{count}}\u003c/strong\u003e messages}}\n\u003c/p\u003e\n~~~\n\n**Note:** English has only 2 plural forms (`one` and `other`), but other languages\nhave more of them, from this list: `zero`, `one`, `two`, `few`, `many`,\n`other`.\n\nYou can find the complete list of plural forms and plural rules here:\nhttps://translation.io/docs/languages_with_plural_cases\n\n### JavaScript\n\nMark text as being translatable by using `$localize` and surrounding the text with backticks ( \\` ).\n\n~~~javascript\n// Regular\n$localize `Text to be translated`;\n\n// Variable interpolation\n$localize `Hello ${name}`;\n\n// Context\n// Differentiate translations for the same source text\n$localize `:meeting someone|:Date`;\n$localize `:moment in time|:Date`;\n\n// Comment\n// Provide a plain-text description to the translators in the interface\n$localize `:Big button at the bottom of the invoicing page:Send the invoice`;\n\n// Context \u0026 Comment\n$localize `:invoicing|Big button at the bottom of the invoicing page:Send the invoice`;\n~~~\n\n## Installation\n\n### 1. Check your Angular i18n configuration\n\nMake sure that you have [Angular's localize package](https://angular.io/guide/i18n-common-add-package) installed, or install it.\n\n~~~bash\nng add @angular/localize\n~~~\n\nConfigure the [i18n options](https://angular.io/guide/i18n-common-merge#define-locales-in-the-build-configuration) in your `angular.json` file.\n\n### 2. Install our package\n\n~~~bash\n# NPM\nnpm install @translation/angular\n\n# Yarn\nyarn add @translation/angular\n~~~\n\n### 3. Add the following scripts\n\nAdd these lines to your `package.json` to make your life easier:\n\n~~~json\n{\n  \"scripts\": {\n    \"extract\": \"ng extract-i18n --output-path=src/locale\",\n    \"translation:init\": \"npm run extract \u0026\u0026 tio init\",\n    \"translation:sync\": \"npm run extract \u0026\u0026 tio sync\"\n  }\n}\n~~~\n\n**Note:** If you are using Angular version 10 or lower, replace **extract-i18n** by **xi18n** in the \"extract\" command.\n\n### 4. Create a new translation project\n\nSign in to [Translation.io](https://translation.io/angular) and create a new project, selecting the appropriate source and target locales.\n\n### 5. Configure your project\n\nCopy the generated `tio.config.json` file to the root of your application.\n\nThe configuration file looks like this:\n\n~~~json\n{\n  \"api_key\": \"abcdefghijklmnopqrstuvwxyz123456\",\n  \"source_locale\": \"en\",\n  \"target_locales\": [\"fr\", \"it\", \"es\"]\n}\n~~~\n\n### 6. Initialize your project\n\nRun the following command to push your source keys and existing translations to Translation.io\n\n~~~bash\n# NPM\nnpm run translation:init\n\n# YARN\nyarn translation:init\n~~~\n\n## Usage\n\n### Sync\n\nPush new translatable source keys/strings and get translations from Translation.io with:\n\n~~~bash\n# NPM\nnpm run translation:sync\n\n# YARN\nyarn translation:sync\n~~~\n\n### Sync and Purge\n\nRemove unused source keys/strings from Translation.io, using your current local application as reference, with:\n\n~~~bash\n# NPM\nnpm run translation:sync -- --purge\n\n# YARN\nyarn translation:sync -- --purge\n~~~\n\n**Warning:** all source keys/strings that are not present in your current local branch will be **permanently deleted from Translation.io**.\n\n## Manage Languages\n\n### Add or Remove Language\n\nYou can add or remove a locale by updating `\"target_locales\": []` in your\n`tio.config.json` file, and syncing your project again.\n\nIf you want to add a new locale with existing translations (for instance if you\nalready have a translated XLF file in your project), you will need to create a\nnew empty project on Translation.io and init it for the first time again.\n\n### Edit Language\n\nTo edit existing locales while keeping their translations (e.g. changing from `en` to `en-US`):\n\n 1. Create a new project on Translation.io with the correct locales.\n 2. Update the `tio.config.json` file with the new API key and correct locales.\n 3. Adapt the locale codes in the  XLF files' names.\n 4. Initialize your new project and check that everything went fine.\n 5. Invite your collaborators in the new project.\n 6. Remove the old project.\n\nSince you created a new project, the translation history and tags will unfortunately be lost.\n\n### Custom Languages\n\nCustom languages are convenient if you want to customize translations for a specific customer\nor another instance of your application.\n\nA custom language is always be derived from an [existing language](https://translation.io/docs/languages).\nIts structure should be like:\n\n~~~javascript\n`${existingLanguageCode}-${customText}`\n~~~\n\nwhere `customText` can only contain alphabetic characters and `-`.\n\nExamples: `en-microsoft` or `fr-BE-custom`.\n\n## Continuous Integration\n\nIf you want fresh translations in your Continuous Integration workflow, you may\nfind yourself calling `npm run translation:sync` very frequently.\n\nSince this task can't be concurrently executed\n(we have a [mutex](https://en.wikipedia.org/wiki/Mutual_exclusion) strategy with\na queue but it returns an error under heavy load), we implemented this\nthreadsafe readonly task:\n\n~~~bash\n# NPM\nnpm run translation:sync -- --readonly\n\n# YARN\nyarn translation:sync -- --readonly\n~~~\n\nThis task will prevent your CI from failing and still provide new translations. But\nbe aware that it won't send new keys from your code to Translation.io so you\nstill need to sync at some point during development.\n\n## Advanced Configuration Options\n\nThe `tio.config.json` file, at the root of your application, can take other optional configuration options.\n\nWe always favor \"[_convention over configuration_](https://en.wikipedia.org/wiki/Convention_over_configuration)\", so we strongly recommend that you use the default paths and file names in your localization process, but you may specify custom source and target paths for your application if necessary.\n\n### Source File Path\n\nYou may specify a custom source locale path in your `tio.config.json` file \nif your source locale file (XLF) is not located in the default `src/locale` \ndirectory and/or is not named `messages.xlf` (default name):\n\n~~~json\n{\n  \"source_file_path\" : \"src/translations/sources.xlf\"\n}\n~~~\n\n**Warning!** The name of your source file should match the one generated by the `extract` script. \nMake sure to stay consistent in your `package.json`:\n\n~~~json\n{\n  \"scripts\": {\n    \"extract\": \"ng extract-i18n --output-path=src/translations  --out-file=sources.xlf\"\n  }\n}\n~~~\n\n### Target Files Path\n\nYou may specify a custom path for the target locale files (XLF) if you need them \nto have a name other than the defaut `messages.{lang}.xlf` or to be located in \na directory other than the default `src/locale` directory. \n\nSimply add the following line to your `tio.config.json`, but make sure that it \ncontains the `{lang}` placeholder as such:\n\n~~~json\n{\n  \"target_files_path\": \"src/translations/translations.{lang}.xlf\"\n}\n~~~\n\nor\n\n~~~json\n{\n  \"target_files_path\": \"src/locale/{lang}/translations.xlf\"\n}\n~~~\n\n### Proxy\n\nIf you need to use a proxy to connect to Translation.io, add the following line to your `tio.config.json` file:\n\n~~~json\n{\n  \"proxy\": \"http://login:pass@127.0.0.1:8080\"\n}\n~~~\n\n## Localization - Good Practices\n\nThe \"unicity\" of a source key is determined by its source text and its context \n(if any). The comment plays no role in this unicity.\n\nIf you use a meaning without a comment, make sure to add a \npipe (`|`) after the meaning, otherwise it will be considered as a comment.\n\n### Good use cases\n\n~~~html\n\u003c!--\n  The context helps distinguish between two keys with the same source text\n   =\u003e This will result in two distinct source keys\n--\u003e\n\u003cspan i18n=\"Numbered day in a calendar|\"\u003eDate\u003c/span\u003e\n\u003cspan i18n=\"Social meeting with someone|\"\u003eDate\u003c/span\u003e\n\n\u003c!--\n  Adding a comment after the context will be useful to translators\n   =\u003e This will result in two distinct source keys\n--\u003e\n\u003cspan i18n=\"Verb|Text on a button used to report a problem\"\u003eReport\u003c/span\u003e\n\u003cspan i18n=\"Noun|Title of the Report section in the app\"\u003eReport\u003c/span\u003e\n~~~\n\n### Bad use case\n\n~~~html\n\u003c!--\n  Using only comments, without context (note the missing pipe | )\n   =\u003e This will result in only one source key\n--\u003e\n\u003cspan i18n=\"Label for the datepicker\"\u003eDate\u003c/span\u003e\n\u003cspan i18n=\"Type of event in a dropdown\"\u003eDate\u003c/span\u003e\n~~~\n\n## Testing\n\nRun the specs with:\n\n~~~bash\njest\n~~~\n\nor \n\n~~~bash\nnpm run test\n~~~\n\nPlease note that [GitHub Actions](.github/workflows/test.yml) contains more specs including real synchronization \ntests between different versions of Angular projects and Translation.io.\n\n## Contributing\n\nPlease read the [CONTRIBUTING](CONTRIBUTING.md) file.\n\n## List of clients for Translation.io\n\nThe following clients are officially supported by [Translation.io](https://translation.io)\nand are well documented.\n\nSome of these implementations (and other non-officially supported ones)\nwere started by contributors for their own translation projects.\nWe are thankful to all contributors for their hard work!\n\n### Ruby on Rails (Ruby)\n\nOfficially supported on [https://translation.io/rails](https://translation.io/rails)\n\n * GitHub: https://github.com/translation/rails\n * RubyGems: https://rubygems.org/gems/translation/\n\nCredits: [@aurels](https://github.com/aurels), [@michaelhoste](https://github.com/michaelhoste)\n\n### Laravel (PHP)\n\nOfficially supported on [https://translation.io/laravel](https://translation.io/laravel)\n\n * GitHub: https://github.com/translation/laravel\n * Packagist: https://packagist.org/packages/tio/laravel\n\nCredits: [@armandsar](https://github.com/armandsar), [@michaelhoste](https://github.com/michaelhoste)\n\n### React, React Native and JavaScript\n\nOfficially supported on [https://translation.io/lingui](https://translation.io/lingui)\n\nTranslation.io is directly integrated in the great\n[Lingui](https://lingui.dev/) internationalization project.\n\n * GitHub: https://github.com/translation/lingui\n * NPM: https://www.npmjs.com/package/@translation/lingui\n\n### Angular\n\nOfficially supported on [https://translation.io/angular](https://translation.io/angular)\n\n * GitHub: https://github.com/translation/angular\n * NPM: https://www.npmjs.com/package/@translation/angular\n \nCredits: [@SimonCorellia](https://github.com/SimonCorellia), [@didier-84](https://github.com/didier-84), [@michaelhoste](https://github.com/michaelhoste)\n\n### Others\n\nIf you want to create a new client for your favorite language or framework, please read our\n[Create a Translation.io Library](https://translation.io/docs/create-library)\nguide and use the special\n[init](https://translation.io/docs/create-library#initialization) and\n[sync](https://translation.io/docs/create-library#synchronization) endpoints.\n\nYou can also use the more [traditional API](https://translation.io/docs/api).\n\nFeel free to contact us on [contact@translation.io](mailto:contact@translation.io)\nif you need some help or if you want to share your library.\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE) for more information.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftranslation%2Fangular","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftranslation%2Fangular","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftranslation%2Fangular/lists"}