Gathering detailed insights and metrics for react-intl-universal
Gathering detailed insights and metrics for react-intl-universal
Gathering detailed insights and metrics for react-intl-universal
Gathering detailed insights and metrics for react-intl-universal
npm install react-intl-universal
Typescript
Module System
Node Version
NPM Version
80.4
Supply Chain
100
Quality
86.7
Maintenance
100
Vulnerability
99.6
License
JavaScript (73.83%)
TypeScript (23.21%)
SCSS (2.96%)
Total Downloads
3,536,680
Last Day
1,784
Last Week
13,019
Last Month
57,128
Last Year
697,961
1,342 Stars
273 Commits
155 Forks
33 Watching
45 Branches
28 Contributors
Minified
Minified + Gzipped
Latest Version
2.12.0
Package Id
react-intl-universal@2.12.0
Unpacked Size
58.49 kB
Size
12.27 kB
File Count
7
NPM Version
6.14.7
Node Version
20.4.0
Publised On
02 Dec 2024
Cumulative downloads
Total Downloads
Last day
-28.2%
1,784
Compared to previous day
Last week
-12%
13,019
Compared to previous week
Last month
0.5%
57,128
Compared to previous month
Last year
1.4%
697,961
Compared to previous year
react-intl-universal is a React internationalization package developed by Alibaba Group.
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.
1import { injectIntl } from 'react-intl'; 2class MyComponent extends Component { 3 render() { 4 const intl = this.props; 5 const title = intl.formatMessage({ id: 'title' }); 6 return (<div>{title}</div>); 7 } 8}; 9export 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.
1export default const rules = { 2 noSpace(value) { 3 if (value.includes(' ')) { 4 return 'Space is not allowed.'; 5 } 6 } 7};
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:
1class App { 2 render() { 3 <MyComponent ref="my"/> 4 } 5 getMyInstance() { 6 console.log('getMyInstance', this.refs.my); 7 } 8}
Instead, you need to use the method getWrappedInstance()
to get that.
1class MyComponent {...} 2export default injectIntl(MyComponent, {withRef: true}); 3 4class App { 5 render() { 6 <MyComponent ref="my"/> 7 } 8 getMyInstance() { 9 console.log('getMyInstance', this.refs.my.getWrappedInstance()); 10 } 11}
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.
If the message contains variables the {variable_name}
is substituted directly into the string. In the example below, there are two variables {name}
and {where}
, the second argument representing the variables in get
method are substituted into the string.
Locale data:
1{ "HELLO": "Hello, {name}. Welcome to {where}!" }
JS code:
1intl.get('HELLO', { name: 'Tony', where: 'Alibaba' }) // "Hello, Tony. Welcome to Alibaba!"
Locale data:
1{ "PHOTO": "You have {num, plural, =0 {no photos.} =1 {one photo.} other {# photos.}}" }
JS code:
1intl.get('PHOTO', { num: 0 }); // "You have no photos." 2intl.get('PHOTO', { num: 1 }); // "You have one photo." 3intl.get('PHOTO', { num: 1000000 }); // "You have 1,000,000 photos."
Plural label supports standard ICU Message syntax.
Number thousands separators also varies according to the user's locale. According to this document, United States use a period to indicate the decimal place. Many other countries use a comma instead.
Locale data:
1{ "SALE_PRICE": "The price is {price, number, USD}" }
JS code:
1intl.get('SALE_PRICE', { price: 123456.78 }); // The price is $123,456.78
As mentioned, the locale data is in ICU Message format.
The syntax is {name, type, format}. Here is description:
price
.number
, date
, and time
.USD
.if type
is number
and format
is omitted, the result is formatted number with thousands separators. If format
is one of currency code, it will show in corresponding currency format.
Locale data:
1{ 2 "SALE_START": "Sale begins {start, date}", 3 "SALE_END": "Sale ends {end, date, long}" 4}
JS code:
1intl.get('SALE_START', {start:new Date()}); // Sale begins 4/19/2017 2intl.get('SALE_END', {end:new Date()}); // Sale ends April 19, 2017
If type
is date
, format
has the following values:
short
shows date as shortest as possiblemedium
shows short textual representation of the monthlong
shows long textual representation of the monthfull
shows dates with the most detailLocale data:
1{ 2 "COUPON": "Coupon expires at {expires, time, medium}" 3}
JS code:
1intl.get('COUPON', {expires:new Date()}); // Coupon expires at 6:45:44 PM
if type
is time
, format
has the following values:
short
shows times with hours and minutesmedium
shows times with hours, minutes, and secondslong
shows times with hours, minutes, seconds, and timezoneWhen the specific key does't exist in current locale, you may want to make it return a default message. Use defaultMessage
method after get
method. For example,
Locale data:
1{ "HELLO": "Hello, {name}" }
JS code:
1const name = 'Tony'; 2intl.get('HELLO', { name }).defaultMessage(`Hello, ${name}`); // "Hello, Tony"
Or using d
for short:
1const name = 'Tony'; 2intl.get('HELLO', { name }).d(`Hello, ${name}`); // "Hello, Tony"
And getHTML
also supports default message.
1const name = 'Tony'; 2intl.getHTML('HELLO').d(<div>Hello, {name}</div>) // React.Element with "<div>Hello, Tony</div>"
The get
method returns string message. For HTML message, use getHTML
instead. For example,
Locale data:
1{ "TIP": "This is <span style='color:red'>HTML</span>" }
JS code:
1intl.getHTML('TIP'); // {React.Element}
react-intl-universal provides a utility helping developer determine the user's currentLocale
. As the running examples, when user select a new locale, it redirect user new location like http://localhost:3000?lang=en-US
. Then, we can use intl.determineLocale
to get the locale from URL. It can also support determine user's locale via cookie, localStorage, and browser default language. Refer to the APIs section for more detail.
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, a solution is proposed: When the debugger mode in react-intl-universal
is enabled, 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:
1intl.init({ 2 // ... 3 debug: true 4})
Message will be wrapped in a span element with the key "data-i18n-key":
When internationalizing a React component, you don't need to intl.init
again.
You could make it as peerDependency, then just load the locale data in the compoent.
1 /** 2 * Initialize properties and load CLDR locale data according to currentLocale 3 * @param {Object} options 4 * @param {string} options.escapeHtml To escape html. Default value is true. 5 * @param {string} options.currentLocale Current locale such as 'en-US' 6 * @param {Object} options.locales App locale data like {"en-US":{"key1":"value1"},"zh-CN":{"key1":"值1"}} 7 * @param {Object} options.warningHandler Ability to accumulate missing messages using third party services. See https://github.com/alibaba/react-intl-universal/releases/tag/1.11.1 8 * @param {string} options.fallbackLocale Fallback locale such as 'zh-CN' to use if a key is not found in the current locale 9 * @param {boolean} options.debug If debugger mode is on, the message will be wrapped by a span with data key 10 * @param {string} options.dataKey If debugger mode is on, the message will be wrapped by a span with this data key. Default value 'data-i18n-key' 11 * @returns {Promise} 12 */ 13 init(options) 14 15 16 /** 17 * Load more locales after init 18 * @param {Object} locales App locale data 19 */ 20 load(locales) 21 22 23 /** 24 * Get the formatted message by key 25 * @param {string} key The string representing key in locale data file 26 * @param {Object} variables Variables in message 27 * @returns {string} message 28 */ 29 get(key, variables) 30 31 /** 32 * Get the formatted html message by key. 33 * @param {string} key The string representing key in locale data file 34 * @param {Object} variables Variables in message 35 * @returns {React.Element} message 36 */ 37 getHTML(key, options) 38 39 /** 40 * Helper: determine user's locale via URL, cookie, and browser's language. 41 * You may not need this API, if you have other rules to determine user's locale. 42 * @param {string} options.urlLocaleKey URL's query Key to determine locale. Example: if URL=http://localhost?lang=en-US, then set it 'lang' 43 * @param {string} options.cookieLocaleKey Cookie's Key to determine locale. Example: if cookie=lang:en-US, then set it 'lang' 44 * @param {string} options.localStorageLocaleKey LocalStorage's Key to determine locale such as 'lang' 45 * @returns {string} determined locale such as 'en-US' 46 */ 47 determineLocale(options) 48 49 /** 50 * Change current locale 51 * @param {string} newLocale Current locale such as 'en-US' 52 */ 53 changeCurrentLocale(newLocale) 54 55 /** 56 * Get the inital options 57 * @returns {Object} options includes currentLocale and locales 58 */ 59 getInitOptions()
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.
1 /** 2 * As same as get(...) API 3 * @param {Object} options 4 * @param {string} options.id 5 * @param {string} options.defaultMessage 6 * @param {Object} variables Variables in message 7 * @returns {string} message 8 */ 9 formatMessage(options, variables)
1 /** 2 * As same as getHTML(...) API 3 * @param {Object} options 4 * @param {string} options.id 5 * @param {React.Element} options.defaultMessage 6 * @param {Object} variables Variables in message 7 * @returns {React.Element} message 8 */ 9 formatHTMLMessage(options, variables)
For example, the formatMessage
API
1const name = 'Tony'; 2intl.formatMessage({ id:'hello', defaultMessage: `Hello, ${name}`}, {name});
is equivalent to get
API
1const name = 'Tony'; 2intl.get('hello', {name}).d(`Hello, ${name}`);
And the formatHTMLMessage
API
1const name = 'Tony';
2intl.formatHTMLMessage({ id:'hello', defaultMessage: <div>Hello</div>}, {name});
is equivalent to getHTML
API
1const name = 'Tony'; 2intl.getHTML('hello', {name}).d(<div>Hello</div>);
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
.
1// Wrong: the message in constants.fruits is loaded before `intl.init(...)` 2const constants = { 3 fruits : [ 4 { label: intl.get('banana'), value: 'banana' }, 5 { label: intl.get('apple'), value: 'apple' }, 6 ] 7} 8function MyComponent() { 9 return <Select dataSource={constants.fruits} /> 10}
To fix this, you should call intl.init
before render
.
Make the message object as a function, and call it at render function.
1const constants = { 2 fruits : () => [ // as arrow function 3 { label: intl.get('banana'), value: 'banana' }, 4 { label: intl.get('apple'), value: 'apple' }, 5 ] 6} 7function MyComponent() { 8 // fruits is a function which returns message when rendering 9 return <Select dataSource={constants.fruits()} /> 10}
Use getter syntax to make a function call when that property is looked up
1const constants = { 2 fruits: [ 3 { 4 get label() { 5 return intl.get("banana"); 6 }, 7 value: "banana", 8 }, 9 { 10 get label() { 11 return intl.get("apple"); 12 }, 13 value: "apple", 14 }, 15 ], 16}; 17function MyComponent() { 18 // When "label" property is looked up, it actually make a function call 19 return <Select dataSource={constants.fruits} />; 20}
1const MyComp = (props) => { 2 const onClick = (e) => { 3 if (e.target.tagName === 'A') { 4 // event handler for "A" tag in the message 5 } 6 }; 7 return ( 8 // Wrap the message in a container and listen for the children's events. 9 <span onClick={onClick}> 10 {intl.getHTML('more_detail').d(<span>Please refer to the <a>document</a> for more detail.</span>)} 11 </span> 12 ) 13}
This software is free to use under the BSD license.
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
4 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 5
Reason
Found 6/29 approved changesets -- score normalized to 2
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
license file not detected
Details
Reason
project is not fuzzed
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Reason
28 existing vulnerabilities detected
Details
Score
Last Scanned on 2024-12-23
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn Morereact-intl-universal-extract
A react-intl-universal message extractor
kiwi-intl
I18N tools for universal javascript apps, easy use & better api;
react-intl-universal-extract-pluto
A react-intl-universal message extractor
eslint-plugin-react-intl-universal
ESLint plugin for React Intl Universal