<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Vadim Namniak</title>
    <description>The latest articles on Forem by Vadim Namniak (@namniak).</description>
    <link>https://forem.com/namniak</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F175408%2Fd106fe18-22aa-4f6b-9127-76fa63c30d80.jpeg</url>
      <title>Forem: Vadim Namniak</title>
      <link>https://forem.com/namniak</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/namniak"/>
    <language>en</language>
    <item>
      <title>Creating a localized experience for visitors from other countries using React Redux</title>
      <dc:creator>Vadim Namniak</dc:creator>
      <pubDate>Tue, 15 Oct 2019 21:02:34 +0000</pubDate>
      <link>https://forem.com/jam3/creating-a-localized-experience-for-visitors-from-other-countries-using-react-redux-6gk</link>
      <guid>https://forem.com/jam3/creating-a-localized-experience-for-visitors-from-other-countries-using-react-redux-6gk</guid>
      <description>&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;It is assumed you are already familiar with both React and Redux and looking to add internalization to your application. If you are not, there is a number of boilerplate options out there that can help you get started. &lt;br&gt;
Feel free to check out &lt;a href="https://github.com/Jam3/nyg-jam3"&gt;our implementation&lt;/a&gt; of it that we use at &lt;a href="https://www.jam3.com/"&gt;Jam3&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;You are highly advised to read the &lt;a href="https://www.i18next.com"&gt;i18next&lt;/a&gt; internationalization framework documentation to get an understanding of the main &lt;a href="https://www.i18next.com/#complete-solution"&gt;concepts&lt;/a&gt; and benefits of using it.&lt;/p&gt;

&lt;p&gt;List of required extra dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/i18next"&gt;i18next&lt;/a&gt; (37kB / 10.5kB)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/react-i18next/v/9.0.10"&gt;react-i18next v.9&lt;/a&gt; (12.4kB / 4.6kB)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/i18next-browser-languagedetector"&gt;i18next-browser-languagedetector&lt;/a&gt; (6kB / 2kB)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/i18next-redux-languagedetector"&gt;i18next-redux-languagedetector&lt;/a&gt; (2.2kB / 790B)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/i18next-chained-backend"&gt;i18next-chained-backend&lt;/a&gt; (2.2kB / 933B)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/i18next-fetch-backend"&gt;i18next-fetch-backend&lt;/a&gt; (4.3kB / 1.7kB)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Take a sneak peek at these libraries before we proceed.&lt;/p&gt;

&lt;p&gt;👉 &lt;em&gt;Consider the overall additional cost of roughly 20kB (minified and gzipped) added to the production build&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;Run this command in your terminal to install the above modules in one batch:&lt;br&gt;
&lt;code&gt;$ npm i --save i18next react-i18next@9.0.10 i18next-fetch-backend i18next-browser-languagedetector i18next-redux-languagedetector i18next-chained-backend&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;The example we’ll be referring to is bootstrapped with &lt;a href="https://github.com/facebook/create-react-app"&gt;Create React App&lt;/a&gt; with added Redux on top.&lt;br&gt;
Here’s what our application structure will look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VtI5Kd6T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/hx7k81886fgzpzb6gqwx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VtI5Kd6T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/hx7k81886fgzpzb6gqwx.png" alt="App structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://codesandbox.io/s/github/Jam3/react-redux-i18n"&gt;CodeSandbox example&lt;/a&gt; or check this &lt;a href="https://github.com/Jam3/react-redux-i18n"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Creating translation files
&lt;/h3&gt;

&lt;p&gt;We are going to use English and Russian translations as an example.&lt;br&gt;
Let’s create two JSON files with identical structure and keep them in their respective folders:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 &lt;center&gt;&lt;code&gt;/public/locales/en-US/common.json&lt;/code&gt;&lt;/center&gt;
&lt;br&gt;
 &lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 &lt;center&gt;&lt;code&gt;/public/locales/ru/common.json&lt;/code&gt;&lt;/center&gt;

&lt;p&gt;These files will serve as our translation resources that are automatically loaded based on the detected browser language.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Creating the i18n config file
&lt;/h3&gt;

&lt;p&gt;Make sure to check the complete list of available &lt;a href="https://www.i18next.com/overview/configuration-options"&gt;i18next config options&lt;/a&gt;.&lt;br&gt;
This is our main localization config file:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 &lt;center&gt;&lt;code&gt;/src/i18n/index.js&lt;/code&gt;&lt;/center&gt;

&lt;ul&gt;
&lt;li&gt;First off, we need to add the &lt;code&gt;i18next-chained-backend&lt;/code&gt; plugin which allows chaining multiple backends. There are several &lt;a href="https://www.i18next.com/overview/plugins-and-utils#backends"&gt;backend types&lt;/a&gt; available for different purposes. We are using &lt;code&gt;fetch&lt;/code&gt; to load our translation resources.&lt;/li&gt;
&lt;li&gt;Then we are adding &lt;code&gt;Browser Language Detector&lt;/code&gt; (connected with Redux store through &lt;code&gt;Redux Language Detector&lt;/code&gt;) for automatic user language detection in the browser. Read more about &lt;a href="https://github.com/i18next/i18next-browser-languageDetector#introduction"&gt;the approach&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Next up, we use &lt;code&gt;reactI18nextModule&lt;/code&gt; to pass &lt;code&gt;i18n&lt;/code&gt; instance down to &lt;code&gt;react-i18next&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Finally, we initialize &lt;code&gt;i18next&lt;/code&gt; with basic config options.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Step 3: Adding i18next reducer to the store
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Redux Language Detector&lt;/code&gt; provides &lt;code&gt;i18nextReducer&lt;/code&gt; so you don’t need to implement your own reducers or actions for it — simply include it in your store:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 &lt;center&gt;&lt;code&gt;/src/redux/index.js&lt;/code&gt;&lt;/center&gt;

&lt;p&gt;👉 &lt;em&gt;For your convenience, use Redux dev tools in dev environment and make sure you import &lt;code&gt;composeWithDevTools&lt;/code&gt; from &lt;code&gt;redux-devtools-extension/developmentOnly&lt;/code&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Creating the main app file
&lt;/h3&gt;

&lt;p&gt;There’s nothing specifically related to the internalization in this file.&lt;br&gt;
We simply set the routes for our pages in a standard way.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 &lt;center&gt;&lt;code&gt;/src/app/index.js&lt;/code&gt;&lt;/center&gt;
&lt;h3&gt;
  
  
  Step 5: Initializing the app and adding &lt;a href="https://react.i18next.com/legacy-v9/i18nextprovider"&gt;I18nextProvider&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The provider is responsible for passing the &lt;code&gt;i18next&lt;/code&gt; instance down to &lt;a href="https://react.i18next.com/legacy-v9/withnamespaces"&gt;withNamespaces&lt;/a&gt; HOC or &lt;a href="https://react.i18next.com/legacy-v9/namespacesconsumer"&gt;NamespacesConsumer&lt;/a&gt; render prop.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 &lt;center&gt;&lt;code&gt;/src/index.js&lt;/code&gt;&lt;/center&gt;

&lt;p&gt;We initialized our store and &lt;code&gt;i18n&lt;/code&gt; config file with the same options to keep both in sync.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Using translation keys
&lt;/h3&gt;

&lt;p&gt;We‘ll use &lt;a href="https://react.i18next.com/legacy-v9/withnamespaces"&gt;withNamespaces&lt;/a&gt; HOC that passes the &lt;a href="https://www.i18next.com/overview/api#t"&gt;&lt;em&gt;t&lt;/em&gt; function&lt;/a&gt; as a prop down to the component. We need to specify the namespace(s), and the copy is now accessible via object properties using &lt;em&gt;&lt;code&gt;t&lt;/code&gt;&lt;/em&gt; function: &lt;code&gt;t(‘homePage.title’)&lt;/code&gt;.&lt;br&gt;
Note, it is required to prepend the namespace when accessing the copy from multiple namespaces within one component e.g. &lt;code&gt;t('shared:banner.title')&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 &lt;center&gt;&lt;code&gt;/src/pages/Home.js&lt;/code&gt;&lt;/center&gt;

&lt;p&gt;Alternatively, we could use &lt;a href="https://react.i18next.com/legacy-v9/namespacesconsumer"&gt;NamespacesConsumer&lt;/a&gt; component which would also give us access to the &lt;em&gt;&lt;code&gt;t&lt;/code&gt;&lt;/em&gt; function. We’ll cover it in the next step.&lt;/p&gt;

&lt;p&gt;👉 &lt;em&gt;You can test language detection by changing your default browser language. When using Chrome, go to &lt;code&gt;chrome://settings/languages&lt;/code&gt; and move the languages up and down in the list&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7 (Bonus part): Creating language switcher
&lt;/h3&gt;

&lt;p&gt;Ok, we’ve implemented language auto-detection and dynamic translation resources loading. Now it’s time to take it up a notch and create a component that allows users switching the language through user interface.&lt;br&gt;
Make sure to include this component in your app.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 &lt;center&gt;&lt;code&gt;/src/components/LanguageSwitcher.js&lt;/code&gt;&lt;/center&gt;

&lt;p&gt;&lt;code&gt;NamespacesConsumer&lt;/code&gt; render prop provides access to the &lt;code&gt;i18n&lt;/code&gt; instance. Its &lt;code&gt;changeLanguage&lt;/code&gt; method can be used to change language globally. This will force the app to re-render and update the site with the translated content.&lt;/p&gt;

&lt;p&gt;🎉That’s a wrap!&lt;/p&gt;

&lt;h2&gt;
  
  
  Code examples
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://codesandbox.io/s/github/Jam3/react-redux-i18n"&gt;CodeSandbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Jam3/react-redux-i18n"&gt;GitHub example&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Related documentation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://react.i18next.com/"&gt;i18next&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://react.i18next.com/legacy-v9/"&gt;React i18next (v.9)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/i18next-browser-languagedetector"&gt;i18next Browser Language Detector&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>redux</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
