martinandert / react-translate-component

A component for React that utilizes the Counterpart module to provide multi-lingual/localized text content.
MIT License
322 stars 31 forks source link

Allow counterpart instances passed in via context #6

Closed nikuph closed 9 years ago

nikuph commented 9 years ago

When you use the component on the server side you have to create different counterpart instances to ensure consistent locale settings for every request.

martinandert commented 9 years ago

I don't get it. Do you have a use case for this or a failing test? Can you show me a scenario where the locale settings become inconsistent?

nikuph commented 9 years ago

Here is a short example which shows the problem

'use strict';

var http = require('http');
var url = require('url');
var counterpart = require('counterpart');
var React = require('react');
var Translate = require('react-translate-component');

var en = {hello: 'Hello'};
var de = {hello: 'Hallo'};

counterpart.registerTranslations('en', en);
counterpart.registerTranslations('de', de);

http.createServer(function(req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});

  var queryData = url.parse(req.url, true).query;
  counterpart.setLocale(queryData.locale || 'en');

  setTimeout(function() {
    res.end(
      React.renderToStaticMarkup(
        React.createElement(Translate, {content: 'hello'})
      )
    );
  }, 3000);
}).listen(process.env.PORT || 8080);

When you visit http://localhost:8080?locale=de and http://localhost:8080?locale=en sequentially, everything is fine. But when you hit them in parallel, you will get both responses with the same locale (from the last request).

martinandert commented 9 years ago

Ah, I see. Good catch.

Can you give me an example how context will solve this problem? E.g. by rewriting the code of you last comment.

nikuph commented 9 years ago

In this example I create a new counterpart instance for each request and pass it via context to the Translate component. This works with the adjustments of the pull request.

'use strict';

var http = require('http');
var url = require('url');
var Counterpart = require('counterpart').Instance;
var React = require('react');
var Translate = require('react-translate-component');

var en = {hello: 'Hello'};
var de = {hello: 'Hallo'};

var MyApp = React.createClass({
  childContextTypes: {
    counterpart: React.PropTypes.object
  },

  getChildContext: function() {
    return {
      counterpart: this.props.counterpart
    };
  },

  render: function() {
    return React.createElement(Translate, {content: 'hello'});
  }
});

http.createServer(function(req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});

  var queryData = url.parse(req.url, true).query;

  var counterpart = new Counterpart();
  counterpart.registerTranslations('en', en);
  counterpart.registerTranslations('de', de);
  counterpart.setLocale(queryData.locale || 'en');

  setTimeout(function() {
    res.end(
      React.renderToStaticMarkup(
        React.createElement(MyApp, {counterpart: counterpart})
      )
    );
  }, 3000);
}).listen(process.env.PORT || 8080);
martinandert commented 9 years ago

Thanks for the code sample. That made everything clear.

martinandert commented 9 years ago

I've made some adjustments: renamed context.counterpart to context.translator, exported a translatorType prop type, and added a test.

Would you give v0.9.0 a try a tell me if everything is okay for you?

Thanks again for finding this issue and for your contribution!

martinandert commented 9 years ago

@nikuph Did you find some time to test whether v0.9 works for you?

nikuph commented 9 years ago

@martinandert Yes, seems to be fine. Thanks for taking the adjustments.

martinandert commented 9 years ago

Thanks for the confirmation. I've updated the readme accordingly:

https://github.com/martinandert/react-translate-component#asynchronous-rendering-on-the-server-side

Just out of curiosity: Why didn't you just move the setLocale call inside the callback function? Example:

setTimeout(function() {
  counterpart.setLocale(queryData.locale || 'en');

  res.end(
    React.renderToStaticMarkup(
      React.createElement(Translate, {content: 'hello'})
    )
  );
}, 3000);