A GNU gettext based localization workflow for ember.
ember install ember-l10n
Using the string extractor requires:
- GNU gettext - Convert from/to .po & .pot files
Note: Addon's CLI commands will check dependencies for you and install them on demand (by executing ember l10n:install
), so you don't have to do this on your own.
- Ember.js v3.20 or above
- Ember CLI v3.20 or above
- Node.js v12 or above
You configure ember-l10n in your config/environment.js
:
ENV['ember-l10n'] = {
// This is required to be set
locales: ['en', 'de'],
// These are optional (defaults listed)
defaultLocale: 'en',
autoInitialize: false,
defaultPluralForm: 'nplurals=2; plural=(n != 1);',
jsonPath: '/assets/locales'
}
locales
: The available locales for your application.defaultLocale
: The default locale to use, if no other matching locale is found.autoInitialize
: If you set this to true, the browser locale will be detected on initialization and automatically be set.defaultPluralForm
: Overwrite this if your default locale has a different plural form.jsonPath
: The folder where the JSON files containing the translations can be found.
You should also activate fingerprinting for your translation files, to ensure they can be properly cached.
To do so, you need to add this to your ember-cli-build.js
:
let app = new EmberAddon(defaults, {
// ... other options...
fingerprint: {
// We need to add json to the fingerprinted extensions
extensions: ['js', 'css', 'png', 'jpg', 'gif', 'map', 'svg', 'json']
}
});
There are two primary parts to ember-l10n
- Ember side:
- Service: API and messages in
JS
files - Helpers: Template messages from
HBS
files - Components: For complex messages in
HBS
files
- Service: API and messages in
- CLI:
- Extractor: Extracts messages from both
JS
andHBS
files - Converter: Converts
PO
files toJSON
consumed by addon - Synchronizer: Synchronizes message strings with ids from source code (proof reading)
- Extractor: Extracts messages from both
ember-l10n
follows the gettext convention that the message ids in your source files are the default language (usually English).
In the ember-l10n workflow, you use the t
, and n
helpers and l10n.t()
/ l10n.n()
functions to define your strings in your project. Then you run the extractor script to generate pot and po files, which you send off to your translators. After receiving the translated po files for additional locales, you use the same script to convert them into json files. These json files are then loaded by ember-l10n in your application and replaced at runtime.
ember-l10n
provides powerful string substitution and even component substitution for dynamic strings. See the Components section below.
The service translates through gettext.js. There are two available methods to be used for translations message ids from JS source:
t(msgid, hash)
n(msgid, msgidPlural, count, hash)
pt(msgid, msgctxt, hash)
pn(msgid, msgidPlural, count, msgctxt, hash)
tVar(msgid, hash)
tVar()
works exactly the same as t()
, but it will be ignored by the gettext parser. This is useful if your message ids are variables, for example: l10n.t(myProperty)
would create a myProperty
entry in your po-file when gettext is run. So in this case, l10n.tVar(myProperty)
should be used instead.
Furthermore, there's an auto initialization feature (default: false), which detects user's locale according to system preferences. If the user's locale is supported , the corresponding translations are loaded. If the user's locale is not supported, the default locale will be used instead (default: "en"). Please use the following method to change locales:
setLocale(locale)
The following utility methods are also available:
getLocale()
hasLocale(locale)
detectLocale()
setDetectedLocale()
For handling your translations within your templates you can use t
and n
helper:
The t
helper provides gettext singularization for message ids. It takes singular message id as positional arguments. All placeholders can be provided through named arguments.
If you have strings which are variables (e.g. enums), you can also use the t-var helper: {{t-var myProperty}}
. It works the same way as the t-helper, but it will be ignored by the gettext parser.
The n
helper provides gettext pluralization for message ids. It takes singular and plural message ids as well as actual amount as positional arguments. All placeholders can be provided through named arguments (hash).
Short version:
Long version:
Please note: If your count placeholder has another name than "{{count}}", you have to explicitly provide it as named hashed in addition to positional parameter (as well as for all other placeholders within those message ids!).
To support contextual translations from templates, there exist both pt
and pn
helpers, which accept a context as 2nd or 4th paremeter:
Please note: Both contextual helpers also accept placeholders just as their non-contextual counterparts t
and n
.
If you have complex message ids, which should contain "dynamic" placeholders, which can also be replaced with components (such as a link-to
), you can use the get-text
component.
Please note: If your message id contains HTML, you have to set @unescapeText={{true}}
on the component. Be sure to use this option only in combination with safe strings and don't make use of it when dealing with user generated inputs (XSS)!
In tests, ember-l10n should work without any further work.
The extractor extracts message ids from the JS and HBS files in your Ember project. It generates the corresponding PO files for translation. Later, it will convert the translated POs into JSON files to be used for client side translation within your Ember app. Please note: Make sure turning off the development server while extracting, otherwise process slows down due to livereload!
Run the following command from your Ember project root for extraction:
ember l10n:extract
To see all available command line options for the extractor script please run:
ember l10n:extract -h
ember l10n:extract <options...>
Extract message ids from app
--default-language (String) (Default: 'en') The default language used in message ids
aliases: -d <value>
--bug-address (String) (Default: 'support@mycompany.com') The email address for translation bugs (configured in config/l10n-extract.js)
aliases: -b <value>
--copyright (String) (Default: 'My Company') The copyright information (configured in config/l10n-extract.js)
aliases: -c <value>
--from-code (String) (Default: 'UTF-8') The encoding of the input files
aliases: -e <value>
--extract-from (Array) (Default: ['./app']) The directory from which to extract the strings
aliases: -i <value>
--include-patterns (Array) (Default: []) List of regex patterns to include for extraction. Defaults to all files. (configured in config/l10n-extract.js)
aliases: -x <value>
--skip-patterns (Array) (Default: ['mirage','fixtures','styleguide']) List of regex patterns to completely ignore from extraction
aliases: -s <value>
--skip-dependencies (Array) (Default: []) An array of dependency names to exclude from parsing.
aliases: -sd <value>
--skip-all-dependencies (Boolean) (Default: true) If this is true, do not parse the node_modules/lib folders. (configured in config/l10n-extract.js)
aliases: -sad
--extract-to (String) (Default: './translations') Output directory of the PO-file
aliases: -o <value>
--keys (Array) (Default: ['t', 'pt:1,2c', 'n:1,2', 'pn:1,2,4c']) Function/Helper Keys to be used for lookup
aliases: -k <value>
--language (String) (Default: 'en') Target language of the PO-file
aliases: -l <value>
--pot-name (String) (Default: 'messages.pot') The name of generated POT-file (configured in config/l10n-extract.js)
aliases: -n <value>
--package (String) (Default: 'My App') The name of the package (configured in config/l10n-extract.js)
aliases: -p <value>
--generate-only (Boolean) (Default: false) If only PO-file should be created from POT without extraction
aliases: -g
--generate-from (String) (Default: 'messages.pot') Source POT-file to be used in conjunction with `-g` flag
aliases: -f <value>
--generate-to (String) (Default: null) Target PO-file to be used in conjunction with `-g` flag - CAUTION: uses `${language}.po` as default
aliases: -t <value>
Once you have extracted message ids with ember l10n:extract
, which creates a domain messages.pot
file, you can generate PO-files
for other languages by using -g
option without having to run extraction again like so:
ember l10n:extract -g -l de
(creates german PO file from POT file)
If you have excluded some files from prior extractions with -x
and want to merge them with your messages.pot you can do:
ember l10n:extract -g -l en
(merge english PO file)ember l10n:extract -g -l de
(merge german PO file)
The converter will turn a given PO
into a JSON
file to be loaded by the service.
Run the following command from your Ember project root for conversion:
ember l10n:convert
To see all available command line options for the converter script please run:
ember l10n:convert -h
ember l10n:convert <options...>
Convert PO files to JSON
--convert-from (String) (Default: ./translations) Directory of PO file to convert
aliases: -i <value>
--convert-from-file (String) Optional full path to file to convert. Takes precedence over convert-from & language.
aliases: -f <value>
--convert-to (String) (Default: ./public/assets/locales) Directory to write JSON files to
aliases: -o <value>
--language (String) (Default: en) Target language for PO to JSON conversion
aliases: -l <value>
--validate-throw (String) (Default: null) For which validation level the script should abort. Can be: ERROR, WARNING, null
aliases: -vt <value>
--dry-run (Boolean) (Default: false) If true, only generate but do not actually write to a file
aliases: -dr
Note that this will also validate the generated JSON file for common syntax errors.
For example, it will check if e.g. This is {{description}}
is wrongly translated to Das ist die {{Beschreibung}}
. It will print out any found issues to the console. Alternatively, you can specify validate-throw=ERROR
to force the script to abort if an error is found.
The synchronizer will parse a given PO
file, use message strings from each entry and uses them as new message ids accross JS
and HBS
files in your app. This is especially helpful if you proof read your current message ids before handing them over to translators for other languages.
Run the following command from your Ember project root for synchronization:
ember l10n:sync
To see all available command line options for the synchronization script please run:
ember l10n:sync -h
ember l10n:sync <options...>
Synchronize message strings with message ids (proof reading)
--sync-from (String) (Default: './translations') Directory of PO files
aliases: -i <value>
--sync-to (Array) (Default: ['./app']) Directory of JS/HBS files
aliases: -o <value>
--language (String) (Default: 'en') Language of PO file being used as base
aliases: -l <value>
--keys (Array) (Default: ['t', 'pt:1,2c', 'n:1,2', 'pn:1,2,4c']) Function/Helper Keys to be used for lookup
aliases: -k <value>
If you want to set global options for any of the above commands for your project, you can do so by providing a config file under config/l10n-${command}.js
. An example of global options for extract
command located under config/l10n-extract.js
could look like this:
module.exports = {
"bug-address": "support@anothercompany.com",
"copyright": "Copyright by Another Company",
"package": "Another App",
"exclude-patterns": [
"\/some\/exclude\/path",
"some-other-pattern(?!not-followed-by-this)",
],
"skip-patterns": [
"\/some\/skip\/path",
"(?:\/another\/skip)?path",
]
}
In 5.0.0, the configuration format was changed, in order to align better with the Octane world.
Instead of overwriting the l10n service in your app, you now pass the configuration in config/environment.js
:
ENV['ember-l10n'] = {
// This is required to be set
locales: ['en', 'de'],
// These are optional (defaults listed)
defaultLocale: 'en',
autoInitialize: false,
defaultPluralForm: 'nplurals=2; plural=(n != 1);',
jsonPath: '/assets/locales'
}
Other notable changes:
autoInitialize
defaults to false now, as you usually want to set the locale manually (e.g. in the application route'sbeforeModel
hook).- If you have been overwriting some fields for tests, the recommended way to do so now is different:
class ExtendedL10nService extends L10nService {
_loadConfig() {
let config = {
locales: ['de', 'en', 'ko'],
autoInitialize: false,
defaultLocale: 'de',
};
return super._loadConfig(config);
}
_getWindow() {
return {};
}
}
Unless you are doing something very special, you shouldn't need to extend ember-l10n/services/l10n
anymore.
In 4.0.0, the dependency on ember-cli-ifa
was dropped.
If this was only used by ember-l10n
, you can safely remove it and any configuration for it from your app,
including generating (and fingerprinting) an assetMap.json file.
If you used to have a custom jsonPath
configured in your application, please remove it from your l10n
service,
and instead configure it in your config/environment.js
:
'ember-l10n': {
jsonPath: 'assets/my-custom-locales-path'
}
If it is a bug please open an issue on github.
This library follows Semantic Versioning
Cropster, GmbH © 2020