Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-intl

Package Overview
Dependencies
Maintainers
4
Versions
341
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-intl - npm Package Compare versions

Comparing version 0.1.0-rc-1 to 1.0.0-rc-1

.npmignore

16

index.js

@@ -0,9 +1,15 @@

'use strict';
// setting up the global requirements of the component
global.Intl = global.Intl || global.IntlPolyfill || require('intl');
global.IntlMessageFormat = require('intl-messageformat');
// Expose `React` as a global, because the ReactIntlMixin assumes it's global.
var oldReact = global.React;
global.React = require('react');
require('./src/component.js');
exports = module.exports = require('./lib/mixin').default;
Object.defineProperty(exports, 'default', {value: exports});
module.exports = global.ReactIntlMixin;
// Put back `global.React` to how it was.
if (oldReact) {
global.React = oldReact;
} else {
delete global.React;
}
{
"name": "react-intl",
"version": "0.1.0-rc-1",
"description": "reactjs helpers for internationalization",
"version": "1.0.0-rc-1",
"description": "React mixin for internationalization.",
"keywords": [

@@ -12,38 +12,33 @@ "intl",

"author": "Caridy Patino <caridy@gmail.com>",
"contributors": [
"Eric Ferraiuolo <eferraiuolo@gmail.com>"
],
"license": "BSD-3-Clause",
"bugs": {
"url": "https://github.com/caridy/react-intl/issues"
"url": "https://github.com/yahoo/react-intl/issues"
},
"repository": {
"type": "git",
"url": "git@github.com:caridy/react-intl.git"
"url": "git@github.com:yahoo/react-intl.git"
},
"files": ["src/", "index.js"],
"main": "index.js",
"directories": {
"test": "tests"
},
"jsnext:main": "src/mixin.js",
"dependencies": {
"intl-messageformat": "^0.1.0",
"react": "*"
"intl-format-cache": "^1.0.0",
"react": "^0.11.1"
},
"devDependencies": {
"chai": "1.8.*",
"grunt": "0.4.*",
"grunt-cli": "0.1.*",
"grunt-contrib-jshint": "0.7.*",
"grunt-wrap": "~0.3.0",
"grunt-contrib-uglify": "0.2.*",
"react": "*",
"istanbul": "0.1.*",
"mocha": "1.15.*",
"intl": "*",
"benchmark": "~1.0.0",
"xunit-file": "*",
"grunt-contrib-watch": "^0.6.1",
"grunt-contrib-concat": "^0.4.0"
"grunt": "^0.4.5",
"grunt-bundle-jsnext-lib": "^0.2.1",
"grunt-cli": "^0.1.13",
"grunt-contrib-clean": "^0.6.0",
"grunt-contrib-copy": "^0.5.0",
"grunt-contrib-jshint": "^0.10.0",
"grunt-contrib-uglify": "^0.5.1",
"intl": "^0.1.4"
},
"scripts": {
"pretest": "grunt jshint build",
"test": "istanbul cover -- _mocha tests/ --reporter spec"
}
"prepublish": "grunt"
},
"homepage": "https://github.com/yahoo/react-intl"
}
React Intl Mixin
================
This repository contains a [ReactJS][] Component Mixin to implement Internationalization
features in a React component. The Intl Mixin provides a series of methods that
can be used in the `render()` method of the component to provide date formatting,
number formatting, as well as plural and gender based translations.
This repository contains a [ReactJS][] Component Mixin to implement Internationalization features for a React component. The Intl Mixin provides a set of methods that can be used in the `render()` method of the component to provide date, number, and message formatting, as well as plural and gender based translations.
## Overview
[![npm Version][npm-badge]][npm]
[![Dependency Status][david-badge]][david]
Overview
--------
The `ReactIntlMixin` implements a [ReactJS][] Component [Mixin][] that adds these new methods to any React component:
* `intlDate()` to format a date value
* `intlNumber()` to format a numeric value
* `intlMessage()` to format a complex message
* `formatDate()` to format a date value
* `formatTime()` to format a date value with `time` formats
* `formatNumber()` to format a numeric value
* `formatMessage()` to format a complex message
`intlDate()` and `intlNumber()` are just sugar on top of [Intl.NumberFormat][] and [Intl.DateTimeFormat][], APIs implemented by most modern browsers. On top of them, React Intl Mixin uses an internal caching mechanism to reuse instances of `Intl.NumberFormat` and `Intl.DateTimeFormat` when possible to avoid the performance penalty of creating these objects over and over again.
`formatDate()`, `formatTime()`, and `formatNumber()` are sugar on top of [Intl.NumberFormat][] and [Intl.DateTimeFormat][] APIs implemented by most modern browsers. To improve runtime performance, React Intl Mixin uses an internal cache to reuse instances of `Intl.NumberFormat` and `Intl.DateTimeFormat` when possible.
Similarly, `intlMessage()` is a sugar layer on top of [intl-messageformat][], a library to support more advanced translation patterns that include complex pluralization and gender support. This library is based on the [Strawman Draft][] that is set to evolve [ECMAScript 402][] to provide a standardized way to concatenate strings with localization support in JavaScript.
Similarly, `formatMessage()` is a sugar layer on top of [intl-messageformat][], a library to support more advanced translation patterns that include complex pluralization and gender support. This library is based on a [Strawman Draft][] proposing to evolve [ECMAScript 402][] to provide a standard way to format message strings with localization support in JavaScript.
In general, `intlMessage()` provides different ways to translate content in the `render()` method of your React components. It also provides the right hooks for your application to implement i18n in an effective way, including the ability to cache expensive objects created through `new IntlMessageFormat(pattern, locale, [optFieldFormatters])`.
The `formatMessage()` method accepts a string message and values to format it with. It too uses an internal cache to improve runtime performance by reusing `IntlMessageFormat` instances.
The data consumed by `intlMessage()` follows the same format supported by [intl-messageformat][], which is one of the industry standards used in other programming languages like Java and PHP. Although this format looks complex, professional translators are familiar with it. You can learn more about this format here: https://github.com/yahoo/intl-messageformat#how-it-works.
The data consumed by `formatMessage()` follows the same format supported by [intl-messageformat][], which is one of the industry standards used in other programming languages like Java and PHP. Although this format looks complex, professional translators are familiar with it. You can [learn more about this format](https://github.com/yahoo/intl-messageformat#how-it-works).
## Installation
Installation
------------
### Browser

@@ -44,10 +49,8 @@

mixins: [ReactIntlMixin],
getMyMessage: function () {
return "{product} will cost {price, number} if ordered by {deadline, date}"
},
render: function () {
return <div>
<p>{this.intlDate(new Date())}</p>
<p>{this.intlNumber(600)}</p>
<p>{this.intlMessage(this.getMyMessage(), {
<p>{this.formatDate(new Date())}</p>
<p>{this.formatNumber(600)}</p>
<p>{this.formatMessage(this.getIntlMessage('product.info'), {
product: 'Mac Mini',

@@ -65,4 +68,13 @@ price: 2000.0015,

```javascript
var i18n = {
locales: ['en-US'],
messages: {
product: {
info: '{product} will cost {price, number} if ordered by {deadline, date}'
}
}
};
React.renderComponent(
<MyComponent locales={["fr-FR"]}/>,
<MyComponent locales={i18n.locales} messages={i18n.messages}/>,
document.getElementById('example')

@@ -81,9 +93,10 @@ );

## Advanced Options
Advanced Options
----------------
### Date and Time formatters
### Date and Time Formats
#### Explicit formats
#### Explicit Formats
By default, when using `{this.intlDate(new Date())}` and `{this.intlNumber(600)}`, `react-intl` will use the default format for the data, and the default numeric format for the number. To specify a custom format you can pass in a second argument with the format you want to use. The following examples will ilustrate this option:
By default, when using `{this.formatDate(new Date())}` and `{this.formatNumber(600)}`, `react-intl` will use the default format for the date, and the default numeric format for the number. To specify a custom format you can pass in a second argument with the format you want to use. The following examples will illustrate this option:

@@ -93,6 +106,10 @@ ```javascript

mixins: [ReactIntlMixin],
render: function () {
return <div>
<p>A: {this.intlDate(1390518044403, { hour: 'numeric', minute: 'numeric' })}</p>
<p>B: {this.intlNumber(400, { style: 'percent' })}</p>
<p>A: {this.formatDate(1390518044403, {
hour: 'numeric',
minute: 'numeric'
})}</p>
<p>B: {this.formatNumber(400, { style: 'percent' })}</p>
</div>;

@@ -106,4 +123,6 @@ }

```html
A: 18:00
B: 40 000 %
<div>
<p>A: 18:00</p>
<p>B: 40 000 %</p>
</div>
```

@@ -114,48 +133,48 @@

```html
A: 6:00 PM
B: 40,000%
<div>
<p>A: 6:00 PM</p>
<p>B: 40,000%</p>
</div>
```
This explicit way to specify a format works well for simple cases, but for complex applications, it falls short because you will have to pass these values everywhere. Also, it doesn't work with complex structures processed by `intlMessage()` because there is no way to pass the formatter for each individual element. To overcome this limitation, we introduced the concept of "custom formatters".
This explicit way to specify a format works well for simple cases, but for complex applications, it falls short because you will have to pass these format config objects through the component hierarchy. Also, it doesn't work with complex structures processed by `formatMessage()` because there is no way to pass the format options for each individual element. To overcome this limitation, we introduced the concept of "custom formats".
#### Custom Formats
#### Custom formatters
With custom format, you can name a set of options that can be used within the entire application or within a component subtree (a component and its child components). These custom formats will also be used by the `formatMessage()` method for complex messages. The following examples will illustrates how custom formats work.
With custom formatters, you can specify a set of rules that can be applied to your entire application or to a section of the page (a component and its child components). These custom formatters can also be used thru `intlMessage()` API for complex language sentences. The following examples will ilustrate how custom formatters work.
```javascript
var MyContainer = React.createClass({
mixins: [ReactIntlMixin],
getDefaultProps: function() {
return {
// hardcoding formats as properties, but they can be passed from parent...
"formats": {
"date": {
"timeStyle": {
"hour": "numeric",
"minute": "numeric"
// Hard-coding formats as properties, but they can be passed from the
// parent component or outside of React.
formats: {
date: {
timeStyle: {
hour: "numeric",
minute: "numeric"
}
},
"number": {
"percentStyle": {
"style": "percent"
number: {
percentStyle: {
style: "percent"
},
"eur": {
"style": "currency",
"currency": "EUR"
EUR: {
style: "currency",
currency: "EUR"
}
}
},
// using properties or a mixin to bring the messages in different languages...
"MyMessage": "{product} will cost {price, number, eur} if ordered by {deadline, date, timeStyle}"
}
};
},
render: function () {
return <div>
<p>A: {this.intlDate(1390518044403, "timeStyle")}</p>
<p>B: {this.intlNumber(400, "percentStyle")}</p>
<p>{this.intlMessage(this.props.MyMessage, {
<p>A: {this.formatDate(1390518044403, "timeStyle")}</p>
<p>B: {this.formatNumber(400, "percentStyle")}</p>
<p>C: {this.formatMessage(this.getIntlMessage('product.info'), {
product: 'Mac Mini',

@@ -170,21 +189,48 @@ price: 2000.0015,

In the example above, if `locales` is set to `["en-US"]`, the output will be:
The component above will now be rendered with `locales` and `mesages` set externally:
```javascript
var i18n = {
locales: ["en-US"],
messages: {
product {
info: "{product} will cost {price, number, eur} if ordered by {deadline, date, timeStyle}"
}
}
};
React.renderComponent(
<MyComponent locales={i18n.locales} messages={i18n.messages}/>,
document.body
);
```
The above rendering of `MyComponent` will output:
```html
A: 6:00 PM
B: 40,000%
C: Mac Mini will cost €200 if ordered by 6:00 PM
<div>
<p>A: 6:00 PM</p>
<p>B: 40,000%</p>
<p>C: Mac Mini will cost €200 if ordered by 6:00 PM</p>
</div>
```
By defining `this.props.formats`, which specifies a set of named formats under `date` and `number` members, you can use those named formats as a second argument for `intlNumber()` and `intlDate()`. You can also reference them as a third token when defining the messages, e.g: `{deadline, date, timeStyle}`. In this case `deadline` describes the format options for its value, specifying that it is a `date` and should be formatted using the `timeStyle` custom formatter.
By defining `this.props.formats`, which specifies a set of named formats under `date` and `number` members, you can use those named formats as a second argument for `formatNumber()`, `formatDate()`, and `formatTime()`. You can also reference them as the third token when defining the messages, e.g: `{deadline, date, timeStyle}`. In this case `deadline` describes the format options for its value, specifying that it is a `date` and should be formatted using the `timeStyle` custom format.
### App Configuration
Another feature of the Intl Mixin is its ability to propagate `formats` and `locales` to any child component. Internally, it laverages `context` to allow those child components to reuse the values defined at the parent level, making this ideal to define custom formatters for the app, and the language or the application by defining them or passing them into the root component when rendering the application. Ideally, you will do this:
Another feature of the Intl Mixin is its ability to propagate `formats` and `locales` to any child component. Internally, it leverages the `context` to allow those child components to reuse the values defined at the parent level, making this ideal to define custom formats and the locale for the app by defining them or passing them into the root component when rendering the application. **This is always the recommended way to provide i18n message strings to the React component hierarchy.** Ideally, you will do this:
```javascript
var appLocales = ['en-US'];
var appFormats = { number: {}, date: {} };
var i18n = {
locales: ['en-US'],
formats: { number: {}, date: {}, time: {} },
messages: {}
};
React.renderComponent(
<MyRootComponent locales={appLocales} formats={appFormats} />,
<MyRootComponent
locales={i18n.locales}
formats={i18n.formats}
messages={i18n.messages} />,
document.getElementById('container')

@@ -194,15 +240,16 @@ );

Then make sure `MyRootComponent` uses the `ReactIntlMixin`. By doing that, you can define the list of `locales`, normally one or more in case you want to support fallback, (e.g.: `["fr-FR", "en"]`); and you can define `formats` to describe how the application will format dates and numbers. All child components will be able to inherit these two structures in such a way that you don't have to propagate or define `locales` or `formats` at each level in your application. Just apply this mixin in those components that are suppose to use `this.intlNumber()`, `this.intlDate()` and/or `this.intlMessage()` in the `render()` method and you're all set.
Then make sure `MyRootComponent` uses the `ReactIntlMixin`. By doing that, you can define the list of `locales`, normally one or more in case you want to support fallback, (e.g.: `["fr-FR", "en"]`); and you can define `formats` to describe how the application will format dates and numbers. You will also want to mass the `messages` for the current locale, since the string will be locale-specific. All child components will be able to inherit these three structures in such a way that you don't have to propagate or define them at each level in your application. Just apply this mixin in those components that are suppose to use `this.formatNumber()`, `this.formatDate()` and/or `this.formatMessage()` in the `render()` method and you're all set.
## How to use intlMessage()
How to Use `formatMessage()`
----------------------------
### Example #1: Simple String Replacement
### Example #1: simple string replacement
```javascript
var MyComponent = React.createClass({
mixins: [ReactIntlMixin],
render: function () {
return <p>{this.intlMessage(GlobalMessages.MSG1, {
return <p>{this.formatMessage(this.getIntlMessage("reporting"), {
employee: this.props.name,

@@ -214,8 +261,16 @@ manager: this.props.manager

// render in English:
GlobalMessages = {
MSG1: "{employee} reports to {manager}."
var messages = {
"en-US": {
reporting: "{employee} reports to {manager}."
},
"de-DE": {
reporting: "{employee} berichtet an {manager}."
}
};
// Render in English:
React.renderComponent(
<MyComponent locales={["en-US"]} name="John" manager="Mike" />,
<MyComponent locales={["en-US"]} messages={messages["en-US"]}
name="John" manager="Mike" />,
document.getElementById('example')

@@ -225,15 +280,12 @@ );

// render in german:
GlobalMessages = {
MSG1: "{EMPLOYEE} berichtet an {MANAGER}."
};
// Render in german:
React.renderComponent(
<MyComponent locales={["de-DE"]} name="John" manager="Mike" />,
<MyComponent locales={["de-DE"]} messages={messages["de-DE"]}
name="John" manager="Mike" />,
document.getElementById('example')
);
// - german output: "John berichtet an Mike."
// - German output: "John berichtet an Mike."
```
### Example #2: string replacement with pluralization
### Example #2: String Replacement with Pluralization

@@ -243,4 +295,5 @@ ```javascript

mixins: [ReactIntlMixin],
render: function () {
return <p>{this.intlMessage(GlobalMessages.OTHER, {
return <p>{this.formatMessage(this.getIntlMessage("publishers"), {
COMPANY_COUNT: this.props.count

@@ -251,19 +304,30 @@ })}</p>;

// render in English:
GlobalMessages = {
OTHER: "{COMPANY_COUNT, plural, one {One company} other {# companies}} published new books."
var messages = {
"en-US": {
publishers: "{COMPANY_COUNT, plural," +
"one {One company}" +
"other {# companies}}" +
" published new books."
},
"ru-RU": {
publishers: "{COMPANY_COUNT, plural," +
"one {Одна компания опубликовала}" +
"few {# компании опубликовали}" +
"many {# компаний опубликовали}" +
"other {# компаний опубликовали}}" +
" новые книги."
}
};
// Render in English:
React.renderComponent(
<MyComponent locales={["en-US"]} count=1 />,
document.getElementById('example')
<MyComponent locales={["en-US"]} messages={messages["en-US"]} count=1 />,
document.getElementById("example")
);
// - English output: "One company published new books."
// render in Russian:
GlobalMessages = {
OTHER: "{COMPANY_COUNT, plural, one {Одна компания опубликовала} few {# компании опубликовали} many {# компаний опубликовали} other {# компаний опубликовали}} новые книги."
};
// Render in Russian:
React.renderComponent(
<MyComponent locales={["ru-RU"]} count=1 />,
<MyComponent locales={["ru-RU"]} messgaes={messages["ru-RU"]} count=1 />,
document.getElementById('example')

@@ -274,3 +338,3 @@ );

// if the `count` property that is passed into `MyComponent` is 2, then:
// If the `count` property that is passed into `MyComponent` is 2, then:
// - English output: "2 companies published new books."

@@ -284,6 +348,7 @@ // - Russian output: "2 компании опубликовали новые книги."

As you can see in this example, Russian has different rules when it comes to pluralization, having different messages for `one`, `few` and `other`, while American English is just targeting `one` and `other`.
As you can see in this example, Russian has different rules when it comes to pluralization, having different sub-messages for `one`, `few` and `other`, while American English is just targeting `one` and `other`.
### Example #3: Dates and Numbers Within Messages
### Example #3: string replacement with pluralization and gender
In any message, you can use `{<valueName>, number [, <optionalFormat>]}` and `{<valueName>, date [, <optionalFormat>]}` to format numbers and dates, which that includes combining them with plural and gender structures as well.

@@ -293,100 +358,62 @@ ```javascript

mixins: [ReactIntlMixin],
render: function () {
return <p>{this.intlMessage(GlobalMessages.ANOTHER, this.props)}</p>;
return <p>
{this.formatMessage(this.getIntlMessage('product'), this.props)}
</p>;
}
});
// render in French:
GlobalMessages = {
ANOTHER: "{TRAVELLER_COUNT} {TRAVELLER_COUNT, plural, one {est {GENDER, select, female {allée} other {allé}}} other {sont {GENDER, select, female {allées} other {allés}}}} à {CITY}."
};
React.renderComponent(
<MyComponent locales={["fr-FR"]} TRAVELLER_COUNT=1 GENDER="female" />,
document.getElementById('example')
);
// - French output: "1 est allée à Havana"
var i18n = {
locales: ["en-US"],
messages: {
product: "{product} will cost {price, number, eur} if ordered by {deadline, date, timeStyle}"
},
// render in English
GlobalMessages = {
ANOTHER: "{TRAVELLER_COUNT} went to {CITY}."
};
React.renderComponent(
<MyComponent locales={["en-US"]} TRAVELLER_COUNT=1 GENDER="female" />,
document.getElementById('example')
);
// - English output: "1 went to Havana"
formats: {
date: {
timeStyle: {
hour: "numeric",
minute: "numeric"
},
// render in French:
GlobalMessages = {
ANOTHER: "{TRAVELLER_COUNT} {TRAVELLER_COUNT, plural, one {est {GENDER, select, female {allée} other {allé}}} other {sont {GENDER, select, female {allées} other {allés}}}} à {CITY}."
number: {
EUR: {
style: "currency",
currency: "EUR"
}
}
}
};
React.renderComponent(
<MyComponent locales={["fr-FR"]} TRAVELLER_COUNT=3 />,
document.getElementById('example')
);
// - French output: "3 sont allés à Havana"
// render in English
GlobalMessages = {
ANOTHER: "{TRAVELLER_COUNT} went to {CITY}."
};
// Render in English:
React.renderComponent(
<MyComponent locales={["en-US"]} TRAVELLER_COUNT=3 />,
<MyComponent
locales={i18n.locales} formats={i18n.formats} messages={i18n.messages}
product="Mac Mini" price=200 deadline=1390518044403 />,
document.getElementById('example')
);
// - English output: "3 went to Havana"
// - English output: "Mac Mini will cost €200 if ordered by 6:00 PM"
```
The example above is more generic, and we pass all props as data into the `intlMessage()` method instead of picking up individual `props` that we need per translation. This is a common practive for small components.
_Note: `formatMessage()` will take care of creating the internal date and number format instances, and cache them to avoid creating unnecessary objects by reusing existing instances when similar formats are applied._
You can also see how the French version of `GlobalMessages.ANOTHER` is combining the use of pluralization (for `TRAVELLER_COUNT`) and the gender of the traveler or travelers because it is derived from Latin, in which case the gender might change the structure of the sentence, while in American English this is not affecting the output of the translation.
Limitations
-----------
### Example #4: dates and numbers within messages
Not all browsers have implemented [ECMAScript 402][], which is the Internationalization API, for older browsers, and Safari, you might need to patch the browser by loading [Intl.js][] polyfill before including `react-intl.js` library.
In any message, you can use `{<valueName>, number[, <optionalFormat>]}` and `{<valueName>, date[, <optionalFormat>]}` to format numbers and dates, and that includes combining them with plural and gender structures as well.
License
-------
```javascript
var MyComponent = React.createClass({
mixins: [ReactIntlMixin],
render: function () {
return <p>{this.intlMessage(GlobalMessages.COMBINE, this.props)}</p>;
}
});
This software is free to use under the Yahoo Inc. BSD license.
See the [LICENSE file][] for license text and copyright information.
// render in English:
GlobalMessages = {
COMBINE: "{product} will cost {price, number, eur} if ordered by {deadline, date, timeStyle}"
};
GlobalLocales = ["en-US"];
GlobalFormats = {
"date": {
"timeStyle": {
"hour": "numeric",
"minute": "numeric"
}
"number": {
"eur": {
"style": "currency",
"currency": "EUR"
}
}
};
React.renderComponent(
<MyComponent locales={GlobalLocales} formats={GlobalFormats} product="Mac Mini" price=200 deadline=1390518044403 />,
document.getElementById('example')
);
// - English output: "Mac Mini will cost €200 if ordered by 6:00 PM"
```
_Note: `IntlMessage()` will take care of caching internal structures for date and numbers to avoid creating unnecessary objects by reusing existing instances when similar formats are applied._
Limitations
-----------
Not all browsers have implemented [ECMAScript 402][], which is the internationalization API, for older browsers, and Safari, you might need to patch the browser by loading [Intl.js][] polyfill before including `react-intl.js` library.
[npm]: https://www.npmjs.org/package/react-intl
[npm-badge]: https://img.shields.io/npm/v/react-intl.svg?style=flat
[david]: https://david-dm.org/yahoo/react-intl
[david-badge]: https://img.shields.io/david/yahoo/react-intl.svg?style=flat
[Intl.js]: https://github.com/andyearnshaw/Intl.js

@@ -401,1 +428,2 @@ [ECMAScript 402]: http://www.ecma-international.org/ecma-402/1.0/

[Strawman Draft]: http://wiki.ecmascript.org/doku.php?id=globalization:messageformatting
[LICENSE file]: https://github.com/yahoo/react-intl/blob/master/LICENSE.md
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc