2019-12-07 00:23:43 -05:00
# Viewer: Internationalization
2019-06-07 19:53:30 -03: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 18:57:19 -03: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-12-06 22:56:00 -05:00
## Installing
2019-06-07 19:53:30 -03:00
2019-06-06 18:57:19 -03:00
```bash
2019-06-07 19:53:30 -03:00
yarn add @ohif/i18n
2019-06-06 18:57:19 -03:00
# OR
2019-06-07 19:53:30 -03:00
npm install --save @ohif/i18n
2019-06-06 18:57:19 -03:00
```
2019-12-06 22:56:00 -05:00
## How it works
2019-06-06 18:57:19 -03:00
2019-06-07 19:53:30 -03: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 18:57:19 -03:00
2019-06-07 19:53:30 -03: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 18:57:19 -03:00
E.g.
Before:
2019-06-07 19:53:30 -03:00
```html
2019-06-06 18:57:19 -03:00
< div > my translated text</ div >
2019-06-07 19:53:30 -03:00
```
2019-06-06 18:57:19 -03:00
After:
2019-06-07 19:53:30 -03:00
```html
2019-06-06 18:57:19 -03:00
< div > {t('my translated text')}</ div >
2019-06-07 19:53:30 -03:00
```
2019-06-06 18:57:19 -03:00
2019-06-07 19:53:30 -03: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 18:57:19 -03:00
---
2019-06-07 19:53:30 -03:00
2019-12-06 22:56:00 -05:00
### With React
2019-06-07 19:53:30 -03: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 18:57:19 -03:00
2019-12-06 22:56:00 -05:00
#### Using HOCs
2019-06-06 18:57:19 -03:00
2019-06-07 19:53:30 -03:00
In most cases we used
[High Order Components ](https://react.i18next.com/latest/withtranslation-hoc ) to
2019-06-12 03:35:17 -03:00
share the `t` function among OHIF's components.
2019-06-07 19:53:30 -03:00
E.g.
2019-06-06 18:57:19 -03:00
```js
import React from 'react' ;
2019-06-07 19:53:30 -03:00
import { withTranslation } from '@ohif/i18n' ;
2019-06-06 18:57:19 -03:00
function MyComponent ({ t , i18n }) {
2019-06-07 19:53:30 -03:00
return < p > { t ( 'my translated text' )} < /p>;
2019-06-06 18:57:19 -03:00
}
export default withTranslation ( 'MyNameSpace' )( MyComponent );
```
2019-06-07 19:53:30 -03: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 18:57:19 -03:00
2019-12-06 22:56:00 -05:00
#### Using Hooks
2019-06-06 18:57:19 -03:00
2019-06-07 19:53:30 -03: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 03:35:17 -03:00
requires at least React > 16.8 😉
2019-06-07 19:53:30 -03:00
2019-12-06 22:56:00 -05:00
### Using outside of OHIF viewer
2019-06-06 18:57:19 -03:00
2019-06-07 19:53:30 -03:00
OHIF Viewer already sets a main
[I18nextProvider ](https://react.i18next.com/latest/i18nextprovider ) connected to
2019-06-12 03:35:17 -03:00
the shared i18n instance from `@ohif/i18n` , all extensions inside OHIF Viewer
2019-06-27 07:01:11 -03:00
will share this same provider at the end, you don't need to set new providers at
all.
2019-06-06 18:57:19 -03:00
2019-06-07 19:53:30 -03:00
But, if you need to use it completely outside of OHIF viewer, you can set the
I18nextProvider this way:
2019-06-06 18:57:19 -03:00
```js
2019-06-27 07:01:11 -03:00
import i18n from '@ohif/i18n' ;
import { I18nextProvider } from 'react-i18next' ;
2019-06-06 18:57:19 -03:00
import App from './App' ;
< I18nextProvider i18n = { i18n } >
< App />
2019-06-07 19:53:30 -03:00
< /I18nextProvider>;
2019-06-06 18:57:19 -03:00
```
2019-06-07 19:53:30 -03:00
After setting `I18nextProvider` in your React App, all translations from
2019-06-27 07:01:11 -03:00
`@ohif/i18n` should be available following the basic [With React ](#with-react )
usage.
2019-06-07 19:53:30 -03:00
---
2019-06-06 18:57:19 -03:00
2019-12-06 22:56:00 -05:00
### Without React
2019-06-07 19:53:30 -03:00
When needed, you can also use available translations _without React_ .
2019-06-06 18:57:19 -03:00
E.g.
```js
2019-06-29 04:33:38 -03:00
import { T } from '@ohif/i18n' ;
console . log ( T ( 'my translated text' ));
console . log ( T ( '$t(Common:Play) my translated text' ));
2019-06-06 18:57:19 -03:00
```
---
# Main Concepts While Translating
2020-04-02 15:24:49 +02:00
## Namespaces
2019-06-06 18:57:19 -03:00
2019-06-07 19:53:30 -03: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 18:57:19 -03:00
- Buttons: All buttons translations
- CineDialog: Translations for the toll tips inside the Cine Player Dialog
2019-06-12 03:35:17 -03:00
- Common: all common jargons that can be reused like `t('$t(common:image)')`
2019-06-06 18:57:19 -03:00
- Header: translations related to OHIF's Header Top Bar
2019-09-05 21:52:45 -04:00
- MeasurementTable - Translations for the `@ohif/ui` Measurement Table
- UserPreferencesModal - Translations for the `@ohif/ui` Preferences Modal
2019-06-06 18:57:19 -03:00
2019-06-12 03:35:17 -03:00
### How to use another NameSpace inside the current NameSpace?
2019-06-27 07:01:11 -03: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 03:35:17 -03:00
```
$t(Common:Reset)
```
2020-04-02 15:24:49 +02:00
## Extending Languages in @ohif/i18n
2019-06-06 18:57:19 -03:00
2019-06-27 07:01:11 -03: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 18:57:19 -03:00
2019-06-27 07:01:11 -03: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 03:35:17 -03:00
2019-06-27 07:01:11 -03:00
This new folder must to be called with a double character name, like the `UK` in
the following file tree:
2019-06-06 18:57:19 -03:00
2019-06-13 14:59:16 -03:00
```bash
| -- src
| -- locales
2019-06-27 07:01:11 -03:00
index.js
2019-06-13 14:59:16 -03:00
| -- en
| -- Buttons.json
2019-06-27 07:01:11 -03:00
index.js
2019-06-13 14:59:16 -03:00
| UK
| -- Buttons.js
2019-06-27 07:01:11 -03:00
indes.js
2019-06-13 14:59:16 -03:00
| US
| -- Buttons.js
2019-06-27 07:01:11 -03:00
index.js
2019-06-13 14:59:16 -03:00
...
```
2019-06-06 18:57:19 -03:00
2019-06-27 07:01:11 -03: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 03:35:17 -03:00
2019-06-27 07:01:11 -03: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 18:57:19 -03:00
2020-04-02 15:24:49 +02:00
### Extending languages dynamically
2019-06-06 18:57:19 -03:00
2019-06-27 07:01:11 -03:00
You have access to the i18next instance, so you can use the
2019-06-07 19:53:30 -03:00
[addResourceBundle ](https://www.i18next.com/how-to/add-or-load-translations#add-after-init )
2019-06-27 07:01:11 -03:00
method to add and change language resources as needed.
2019-06-06 18:57:19 -03:00
E.g.
2019-06-07 19:53:30 -03:00
2019-06-06 18:57:19 -03:00
```js
2019-06-07 19:53:30 -03:00
import { i18n } from '@ohif/i18n' ;
2019-06-06 18:57:19 -03:00
i18next . addResourceBundle ( 'pt-BR' , 'Buttons' , {
2019-06-07 19:53:30 -03:00
Angle : 'Ângulo' ,
2019-06-06 18:57:19 -03:00
});
```
2019-06-07 19:53:30 -03:00
---
2019-06-06 18:57:19 -03:00
### How to set a whole new language
2019-06-07 19:53:30 -03:00
2019-06-06 18:57:19 -03:00
To set a brand new language you can do it in two different ways:
2019-06-07 19:53:30 -03:00
- Opening a pull request for `@ohif/i18n` and sharing the translation with the
2019-06-27 07:01:11 -03:00
community. 😍 Please see [Contributing ](#contributing-with-new-languages )
section for further information.
2019-06-12 03:35:17 -03:00
- Setting it only in your project or extension:
2019-06-27 07:01:11 -03: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 03:35:17 -03:00
2019-06-27 07:01:11 -03:00
```js
const newLanguage =
{
fr : {
Commons : {
"Reset" : "Réinitialiser" ,
"Previous" : "Précédent" ,
},
Buttons : {
"Rectangle" : "Rectangle" ,
"Circle" : "Cercle" ,
}
}
2019-06-06 18:57:19 -03:00
```
2019-06-27 07:01:11 -03: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 03:35:17 -03:00
E.g. of `addLocales` usage
2019-06-27 07:01:11 -03:00
2019-06-06 18:57:19 -03:00
```js
2019-06-12 03:35:17 -03:00
import { addLocales } from '@ohif/i18n' ;
2019-06-27 07:01:11 -03:00
import locales from './locales/index.js' ;
addLocales ( locales );
2019-06-06 18:57:19 -03:00
```
2019-06-12 03:35:17 -03:00
2019-06-27 07:01:11 -03:00
You can also set them manually, one by one, using this
[method ](#extending-languages-dynamically ).
2019-06-12 03:35:17 -03:00
---
2019-06-27 07:01:11 -03: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 03:35:17 -03:00
### Changing the language
2019-06-27 07:01:11 -03:00
OHIF Viewer accepts a query param called `lng` in the url to change the
language.
E.g.
2019-06-12 03:35:17 -03:00
```
https://docs.ohif.org/demo/?lng=es-MX
```
### Language Persistence
2019-06-27 07:01:11 -03: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 18:57:19 -03:00
2019-06-07 19:53:30 -03:00
## Debugging translations
2019-06-27 07:01:11 -03:00
There is an environment variable responsible for debugging the translations,
called `REACT_APP_I18N_DEBUG` .
2019-06-06 19:13:16 -03:00
2019-06-12 03:35:17 -03:00
Run the project as following to get full debug information:
2019-06-07 19:53:30 -03:00
```bash
2019-06-12 03:35:17 -03:00
REACT_APP_I18N_DEBUG = true yarn run dev
2019-06-07 19:53:30 -03:00
```
2019-06-06 19:13:16 -03:00
2019-06-06 18:57:19 -03:00
### Contributing with new languages
2019-06-07 19:53:30 -03:00
Contributions of any kind are welcome! Please check the
2020-04-02 15:24:49 +02:00
[instructions ](../development/contributing.md ).