I18N libraries and tools for your react application.
Features:
- String localization with counterpart;
- Messages extraction;
- Catalogs management (similar to gettext);
- Date & Time formats with momentjs;
- Prices and number format with intljs;
- Several components & functions.
npm install --save @gandi/react-translate
Add the following script to your package.json
, it's a simple shortcut for extraction
scripts:
// ...
"scripts": {
// ...
"i18n": "react-translate-scripts"
}
Extraction script requires babel-cli
, babel-gettext-plugin
and po2json
in your dependencies
(it's up to you to select the version saved in your project):
npm install --save-dev babel-cli babel-gettext-plugin po2json
Provide some helpers functions in the React context.
It's up to you to load translations
from the json generated by scripts (cf.
[How to create language files]). So you will be able to promise a json object or preload translations
directly in the DOM (e.g. via server side rendering).
import { provideTranslate, createTranslator } from '@gandi/react-translate';
const translatorParams = {
translations: { // catalog
'This is a test %(username)s!': 'C\'est un test %(username)s!',
},
locale: 'fr', // user's locale
utcOffset: 0, // user's zone offset
defaultLocale: 'en', // default application locale
logMissing: false, // display warnings when translations are missing (except on production)
localeData: { // IntlPolyfill localeData configuration
locale: 'fr',
number: {
currencies: {
USD: '$US',
EUR: '€',
},
},
},
};
const translator = createTranslator(translatorParams);
@provideTranslate(translator)
class App {
render() {
...
}
}
Inject helpers into the components props from context variables.
import React, { Component, PropTypes } from 'react';
import { withTranslator } from '@gandi/react-translate';
@withTranslator()
class MyComponent extends Component {
static propTypes = {
__: PropTypes.func.isRequired,
};
static preFetch({ __ }) {
console.log(__('So i18n'));
}
render() {
const { __ } = this.props;
return (<div>{ __('So i18n') }</div>);
}
}
In order to prevent the unknown props warning
(and non-standard DOM attributes), you can use the propsNamespace
option.
bundle.js:2009 Warning: Unknown props formatDate
, formatNumber
, formatPrice
, formatCurrency
, localize
on tag. Remove these props from the element. For details, see https://fb.me/react-unknown-prop
```js
@withTranslator({ propsNamespace: 'translator' })
class Presenter extends React.Component {
static propTypes = {
translator: PropTypes.shape({ __: PropTypes.func.isRequired }),
};
render() {
const { translator: { __ }, ...props } = this.props;
return <Button {...props}>{__('foobar')}</Button>;
}
}
This library uses babel and the plugin babel-gettext-plugin to extract your internationalized strings.
In case you created your app with create-react-app you have to declare the babel preset you need to build your application, for example:
// file:.babelrc
{
"presets": ["react"]
}
First create a template message file with all the translation strings in a json:
npm run i18n extract_messages [folder/to/extract] [namespace]
(All commands are launched from the root directory of your node project.)
A catalog file is a json file, representing a single language.
Before the first run you'll need to create one folder per needed locale, for instance:
mkdir locales/{fr,it,es}
After you created your message file – and each time you make changes to it – you’ll need to create or update the catalogs:
npm run i18n create_catalog && npm run i18n update_catalog
Sometimes you must clean the catalogs by running this command:
npm run i18n clean_catalog
Tips: In case you use a tool like weblate, you may not clean every time you are extracting messages or updating catalogs to avoid losing old translations that could be used by the tool to suggest translations.
- Translator (aka
__
) - Date/Time (aka
localize
) - Pricing (aka prize)
- formatCurrency (aka MapCurrencyISOToSymbol)
- Number formatting (aka formatNumber)
More in testing documentation.
You have various ways to stub your translator.
import { createTranslateContext, createTranslateContextTypes }
from '@gandi/react-translate/dist/test';
describe('...', () => {
it('...', () => {
const wrapper = mount(<Component />, {
context: createTranslateContext(),
childContextTypes: createTranslateContextTypes(),
});
});
});
import { stubProvideTranslate } from '@gandi/react-translate/dist/test';
describe('LocalLoader component', () => {
it('should render a spinner', () => {
const LocalLoader_ = stubProvideTranslate({ locale: 'fr' })(LocalLoader);
// ...
});
});
@gandi/react-translate
comes bundled wit some components:
<div>
<DateTime>1982-03-28 12:00:00 UTC</DateTime>
<FromNow>1982-03-28 12:00:00 UTC</FromNow>
</div>
To use localization programmatically, just do:
import React, { Component, PropTypes } from 'react';
import { withTranslator } from '@gandi/react-translate';
@withTranslator()
class MyComponent extends Component {
static propTypes = {
localize: PropTypes.func.isRequired,
};
static preFetch({ localize }) {
console.log(localize(new Date()).format('LLLL'));
}
render() {
const { localize } = this.props;
return (<div>{ localize(new Date()).format('LLLL') }</div>);
}
}
Check the samples/app directory to see a "real" application in action.
cd samples/app
npm i
npm run start
All notable changes to this project will be documented in this section.
This project adheres to Semantic Versioning and Keep A Changelog.
The work on this project was possible thanks to Gandi.net (#no_bullshit).
Please open an issue. If it's clear and well labelized, it's quicker to fix!
Else you can start with CONTRIBUTING.md.
- Document
Pricing
features - Add formatCurrency component
- Improve doc on how to load translations (at least give an example)
- Link translator options to related libs
- Allow user to init a logger for missing translations and use
warning
as fallback - Fix or change build process in
bin/merge_catalogs
which looks for legacy gandi's catalogs