apostrophecms / apostrophecms/apostrophe

Technical design: static text localization and internationalization in 3.x

Open
#3,204 13 comments 0 reactions 1 assignee Claimed by @boutell View on GitHub
enhancement
Dominant language
JavaScript
Stars
4.6k
Forks
650
Avg merge
19h 21m
Merged PRs (30d)
23

Description

This issue concerns static text. For editable content localization see:

https://github.com/apostrophecms/apostrophe/issues/3205

The proposal we have arrived at internally is as follows, with additional details describing the process for shipping JSON files:

* Use the `i18next` npm module server side, with namespaces. Specifically all Apostrophe phrases will be in the apostrophe namespace, regardless of origin. This keeps admin phrases separate from project level phrases.

* Use the middleware support of i18next, and also inject a function to get the benefit of this in templates.

* Push all of the apostrophe namespace phrases to the front end, via `getBrowserOptions` of the `@apostrophecms/ui` module, and configure `vue-i18next` with them.

* Other apostrophe modules making up our UI will have to wait for i18next to initialize or they might not produce sensible output at startup. So we need to add a convention to control the order in which apostrophe’s frontend js apps (found in `ui/apos/apps` folders) are started so we don’t have to do a lot of listening on the bus. We will do this with a bit of new syntax. Rather than exporting a function, apps (like ApostropheI18nNext or ApostropheAdminBar) can export an object:

```
export default {
priority: 1000,
app() { ... }
}
```

Any app that exports just a function is considered to have a priority of 0. Then apps will be initialized in priority order, highest priority first. Initially it is expected that the only app needing to explicitly use this mechanism will be the app in the `ui` module that initializes `vue-i18next`.

## i18n syntax examples

### EXPRESS

We will use the `i18next-http-middleware` so we can write:

```
req.t('myKey', { ns: 'apostrophe' })
```

... Anytime we want to do this directly rather than in Nunjucks. If `ns` is not specified the default namespace is the project level one.

### NUNJUCKS

We will inject a function that wraps `req.t` so that we can write:

```
{# apostrophe UI static text #}

{{ __t('myKey', { ns: 'apostrophe' }) {{

{# project level static text #}

{{ __t('myKey') }}
```

### VUE

Via `vue-i18next` we will be able to write this in any Apostrophe admin UI Vue component:

```
{{ $t('myKey') }}
```

**In browerspace the default namespace is apostrophe**.

### ui/src javascript

For now only ui/apos Vue components will have access to i18next phrases on the browser side. Support for access to i18next phrases in ui/src javascript may be added at a later time.

### Other Modules, Other Namespaces

Additional npm modules providing add-on Apostrophe UI will need to be able to use their own namespaces, while still participating on the browser side. To address this, any module may set its own `i18nNamespace` option, like so:

```
options: {
i18next: {
ns: 'my-custom-namespace',
browser: true
}
```

If `browser: true` is not passed then the phrases are only available server-side.

### Special considerations for pieces

All piece types need their own labels, distinct from other piece types. So {{ __t('label') }} would not be a good solution in a Vue template as there can only be one i18next phrase with the key `label`. Instead, these labels will be localized server-side via `req.t` and made available via `getBrowserData` to the individual module as they already are today.

### Keys versus default English text phrases

Apostrophe will ship with keys in i18next calls, rather than "default English" text phrases.

That is, a Vue component might contain: `{{ $t('toggleSelectionOf', { label: this.label })`

### Shipping JSON files: Apostrophe core

The apostrophe core module and other apos UI npm modules will ship with JSON files in i18next JSON format, version 3.

These will ship in a `locales` subdirectory of the `@apostrophecms/ui` module, for the `apostrophe` namespace, and in other modules that choose to have i18next namespaces.

Within `locales` files we will follow the i18next version 3 format. For example, `modules/@apostrophecms/ui/locales/en.json` will contain:

```
{
"toggleSelectionOf": "Toggle selection of {{ label }}"
}
```

Our intention is to add additional JSON files over time for other languages and locales. We welcome contributions to this project.

### Shipping JSON files: other npm modules

Other npm modules that set the `i18next` option may also ship with a `locales` folder, which will automatically be loaded.

### Shipping JSON files: project-level code

The project-level default i18next namespace, which is currently never pushed to browser-side JavaScript but is available for server-side localization in Nunjucks templates etc., can be populated by creating a `locales` folder at the root of the project.

### Interactive Editing

It is our intention to eventually ship a module similar in functionality to the 2.x `apostrophe-i18n-static` module, which provided the ability to edit the translation of static text phrases as pieces in the Apostrophe UI. This will supplement the JSON support rather than replacing it altogether.

### Distinct admin and project-level locales

In some cases, users with editing privileges may wish to view project-level static text in a selected locale without also translating apostrophe admin UI, even though translations are available. This is an enterprise requirement that has come up in the past. With a growing set of translations available it will essentially be necessary to support this feature, however this will arrive in a later phase of development. Initially, setting the locale to `fr-fr` will impact both the admin UI and the project level static text, assuming translations exist.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.