APSL/redux-i18n

Translate a string from outside of a component

Closed this issue · 1 comments

Hi, and thanks for your nice and simple library!

Is it any way to translate a string from, for example, a reducer?
I need to store in the state some localized text that includes localized dates. The text is computed in a reducer called after some complex actions, so I can not move this logic in the component where the initial action is dispatched without a lot of complexity. It uses the author's locale, and can then be changed by the author, so I need it to be stored as-it in the state, and not translated when displayed.

As the translations and the current locale are in the state, what would be the best way to get a function like I18n.translate("My string", state: state.i18nState)?

Does this makes sense?

Hi, I don't exactly get the reason why you need to store localized strings in the Redux store, but I guess it's not a good idea, as a reducer should be a pure function with an output computed only based on the previous state and an action. If I'm not wrong, translations are not in the Redux store but in the t() function scope, which is in React's context.

What I've found helpful for translating a string from "outside" a component is taking a more "functional" approach and just pass the t() function as an argument to other functions, specially selectors (which is where I prefer to place complex computations, and not inside reducers). For example:

import { connect } from 'react-redux';
import React from 'react';

const MyComponent = ({ myComplexData }, { t }) => {
  return (
    <div>
      {myComplexData(t)}
    </div>
  );
};

MyComponent.propTypes = {
  myComplexData: React.PropTypes.func.isRequired
};

MyComponent.contextTypes = {
  t: React.PropTypes.func.isRequired
};

const mapStateToProps = state => ({
  myComplexData: t => {
    // really complex computations here using state and whatever...
    // We have the t() function in scope!
    return someLocalizedString;
  }
});

export default connect(mapStateToProps)(MyComponent);

So, it's not a traditional selector in the sense that it doesn't return the data ready to be consumed by the component, but it returns a function that receives t() and then returns the localized data.

If inside the selector there are calls to some other helper functions that need to use t(), I just pass it to them as an argument and repeat the strategy...

I hope this idea help you!