Internationalize React apps. Not only for Component but also for Vanilla JS.
Internationalize React apps. Not only for Component but also for Vanilla JS.
react-intl-universal is a React internationalization package developed by Alibaba Group.
intl.get.intl.getUpgrade to [email protected]+ to use intl.get(...) as the recommended unified API for plain text, ICU variables, and rich React components.
See the live demo for runnable examples. You can keep one complete sentence in the locale message, while React code controls the actual component, props, and event handlers:
Use the use-react-intl-universal skill to give AI coding agents a practical i18n workflow, not just API hints.
It helps agents:
In case of internationalizing React apps, react-intl is one of most popular package in industry. react-intl decorate your React.Component with wrapped component which is injected internationalized message dynamically so that the locale data is able to be loaded dynamically without reloading page. The following is the example code using react-intl.
import { injectIntl } from 'react-intl';
class MyComponent extends Component {
render() {
const intl = this.props;
const title = intl.formatMessage({ id: 'title' });
return (
);
}
};
export default injectIntl(MyComponent);However, this approach introduces two major issues.
Firstly, Internationalizing can be applied only in view layer such as React.Component. For Vanilla JS file, there's no way to internationalize it. For example, the following snippet is general form validator used by many React.Component in our apps. We definitely will not have such code separated in different React.Component in order to internationalize the warning message. Sadly, react-intl can't be used in Vanilla JS.
export default const rules = {
noSpace(value) {
if (value.includes(' ')) {
return 'Space is not allowed.';
}
}
};Secondly, since your React.Component is wrapped by another class, the behavior is not as expected in many way. For example, to get the instance of React.Component, you can't use the normal way like:
class App {
render() {
<MyComponent ref="my"/>
}
getMyInstance() {
console.log('getMyInstance', this.refs.my);
}
}Instead, you need to use the method getWrappedInstance() to get that.
class MyComponent {...}
export default injectIntl(MyComponent, {withRef: true});
class App {
render() {
<MyComponent ref="my"/>
}
getMyInstance() {
console.log('getMyInstance', this.refs.my.getWrappedInstance());
}
}Furthermore, your React.Component's properties are not inherited in subclass since component is injected by react-intl.
Due to the problem above, we create react-intl-universal to internationalize React app using simple but powerful API.
…As mentioned in the issue Mirror react-intl API, to make people switch their existing React projects from react-intl to react-intl-universal. We provide two compatible APIs as following.
/**
* As same as get(...) API
* @param {Object} options
* @param {string} options.id
* @param {string} options.defaultMessage
* @param {Object} variables Variables in message
* @returns {string|React.ReactNode[]} message
*/
formatMessage(options, variables) /**
* Legacy API: as same as getHTML(...) API
* @param {Object} options
* @param {string} options.id
* @param {React.Element} options.defaultMessage
* @param {Object} variables Variables in message
* @returns {React.Element} message
*/
formatHTMLMessage(options, variables)For example, the formatMessage API
const name = 'Tony';
intl.formatMessage({ id:'hello', defaultMessage: 'Hello, {name}'}, {name}); is equivalent to get API
const name = 'Tony';
intl.get('hello', {name}).d('Hello, {name}');And the legacy formatHTMLMessage API
const name = 'Tony';
intl.formatHTMLMessage({ id:'hello', defaultMessage:
}, {name}); is equivalent to getHTML API
const name = 'Tony';
intl.getHTML('hello', {name}).d(
);react-intl-universal provides a helper to determine the user's currentLocale. In the running examples, when a user selects a new locale, the page is redirected to a URL like http://localhost:3000?lang=en-US. Then you can use intl.determineLocale to read the locale from the URL.
It can also determine the user's locale from cookies, localStorage, or the browser's default language. Refer to the APIs section for more detail.
When internationalizing a React component, you don't need to call intl.init again.
You can make react-intl-universal a peerDependency, then just load the locale data in the component.
When developing a website with multiple languages (i18n), translators are usually responsible for translating the content instead of the web developer. However, translators often struggle to find the specific message they need to edit on the webpage because they don't know its key. This leads to them having to ask the developer for the key, resulting in a lot of time wasted on communication.
To solve this issue, enable debugger mode in react-intl-universal. Each message on the webpage will be wrapped in a special span element with the key data-i18n-key. This way, translators can easily see the key of the message and make the necessary edits themselves using some message management system, without needing to ask the developer.
Enabling debugger mode:
intl.init({
// ...
debug: true
})Message will be wrapped in a span element with the key data-i18n-key:
If constants are defined outside of a React component, the message in constants.fruits may get loaded before intl.init(...). This can cause a warning to be displayed, such as react-intl-universal locales data "null" not exists.
// Wrong: the message in constants.fruits is loaded before `intl.init(...)`
const constants = {
fruits : [
{ label: intl.get('banana'), value: 'banana' },
{ label: intl.get('apple'), value: 'apple' },
]
}
function MyComponent() {
return <Select dataSource={constants.fruits} />
}To fix this, you should call intl.init before render.
Make the message object as a function, and call it at render function.
const constants = {
fruits : () => [ // as arrow function
{ label: intl.get('banana'), value: 'banana' },
{ label: intl.get('apple'), value: 'apple' },
]
}
function MyComponent() {
// fruits is a function which returns message when rendering
return <Select dataSource={constants.fruits()} />
}Use getter syntax to make a function call when that property is looked up
const constants = {
fruits: [
{
get label() {
return intl.get("banana");
},
value: "banana",
},
{
get label() {
return intl.get("apple");
},
value: "apple",
},
],
};
function MyComponent() {
// When "label" property is looked up, it actually make a function call
return <Select dataSource={constants.fruits} />;
}Usage Trend of react-intl-universal
This software is free to use under the BSD license.
No open issues yet, or sync has not completed.