2019-06-06 23:57:19 +02:00
# Translating
2019-06-08 00:53:30 +02:00
OHIF supports internationalization using [i18next ](https://www.i18next.com/ )
through the npm package [@ohif/i18n ](https://www.npmjs.com/package/@ohif/i18n ),
where is the main instance of i18n containing several languages and tools.
2019-06-06 23:57:19 +02:00
2019-07-01 12:10:56 +02:00
< div class = 'row' >
< div class = 'column' >
< p > Our translation management is powered by < a href = "https://locize.com/" target = "_blank" rel = "noopener noreferrer" > Locize< / a > through their generous support of open source.< / p >
< / div >
< div class = 'column' >
< a href = "https://locize.com/" target = "_blank" rel = "noopener noreferrer" style = 'padding: 20px' >
< img src = "../assets/img/locizeSponsor.svg" alt = "Locize Translation Management Logo" >
< / a >
< / div >
< / div >
2019-06-06 23:57:19 +02:00
### Installing
2019-06-08 00:53:30 +02:00
2019-06-06 23:57:19 +02:00
```bash
2019-06-08 00:53:30 +02:00
yarn add @ohif/i18n
2019-06-06 23:57:19 +02:00
# OR
2019-06-08 00:53:30 +02:00
npm install --save @ohif/i18n
2019-06-06 23:57:19 +02:00
```
### How it works
2019-06-08 00:53:30 +02:00
After installing `@ohif/i18n` npm package, the translation function
[t ](https://www.i18next.com/overview/api#t ) can be used [with ](#with-react ) or
[without ](#without-react ) React.
2019-06-06 23:57:19 +02:00
2019-06-08 00:53:30 +02:00
A translation will occur every time a text match happens in a
[t ](https://www.i18next.com/overview/api#t ) function.
The [t ](https://www.i18next.com/overview/api#t ) function is responsible for
getting translations using all the power of i18next.
2019-06-06 23:57:19 +02:00
E.g.
Before:
2019-06-08 00:53:30 +02:00
```html
2019-06-06 23:57:19 +02:00
< div > my translated text< / div >
2019-06-08 00:53:30 +02:00
```
2019-06-06 23:57:19 +02:00
After:
2019-06-08 00:53:30 +02:00
```html
2019-06-06 23:57:19 +02:00
< div > {t('my translated text')}< / div >
2019-06-08 00:53:30 +02:00
```
2019-06-06 23:57:19 +02:00
2019-06-08 00:53:30 +02:00
If the translation.json file contains a key that matches the HTML content e.g.
`my translated text` , it will be replaced automatically by the
[t ](https://www.i18next.com/overview/api#t ) function.
2019-06-06 23:57:19 +02:00
---
2019-06-08 00:53:30 +02:00
2019-06-06 23:57:19 +02:00
#### With React
2019-06-08 00:53:30 +02:00
This section will introduce you to [react-i18next ](https://react.i18next.com/ )
basics and show how to implement the [t ](https://www.i18next.com/overview/api#t )
function easily.
2019-06-06 23:57:19 +02:00
##### Using HOCs
2019-06-08 00:53:30 +02:00
In most cases we used
[High Order Components ](https://react.i18next.com/latest/withtranslation-hoc ) to
2019-06-12 08:35:17 +02:00
share the `t` function among OHIF's components.
2019-06-08 00:53:30 +02:00
E.g.
2019-06-06 23:57:19 +02:00
```js
import React from 'react';
2019-06-08 00:53:30 +02:00
import { withTranslation } from '@ohif/i18n';
2019-06-06 23:57:19 +02:00
function MyComponent({ t, i18n }) {
2019-06-08 00:53:30 +02:00
return < p > {t('my translated text')}< / p > ;
2019-06-06 23:57:19 +02:00
}
export default withTranslation('MyNameSpace')(MyComponent);
```
2019-06-08 00:53:30 +02:00
> Important: if you are using React outside the OHIF Viewer, check the
> [I18nextProvider](#using-outside-of-ohif-viewer) section, `withTranslation`
> HOC doesnt works without a I18nextProvider
2019-06-06 23:57:19 +02:00
##### Using Hooks
2019-06-08 00:53:30 +02:00
Also, it's possible to get the `t` tool using
[React Hooks ](https://react.i18next.com/latest/usetranslation-hook ), but it
2019-06-12 08:35:17 +02:00
requires at least React > 16.8 😉
2019-06-08 00:53:30 +02:00
#### Using outside of OHIF viewer
2019-06-06 23:57:19 +02:00
2019-06-08 00:53:30 +02:00
OHIF Viewer already sets a main
[I18nextProvider ](https://react.i18next.com/latest/i18nextprovider ) connected to
2019-06-12 08:35:17 +02:00
the shared i18n instance from `@ohif/i18n` , all extensions inside OHIF Viewer
2019-06-27 12:01:11 +02:00
will share this same provider at the end, you don't need to set new providers at
all.
2019-06-06 23:57:19 +02:00
2019-06-08 00:53:30 +02:00
But, if you need to use it completely outside of OHIF viewer, you can set the
I18nextProvider this way:
2019-06-06 23:57:19 +02:00
```js
2019-06-27 12:01:11 +02:00
import i18n from '@ohif/i18n';
import { I18nextProvider } from 'react-i18next';
2019-06-06 23:57:19 +02:00
import App from './App';
< I18nextProvider i18n = {i18n} >
< App / >
2019-06-08 00:53:30 +02:00
< / I18nextProvider > ;
2019-06-06 23:57:19 +02:00
```
2019-06-08 00:53:30 +02:00
After setting `I18nextProvider` in your React App, all translations from
2019-06-27 12:01:11 +02:00
`@ohif/i18n` should be available following the basic [With React ](#with-react )
usage.
2019-06-08 00:53:30 +02:00
---
2019-06-06 23:57:19 +02:00
#### Without React
2019-06-08 00:53:30 +02:00
When needed, you can also use available translations _without React_ .
2019-06-06 23:57:19 +02:00
E.g.
```js
2019-06-29 09:33:38 +02:00
import { T } from '@ohif/i18n';
console.log(T('my translated text'));
console.log(T('$t(Common:Play) my translated text'));
2019-06-06 23:57:19 +02:00
```
---
# Main Concepts While Translating
2019-06-12 08:35:17 +02:00
## - Namespaces
2019-06-06 23:57:19 +02:00
2019-06-08 00:53:30 +02:00
Namespaces are being used to organize translations in smaller portions, combined
semantically or by use. Each `.json` file inside `@ohif/i18n` npm package
becomes a new namespace automatically.
2019-06-06 23:57:19 +02:00
- Buttons: All buttons translations
- CineDialog: Translations for the toll tips inside the Cine Player Dialog
2019-06-12 08:35:17 +02:00
- Common: all common jargons that can be reused like `t('$t(common:image)')`
2019-06-06 23:57:19 +02:00
- Header: translations related to OHIF's Header Top Bar
2019-09-06 03:52:45 +02:00
- MeasurementTable - Translations for the `@ohif/ui` Measurement Table
- UserPreferencesModal - Translations for the `@ohif/ui` Preferences Modal
2019-06-06 23:57:19 +02:00
2019-06-12 08:35:17 +02:00
### How to use another NameSpace inside the current NameSpace?
2019-06-27 12:01:11 +02:00
i18next provides a parsing feature able to get translations strings from any
NameSpace, like this following example getting data from `Common` NameSpace:
2019-06-12 08:35:17 +02:00
```
$t(Common:Reset)
```
## - Extending Languages in @ohif/i18n
2019-06-06 23:57:19 +02:00
2019-06-27 12:01:11 +02:00
Sometimes, even using the same language, some nouns or jargons can change
according to the country, states or even from Hospital to Hospital.
2019-06-06 23:57:19 +02:00
2019-06-27 12:01:11 +02:00
In this cases, you don't need to set an entire language again, you can extend
languages creating a new folder inside a pre existent language folder and
@ohif/i18n will do the hard work.
2019-06-12 08:35:17 +02:00
2019-06-27 12:01:11 +02:00
This new folder must to be called with a double character name, like the `UK` in
the following file tree:
2019-06-06 23:57:19 +02:00
2019-06-13 19:59:16 +02:00
```bash
|-- src
|-- locales
2019-06-27 12:01:11 +02:00
index.js
2019-06-13 19:59:16 +02:00
|-- en
|-- Buttons.json
2019-06-27 12:01:11 +02:00
index.js
2019-06-13 19:59:16 +02:00
| UK
|-- Buttons.js
2019-06-27 12:01:11 +02:00
indes.js
2019-06-13 19:59:16 +02:00
| US
|-- Buttons.js
2019-06-27 12:01:11 +02:00
index.js
2019-06-13 19:59:16 +02:00
...
```
2019-06-06 23:57:19 +02:00
2019-06-27 12:01:11 +02:00
All properties inside a Namespace will be merged in the new sub language, e.g
`en-US` and `en-UK` will merge the props with `en` , using i18next's fallback
languages tool.
2019-06-12 08:35:17 +02:00
2019-06-27 12:01:11 +02:00
You will need to export all Json files in your `index.js` file, mounting an
object like this:
```js
{
en: {
NameSpace: {
keyWord1: 'keyWord1Translation',
keyWord2: 'keyWord2Translation',
keyWord3: 'keyWord3Translation',
}
},
'en-UK': {
NameSpace: {
keyWord1: 'keyWord1DifferentTranslation',
}
}
}
```
Please check the `index.js` files inside locales folder for an example of this
exporting structure.
2019-06-06 23:57:19 +02:00
2019-06-12 08:35:17 +02:00
### - Extending languages dynamically
2019-06-06 23:57:19 +02:00
2019-06-27 12:01:11 +02:00
You have access to the i18next instance, so you can use the
2019-06-08 00:53:30 +02:00
[addResourceBundle ](https://www.i18next.com/how-to/add-or-load-translations#add-after-init )
2019-06-27 12:01:11 +02:00
method to add and change language resources as needed.
2019-06-06 23:57:19 +02:00
E.g.
2019-06-08 00:53:30 +02:00
2019-06-06 23:57:19 +02:00
```js
2019-06-08 00:53:30 +02:00
import { i18n } from '@ohif/i18n';
2019-06-06 23:57:19 +02:00
i18next.addResourceBundle('pt-BR', 'Buttons', {
2019-06-08 00:53:30 +02:00
Angle: 'Ângulo',
2019-06-06 23:57:19 +02:00
});
```
2019-06-08 00:53:30 +02:00
---
2019-06-06 23:57:19 +02:00
### How to set a whole new language
2019-06-08 00:53:30 +02:00
2019-06-06 23:57:19 +02:00
To set a brand new language you can do it in two different ways:
2019-06-08 00:53:30 +02:00
- Opening a pull request for `@ohif/i18n` and sharing the translation with the
2019-06-27 12:01:11 +02:00
community. 😍 Please see [Contributing ](#contributing-with-new-languages )
section for further information.
2019-06-12 08:35:17 +02:00
- Setting it only in your project or extension:
2019-06-27 12:01:11 +02:00
You'll need a a final object like the following, what is setting French as
language, and send it to `addLocales` method.
2019-06-12 08:35:17 +02:00
2019-06-27 12:01:11 +02:00
```js
const newLanguage =
{
fr: {
Commons: {
"Reset": "Réinitialiser",
"Previous": "Précédent",
},
Buttons: {
"Rectangle": "Rectangle",
"Circle": "Cercle",
}
}
2019-06-06 23:57:19 +02:00
```
2019-06-27 12:01:11 +02:00
To make it easier to translate, you can copy the .json files in the /locales
folder and theirs index.js exporters, keeping same keys and NameSpaces.
Importing the main index.js file, will provide you an Object as expected by the
method `addlocales` ;
2019-06-12 08:35:17 +02:00
E.g. of `addLocales` usage
2019-06-27 12:01:11 +02:00
2019-06-06 23:57:19 +02:00
```js
2019-06-12 08:35:17 +02:00
import { addLocales } from '@ohif/i18n';
2019-06-27 12:01:11 +02:00
import locales from './locales/index.js';
addLocales(locales);
2019-06-06 23:57:19 +02:00
```
2019-06-12 08:35:17 +02:00
2019-06-27 12:01:11 +02:00
You can also set them manually, one by one, using this
[method ](#extending-languages-dynamically ).
2019-06-12 08:35:17 +02:00
---
2019-06-27 12:01:11 +02:00
## Language Detections
@ohif/i18n uses
[i18next-browser-languageDetector ](https://github.com/i18next/i18next-browser-languageDetector )
to manage detections, also exports a method called initI18n that accepts a new
detector config as parameter.
2019-06-12 08:35:17 +02:00
### Changing the language
2019-06-27 12:01:11 +02:00
OHIF Viewer accepts a query param called `lng` in the url to change the
language.
E.g.
2019-06-12 08:35:17 +02:00
```
https://docs.ohif.org/demo/?lng=es-MX
```
### Language Persistence
2019-06-27 12:01:11 +02:00
The user's language preference is kept automatically by the detector and stored
at a cookie called 'i18next', and in a localstorage key called 'i18nextLng'.
These names can be changed with a new
[Detector Config ](https://github.com/i18next/i18next-browser-languageDetector ).
2019-06-06 23:57:19 +02:00
2019-06-08 00:53:30 +02:00
## Debugging translations
2019-06-27 12:01:11 +02:00
There is an environment variable responsible for debugging the translations,
called `REACT_APP_I18N_DEBUG` .
2019-06-07 00:13:16 +02:00
2019-06-12 08:35:17 +02:00
Run the project as following to get full debug information:
2019-06-08 00:53:30 +02:00
```bash
2019-06-12 08:35:17 +02:00
REACT_APP_I18N_DEBUG=true yarn run dev
2019-06-08 00:53:30 +02:00
```
2019-06-07 00:13:16 +02:00
2019-06-06 23:57:19 +02:00
### Contributing with new languages
2019-06-08 00:53:30 +02:00
Contributions of any kind are welcome! Please check the
[instructions ](https://docs.ohif.org/contributing.html ).