React update intl dont work: Uncaught ReferenceError: Could not find Intl message:

- 1 answer

Ad

I did upgrade from react 0.13 to the newest one. Here a list of the dependencies I changed.

react: 0.13.3 -> 0.14.3  
react-dom: none  -> 0.14.3  
react-router: 0.13.3 -> 1.0.3  
react-history: none -> 1.0.3  
react-intl: 1.2.0 -> 1.2.2  
intl: 1.0.0 -> 1.0.1  

But I cant get the translations work again.

Uncaught ReferenceError: Could not find Intl message: test

// app.js
var React = require('react');
var ReactDom = require('react-dom');
var Router = require('react-router').Router;
var routes = require('./routes');
var createHistory = require('history').createHistory;

var intlData = {
    locales: 'en',
    messages: {
        test: 'Test'
    }
};

ReactDom.render(<Router history={createHistory()} intl={intlData}>{routes}</Router>, document.getElementById('app'));


// Test.js
var React = require('react');
var ReactIntl = require('react-intl');
var IntlMixin = ReactIntl.IntlMixin;

var Test = React.createClass({

    mixins: [IntlMixin],

    render: function() {
        return (
            <div>
                <h1>
                    {this.getIntlMessage('test')}
                </h1>
            </div>
        );
    }
});

module.exports = Test;

What did I miss in the update? What is the correct way to init my messages.

Ad

Answer

Ad

IntlMixin works by looking on the context for the relevant data, specifically, this.context.locales, this.context.formats, and this.context.messages. It was probably the React Router upgrade from 0.x to 1.x — which changed the way the top-level component is handled — that broke things.

However, if you look at the source linked above, you can see that the mixin looks for the data on this.contextonly if it's not found on this.props. Thus, if you could pass your internationalization data to every route handler as a prop, things would work fine. Luckily, React Router allows you to do just that via createElement.

createElement should be a function that takes two arguments: the component React Router wants to render, and the props it wants to send it. The function should render that component with the given props. The default implementation looks like this:

function createElement(Component, props) {
  return <Component {...props} />
}

However, you can further customize how the component gets rendered. For your case, it might look something like:

function createIntlElement(Component, props) {
  return <Component intl={intlData} {...props} />
}

although it looks like from the React Intl docs that the props should be split out, so if that doesn't work, maybe more like:

function createIntlElement(Component, props) {
  return <Component {...props}
                    locales={intlData.locales}
                    messages={intlData.messages} />
}

or, more simply using the spread syntax,

function createIntlElement(Component, props) {
  return <Component {...props} {...intlData} />
}

You then instruct the router to use your createElement function by passing it to the createElement prop:

var router = (
  <Router history={createHistory()} createElement={createIntlElement}>
    {routes}
  </Router>
);
ReactDom.render(router, document.getElementById('app'));

Don't forget to include IntlMixin on all your route handlers so that child components that aren't directly rendered by the router still have access to the context.


React Intl version 2 (now in beta) appears to use a IntlProvider component, much like Redux's Provider component, to provide the correct context for you, so using createElement should not be necessary when using that version.

Ad
source: stackoverflow.com
Ad