Git Product home page Git Product logo

redux-i18n's Introduction

Description

redux-i18n is a simple yet powerful package to translate your react applications using react-redux.

npm version downloads

Installation

npm i redux-i18n --save

or

yarn add redux-i18n

Features

  • Translate literals.
  • Pluralize literals.
  • Designed for react-redux.
  • Compatible with Immutable.js.
  • Export translations to POT files (make your translations with Poedit).
  • Import translations from .PO files to translations.js object (for use in your project).
  • Add comments for translators.

Requirements

  • node >= 4.0.0

Overview

redux-i18n offers your app the t() function to translate literals.

The t() function is available in the components of your app via React context. To achieve this you need to wrap your app into the <I18n /> component from redux-i18n that provides for the context. Furthermore, for all components that want to use the t() function you need to define contextTypes, e.g.:

// import ...
import PropTypes from 'prop-types'

class MyComponent extends React.Component {
  render() {
    return <div>{this.context.t('Hello World!')}</div>
  }
}

MyComponent.contextTypes = {
  t: PropTypes.func
}

If contextTypes is not defined, then context will be an empty object.

The t() function takes up to three arguments t(textKey [, params, comments]), where textKey is either the string to be translated or --- for pluralization --- an object as defined below.

For setting the language in the redux store redux-i18n offers an action creator setLanguage.

To manage the translations in your React app, redux-i18n supports two choices:

  1. load all your translations into a one big JS object
  2. load your translations into a slice of your redux store

For the latter redux-i18n provides an action function creator setTranslations. As setTranslations is an action function creator you need to add redux-thunk to your middleware for it to work.

redux-i18n supports your store in plain JavaScript structures, but also if it is managed by help of immutable.js.

Finally, redux-i18n offers scripts to generate a translations object from po files that can be managed in Poedit.

Usage

The package provides a parent component to encapsulate your application as well as helpers functions to translate your project.

// import ...
import I18n from 'redux-i18n'
// with Immutable.js:
import I18n from 'redux-i18n/immutable'

import { translations } from './translations'

class Root extends React.Component {
  render() {
    return (
      <Provider store={store}>
        <I18n translations={translations}>
          <App />
        </I18n>
      </Provider>
    )
  }
}

Where translations is a dictionary similar to this:

export const translations = {
  es: {
    'Translate this text': 'Traduce este texto',
    'Hello {n}!': 'Hola {n}!'
  }
}

You can also set the initial language with the initialLang prop:

<I18n translations={translations} initialLang="es">
  <div>
    <h1>My Project</h1>
    {this.props.children}
  </div>
</I18n>

If you have partial translations, this means that you don't have your translations at 100% and you want to show untranslated literals in an other language, you can use the fallbackLang prop.

<I18n translations={translations} initialLang="de" fallbackLang="en">
  <div>
    <h1>My Project</h1>
    {this.props.children}
  </div>
</I18n>

In this case, if you want to show this translations:

<div>{this.context.t('_hello_')}</div>

And this isn't in "de" language, it will show in "en".

Redux Reducer

The language state is managed in a slice of the store named i18nState. Therefore, you have to add the i18nState reducer in your combineReducers.

import { otherreducers } from './Yourproject'

import { i18nState } from 'redux-i18n'
// with Immutable.js:
import { i18nState } from 'redux-i18n/immutable'

const appReducer = combineReducers({
  otherreducers,
  i18nState
})

The current language is contained in the lang key of i18nState.

The i18nState is initially defined as

const defaultI18nState = {
  lang: 'en',
  translations: {},
  forceRefresh: false
}

// immutablejs
const defaultI18nState = new Map({
  lang: 'en',
  translations: {},
  forceRefresh: false
})

When you map your state to props with connect you can also access the lang attribute in your components:

export default connect(state => ({
  lang: state.i18nState.lang,
}))(Home)

// with Immutable.js:
export default connect(state => ({
  lang: state.getIn(['i18nState', 'lang']),
}))(Home)

Translate literals

You can access the functions of <I18n /> using your component's context. For example:

Home.contextTypes = {
  t: PropTypes.func.isRequired
}

...you will then be able to use the t() method in your component.

render() {
  return (
    <div>
      <strong>Your current language, is: {this.props.lang}</strong><br/>
      {this.context.t("Translate this text")}<br/>
      {this.context.t("Hello {n}!", {n: "World"})}<br/><br/>
      <button onClick={this.changeLanguage.bind(this)}>Change Language</button>
    </div>
  )
}

You can also use the t() function to change date formats

export const translations = {
  de: {
    'YYYY-MM-DD': 'DD.MM.YYYY'
  }
}
render() {
  let today = moment()
  return (
    <div>
      {today.format(this.context.t("YYYY-MM-DD"))}
    </div>
  )
}

Add comments for translators.

render() {
  return (
    <div>
      {this.context.t("Translate this text", {},
                      "This is a comment for translators.")}
      {this.context.t("Hello {n}!", {n: "Cesc"},
                      "This is another comment.")}
    </div>
  )
}

Here's how Poedit will show the comments:

Poedit screenshot

HTML Object as parameter

const user = { name: 'World' }
const name = <span>{user.name}</span>
return <div dangerouslySetInnerHTML={{ __html: context.t('Hello {name}', { name: name }) }} />

Result:

Hello <span>Cesc</span>

Notice that for security reasons we can't print html code directly, which is why we need to use the "dangerouslySetInnerHTML" method for that.

Stateless components

Example:

const Foo = ({}, context) => <h1>{context.t('Hello World')}</h1>

Pluralize

To use plurals in your translations.

<div>{this.context.t(['una noche', '{n} noches', 'n'], { n: 1 })}</div>

Pass an array instead of a string as first parameter. The first element is a singular term, the second is the plural form and the last one is an object used to set the quantity.

After extracting the translations to a POT file and opening it with Poedit you will see the following:

Poedit screenshot

Also the translations object allows to set an options node. There you can set a plurals form rule and a plurals number. Also, you can suppress warnings logged in console. For example:

export const translations = {
  es: {
    'Translate this text': 'Traduce este texto',
    'Hello {n}!': 'Hola {n}!'
  },
  options: {
    plural_rule: 'n > 1',
    plural_number: '2',
    suppress_warnings: true // defaults to false
  }
}

When the translations are generated from po import file, this node is created automatically.

Note: Versions >=1.5.10 allow to use all existing pluralization rules: http://docs.translatehouse.org/projects/localization-guide/en/latest/l10n/pluralforms.html

Change language

Use the setLanguage action.

import {setLanguage} from "redux-i18n"

componentWillMount() {
  this.props.dispatch(setLanguage("es"))
}

If you work with combined languages like "es-ES", "en-GB", but your translations object doesn't include those properties...

export const translations = {
  "es": {
    ...
  },
  "en": {
    ...
  }
}

...redux-i18n will fallback on the closest property. In this case, "es" or "en".

Extract/Import scripts

redux-i18n includes a script to extract your translation strings to a .pot template which you can use in Poedit, and another to import strings from po files to a translation.js.

Add the scripts in your package.json for this purpose:

"scripts": {
  "extract": "i18n_extract",
  "import": "i18n_import"
}

You can then run the following commands in your terminal:

npm run extract
npm run import

Extract texts and build template.pot

npm run extract

By default, this script will search for all literals inside your src folder with a regular expression and build a locales/template.pot file. This file can then be used in Poedit to build en.po, es.po, etc. files.

If you want to set other source folder, you can use the --source switch.

"scripts": {
  "extract": "i18n_extract --source=mysourcefolder",
  "import": "i18n_import"
}

Or if you want to export your locales to a different folder...

"scripts": {
  "extract": "i18n_extract --source=mysourcefolder --locales=mylocalesfolder",
  "import": "i18n_import"
}

By default this command find in all .js and .jsx file extensions, but you can customize it with fexts parameter. Check out this example:

"scripts": {
  "extract": "i18n_extract --fexts=js,jsx,coffee",
  "import": "i18n_import"
}

The default regular expression will search all occurrences of this.context.t string, but you can also supply your own custom pattern, as in the following example:

export default function App({ aProp, bProp }, { t: translate }) {
  return <div>{translate('Hello world!')}</div>
}

You will then need to set the --pattern flag in package.json:

"scripts": {
  "extract": "i18n_extract --pattern=translate",
  "import": "i18n_import"
}

Import .po files

When your translators are done translating your terms, you can import your po files running the import script:

npm run import

This script read all po files inside your locales folder, extract all translations and build a src/translations.js that you can then use in your project.

Your .po files must define header language, check mininal format for more information.

You can also set another locales folder:

"scripts": {
  "extract": "i18n_extract --source=mysource --locales=mylocales",
  "import": "i18n_import --locales=mylocales"
}

Or, save translation.js to a different location:

"scripts": {
  "extract": "i18n_extract --source=mysource --locales=mylocales",
  "import": "i18n_import --locales=mylocales --translations=myfolder"
}

You can also change the encoding for your extraction from PO (default is iso-8859-1)

"scripts": {
  "extract": "i18n_extract --source=mysource --locales=mylocales",
  "import": "i18n_import --encoding=utf-8"
}

Async translations

When applications grow, translations tend to bigger as well, adding a lot to the overall size of the js bundle.

You can set an empty translations object to the <I18n/> component and set the useReducer prop to true to use the store as the source of strings. For example:

<Provider store={this.store}>
  <I18n translations={{}} useReducer={true}>
    <MainApp />
  </I18n>
</Provider>

Then you can use the setTranslations action.

import { setTranslations } from 'redux-i18n'
api.get('...').then((r) => this.props.dispatch(setTranslations(r.translations)))

You can pass a second parameter to the action to set the language. Depending on your response's structure, it could look like this:

api.get('...').then((r) => this.props.dispatch(setTranslations(r.translations, 'en')))

Since version 1.5.1 is possible pass a dictionary as a second param with some options. This allows us set more functionalities to method.

  • preserveExisting (bool): If is true, the translations received does merge with existing translations.
  • language (string): Language code

Some examples:

setTranslations(newTranslations, { preserveExisting: true })
setTranslations({ Hello: 'Hallo' }, { language: 'de' })

InitialState

Sometimes language is set initially by the redux store creation, or in an isomorphic way. In this case, you can set the initialized prop to stop the I18n provider from dispatching an action.

HOC

If you want to isolate the use of context from your components, you can import the Localize Hoc to provide the translate function as a prop to your component. For example:

import { localize } from 'redux-i18n'

class SomeComponent extends Component {
  render() {
    return this.props.t('hello world')
  }
}

export default localize()(SomeComponent)

You can also change the name of the provided prop:

import { localize } from 'redux-i18n'

class SomeComponent extends Component {
  render() {
    return this.props.translate('hello world')
  }
}

export default localize('translate')(SomeComponent)

Please, if you like my package, don't forget to rate it. Click on the "star"!

redux-i18n's People

Contributors

aherbots avatar aherbotsdvtm avatar andreewille avatar bjackson avatar doei avatar francescarpi avatar gannoncurran avatar hussainshaikh12 avatar jhta avatar josephbrooksbank avatar karland avatar kwangminini avatar mac2000 avatar nicolascrop avatar renchap avatar salec avatar stayman avatar stuk88 avatar tagoro9 avatar theactualwalko avatar tiii avatar topaxi avatar tuyakhov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

redux-i18n's Issues

React 16 language switching does not work

After updating to React 16.2.0 and after switching the language(REDUX_I18N_SET_LANGUAGE) , an error occurs that occurs in the dependent library "react-deep-force-update". The error appears only in the compiled version and does not appear in the local version.

main.6296193c.js:2182 TypeError: Cannot read property '_pendingForceUpdate' of undefined at setPendingForceUpdate (main.6296193c.js:22530) at traverseRenderedChildren (main.6296193c.js:22516) at deepForceUpdate (main.6296193c.js:22550) at I18n.componentDidUpdate (main.6296193c.js:28831) at commitLifeCycles (main.6296193c.js:2164) at c (main.6296193c.js:2175) at k (main.6296193c.js:2178) at p (main.6296193c.js:2179) at batchedUpdates (main.6296193c.js:2185) at qb (main.6296193c.js:2036) x @ main.6296193c.js:2182 c @ main.6296193c.js:2176 k @ main.6296193c.js:2178 p @ main.6296193c.js:2179 batchedUpdates @ main.6296193c.js:2185 qb @ main.6296193c.js:2036 ob @ main.6296193c.js:2036 batchedUpdates @ main.6296193c.js:2037 dispatchEvent @ main.6296193c.js:2040 main.6296193c.js:22530 Uncaught TypeError: Cannot read property '_pendingForceUpdate' of undefined at setPendingForceUpdate (main.6296193c.js:22530) at traverseRenderedChildren (main.6296193c.js:22516) at deepForceUpdate (main.6296193c.js:22550) at I18n.componentDidUpdate (main.6296193c.js:28831) at commitLifeCycles (main.6296193c.js:2164) at c (main.6296193c.js:2175) at k (main.6296193c.js:2178) at p (main.6296193c.js:2179) at batchedUpdates (main.6296193c.js:2185) at qb (main.6296193c.js:2036) setPendingForceUpdate @ main.6296193c.js:22530 traverseRenderedChildren @ main.6296193c.js:22516 deepForceUpdate @ main.6296193c.js:22550 componentDidUpdate @ main.6296193c.js:28831 commitLifeCycles @ main.6296193c.js:2164 c @ main.6296193c.js:2175 k @ main.6296193c.js:2178 p @ main.6296193c.js:2179 batchedUpdates @ main.6296193c.js:2185 qb @ main.6296193c.js:2036 ob @ main.6296193c.js:2036 batchedUpdates @ main.6296193c.js:2037 dispatchEvent @ main.6296193c.js:2040
orca - inbox 2017-12-25 15-19-39
orca - inbox 2017-12-25 15-29-16

You need to update the library react-deep-force-update to version 2.1.1

Extract script throws error

After updating package.json and running npm run extract, I get the following error:

> i18n_extract

module.js:327
    throw err;
    ^

Error: Cannot find module 'glob'
    at Function.Module._resolveFilename (module.js:325:15)
    at Function.Module._load (module.js:276:25)
    at Module.require (module.js:353:17)
    at require (internal/module.js:12:17)
    at Object.<anonymous> (/Users/edavis/Projects/turo-web-client/node_modules/redux-i18n/bin/i18n_extract.js:2:12)
    at Module._compile (module.js:409:26)
    at Object.Module._extensions..js (module.js:416:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Function.Module.runMain (module.js:441:10)

Possibly a missing dependency?

Plural form adds undefined to translations file when missing

Take for example this Chinese (no plural forms) translation:

msgid "1 item is selected."
msgid_plural "{n} items are selected."
msgstr[0] "{n} 个项目已选中."

msgstr[1] is not present
This is the result after importing

'1 item is selected.': '{n} 个项目已选中.',
'{n} items are selected.': 'undefined',

Translate constant files

Hi.
I have this use case of translating config files which are outside the scope of react. Though currently, I am passing the context.t to these constant .js files from the components and getting the translated labels.

Is there a better way of doing it ?

PS: awesome package !

Add new language translations on demand.

Have you considered the possibility to add the languages into reducer?

It would help loading additional strings on demand, when changing a language, instead of including the whole language array in the first load.

Let me know what you think (even if it's a bad idea). I might be able to help

override the default state

Is there a way to simply override the default i18nState values when initializing the reducer?

I would need to override the lang property of it based on another value stored in a configuration file.

i've found this in the docs, but nothing on how to override the defaults. What i'm thinking now is to just manually call the action to set the language after it has been initialized, but would like to know if there is a better more direct way to do it already while initializing.

import {otherreducers} from "./Yourproject"

import {i18nState} from "redux-i18n"
// with Immutable.js:
import {i18nState} from "redux-i18n/immutable"

const appReducer = combineReducers({
  otherreducers,
  i18nState //here I would like to somehow pass the default lang value, if possible
})

how to pass to setLanguage to mapDispatchToProps

hi, I believe this is very stupid question from the very beginner (which I am), but I'm stuck, so please help!

In my component which is connect via connect() I initialize mapDispatchToProps in order to get access to actions:

import * as newsActions from '../actions/news'
import * as langActions from '../actions/lang'

const mapStateToProps = state => {
  const { language } = state
  const { lang } = state.i18nState
  return { language, lang }
}

const mapDispatchToProps = dispatch => {
  return bindActionCreators(Object.assign({},
    langActions, 
    newsActions
  ), dispatch)
}

export default connect(mapStateToProps, mapDispatchToProps)(Nav);

However if import setLanguage and add it inside Object.assign nothing happens and I don't see setLanguage in my props, so this doesn't work:

const mapDispatchToProps = dispatch => {
  return bindActionCreators(Object.assign({},
    langActions, 
    newsActions, 
    setLanguage
  ), dispatch)
}

However, I need to do it this way, I can't just use dispatch(setLanguage) because I don't have dispatch available at my props. Though if I delete mapDispatchToProps than I have dispatch available and everything works fine.

So how do I add setLanguage to my functions in mapDispatchToProps?

Extract method broken

When I run the "extract" method gives me the following error:

../node_modules/redux-i18n/bin/extract_utils.js:30
let group = {}
^^^
SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode

Im runing node v4.0.0

Stateless components

Can not find docs, tests, samples for stateless components is it possible to use redux-i18n with them at all?

E.g. dummy components do not have this, context, etc

import React from 'react'

const Foo = () => <h1>{context.t("Hello World")}</h1>

Foo.contextTypes = {
    t: React.PropTypes.func.isRequired
}

export default Foo

May be some kind of connect may pass translation function via props or something like this?

unwanted init of redux-i18n when page refreshes

Hey guys,

So consider this case – user switched language, then refresh page and bam! everything is goes to initialized values. How to avoid that?

What is the logic behind action REDUX_i18N_SET_LANGUAGE ???
It fires on every component no matter what – how to turn it off? Or force it to fire just once?

Add a way to preserve already existing translations

Right now I'm using the translations prop in the I18n component, but I would like to use the reducer to keep the translations.

The problem is that in a project I'm working on, the translations are loaded partially (by route) and there is also a set of translations that are loaded all the time. If I wanna use the setTranslations action, this cannot be achieved, as the initial shared translations will be deleted by the route translations. So, I would like to have a way to merge translations (within a language) instead of replacing them.

Does it make sense to have such a feature?

I can work on this, but since there are different approaches to solve the problem, I would like to get some guidance on which option to implement (if it makes sense to add this feature) before I get started. Some ideas that I have:

  • Add an option to the existing setTranslations action. This involves some refactor. Since both language and a possible new parameter preserveExisting are optional (method signature would change to something like setTranslations(translations, {language, preserveExisting}), but this method is not compatible with the existing signature so we would have to check if the second arg is a string (language) or an object (new way) and it doesn't feel totally right.
  • Preserve the translations as a default. This is fine, but it may brake the existing functionality for certain users (Not quite sure of this).
  • Add a new public mergeTranslations action that merges the new translations with the existing ones.

Can you think of any other possibilities?

Thank you very much.

Import script giving error

Hi,

Extract script was writing the file with name template.pot. While import script was reading 'locales'}/*.po. After fixing that, I am facing below error.

****/node_modules/redux-i18n/bin/import_utils.js:11
  const lang = pocontent.headers.language.replace('_', '-')
                                ^

TypeError: Cannot read property 'language' of undefined
    at exports.getTrans (/home/vagrant/www/ray/modules/react-apps/node_modules/redux-i18n/bin/import_utils.js:11:33)
    at /home/vagrant/www/ray/modules/react-apps/node_modules/redux-i18n/bin/i18n_import.js:18:5
    at Array.map (native)
    at glob (/home/vagrant/www/ray/modules/react-apps/node_modules/redux-i18n/bin/i18n_import.js:17:9)
    at f (/home/vagrant/www/ray/modules/react-apps/node_modules/once/once.js:25:25)
    at Glob.<anonymous> (/home/vagrant/www/ray/modules/react-apps/node_modules/glob/glob.js:151:7)
    at emitOne (events.js:96:13)
    at Glob.emit (events.js:188:7)
    at Glob._finish (/home/vagrant/www/ray/modules/react-apps/node_modules/glob/glob.js:197:8)
    at done (/home/vagrant/www/ray/modules/react-apps/node_modules/glob/glob.js:182:14)

Option for custom regexp when extracting

I am using CoffeeScript for some of my React components, and currently i18n_extract only reads .js / .jsx files.
It would be great to have an additional argument to either specify the extensions of the source files, or the full regexp.

Changing srcPath to

var srcPath = `${args.source || 'src'}/**/*.{js,coffee}*`;

works fine for me. I expect it will also be helpful for Typescript user, as Typescript is a superset of JS.

Generic type 'ThunkAction' requires 4 type argument(s).

I'm using typescript and when I added your library to my projet I got this error and it wont compile.
Even if I modify the code to add an argument It wont compile. Here's the error :

C:/Users/xxxxx/dev/react_project/node_modules/redux-i18n/index.d.ts
(53,116): Generic type 'ThunkAction' requires 4 type argument(s).

Here's my dependencies :

"dependencies": {
"react": "^16.4.2",
"react-dom": "^16.4.2",
"react-redux": "^5.0.7",
"react-router-dom": "^4.3.1",
"react-scripts-ts": "2.17.0",
"redux": "^4.0.0",
"redux-devtools-extension": "^2.13.5",
"redux-i18n": "^1.5.13",
"redux-saga": "^0.16.0",
"redux-thunk": "^2.3.0",
"save-dev": "^2.0.0"
}

Deep objects value

Is there a possibility to getting deep objects value? In some 'official' way?
For example t('SOME.SOME.SOME')

From:

SOME: {
    SOME: {
        SOME: 'value'

Potential incompatability with react-functional

In general this repo works great, but I've got one small issue: the t contextType doesn't work if my component uses react-functional.

If I use react-functional, such as:

import React from 'react';
import functional from 'react-functional';

const MyFunctionalComponent = (props, {t}) => {
  return (
    <div>
      {t("I've got something to say")}
    </div>
  );
};

MyFunctionalComponent.contextTypes = {
  t: PropTypes.func.isRequired,
};

MyFunctionalComponent.componentWillMount = ({}) => doSomething();

export default functional(MyFunctionalComponent);

Uncaught TypeError: t is not a function

I've not produced a minimal test case repo yet, but it happens consistently in my app. Happy to produce a testcase repo if needed – if it's not obvious why react-functional would be causing the context not to work.

Support for defaultLocale

Is there a way to set defaultLocale which would basically default to a certain language if translation is not found?

For eg. we have all translations for en but missing some for de. In this case we would set defaultLocale to en and make sure that user with locale de does not see empty text but rather en translations.

Thank you for the response.

p.s.: As seen in https://www.npmjs.com/package/i18n

HOC error

Hello,

I want to use your HOC to use the function as "translate", but I have this error:
screenshot from 2017-08-16 19-24-01

I tried without redux connect but I always get the same issue.
I'm using react-router 4

Typescript support

Hello again.

Sorry to bother you guys, but I'm very fond of this package, it suits my needs very well.

I have a suggestion, to support Typescript. Currently, the exporting function only goes through js* files, going through ts* files would be greatly appreciated, possibly to customize this pattern through script parameters. It would also be really cool to be able to configure the name of the translations file when importing, as it's now named translations.js, where as translations.ts would work better for me.

Perhaps to include a definitions file as well, this would require quite some work, and I'd do it myself if I had the time, but it would be great to have, since Typescript is growing, as it's a remarkable addition to JavaScript for closer type control, and so on.

Simply something to think about, It'd be super if some day, you'd find the time and energy to add support for the ts-files at least, that'd be glorious.

Thanks!

comment argument doesn't work

Hey, there!
Your lib saves a lot of time.
But I can't extract comments.

// NavigationMenu.jsx
{
    this.context.t(
        'MenuItem1_Text', {}, 'Menu 1st item link text. Comment.'
    )
}
npm run extract

Output:

## template.pot

#: src/js/components/NavigationMenu.jsx
msgid "MenuItem1_Text"
msgstr ""

ie11 Dollar sign bug

Hi —

We've happily been using redux-i18n, but recently discovered a bug that affects our app (mostly in Internet Explorer 11).

Javascript's String.prototype.replace() interprets '$'s in params as replacement patterns unless they're escaped. Worse, IE interprets '$0' as a '$n' pattern and inserts the nth parenthesized submatch.

For example:
t("You’ll be charged an additional {amount} per hour", {amount: '$0.75'})
renders in ie11 as:
You’ll be charged an additional {amount}.75 per hour

Additionally, all browsers will render things like
t("I love dollar signs {dollarSigns}!", {dollarSigns: '$$'})
as:
I love dollar signs $! instead of the expected I love dollar signs $$!

I offer PR #14 as a fix.

Thanks!

Translate a string from outside of a component

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?

Dynamic Fallback language when field doesn't exist.

RIght now, the fallback language is set statically in the definition of the component.

But when somebody uses dual locales like en-US, en, de-CH and de to the translations object, when the item isn't found int the lan-XX, the fallback language should be lan, or at least it should be able to be set dynamically.

Eg:

export const translations = {
    'nl-BE':{
        "Random" : "Random"
    },
    'nl-NL':{
        "Search" : "Zoeken"
     },
     'nl':{
        "Search" : "Zoeken"
    } ... other languages ...
    'en':{
        "Search" : "Search"
    }
}

If the language is set to 'nl-BE' and the default language is en, it would be wise for the t() function to first search to see if the field exists in the "parent" language (nl) and then in the fallback.

If this is not possible, it would be great if the fallback language was also settable.

this.context.t is not a function

I combine redux-i18n with redux project, but I am very confused. Although I remember to write the contextTypes but when I the npm run dev, sometimes it works, sometimes it menetions the this.context.t is not a function

Having some trouble with react native

Hi

I am using your library with a react webapp and I wanted to use it with react native

I have a wierd error, it says : Cannot read property 'lang' of undefined

Any ideas ?

Context.t not being passed on server-side (isomorphic) render

The docs allude to the fact that there might be an additional configuration step to make isomorphic work, but I can't for the life of me work out what it is.

Say I've got i18n set up like this:

    <Provider store={store}>
      <I18n translations={translations} initialLang="en-GB" fallbackLang="en-GB">
        <Router history={history}>{routes}</Router>
      </I18n>
    </Provider>

and a component like:

const ComponentName = (props, {t}) => {
  return (
    <div>
      {t("Traduisez-moi!")}
    </div>
  );
};

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

it all works fine if I don't render on the server, but as soon as I introduce isomporhic, the server falls over on first page load with errors (on the server side) like:

Warning: Failed context type: The context `t` is marked as required in `ComponentName`, but its value is `undefined`.
    in ComponentName (created by Connect(ComponentName))
    in Connect(ComponentName)
    in div
    in MuiThemeProvider (created by MuiThemeProviderWrapper)
    in MuiThemeProviderWrapper
    in App (created by Connect(App))
    in Connect(App) (created by withTheme(Connect(App)))
    in withTheme(Connect(App)) (created by RouterContext)
    in RouterContext
    in JssProvider
    in Provider
TypeError: t is not a function
    at ComponentName (/usr/src/app/client/App/ComponentName.js:67:36)
    at /usr/src/node_modules/react-dom/lib/ReactCompositeComponent.js:303:16
    at measureLifeCyclePerf (/usr/src/node_modules/react-dom/lib/ReactCompositeComponent.js:73:12)
    ...

Obviously I can hack it and only use tranlsations on the client, but it doesn't feel right...

EDIT:

That's not true because, although I can remove my <I18n /> component on the client site, all of my components are now tightly bound to having the t context around...

Pluralization rules per language

Right now one can define pluralization rules for all of the languages supported. Since those rules are depending on language itself there should be an option to define it per each language, not just one, common rules for all of the languages.

Tick's support

Hey
I have added a tick to a word, and the extract just cuts the text where the tick is.
The problem is with the regex.

For example, the sentence:
Tom's house is very big
The text line in the translation will be:
Tom

Not able to call the t function from outside utility.

Hi, I found your library quite useful, thank you for this.

I see a problem with my code that I have to write context.t("KEY_TO_TRANSLATE"); everywhere in my components wherever I require labels to be replaced based on locale.

So I thought of an approach to writing this context.t("KEY_TO_TRANSLATE"); to a separate file and using it as a function. Now I know that I have to give the context to this file separately. For this, I am using the App context's render method to populate the context in the file that I have written.

Below is my code.

`let globalContext;
export function setContext(context){
globalContext = context;
}

export function translate(key){
console.log(globalContext);
return globalContext.t(key);
}`

and below is the other file:

`class App extends Component {
componentWillMount() {
//SOme code
}

constructor(props,context) {
super();
console.log("Consturctor",context);
this.state = {
appContext : context
}
}
componentDidMount() {
console.log("componentDidMount",this.state.appContext);
}
render() {
if(this.state.appContext) {
console.log("1",this.state.appContext);
setContext(this.state.appContext);
}
return (





)
}
}

App.contextTypes = {
t: PropTypes.func.isRequired
}
export default App;`

Is this possible to achieve? This way I can extract out the code for translation from all of the components and keep it at one place.

Import translations into seperate files

Is there a possibility to import translations into seperate files like fr.json, es.json, it.json and so on, instead of importing everything into translations.js?

This would allow using Async translations easily

Invariant Violation

This example throws an invariant violation as well as Warning: React.createElement: type should not be null, undefined, boolean, or number. What am I missing?

import React from 'react';
import I18n, {i18nState} from 'redux-i18n';
import {Provider} from 'react-redux';
import {render} from 'react-dom';

import {combineReducers, createStore, applyMiddleware} from 'redux';
import thunkMiddleware from 'redux-thunk';

const translations = {
  en: {
    'account.messaging.hub.title': 'Messages'
  }
};

const middleware = applyMiddleware(thunkMiddleware);
const store = createStore(combineReducers({i18nState}), {}, middleware);

render(
  <Provider store={store}>
    <I18n translations={translations}>
      <div>Hello World!</div>
    </I18n>
  </Provider>,
  document.getElementById('pageContainer-content')
);

Package versions:

Use a default language different from 'en'

My first language is 'pt-br', but the system seems to be done in such a way that en is always the reference. Is there a way to set 'pt-br' as default and have a translation table to 'en'?

React router history.push error with redux-i18n

When i wrap my app with I18n like this:

ReactDOM.render(
    <Router>
        <Provider store={store}>
            <I18n translations={{}} initialLang={'fr'} fallbackLang="en" useReducer={true}>
                <Switch>
                    <Route path="/" component={App}/>
                </Switch>
            </I18n>
        </Provider>
    </Router>, document.getElementById('root'));

In the App component, which use withRouter, this.props.history.push(url); didn't work.
After commenting out I18n the history.push working well.
There is any advice.
Thanks.
Sorry about my english.

Plural-Forms is ignored

From what I see, the Plural-Forms field of po files is ignored, for example, in french :

"Plural-Forms: nplurals=2; plural=(n > 1);\n"

This should give :

this.context.t(['{n} banana', '{n} bananas', 'n'], {n: 0}) // => "0 banane"
this.context.t(['{n} banana', '{n} bananas', 'n'], {n: 1}) // => "1 banane"
this.context.t(['{n} banana', '{n} bananas', 'n'], {n: 2}) // => "2 bananes"

Maybe I missed something ? If not the case, I can make a PR.

fallbackLang sometimes doesn't work

Right now we are using the Accept-Language header to initialize the app with the proper language, but if the user sends a header with a value for which we don't have translations (let's say es-ES), if I set the fallbackLang prop in the I18n component to be en-US, I would expect that the translations for this default language are used, but what ends up happening is that the translation keys are returned by the trans function inside the I18n component.

I would expect this function to use the translation for the default language instead if there is one set.

This error actually happens with a store state that looks like this:

// No es-ES key
i18nState: {
  translations: {
    'en-US': {...} // English translations 
  }
}

But if I define an initial state like the next one, the bug does not occur and the fallback language prop works as expected:

i18nState: {
  translations: {
    'en-US': {...}, // English translations 
    'es-ES': {} // Empty object
  }
}

This becomes an issue when the translation keys are just keys and not a message as it happens in some of the examples in the readme file.

I think it would make sense that thetrans function used the fallback language translations even if langMessages is undefined.

I think the fix would be quite easy, but before working on an implementation I wanna sure that this is a fix that is wanted.. so I already created a PR with a fix. If this fix is not desired, please close this issue and the linked PR.

I think this explains well what the problem is, but if you need more details, please let me know.

Thank you very much.

How do I support 'dynamic' things?

I'd like to put a list that needs to be translated in my reducer instead of in my component. This works fine, however when it comes time to extract these values out of the code, it won't happen because the 't' function is working with an iterator instead of a hardcoded string.

I've seen workarounds in here on how to get the context out of the component and into other parts of the app, is the reccomended way to translate things that exist outside of the component?

initialLang attribute is forcing language change back to initialLang

If I dispatch an action to change the language to something other than initialLang, the component always dispatches an action to set the language to back to initialLang.

I believe the component should only use initialLang if lang has not already been set. For example, I set the lang for my application in redux state before the first render of the component, the i18n component will reads this as the lang, but then dispatches an action to reset it to initialLang.

It seems initialLang isn't being read from state, and I can't set it from server-side configuration file using a library like config.

As an aside, the default prop value for initialLang is en, which I don't use (I use en-GB). A default initialLang which seems counter-intuitive.

For the time-being I'm going to change my dependency to the previous version, but if you have thoughts on how I can resolve this, I'd appreciate it.

Redux-i18n accessing t() function outside React components, e.g. in action creators

I'm using Redux-i18n inside my React components. Works as designed. Now, I have several business logic as separate functions within my action creator files. This includes additional error handling and validity checks. Some of them are display other are sent by eMail. At this point I know the user / recipient and want to show them the message / mail in their preferred language. I use templates in the backend of course, but I have certain attributes from the application I want to add and translate.

For this reason, I'd like to translate the messages in the action creators. Is there a way to access the translate literals handy like in the components with the t() function?

Plural form translations for numbers over 2 do not work

po file

msgid "una noche"
msgid_plural "{n} noches"
msgstr[0] "одна ночь"
msgstr[1] "{n} ночи"
msgstr[2] "{n} ночей"

translations.js

export const translations = {
  'ru': {
    'una noche': 'одна ночь',
    '{n} noches': '{n} ночи',
  },
}

Pass JSX as params

Is there any way to pass JSX as parameter to the translation function?
I'm trying to do something like this:

      const name = <span className="name">{user.name}</span>;
      return this.context.t("Hello {name}!", {name: name})

Thanks!

setLanguage can't handle de-DE

When dispatching a setLanguage action with payload "de-DE", the language is not set to "de" but defaults to "en". It seems that the component can't handle languages with format xx-YY.

Extract script doesn't run

Hey

I tried the extract-script, but it doesn't run because of what seems to be an ES6-based error, it

var srcPath = ${args.source || 'src'}/**/*.js*;
...........................^
SyntaxError: Unexpected token ILLEGAL

(There are template strings there that can't be rendered on this comment section apparently)

Do I need to install babel or something alike to make it work? Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.