<?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>DEV Community: truongtrongtin</title>
    <description>The latest articles on DEV Community by truongtrongtin (@truongtrongtin).</description>
    <link>https://dev.to/truongtrongtin</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%2F252548%2F0933d051-4e24-4764-83ca-7e9d6ba98330.png</url>
      <title>DEV Community: truongtrongtin</title>
      <link>https://dev.to/truongtrongtin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/truongtrongtin"/>
    <language>en</language>
    <item>
      <title>Localize your React app with i18next and Gridly</title>
      <dc:creator>truongtrongtin</dc:creator>
      <pubDate>Thu, 16 Mar 2023 04:52:34 +0000</pubDate>
      <link>https://dev.to/truongtrongtin/localize-your-react-app-with-i18next-and-gridly-3c85</link>
      <guid>https://dev.to/truongtrongtin/localize-your-react-app-with-i18next-and-gridly-3c85</guid>
      <description>&lt;p&gt;Are you tired of manually managing translations for your React application? Well, look no further! &lt;/p&gt;

&lt;p&gt;In this tutorial, we'll be using Typescript React with Vite to create a multilingual app and setting up a backend with i18next and &lt;a href="https://www.gridly.com/" rel="noopener noreferrer"&gt;Gridly&lt;/a&gt; to achieve continuous localization. &lt;/p&gt;

&lt;p&gt;With &lt;code&gt;i18next–gridly-backend&lt;/code&gt;, new translation keys will be sent to Gridly as soon as you save them in your code. It’s easy to translate your strings once they’re inside Gridly.&lt;/p&gt;

&lt;p&gt;We'll show you how to create a new React project, set up your Gridly Grid, get the Grid API key and view ID, install the required dependencies, and get a read-only API key for production environments. &lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Create your project
&lt;/h2&gt;

&lt;p&gt;In this step, you can use a current React project or create a new one. Here, we’re using Typescript React with &lt;a href="https://vitejs.dev" rel="noopener noreferrer"&gt;Vite&lt;/a&gt;. Run the following commands to generate a new project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm create vite@latest my-react-app -- --template react-ts
cd my-react-app
npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;npm run dev&lt;/code&gt; to start the app. Navigate to &lt;a href="http://localhost:5173" rel="noopener noreferrer"&gt;http://localhost:5173&lt;/a&gt; in your browser:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl4nsgt5le7mq7egeboji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl4nsgt5le7mq7egeboji.png" alt="Default vite react homepage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are going to localize this app in English (en), Swedish (se), German (de) and French (fr).&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Gridly Grid
&lt;/h2&gt;

&lt;p&gt;Create a &lt;a href="https://app.gridly.com/" rel="noopener noreferrer"&gt;Gridly&lt;/a&gt; account&lt;br&gt;
Create your company, project, and database.&lt;/p&gt;

&lt;p&gt;To add a new Grid, click &lt;code&gt;+ Add Grid&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose source language &lt;code&gt;en&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Choose target languages &lt;code&gt;sv&lt;/code&gt;, &lt;code&gt;de&lt;/code&gt;, and &lt;code&gt;fr&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Other columns: remove all.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F50ba4ttkfvvbtj7rc4su.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F50ba4ttkfvvbtj7rc4su.png" alt="Create grid from scratch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;code&gt;Create&lt;/code&gt; to create and navigate to your new Grid.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F834g5wbehxhems6kcpgq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F834g5wbehxhems6kcpgq.png" alt="Grid after sucessfully created"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Change the column ID of each column to match the language code.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F042ka9uzy3ki6ub7hu2e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F042ka9uzy3ki6ub7hu2e.png" alt="Change column ID"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Delete all placeholder records. Make the Record ID column viewable so it’s easy to see what’s happening.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fphqeg7v6u42f3nr5h9lt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fphqeg7v6u42f3nr5h9lt.png" alt="Show Record ID column"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Get Grid API key and view ID
&lt;/h2&gt;

&lt;p&gt;Click the &lt;code&gt;API&lt;/code&gt; symbol on the right panel.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkyo6j45u8azw68qsoh7m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkyo6j45u8azw68qsoh7m.png" alt="API key and view ID on right panel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your React source code, create a &lt;em&gt;.env.local&lt;/em&gt; file. This file is for local usage only and should not be public in your Git repo.&lt;/p&gt;

&lt;p&gt;Add &lt;em&gt;.env.local&lt;/em&gt; in root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VITE_GRIDLY_API_KEY=your_api_key
VITE_GRIDLY_VIEW_ID=your_view_id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: Never expose the Grid API key in your production environment because someone can use it to modify your data. Use the read-only API key from the company settings. At the end of the tutorial, we’ll show you how to find this read-only API key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install dependencies
&lt;/h2&gt;

&lt;p&gt;Let's install some i18next dependencies:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.i18next.com" rel="noopener noreferrer"&gt;i18next&lt;/a&gt;&lt;br&gt;
&lt;a href="https://react.i18next.com" rel="noopener noreferrer"&gt;react-i18next&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/i18next/i18next-browser-languageDetector" rel="noopener noreferrer"&gt;i18next-browser-languagedetector&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/truongtrongtin/i18next-gridly-backend" rel="noopener noreferrer"&gt;i18next-gridly-backend&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install i18next react-i18next i18next-browser-languagedetector i18next-gridly-backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the &lt;em&gt;src/i18n.ts&lt;/em&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;i18next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;LanguageDetector&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;i18next-browser-languagedetector&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;GridlyBackend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GridlyBackendOptions&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;i18next-gridly-backend&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initReactI18next&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-i18next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isProduction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PROD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gridlyOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GridlyBackendOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITE_GRIDLY_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;viewId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITE_GRIDLY_VIEW_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;i18n&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;LanguageDetector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GridlyBackend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initReactI18next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// for all options read: https://www.i18next.com/overview/configuration-options&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fallbackLng&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;gridlyOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;saveMissing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isProduction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Import in &lt;em&gt;src/main.tsx&lt;/em&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  import React from 'react';
  import ReactDOM from 'react-dom/client';
  import App from './App';
  import './index.css';
&lt;span class="gi"&gt;+ import './i18n';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
    &amp;lt;React.StrictMode&amp;gt;
      &amp;lt;App /&amp;gt;
    &amp;lt;/React.StrictMode&amp;gt;,
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  First translation
&lt;/h2&gt;

&lt;p&gt;The original &lt;em&gt;src/App.tsx&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;reactLogo&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./assets/react.svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://vitejs.dev"&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/vite.svg"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"logo"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Vite logo"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://reactjs.org"&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;reactLogo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"logo react"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"React logo"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Vite + React&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          count is &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Edit &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;src/App.tsx&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;code&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; and save to test HMR
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"read-the-docs"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Click on the Vite and React logos to learn more
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we will localize all text, add a language toggle, and update &lt;em&gt;src/App.tsx&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  import { useState } from 'react';
&lt;span class="gi"&gt;+ import { Trans, useTranslation } from 'react-i18next';
&lt;/span&gt;  import './App.css';
  import reactLogo from './assets/react.svg';
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+ const languages = [
+   { value: 'en', name: 'English' },
+   { value: 'sv', name: 'Swedish' },
+   { value: 'de', name: 'German' },
+   { value: 'fr', name: 'French' },
+ ];
+
&lt;/span&gt;  function App() {
    const [count, setCount] = useState(0);
    const { t, i18n } = useTranslation();
&lt;span class="err"&gt;
&lt;/span&gt;    return (
      &amp;lt;div className="App"&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;a href="https://vitejs.dev" target="_blank"&amp;gt;
            &amp;lt;img src="/vite.svg" className="logo" alt="Vite logo" /&amp;gt;
          &amp;lt;/a&amp;gt;
          &amp;lt;a href="https://reactjs.org" target="_blank"&amp;gt;
            &amp;lt;img src={reactLogo} className="logo react" alt="React logo" /&amp;gt;
          &amp;lt;/a&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;h1&amp;gt;Vite + React&amp;lt;/h1&amp;gt;
        &amp;lt;div className="card"&amp;gt;
          &amp;lt;button onClick={() =&amp;gt; setCount((count) =&amp;gt; count + 1)}&amp;gt;
&lt;span class="gd"&gt;-           count is {count}
&lt;/span&gt;&lt;span class="gi"&gt;+           {t('count_is', 'count is {{number}}', { number: count })}
&lt;/span&gt;          &amp;lt;/button&amp;gt;
          &amp;lt;p&amp;gt;
&lt;span class="gd"&gt;-           Edit &amp;lt;code&amp;gt;src/App.tsx&amp;lt;/code&amp;gt; and save to test HMR
&lt;/span&gt;&lt;span class="gi"&gt;+           &amp;lt;Trans i18nKey="description.part1"&amp;gt;
+             Edit &amp;lt;code&amp;gt;src/App.tsx&amp;lt;/code&amp;gt; and save to test HMR
+           &amp;lt;/Trans&amp;gt;
&lt;/span&gt;          &amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;p className="read-the-docs"&amp;gt;
&lt;span class="gd"&gt;-         Click on the Vite and React logos to learn more
&lt;/span&gt;&lt;span class="gi"&gt;+         {t(
+           'description.part2',
+           'Click on the Vite and React logos to learn more',
+         )}
&lt;/span&gt;        &amp;lt;/p&amp;gt;
&lt;span class="gi"&gt;+       &amp;lt;div&amp;gt;
+         {languages.map((lng) =&amp;gt; (
+           &amp;lt;button
+             key={lng.value}
+             style={{
+               fontWeight: i18n.resolvedLanguage === lng ? 'bold' : 'normal',
+             }}
+             onClick={() =&amp;gt; i18n.changeLanguage(lng.value)}
+           &amp;gt;
+             {lng.name}
+           &amp;lt;/button&amp;gt;
+         ))}
+       &amp;lt;/div&amp;gt;
&lt;/span&gt;      &amp;lt;/div&amp;gt;
    );
  }
&lt;span class="err"&gt;
&lt;/span&gt;  export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file and watch as all the new translation keys are sent to Gridly. This works thanks to the i18next option &lt;em&gt;saveMissing: true&lt;/em&gt; and the &lt;em&gt;i18next-gridly-backend&lt;/em&gt; plugin.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3mhp1xu25b4jy6nsn10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3mhp1xu25b4jy6nsn10.png" alt="Add new translation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This allows the translator to translate content as soon as the developer saves a new key into the code. This process is called &lt;strong&gt;continuous localization&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;Next, add the translations for all languages.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxh1u05c68c0pcbs8c0b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxh1u05c68c0pcbs8c0b.png" alt="Translate the content"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try switching to another language. The translated content for the selected language will be downloaded from Gridly.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F35uuufubegidg3njiblo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F35uuufubegidg3njiblo.gif" alt="Switch language"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Read-only API key for production env
&lt;/h2&gt;

&lt;p&gt;To get a read-only API key, go to &lt;code&gt;Company settings&lt;/code&gt; on the dashboard, then select &lt;code&gt;API keys&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdoo5uhv1h7192azl6h08.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdoo5uhv1h7192azl6h08.png" alt="Create read-only api key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a new API key with read-only permission. Use this key in your production environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fihrha5ewiaohfc6n92yd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fihrha5ewiaohfc6n92yd.png" alt="Copy api key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The complete code can be found &lt;a href="https://github.com/truongtrongtin/i18next-gridly-backend/tree/main/examples/react-ts" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
Watch a live demo &lt;a href="https://lambent-dango-1832c7.netlify.app" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>i18next</category>
      <category>tutorial</category>
      <category>localization</category>
    </item>
  </channel>
</rss>
