Apostrophe i18n static
- Usage in production
- Usage with apostrophe-workflow
- Ignoring phrases that come from Apostrophe's admin UI
This module adds editable pieces for translation through i18n to an Apostrophe project.
This module is intendend to localize static text in templates i.e text wrapped with
__("..."), not localize editable content. If your goal is content localization, you should use the Apostrophe workflow module instead.
I18n static pieces are excluded from apostrophe-workflow. To use both
apostrophe-workflow, see Usage with apostrophe-workflow
For static text localization, you are in the right place.
Pieces are edited in the module
apostrophe-i18n-static. Then, JSON files are generated for the i18n module used in Apostrophe.
This will add an entry in the admin bar "I18n static" and pieces will have a schema with:
- optional plural value matching i18n module
The first time a template containing a new string to translate through
__("...") is rendered, the piece is created in the database. When the value of this piece is edited, the matching JSON file is recreated. Therefore, do NOT edit directly the JSON files.
npm i apostrophe-i18n-static
The following options are mandatory:
- locales to edit, in an array with
- a default locale (one of the locales)
// app.jsshortName: 'name-of-project'modules:'apostrophe-i18n-static':defaultLocale: 'en-US'locales:label: 'German'value: 'de-DE'label: 'English'value: 'en-US'label: 'Spanish'value: 'es-ES'label: 'French'value: 'fr-FR'
This will create the corresponding JSON files in the
locales folder of the project (or the
localesDir defined in
apostrophe-i18n module). The format of the locales can be anything (
en-US in this example, but could have been
en or other format fitting your needs).
Other options are:
true, it will render the
keyfield as "disabled" to inform users the key should not be modified.
false, it will not reload JSON files when a translation piece is edited.
false, JSON files are not generated automatically at startup.
true, it uses
localesarray (must have installed and configured
apostrophe-workflowbefore - see 4. Usage with apostrophe-workflow). In this case, the
apostrophe-i18n-staticmodule is not used.
true, this locks the locale displayed in the "list" modal of apostrophe-i18n-static and in the "edit" piece modal. For example, if one is on
es-ESlocale, they would only see spanish translations, and would not be able to edit another locale's translation (unless changing locale in apostrophe-workflow if used).
false. As in
true, the separator will be
.. Otherwise, it will take
objectNotationvalue. For example,
objectNotation: '-'will convert
objectNotation option enables default values too.
For example, with
objectNotation: true, the string
__('obj.with.deep.val:nested value') in a template will be converted into the JSON file as
obj:with:deep:val: 'nested value'
Be aware i18n catches every
__("") key from Apostrophe templates, even the ones from Apostrophe core interface, that is to say every wording in modals, buttons, labels... And dots are used often (e.g: "Search pieces..." in Apostrophe search bar). These dots will be interpreted as separator if
objectNotation default is activated. Therefore, it is recommended to choose another separator. For example,
objectNotation: '-' or
objectNotation: '*' to avoid confusion.
true, it will output messages when adding a new wording or generating a JSON file. Example of output:
Generating i18n file for 'master'master done in: 10102msGenerating i18n file for 'en-US'en-US done in: 3846msGenerating i18n file for 'es-ES'es-ES done in: 5492msGenerating i18n file for 'fr-FR'fr-FR done in: 3887msGenerating i18n file for 'de-DE'de-DE done in: 3441msGenerating i18n file for 'de-AT'de-AT done in: 16639msGenerating i18n file for 'de-CH'de-CH done in: 8960msTotal time: 53139ms
apostrophe-i18n module are taken into account, except
JSON files regeneration
By default, at every startup, JSON files are generated by extracting translations from the database. If this behavior does not fit one's need, it can be disabled by passing the option
generateAtStartup: false. In this situation, the following Apostrophe tasks can be used when manual generation is needed:
node app apostrophe-i18n-static:reload --locale=xxwhere
xxis a valid i18n file name. It generates only the file for the specified locale.
node app apostrophe-i18n-static:reload-allfinds every locale and generate files (see list of files in
As explained above, JSON files should not be edited directly because the reloading of i18n files is made after a translation piece has been edited. To be more accurate, if there are 2 JSON files (for example
fr.json), if an
apostrophe-i18n-static piece is edited for the
en locale, only the
en.json file will be regenerated.
Also, at startup, all JSON files are regenerated automatically, based on the cache if it exists, otherwise from the database values (see 3.2 Performance).
3.1 Distributed system
This module has been designed to work with several running Apostrophe instances sharing the same DB (or a MongoDB sharded cluster). In a docker environnement, if a translation piece is edited on one instance, its JSON file is regenerated inside its container and a new random ID is stored into the DB. This way, the next request coming from the other instance will detect there was a change (due to the new random ID) and regenerate its JSON files too. As a consequence, translations are always up-to-date.
As a general idea, the regeneration of a file containing several hundred translations takes usually a few milliseconds. Every reload is measured and displayed on the standard output.
However, to be sure it scales smoothly, a cache strategy has been implemented. Every edition on a translation piece empties the cache for the edited locale. The next request reloads the JSON file from the database in this case. Otherwise, it is pulled from the cache (useful at startup).
Example of project configuration using
// app.jsconst locales =label: 'German'value: 'de-DE'label: 'English'value: 'en-US'label: 'Spanish'value: 'es-ES'label: 'French'value: 'fr-FR';const defaultLocale = 'fr-FR';shortName: 'apostrophe-test'modules:'apostrophe-i18n-static':defaultLocalelocales'apostrophe-workflow':alias: 'workflow'locales: localesdefaultLocale;
The displayed translations will be taken from current worflow locale. For example, if the user is on the
es-ES-draft) locale according to apostrophe-worflow, translations coming from
es-ES.json will be displayed.
In case of nested locales with apostrophe-workflow, apostrophe-i18n-static will still work. It just needs a flat structure.
const defaultLocale = 'en-US';const apos =modules:shortName: 'apostrophe-test''apostrophe-i18n-static':disabledKey: truedefaultLocalelocales:label: 'English'value: 'en-US'label: 'Spanish'value: 'es-ES'label: 'French'value: 'fr-FR'label: 'German'value: 'de-DE'label: 'Austrian'value: 'de-AT'label: 'Swiss'value: 'de-CH''apostrophe-workflow':alias: 'workflow'locales:label: 'Master'name: 'master'private: truechildren:label: 'English'name: 'en-US'label: 'Spanish'name: 'es-ES'label: 'French'name: 'fr-FR'label: 'Germany'name: 'de-DE'children:label: 'Austria'name: 'de-AT'label: 'Switzerland'name: 'de-CH'defaultLocale;
It is important to have the same
apostrophe-i18n-static can use the locales from
apostrophe-workflow by using the option
const apos =modules:shortName: 'apostrophe-test''apostrophe-i18n-static':defaultLocale: 'en-US'useWorkflowLocales: true'apostrophe-workflow':alias: 'workflow'defaultLocale: 'en-US'locales:label: 'Master'name: 'master'private: truechildren:label: 'English'name: 'en-US'label: 'Spanish'name: 'es-ES'label: 'French'name: 'fr-FR'label: 'Germany'name: 'de-DE'children:label: 'Austria'name: 'de-AT'label: 'Switzerland'name: 'de-CH';
5 Ignoring phrases that come from Apostrophe's admin UI
For some projects, you may not be interested in translating the phrases that make up Apostrophe's admin UI.
The first step is to tell ApostropheCMS to "namespace" those phrases:
When you do so, you will notice that phrases from the admin interface now appear in the translation interface with a prefix. Here is an example:
The default translations have that prefix too, so they can be recognized as defaults, but it should be removed if you do decide to translate them.
The next step is to instruct
apostrophe-i18n-static to hide these phrases from the translation interface, so that the defaults are not changed by your translation team:
Note that you may namespace your own translations using the namespaced versions of the various i18n helpers:
__ns('phrase') __ns_n('phrase', amount)
Etc. These namespaced helpers do not necessarily support 100% of the feature set of the standard i18n helpers.
If you are using the
objectNotationfeature, you must not use your object notation separation character in your namespace name.
A future release of this module will likely support working with namespaces in a more nuanced way, such as filtering by namespace and not displaying the namespace as part of the key. But for the time being, the ability to ignore the
apostrophe namespace has been the most popular request, so we have provided that first.