{"id":19499820,"url":"https://github.com/apsl/redux-i18n","last_synced_at":"2025-04-04T06:07:00.065Z","repository":{"id":8606388,"uuid":"59029008","full_name":"APSL/redux-i18n","owner":"APSL","description":"A simple and powerful package for translate your react applications using react-redux.","archived":false,"fork":false,"pushed_at":"2023-01-26T22:10:53.000Z","size":1125,"stargazers_count":234,"open_issues_count":33,"forks_count":52,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-03-29T11:47:22.151Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/APSL.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-05-17T14:17:10.000Z","updated_at":"2025-01-31T09:26:21.000Z","dependencies_parsed_at":"2023-02-15T01:46:23.691Z","dependency_job_id":null,"html_url":"https://github.com/APSL/redux-i18n","commit_stats":null,"previous_names":[],"tags_count":60,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/APSL%2Fredux-i18n","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/APSL%2Fredux-i18n/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/APSL%2Fredux-i18n/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/APSL%2Fredux-i18n/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/APSL","download_url":"https://codeload.github.com/APSL/redux-i18n/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247128750,"owners_count":20888235,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-10T22:06:24.208Z","updated_at":"2025-04-04T06:07:00.031Z","avatar_url":"https://github.com/APSL.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Description\n\n**redux-i18n** is a simple yet powerful package to translate your _react_ applications using _react-redux_.\n\n[![npm version](https://badge.fury.io/js/redux-i18n.svg)](https://www.npmjs.com/package/redux-i18n)\n![downloads](https://img.shields.io/npm/dm/redux-i18n.svg)\n\n## Installation\n\n```\nnpm i redux-i18n --save\n```\n\nor\n\n```\nyarn add redux-i18n\n```\n\n## Features\n\n- Translate literals.\n- Pluralize literals.\n- Designed for react-redux.\n- Compatible with Immutable.js.\n- Export translations to POT files (make your translations with [Poedit](https://poedit.net/)).\n- Import translations from .PO files to _translations.js_ object (for use in your project).\n- Add comments for translators.\n\n## Requirements\n\n- node \u003e= 4.0.0\n\n## Overview\n\n**redux-i18n** offers your app the `t()` function to translate literals.\n\nThe `t()` function is available in the components of your app via React [context](https://reactjs.org/docs/context.html). To achieve this you need to wrap your app into the `\u003cI18n /\u003e` 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.:\n\n```javascript\n// import ...\nimport PropTypes from 'prop-types'\n\nclass MyComponent extends React.Component {\n  render() {\n    return \u003cdiv\u003e{this.context.t('Hello World!')}\u003c/div\u003e\n  }\n}\n\nMyComponent.contextTypes = {\n  t: PropTypes.func\n}\n```\n\nIf `contextTypes` is not defined, then context will be an empty object.\n\nThe `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.\n\nFor setting the language in the redux store **redux-i18n** offers an action creator `setLanguage`.\n\nTo manage the translations in your React app, **redux-i18n** supports two choices:\n\n1. load all your translations into a one big JS object\n1. load your translations into a slice of your redux store\n\nFor 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.\n\n**redux-i18n** supports your store in plain JavaScript structures, but also if it is managed by help of _immutable.js_.\n\nFinally, **redux-i18n** offers scripts to generate a translations object from po files that can be managed in [Poedit](https://poedit.net/).\n\n## Usage\n\nThe package provides a parent component to encapsulate your application as well as helpers functions to translate your project.\n\n```javascript\n// import ...\nimport I18n from 'redux-i18n'\n// with Immutable.js:\nimport I18n from 'redux-i18n/immutable'\n\nimport { translations } from './translations'\n\nclass Root extends React.Component {\n  render() {\n    return (\n      \u003cProvider store={store}\u003e\n        \u003cI18n translations={translations}\u003e\n          \u003cApp /\u003e\n        \u003c/I18n\u003e\n      \u003c/Provider\u003e\n    )\n  }\n}\n```\n\nWhere `translations` is a dictionary similar to this:\n\n```javascript\nexport const translations = {\n  es: {\n    'Translate this text': 'Traduce este texto',\n    'Hello {n}!': 'Hola {n}!'\n  }\n}\n```\n\nYou can also set the initial language with the _initialLang_ prop:\n\n```javascript\n\u003cI18n translations={translations} initialLang=\"es\"\u003e\n  \u003cdiv\u003e\n    \u003ch1\u003eMy Project\u003c/h1\u003e\n    {this.props.children}\n  \u003c/div\u003e\n\u003c/I18n\u003e\n```\n\nIf 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.\n\n```javascript\n\u003cI18n translations={translations} initialLang=\"de\" fallbackLang=\"en\"\u003e\n  \u003cdiv\u003e\n    \u003ch1\u003eMy Project\u003c/h1\u003e\n    {this.props.children}\n  \u003c/div\u003e\n\u003c/I18n\u003e\n```\n\nIn this case, if you want to show this translations:\n\n```html\n\u003cdiv\u003e{this.context.t('_hello_')}\u003c/div\u003e\n```\n\nAnd this isn't in \"de\" language, it will show in \"en\".\n\n## Redux Reducer\n\nThe language state is managed in a slice of the store named `i18nState`. Therefore, you have to add the **i18nState** reducer in your `combineReducers`.\n\n```javascript\nimport { otherreducers } from './Yourproject'\n\nimport { i18nState } from 'redux-i18n'\n// with Immutable.js:\nimport { i18nState } from 'redux-i18n/immutable'\n\nconst appReducer = combineReducers({\n  otherreducers,\n  i18nState\n})\n```\n\nThe current language is contained in the `lang` key of `i18nState`.\n\nThe `i18nState` is initially defined as\n\n```javascript\nconst defaultI18nState = {\n  lang: 'en',\n  translations: {},\n  forceRefresh: false\n}\n\n// immutablejs\nconst defaultI18nState = new Map({\n  lang: 'en',\n  translations: {},\n  forceRefresh: false\n})\n```\n\nWhen you [map your state to props with connect](https://github.com/reduxjs/react-redux/blob/master/docs/api/connect.md) you can also access the `lang` attribute in your components:\n\n```javascript\nexport default connect(state =\u003e ({\n  lang: state.i18nState.lang,\n}))(Home)\n\n// with Immutable.js:\nexport default connect(state =\u003e ({\n  lang: state.getIn(['i18nState', 'lang']),\n}))(Home)\n\n```\n\n## Translate literals\n\nYou can access the functions of `\u003cI18n /\u003e` using your component's context. For example:\n\n```javascript\nHome.contextTypes = {\n  t: PropTypes.func.isRequired\n}\n```\n\n...you will then be able to use the `t()` method in your component.\n\n```javascript\nrender() {\n  return (\n    \u003cdiv\u003e\n      \u003cstrong\u003eYour current language, is: {this.props.lang}\u003c/strong\u003e\u003cbr/\u003e\n      {this.context.t(\"Translate this text\")}\u003cbr/\u003e\n      {this.context.t(\"Hello {n}!\", {n: \"World\"})}\u003cbr/\u003e\u003cbr/\u003e\n      \u003cbutton onClick={this.changeLanguage.bind(this)}\u003eChange Language\u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\nYou can also use the `t()` function to change date formats\n\n```javascript\nexport const translations = {\n  de: {\n    'YYYY-MM-DD': 'DD.MM.YYYY'\n  }\n}\n```\n\n```javascript\nrender() {\n  let today = moment()\n  return (\n    \u003cdiv\u003e\n      {today.format(this.context.t(\"YYYY-MM-DD\"))}\n    \u003c/div\u003e\n  )\n}\n```\n\nAdd comments for translators.\n\n```javascript\nrender() {\n  return (\n    \u003cdiv\u003e\n      {this.context.t(\"Translate this text\", {},\n                      \"This is a comment for translators.\")}\n      {this.context.t(\"Hello {n}!\", {n: \"Cesc\"},\n                      \"This is another comment.\")}\n    \u003c/div\u003e\n  )\n}\n```\n\nHere's how _Poedit_ will show the comments:\n\n![Poedit screenshot](imgs/poedit1.jpg?raw=true 'Poedit screenshot')\n\n### HTML Object as parameter\n\n```javascript\nconst user = { name: 'World' }\nconst name = \u003cspan\u003e{user.name}\u003c/span\u003e\nreturn \u003cdiv dangerouslySetInnerHTML={{ __html: context.t('Hello {name}', { name: name }) }} /\u003e\n```\n\nResult:\n\n```html\nHello \u003cspan\u003eCesc\u003c/span\u003e\n```\n\nNotice that for [security reasons](https://facebook.github.io/react/docs/dom-elements.html#dangerouslysetinnerhtml) we can't print html code directly, which is why we need to use the \"dangerouslySetInnerHTML\" method for that.\n\n## Stateless components\n\nExample:\n\n```javascript\nconst Foo = ({}, context) =\u003e \u003ch1\u003e{context.t('Hello World')}\u003c/h1\u003e\n```\n\n## Pluralize\n\nTo use plurals in your translations.\n\n```javascript\n\u003cdiv\u003e{this.context.t(['una noche', '{n} noches', 'n'], { n: 1 })}\u003c/div\u003e\n```\n\nPass 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.\n\nAfter extracting the translations to a POT file and opening it with Poedit you will see the following:\n\n![Poedit screenshot](imgs/poedit2.jpg?raw=true 'Poedit screenshot')\n\nAlso 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:\n\n```javascript\nexport const translations = {\n  es: {\n    'Translate this text': 'Traduce este texto',\n    'Hello {n}!': 'Hola {n}!'\n  },\n  options: {\n    plural_rule: 'n \u003e 1',\n    plural_number: '2',\n    suppress_warnings: true // defaults to false\n  }\n}\n```\n\nWhen the translations are generated from po import file, this node is created automatically.\n\n_Note_: Versions \u003e=1.5.10 allow to use all existing pluralization rules:\n[http://docs.translatehouse.org/projects/localization-guide/en/latest/l10n/pluralforms.html](http://docs.translatehouse.org/projects/localization-guide/en/latest/l10n/pluralforms.html)\n\n## Change language\n\nUse the _setLanguage_ action.\n\n```javascript\nimport {setLanguage} from \"redux-i18n\"\n\ncomponentWillMount() {\n  this.props.dispatch(setLanguage(\"es\"))\n}\n```\n\nIf you work with combined languages like `\"es-ES\"`, `\"en-GB\"`, but your translations object doesn't include those properties...\n\n```javascript\nexport const translations = {\n  \"es\": {\n    ...\n  },\n  \"en\": {\n    ...\n  }\n}\n```\n\n..._redux-i18n_ will fallback on the closest property. In this case, `\"es\"` or `\"en\"`.\n\n## Extract/Import scripts\n\n**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`.\n\nAdd the scripts in your _package.json_ for this purpose:\n\n```json\n\"scripts\": {\n  \"extract\": \"i18n_extract\",\n  \"import\": \"i18n_import\"\n}\n```\n\nYou can then run the following commands in your terminal:\n\n```\nnpm run extract\nnpm run import\n```\n\n### Extract texts and build template.pot\n\n```\nnpm run extract\n```\n\nBy 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](https://poedit.net/) to build _en.po_, _es.po_, etc. files.\n\nIf you want to set other source folder, you can use the `--source` switch.\n\n```json\n\"scripts\": {\n  \"extract\": \"i18n_extract --source=mysourcefolder\",\n  \"import\": \"i18n_import\"\n}\n```\n\nOr if you want to export your locales to a different folder...\n\n```json\n\"scripts\": {\n  \"extract\": \"i18n_extract --source=mysourcefolder --locales=mylocalesfolder\",\n  \"import\": \"i18n_import\"\n}\n```\n\nBy default this command find in all _.js_ and _.jsx_ file extensions, but you can customize it with _fexts_ parameter. Check out this example:\n\n```json\n\"scripts\": {\n  \"extract\": \"i18n_extract --fexts=js,jsx,coffee\",\n  \"import\": \"i18n_import\"\n}\n```\n\nThe 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:\n\n```javascript\nexport default function App({ aProp, bProp }, { t: translate }) {\n  return \u003cdiv\u003e{translate('Hello world!')}\u003c/div\u003e\n}\n```\n\nYou will then need to set the `--pattern` flag in _package.json_:\n\n```json\n\"scripts\": {\n  \"extract\": \"i18n_extract --pattern=translate\",\n  \"import\": \"i18n_import\"\n}\n```\n\n### Import .po files\n\nWhen your translators are done translating your terms, you can import your _po_ files running the import script:\n\n```\nnpm run import\n```\n\nThis 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.\n\nYour _.po_ files must define header language, check [mininal format](https://gist.github.com/Salec/3ddcf037e9cc4c44082441f379bf0165) for more information.\n\nYou can also set another _locales_ folder:\n\n```json\n\"scripts\": {\n  \"extract\": \"i18n_extract --source=mysource --locales=mylocales\",\n  \"import\": \"i18n_import --locales=mylocales\"\n}\n```\n\nOr, save _translation.js_ to a different location:\n\n```json\n\"scripts\": {\n  \"extract\": \"i18n_extract --source=mysource --locales=mylocales\",\n  \"import\": \"i18n_import --locales=mylocales --translations=myfolder\"\n}\n```\n\nYou can also change the encoding for your extraction from PO (default is iso-8859-1)\n\n```json\n\"scripts\": {\n  \"extract\": \"i18n_extract --source=mysource --locales=mylocales\",\n  \"import\": \"i18n_import --encoding=utf-8\"\n}\n```\n\n## Async translations\n\nWhen applications grow, translations tend to bigger as well, adding a lot to the overall size of the js bundle.\n\nYou can set an empty translations object to the `\u003cI18n/\u003e` component and set the `useReducer` prop to true to use the store as the source of strings. For example:\n\n```javascript\n\u003cProvider store={this.store}\u003e\n  \u003cI18n translations={{}} useReducer={true}\u003e\n    \u003cMainApp /\u003e\n  \u003c/I18n\u003e\n\u003c/Provider\u003e\n```\n\nThen you can use the `setTranslations` action.\n\n```javascript\nimport { setTranslations } from 'redux-i18n'\napi.get('...').then((r) =\u003e this.props.dispatch(setTranslations(r.translations)))\n```\n\nYou can pass a second parameter to the action to set the language.\nDepending on your response's structure, it could look like this:\n\n```javascript\napi.get('...').then((r) =\u003e this.props.dispatch(setTranslations(r.translations, 'en')))\n```\n\nSince version 1.5.1 is possible pass a dictionary as a second param with some options. This allows us set more functionalities to method.\n\n- preserveExisting (bool): If is true, the translations received does merge with existing translations.\n- language (string): Language code\n\nSome examples:\n\n```javascript\nsetTranslations(newTranslations, { preserveExisting: true })\nsetTranslations({ Hello: 'Hallo' }, { language: 'de' })\n```\n\n## InitialState\n\nSometimes 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.\n\n## HOC\n\nIf 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:\n\n```javascript\nimport { localize } from 'redux-i18n'\n\nclass SomeComponent extends Component {\n  render() {\n    return this.props.t('hello world')\n  }\n}\n\nexport default localize()(SomeComponent)\n```\n\nYou can also change the name of the provided prop:\n\n```javascript\nimport { localize } from 'redux-i18n'\n\nclass SomeComponent extends Component {\n  render() {\n    return this.props.translate('hello world')\n  }\n}\n\nexport default localize('translate')(SomeComponent)\n```\n\n---\n\n**Please**, if you like my package, don't forget to rate it. Click on the \"star\"!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapsl%2Fredux-i18n","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapsl%2Fredux-i18n","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapsl%2Fredux-i18n/lists"}