- ×
A dead simple way to add complex translations (i18n) in a React (DOM/Native) project πππ
Filed under miscellaneousShow Allreact-translated
A dead simple way to add complex translations in a React project πππ
Features
- π₯ Data interpolation
- β Component interpolation
- β Markdown inline-manipulations
- π Custom manipulations, pluralizations, and grammar rules based on input-data
- β Component-level translation files (enables loading only required translations)
Example
Write this:
<Translate text="{difficulty} *translations* in React <ReactLogo>" data={{ difficulty: 'Simple' }} renderMap={{ renderReactLogo: () => <ReactLogo size={14} />, }} />
To render this:
Support
React DOM and React Native π₯
Try
Play around with the library in your browser through the CodeSandbox.
Table of Contents
Installation
Whatever floats your boat:
Setup
Step 1: Create the translations file
Create a file that will contain a mapping of keys to the string in each language you support.
To keep things simple, use the strings of your default language as the key:
// translation.js export default { 'Hi, World!': { en: 'Hi, World!', fr: 'Bonjour le monde!', }, // ... }
NOTE: There is no enforcement on the key used for a language. In these examples, 2-digit country codes (
en
,fr
, etc) are used. Decide on a convention and use that for all translations.Step 2: Connect the
Provider
Wrap your top-level component with the
<Provider>
and set thetranslation
andlanguage
props:// index.js import { Provider } from 'react-translated' import translation from './translation' const App = ( <Provider language="en" translation={translation}> <MyApplicationRoot /> </Provider> )
NOTE: The value of the
language
prop must be one of the keys used for a language defined in Step 1.Step 3: Start translating
That is all!
Continue reading below to see how to handle the various translation scenarios.
Usage
The library can be imported in whatever way you find suitable:
import ReactTranslated from 'react-translated' import * as ReactTranslated from 'react-translated' <ReactTranslated.Translate /*...*/ />
Or:
import { Provider, Translate, Translator } from 'react-translated' <Translate /*...*/ />
Translate
vsTranslator
The
Translate
component should always be used when the translation is rendered as a child component; such as buttons, paragraphs, headings, etc.The
Translator
component should only be used when the translation is needed as a string; such as placeholders, alternate text, etc.Translation scenarios
- Static text
- Templated text
- Dynamically templated text
- Styled text
- Component within text
- Translated text as string (for text input placeholders)
Static text
This is pretty self-explanatory:
// translation.js export default { 'Hi, World!': { en: 'Hi, World!', fr: 'Bonjour le monde!', }, } // any component file <Translate text='Hi, World!' />
Renders as:
Templated text
To use dynamic text, the text can be templated:
// translation.js export default { 'Hi, {firstName}!': { en: 'Hi, {firstName}!', fr: 'Salut {firstName}!', }, } // any component file <Translate text='Hi, {firstName}!' data={{ firstName: 'Sergey' }} />
Renders as:
Dynamically templated text
Sometimes just dynamic text is not enough and the template itself needs to be dynamic (for example pluralization). That can be achieved using a function call:
// translation.js export default { 'There are {catsCount} cats in this room.': { en({ catsCount }) { if (catsCount === 1) { return 'There is {catsCount} cat in this room.' } return 'There are {catsCount} cats in this room.' }, // ... }, } // any component file <Translate text='There are {catsCount} cats in this room.' data={{ catsCount: 2 }} /> <Translate text='There are {catsCount} cats in this room.' data={{ catsCount: 1 }} />
Renders as:
Since these templates are simple function calls, things more complex than pluralization can be done too:
// translation.js export default { 'This is a {fruit}': { en({ fruit }) { if (/^[aeiou]/.test(fruit)) { return 'This is an {fruit}' } return 'This is a {fruit}' }, // ... }, } // any component file <Translate text='This is a {fruit}' data={{ fruit: 'banana' }} /> <Translate text='This is a {fruit}' data={{ fruit: 'apple' }} />
Renders as:
Styled text
The translated text can also have some basic styling applied:
// translation.js export default { 'Hi, *World*!': { en: 'Hi, *World*!', fr: 'Bonjour *le monde*!', }, } // any component file <Translate text='Hi, *World*!' />
Renders as:
And of course the same can be done with dynamic templates:
// translation.js export default { 'Hi, *{firstName}*!': { en: 'Hi, *{firstName}*!', fr: 'Salut *{firstName}*!', }, } // any component file <Translate text='Hi, *{firstName}*!' data={{ firstName: 'Sergey' }} />
Renders as:
Component within text
For more advanced uses where Markdown and Emojis donβt suffice, components can be rendered within the text:
// translation.js export default { 'Tap the <StarIcon> to add': { en: 'Tap the <StarIcon> to add', fr: 'Appuyez sur la <StarIcon> pour ajouter', }, } // any component file <Translate text='Tap the <StarIcon> to add!' renderMap={{ renderStarIcon: () => <StarIcon size={14} /> }} />
Renders as:
Another practical application of this is nested translations - text that requires data that also needs to be translated:
// translation.js export default { 'I was born in <MonthName>': { en: 'I was born in <MonthName>', fr: 'Je suis nΓ© en <MonthName>', }, 'August': { en: 'August', fr: 'aoΓ»t', }, } // any component file const monthName = 'August' <Translate text='I was born in <MonthName>' renderMap={{ renderMonthName: () => <Translate text={monthName} /> }} />
Renders as:
Translated text as string
Added v2.2.0
In scenarios where the translated text is required as a string, such as with text inputs placeholders or accessibility labels, the
Translator
can be used:// translation.js export default { 'Enter your age {firstName}': { en: 'Enter your age {firstName}', fr: 'entrez votre Γ’ge {firstName}', }, } // any component file <Translator> {({ translate }) => ( <input placeholder={translate({ text: 'Enter your age {firstName}', data: { firstName: 'Sergey' }, })} /> )} </Translator>
Renders as:
Contributors
amsul
π» π¨ π π‘ π§
Johnson Su
π π»π Interested becoming a contributor too?
Awesome! This project follows the all-contributors specification. Contributions of any kind are welcome!
You may also want to take a look at our TODOs below and make sure to give our Contributing guide a read.
TODOs
- Add tests using Jest
License
Licensed under MIT.
Β© 2019 Amsul