DEV Community

Cover image for How to Localize Your React Native App With Gridly
Kuldeep Tarapara
Kuldeep Tarapara

Posted on

How to Localize Your React Native App With Gridly

The importance of Localization for App Development

In today's digital world, competition to create top-quality mobile applications is more fierce than ever before. To impact your application, it has to be both practical and attractive but also easily accessible and relevant to a worldwide audience. This is where the concept of localization is essential.

It is tailoring the application to meet various cultures, markets, and languages. It's not only about translation. However, it also involves adapting features, designs and functionality to conform to different cultures' diverse preferences and norms. One tool that could greatly assist in adapting is Gridly, an agile software for managing localization designed to simplify adapting your application to various markets.

Introduction to Gridly

Gridly is a reliable and flexible localization platform that allows teams and developers to oversee and manage localizations and translations of their apps through a central location. Gridly is designed to work with different countries and languages, making it more straightforward for teams to work together and maintain consistency across multiple versions of an app. It's an essential instrument for any app developer trying to make their application universally accessible.

How Gridly Works?

Gridly is a fast-paced and flexible localization management system designed to ease converting digital products to various languages and cultures. It is a central tool that allows teams and developers to manage, store, and manage all their translations in one location to facilitate collaboration and ensure that the same translations are consistent across all product versions.

Gridly can be used with various languages and formats and integrated with multiple frameworks for developing apps and frameworks, making it an ideal solution for managing localization for every development project.

Gridly serves as a complete solution to manage localization projects. It lets you save the information, update, and manage all your translations in one location. It makes it much easier to monitor changes and keep uniformity. Here's a quick summary of the process:

  1. Import your content Gridly lets you import content from multiple sources, including a CSV document, Google Sheets, or directly from your codebase. It supports different formats like XML, JSON, and YAML.

  2. You can manage your translations. After your content has been imported, you can begin coordinating your translations. Gridly has users with a user-friendly interface. You can edit, add, or remove translations if needed.

  3. Work with your team: Gridly fosters team collaboration through the ability of many users to collaborate on translations simultaneously. Additionally, it provides the ability to control version changes efficiently.

  4. After you have completed your translations, it is easy to export them in the desired format and incorporate them into your program.

Set Up of the Gridly Grid

The process of setting the Gridly grid requires the following steps:

*1. Create a new grid. *

Begin by creating a brand new grid on Gridly's Gridly dashboard. This is where you'll handle all of your translations.

Follow these steps to create Grid in Gridly:

a. Login to your Gridly Account.

Image description

b. Click on the “ + Add Grid” button and select “Start from scratch” as we create a new grid.

Image description

c. Give your grid a specific name and choose your source language. I.e. en(English) and then your target language. I.e. ja(Japanese), fr(French), and sv(Swedish)

Image description

d. Remove all columns in other columns
e. Click on the “Create” Button

Image description

The new grid will look like this. Following these steps, you can create more grids according to your needs.

2. Change column properties

a. Click on the downward arrow key and then select the column properties.

Image description

b. Change the column Id to match the language code.
Note: This id will be used in code to change the language.

Image description

c. Repeat steps a and b for all the columns.

d. Select raw from the left side, Right click and then click “Delete record”. Delete all the records, likewise.

Image description

e. Click the “Manage column” button and make the record ID column visible.

Image description

3. Get the Grid API key and view the ID.

Image description

Configuring a React Native App Development Project

We are developing a React Native app. Gridly can be a crucial tool in coordinating the localization process. Here's how to configure it:

Create a new React Native app project.

Use the following command to create a new React native project.

# Create a project named localization-demo
- npx create-expo-app localization-demo 

# Navigate to the project directory
-cd localization-demo

# Start development server
-npx expo start
Enter fullscreen mode Exit fullscreen mode

Image description

Install i18next dependencies

  • i18next
  • react-i18next
  • i18next-browser-languagedetector
  • i18next-gridly-backend
npm install i18next react-i18next @react-native-async-storage/async-storage
Enter fullscreen mode Exit fullscreen mode

Configure Gridly

Once you install the dependencies. This requires a Gridly API key and view ID. Let’s build the app step by step.

In this example, we have used typescript, but you can also follow the same process for javascript.

import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import AsyncStorage from "@react-native-async-storage/async-storage";
import demo from "./demo.json";
Enter fullscreen mode Exit fullscreen mode

Import the required modules and dependencies, including i18n, initReactI18next, AsyncStorage, and demo.json.

const VIEW_ID = "tz8qosssrut37";
const API_KEY = "VVHfJDj4lVlAvs";

var myHeaders = new Headers();
myHeaders.append("Authorization", `ApiKey ${API_KEY}`);
Enter fullscreen mode Exit fullscreen mode

Define constants VIEW_ID and API_KEY for Gridly authentication.

Warning: As we are creating a demonstration application, we have added api key and view key directly in the code, but we do not recommend this way in production deployment. For production deployment, either you should use Gridly read-only api key or you should store it in some secure way.

interface Cell {
 columnId: string;
 sourceStatus?: string;
 dependencyStatus?: string;
 value: string;
}


interface Item {
 id: string;
 cells: Cell[];
}


interface Translations {
 [key: string]: {
   [key: string]: string;
 };
}
Enter fullscreen mode Exit fullscreen mode

Define an interface for a Gridly cell, an interface for a Gridly item, and an interface for translations.

Now execute the below command and store the output in i18n/demo.json

curl GET \
https://api.gridly.com/v1/views/{viewId}/records \
  -H 'Authorization: ApiKey {apiKey}'
Enter fullscreen mode Exit fullscreen mode

You can find this from Gridly grid.

const fallback: Item[] = demo;
Enter fullscreen mode Exit fullscreen mode

Define a fallback constant as demo data for when translation data cannot be retrieved from Gridly.

const convertToTranslations = (data: Item[]): Translations => {
 const translations: Translations = {};

 data.forEach((item: Item) => {
   item.cells.forEach((cell: Cell) => {
     if (!translations[cell.columnId]) {
       translations[cell.columnId] = {};
     }
     translations[cell.columnId][item.id] = cell.value;
   });
 });
 return translations;
};
Enter fullscreen mode Exit fullscreen mode

Define a function called convertToTranslations that takes an array of Gridly items and returns an object of translations.

const getTranslations = async () => {
 let translations: Translations = {};
 let resData: Item[] = [];
 try {
   const response = await fetch(
     `https://api.gridly.com/v1/views/${VIEW_ID}/records`,
     {
       method: "GET",
       headers: myHeaders,
       redirect: "follow",
     }
   );
   if (response.ok) {
     resData = await response.json();
   }
   translations = convertToTranslations(resData);
 } catch (error) {
   const localTranslations = await AsyncStorage.getItem("translations");
   if (localTranslations) {
     translations = JSON.parse(localTranslations);
   } else {
     translations = convertToTranslations(fallback);
   }
 }
 return translations;
};
Enter fullscreen mode Exit fullscreen mode

Define an async function called getTranslations that fetches the translation data from the Gridly view and returns the data as an object of translations. If the fetch fails, the function retrieves the data from AsyncStorage or falls back to the demo data.

i18n
 .use(initReactI18next)
 .init({
   lng: "en",
   compatibilityJSON: "v3",
   fallbackLng: "en",
   debug: true,
   interpolation: {
     escapeValue: false,
   },
   react: {
     useSuspense: false,
   },
 });
Enter fullscreen mode Exit fullscreen mode

We have configured the i18n instance with these plugins and options. If you want to learn more about the initialization options, you can visit the i18next official docs. We have enabled debug mode, set English as the fallback language, and defined the backend options.

(async () => {
 const translations = await getTranslations();
 Object.keys(translations).forEach((key) => {
   i18n.addResources(key, "translation", translations[key]);
 });
 AsyncStorage.setItem(`translations`, JSON.stringify(translations));
})();
Enter fullscreen mode Exit fullscreen mode

async function that retrieves the translations using the getTranslations function and adds them to the i18n library. It then stores the translations in AsyncStorage for later use

Add the i18n/i18n.ts file:

The final i18n.ts file will look like this.

import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import AsyncStorage from "@react-native-async-storage/async-storage";
import demo from "./demo.json";



const VIEW_ID = "tz8qosssrut37";
const API_KEY = "VVHfJDj4lVlAvs";


var myHeaders = new Headers();
myHeaders.append("Authorization", `ApiKey ${API_KEY}`);


interface Cell {
 columnId: string;
 sourceStatus?: string;
 dependencyStatus?: string;
 value: string;
}


interface Item {
 id: string;
 cells: Cell[];
}


interface Translations {
 [key: string]: {
   [key: string]: string;
 };
}


const fallback: Item[] = demo;


const convertToTranslations = (data: Item[]): Translations => {
 const translations: Translations = {};


 data.forEach((item: Item) => {
   item.cells.forEach((cell: Cell) => {
     if (!translations[cell.columnId]) {
       translations[cell.columnId] = {};
     }
     translations[cell.columnId][item.id] = cell.value;
   });
 });
 return translations;
};


const getTranslations = async () => {
 let translations: Translations = {};
 let resData: Item[] = [];
 try {
   const response = await fetch(
     `https://api.gridly.com/v1/views/${VIEW_ID}/records`,
     {
       method: "GET",
       headers: myHeaders,
       redirect: "follow",
     }
   );
   if (response.ok) {
     resData = await response.json();
   }
   translations = convertToTranslations(resData);
 } catch (error) {
   const localTranslations = await AsyncStorage.getItem("translations");
   if (localTranslations) {
     translations = JSON.parse(localTranslations);
   } else {
     translations = convertToTranslations(fallback);
   }
 }
 return translations;
};


i18n
 .use(initReactI18next)
 .init({
   lng: "en",
   compatibilityJSON: "v3",
   fallbackLng: "en",
   debug: true,
   interpolation: {
     escapeValue: false,
   },
   react: {
     useSuspense: false,
   },
 });


(async () => {
 const translations = await getTranslations();
 Object.keys(translations).forEach((key) => {
   i18n.addResources(key, "translation", translations[key]);
 });
 AsyncStorage.setItem(`translations`, JSON.stringify(translations));
})();


export default i18n;
Enter fullscreen mode Exit fullscreen mode

Translation

Original App.tsx file:

import { StyleSheet, Text, View, Button } from "react-native";


export default function App() {
 // List of the languages you want to support. Here value property is the column id we have added in Gridly grid in earlier step
 const languages = [
   { value: "en", name: "English" },
   { value: "ja", name: "Japanese" },
   { value: "fr", name: "French" },
   { value: "sv", name: "Swedish" },
 ];
 return (
   <View style={styles.container}>
     <View style={styles.buttContainer}>
       {/* Render button for all languages */}
       {languages.map((lng) => (
         <Button 
           key={lng.value} 
           title={lng.name} 
         />
       ))}
     </View>
     <Text>Hello from Gridly!</Text>
   </View>
 );
}


const styles = StyleSheet.create({
 container: {
   flex: 1,
   backgroundColor: "#fff",
   alignItems: "center",
   justifyContent: "center",
   gap: 100,
   padding: 20,
 },
 buttContainer: {
   flexDirection: "column",
   gap: 30,
 },
});

Enter fullscreen mode Exit fullscreen mode

Here we have added a basic UI with a list of buttons for each language we support and one message that will be translated by clicking on any button.

Further, we will modify this code to localize all the text and add a language toggle.

Updated App.tsx

import { StyleSheet, Text, View, Button } from "react-native";
**import { useTranslation } from "react-i18next";
import i18n from "./i18n/i18n";**


export default function App() {
 **const { t } = useTranslation();**


 // List of the languages you want to support,
 const languages = [
   { value: "en", name: "English" },
   { value: "ja", name: "Japanese" },
   { value: "fr", name: "French" },
   { value: "sv", name: "Swedish" },
 ];
 return (
   <View style={styles.container}>
     <View style={styles.buttContainer}>
       {/* Render button for all languages */}
       {languages.map((lng) => (
         <Button
           key={lng.value}
           title={lng.name}
           **onPress={() => i18n.changeLanguage(lng.value)}
**         />
       ))}
     </View>
     <Text>
      **{t("description", "Hello from Gridly!")}**
     </Text>
   </View>
 );
}


const styles = StyleSheet.create({
 container: {
   flex: 1,
   backgroundColor: "#fff",
   alignItems: "center",
   justifyContent: "center",
   gap: 100,
   padding: 20,
 },
 buttContainer: {
   flexDirection: "column",
   gap: 30,
 },
});

Enter fullscreen mode Exit fullscreen mode

Here we have imported the i18n instance created earlier. With the click of a button, we are changing the language using i18n.changeLanguage function. Next, we used the useTranslation hook to display a message that will automatically translate the news on the language change.

Image description

Next, add translations for all the languages.

Image description

Now go back to your application and try another language. The translated content for the selected language will be displayed.

Conclusion

Gridly is a platform that can be adapted for managing localization, enabling you to manage translations effortlessly. Communicate with your team and ensure consistency across different versions of your application. Its integration with the most well-known frameworks for developing apps like React Native further enhances its capabilities, making localization an integrated part of the development process.

If you're an app creator trying to expand your market and develop a truly global app, using a comprehensive localization tool like Gridly could be an exciting change. It's not just making your application accessible in multiple languages. It's also about adapting to local practices, standards, norms, and values. With Gridly, it's easy to achieve this.

You can find the source code here
Check out the live demo here

Top comments (0)