Mobile App Localization for React Native Developers

Want your React Native app to connect with users worldwide? Localization should be effortless, not exhausting. Humanicer’s API automates translations whilst maintaining your app’s perfect structure—no messy files or manual updates.

The Power of Localization

Expanding globally means speaking your users’ language—literally. Skip the headache of managing translations manually. Humanicer does the heavy lifting, delivering accurate translations whilst keeping your project files clean and organized.

Localising in React Native

React Native doesn’t have built-in localisation support like iOS. You’ll need to use popular libraries like i18next or react-native-localize.

Setting Up i18next in React Native

First, install the necessary packages:

npm install i18next react-i18next react-native-localize

Create a basic localisation setup:

// i18n.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import * as RNLocalize from 'react-native-localize';

// Language resources
const resources = {
  en: {
    translation: {
      HELLO_WORLD: "Hello, World!",
      WELCOME_MESSAGE: "Welcome to our app!"
    }
  }
  // Other languages will be added dynamically
};

// Get device language
const locales = RNLocalize.getLocales();
const languageDetector = {
  type: 'languageDetector',
  detect: () => {
    // Use the device's language as fallback if available
    return locales[0]?.languageCode || 'en';
  },
  init: () => {},
  cacheUserLanguage: () => {}
};

// Initialize i18next
i18n
  .use(languageDetector)
  .use(initReactI18next)
  .init({
    resources,
    fallbackLng: 'en',
    interpolation: {
      escapeValue: false // React already escapes values
    }
  });

export default i18n;

Using Translations in Components

// App.js
import React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import { useTranslation } from 'react-i18next';
import './i18n'; // Import the i18n configuration

const App = () => {
  const { t } = useTranslation();
  
  return (
    <View style={styles.container}>
      <Text style={styles.text}>{t('HELLO_WORLD')}</Text>
      <Text style={styles.text}>{t('WELCOME_MESSAGE')}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  text: {
    fontSize: 18,
    margin: 10,
  },
});

export default App;

Integrating Humanicer’s API

Now let’s create a script to translate our translation files using Humanicer’s API:

// translate.js
const fs = require('fs');
const path = require('path');
const axios = require('axios');

class TranslationManager {
  constructor(apiKey) {
    /**
     * Initialize the TranslationManager with API key
     * @param {string} apiKey - Humanicer API key
     */
    this.apiKey = apiKey;
    this.apiUrl = 'https://humanicer.com/v1/localize';
  }

  async translateFile(sourcePath, targetLang) {
    /**
     * Translate a JSON translation file to target language
     * @param {string} sourcePath - Path to source JSON file
     * @param {string} targetLang - Target language code (e.g., 'fr')
     * @returns {Object} - Translated JSON object
     */
    try {
      // Read source file
      const sourceContent = fs.readFileSync(sourcePath, 'utf8');
      const sourceJson = JSON.parse(sourceContent);
      
      // Prepare text for translation (JSON stringified)
      const textToTranslate = JSON.stringify(sourceJson, null, 2);
      
      // Call Humanicer API
      const response = await axios.post(
        this.apiUrl,
        {
          text: textToTranslate,
          target_platform: 'mobile',
          target_language: targetLang
        },
        {
          headers: {
            'Content-Type': 'application/json',
            'X-API-Key': this.apiKey
          }
        }
      );
      
      // Parse the response
      const translatedText = response.data.result.localized_text;
      
      // Return parsed JSON
      return JSON.parse(translatedText);
    } catch (error) {
      console.error(`Translation error: ${error.message}`);
      throw error;
    }
  }

  async batchTranslate(sourcePath, targetLanguages, outputDir) {
    /**
     * Translate to multiple languages
     * @param {string} sourcePath - Path to source JSON file
     * @param {Array<string>} targetLanguages - List of language codes
     * @param {string} outputDir - Directory to save translated files
     */
    // Ensure output directory exists
    if (!fs.existsSync(outputDir)) {
      fs.mkdirSync(outputDir, { recursive: true });
    }
    
    // Source file name
    const sourceFileName = path.basename(sourcePath);
    
    for (const lang of targetLanguages) {
      console.log(`Translating to ${lang}...`);
      
      try {
        // Translate content
        const translatedJson = await this.translateFile(sourcePath, lang);
        
        // Write to file
        const outputPath = path.join(outputDir, `${lang}.json`);
        fs.writeFileSync(outputPath, JSON.stringify(translatedJson, null, 2));
        
        console.log(`Translation to ${lang} complete. Saved to ${outputPath}`);
      } catch (error) {
        console.error(`Failed to translate to ${lang}: ${error.message}`);
      }
    }
    
    console.log('Batch translation complete.');
  }
}

// Now use it
const translateResources = async () => {
  const manager = new TranslationManager('your_api_key');
  
  // Translate English resources to French and Spanish
  await manager.batchTranslate(
    path.join(__dirname, 'translations', 'en.json'),
    ['fr', 'es', 'de', 'ja'],
    path.join(__dirname, 'translations')
  );
};

// Run if called directly
if (require.main === module) {
  translateResources().catch(console.error);
}

Updating i18n Configuration to Load All Translations

// i18n.js - Updated to dynamically load translations
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import * as RNLocalize from 'react-native-localize';

// Import all translation files
const translationFiles = {
  en: require('./translations/en.json'),
  fr: require('./translations/fr.json'),
  es: require('./translations/es.json'),
  de: require('./translations/de.json'),
  ja: require('./translations/ja.json'),
  // Add more languages as needed
};

// Prepare resources object for i18next
const resources = Object.keys(translationFiles).reduce((acc, lang) => {
  acc[lang] = {
    translation: translationFiles[lang]
  };
  return acc;
}, {});

// Get device language
const locales = RNLocalize.getLocales();
const deviceLanguage = locales[0]?.languageCode || 'en';

// Check if we support the device language
const languageDetector = {
  type: 'languageDetector',
  detect: () => {
    // Use device language if available in our translations, otherwise use English
    return resources[deviceLanguage] ? deviceLanguage : 'en';
  },
  init: () => {},
  cacheUserLanguage: () => {}
};

// Initialize i18next
i18n
  .use(languageDetector)
  .use(initReactI18next)
  .init({
    resources,
    fallbackLng: 'en',
    interpolation: {
      escapeValue: false
    },
    react: {
      useSuspense: false
    }
  });

export default i18n;

Language Switcher Component

// LanguageSwitcher.js
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { useTranslation } from 'react-i18next';

const LanguageSwitcher = () => {
  const { i18n } = useTranslation();
  
  // Languages available in the app
  const languages = [
    { code: 'en', name: 'English' },
    { code: 'fr', name: 'Français' },
    { code: 'es', name: 'Español' },
    { code: 'de', name: 'Deutsch' },
    { code: 'ja', name: '日本語' }
  ];
  
  /**
   * Changes the app language
   * @param {string} langCode - Language code to switch to
   */
  const changeLanguage = (langCode) => {
    i18n.changeLanguage(langCode);
  };
  
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Select Language:</Text>
      <View style={styles.buttonsContainer}>
        {languages.map((lang) => (
          <TouchableOpacity
            key={lang.code}
            style={[
              styles.button,
              i18n.language === lang.code && styles.activeButton
            ]}
            onPress={() => changeLanguage(lang.code)}
          >
            <Text
              style={[
                styles.buttonText,
                i18n.language === lang.code && styles.activeButtonText
              ]}
            >
              {lang.name}
            </Text>
          </TouchableOpacity>
        ))}
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    padding: 16,
    backgroundColor: '#f8f8f8',
    borderRadius: 8,
    margin: 10,
  },
  title: {
    fontSize: 16,
    fontWeight: 'bold',
    marginBottom: 10,
  },
  buttonsContainer: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    justifyContent: 'center',
  },
  button: {
    paddingVertical: 8,
    paddingHorizontal: 16,
    backgroundColor: '#fff',
    borderRadius: 4,
    borderWidth: 1,
    borderColor: '#ddd',
    margin: 4,
  },
  activeButton: {
    backgroundColor: '#007bff',
    borderColor: '#007bff',
  },
  buttonText: {
    color: '#333',
  },
  activeButtonText: {
    color: '#fff',
  },
});

export default LanguageSwitcher;

Updated App Component with Language Switcher

// App.js
import React, { useEffect } from 'react';
import { Text, View, StyleSheet, SafeAreaView } from 'react-native';
import { useTranslation } from 'react-i18next';
import './i18n'; // Import the i18n configuration
import LanguageSwitcher from './LanguageSwitcher';
import AsyncStorage from '@react-native-async-storage/async-storage';

const App = () => {
  const { t, i18n } = useTranslation();
  
  // Load saved language preference on startup
  useEffect(() => {
    const loadSavedLanguage = async () => {
      try {
        const savedLang = await AsyncStorage.getItem('userLanguage');
        if (savedLang && i18n.language !== savedLang) {
          i18n.changeLanguage(savedLang);
        }
      } catch (error) {
        console.error('Failed to load language preference:', error);
      }
    };
    
    loadSavedLanguage();
  }, []);
  
  // Save language preference when it changes
  useEffect(() => {
    const saveLanguagePreference = async () => {
      try {
        await AsyncStorage.setItem('userLanguage', i18n.language);
      } catch (error) {
        console.error('Failed to save language preference:', error);
      }
    };
    
    saveLanguagePreference();
  }, [i18n.language]);
  
  return (
    <SafeAreaView style={styles.safeArea}>
      <View style={styles.container}>
        <Text style={styles.header}>{t('APP_NAME', 'My App')}</Text>
        
        <View style={styles.contentContainer}>
          <Text style={styles.greeting}>{t('HELLO_WORLD')}</Text>
          <Text style={styles.welcome}>{t('WELCOME_MESSAGE')}</Text>
        </View>
        
        <LanguageSwitcher />
      </View>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  safeArea: {
    flex: 1,
    backgroundColor: '#fff',
  },
  container: {
    flex: 1,
    padding: 16,
  },
  header: {
    fontSize: 24,
    fontWeight: 'bold',
    textAlign: 'center',
    marginVertical: 20,
  },
  contentContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  greeting: {
    fontSize: 28,
    marginBottom: 16,
  },
  welcome: {
    fontSize: 18,
    textAlign: 'center',
    color: '#555',
  }
});

export default App;

Integrating Humanicer API with React Native

Let’s create a utility class that can be used directly within a React Native app to fetch translations on demand:

// HumanicerService.js
import axios from 'axios';
import AsyncStorage from '@react-native-async-storage/async-storage';
import i18n from './i18n';

class HumanicerService {
  /**
   * Create a new HumanicerService instance
   * @param {string} apiKey - Your Humanicer API key
   */
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.apiUrl = 'https://humanicer.com/v1/localize';
    this.translationCache = {};
    
    // Load cached translations from storage
    this.loadCachedTranslations();
  }
  
  /**
   * Load previously cached translations from AsyncStorage
   */
  async loadCachedTranslations() {
    try {
      const cachedData = await AsyncStorage.getItem('humanicer_translations');
      if (cachedData) {
        this.translationCache = JSON.parse(cachedData);
      }
    } catch (error) {
      console.error('Failed to load cached translations:', error);
    }
  }
  
  /**
   * Save translations to AsyncStorage cache
   */
  async saveTranslationsToCache() {
    try {
      await AsyncStorage.setItem(
        'humanicer_translations', 
        JSON.stringify(this.translationCache)
      );
    } catch (error) {
      console.error('Failed to save translations to cache:', error);
    }
  }
  
  /**
   * Translate a single text string
   * @param {string} text - Text to translate
   * @param {string} targetLang - Target language code
   * @returns {Promise<string>} - Translated text
   */
  async translateText(text, targetLang) {
    // Check cache first
    const cacheKey = `${text}_${targetLang}`;
    if (this.translationCache[cacheKey]) {
      return this.translationCache[cacheKey];
    }
    
    try {
      const response = await axios.post(
        this.apiUrl,
        {
          text,
          target_platform: 'mobile',
          target_language: targetLang
        },
        {
          headers: {
            'Content-Type': 'application/json',
            'X-API-Key': this.apiKey
          }
        }
      );
      
      const translatedText = response.data.result.localized_text;
      
      // Add to cache
      this.translationCache[cacheKey] = translatedText;
      this.saveTranslationsToCache();
      
      return translatedText;
    } catch (error) {
      console.error('Translation error:', error);
      throw error;
    }
  }
  
  /**
   * Translate an object containing translations
   * @param {Object} translationObj - Object with translation keys/values
   * @param {string} targetLang - Target language code
   * @returns {Promise<Object>} - Translated object
   */
  async translateObject(translationObj, targetLang) {
    try {
      // Convert object to JSON string for translation
      const textToTranslate = JSON.stringify(translationObj);
      
      const translatedText = await this.translateText(textToTranslate, targetLang);
      
      // Parse the translated JSON back to object
      return JSON.parse(translatedText);
    } catch (error) {
      console.error('Failed to translate object:', error);
      throw error;
    }
  }
  
  /**
   * Dynamically load translations for a new language
   * @param {string} langCode - Language code to load
   * @returns {Promise<boolean>} - Success status
   */
  async loadLanguage(langCode) {
    try {
      // Check if we already have this language loaded
      if (i18n.hasResourceBundle(langCode, 'translation')) {
        return true;
      }
      
      // Get the English translations as source
      const sourceTranslations = i18n.getResourceBundle('en', 'translation');
      
      // Translate to target language
      const translatedBundle = await this.translateObject(sourceTranslations, langCode);
      
      // Add translations to i18next
      i18n.addResourceBundle(langCode, 'translation', translatedBundle);
      
      return true;
    } catch (error) {
      console.error(`Failed to load language ${langCode}:`, error);
      return false;
    }
  }
}

// Export as singleton
export default new HumanicerService('your_api_key');

Automated Build Step to Generate Translations

To integrate translations into your build process, create a script that runs during your build:

// generate-translations.js
const fs = require('fs');
const path = require('path');
const axios = require('axios');

class TranslationBuilder {
  /**
   * Create a new translation builder
   * @param {string} apiKey - Humanicer API key
   */
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.apiUrl = 'https://humanicer.com/v1/localize';
    this.baseDir = path.resolve(__dirname);
    this.sourceLanguage = 'en';
    this.sourceFile = path.join(this.baseDir, 'src/translations/en.json');
    this.outputDir = path.join(this.baseDir, 'src/translations');
  }
  
  /**
   * Read the source translation file
   * @returns {Object} - Source translations
   */
  readSourceFile() {
    try {
      const fileContent = fs.readFileSync(this.sourceFile, 'utf8');
      return JSON.parse(fileContent);
    } catch (error) {
      console.error(`Error reading source file: ${error.message}`);
      throw error;
    }
  }
  
  /**
   * Translate content to target language
   * @param {string} content - Content to translate
   * @param {string} targetLang - Target language code
   * @returns {Promise<string>} - Translated content
   */
  async translate(content, targetLang) {
    try {
      const response = await axios.post(
        this.apiUrl,
        {
          text: content,
          target_platform: 'mobile',
          target_language: targetLang
        },
        {
          headers: {
            'Content-Type': 'application/json',
            'X-API-Key': this.apiKey
          }
        }
      );
      
      return response.data.result.localized_text;
    } catch (error) {
      console.error(`Translation error: ${error.message}`);
      if (error.response) {
        console.error(`API response: ${JSON.stringify(error.response.data)}`);
      }
      throw error;
    }
  }
  
  /**
   * Generate translations for all target languages
   * @param {Array<string>} targetLanguages - List of language codes to generate
   */
  async generateAll(targetLanguages) {
    console.log('Starting translation generation...');
    
    // Ensure output directory exists
    if (!fs.existsSync(this.outputDir)) {
      fs.mkdirSync(this.outputDir, { recursive: true });
    }
    
    // Read source translations
    const sourceTranslations = this.readSourceFile();
    const sourceContent = JSON.stringify(sourceTranslations, null, 2);
    
    // Translate to each target language
    for (const lang of targetLanguages) {
      console.log(`Translating to ${lang}...`);
      
      try {
        // Skip source language
        if (lang === this.sourceLanguage) {
          console.log(`Skipping source language ${lang}`);
          continue;
        }
        
        // Check if file already exists and needs update
        const outputFile = path.join(this.outputDir, `${lang}.json`);
        const shouldUpdate = this.shouldUpdateFile(outputFile);
        
        if (!shouldUpdate) {
          console.log(`Skipping ${lang} - already up to date`);
          continue;
        }
        
        // Translate content
        const translatedContent = await this.translate(sourceContent, lang);
        
        // Write to file
        fs.writeFileSync(outputFile, translatedContent);
        console.log(`Successfully generated ${lang} translations`);
      } catch (error) {
        console.error(`Failed to generate ${lang} translations: ${error.message}`);
      }
    }
    
    console.log('Translation generation complete!');
  }
  
  /**
   * Check if a translation file needs update
   * @param {string} filePath - Path to check
   * @returns {boolean} - True if update needed
   */
  shouldUpdateFile(filePath) {
    // If file doesn't exist, it needs to be created
    if (!fs.existsSync(filePath)) {
      return true;
    }
    
    // Get modification times
    const sourceStats = fs.statSync(this.sourceFile);
    const targetStats = fs.statSync(filePath);
    
    // If source is newer than target, update needed
    return sourceStats.mtime > targetStats.mtime;
  }
}

// Run the translation generation
const run = async () => {
  // Get API key from environment or config
  const apiKey = process.env.HUMANICER_API_KEY || 'your_api_key';
  
  // Target languages to generate
  const targetLanguages = ['fr', 'es', 'de', 'ja', 'zh', 'ru', 'pt', 'it'];
  
  const builder = new TranslationBuilder(apiKey);
  await builder.generateAll(targetLanguages);
};

// Run if called directly
if (require.main === module) {
  run().catch(error => {
    console.error('Translation generation failed:', error);
    process.exit(1);
  });
}

Adding to Your Build Process

{
  "name": "multilingual-react-native-app",
  "version": "1.0.0",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "generate-translations": "node scripts/generate-translations.js",
    "prebuild": "npm run generate-translations",
    "build": "expo build",
    "eject": "expo eject"
  },
  "dependencies": {
    "@react-native-async-storage/async-storage": "^1.15.0",
    "axios": "^0.24.0",
    "expo": "~44.0.0",
    "expo-status-bar": "~1.2.0",
    "i18next": "^21.6.0",
    "react": "17.0.1",
    "react-dom": "17.0.1",
    "react-i18next": "^11.15.0",
    "react-native": "0.64.3",
    "react-native-localize": "^2.1.5",
    "react-native-web": "0.17.1"
  },
  "devDependencies": {
    "@babel/core": "^7.12.9"
  },
  "private": true
}

Best Practices for React Native Localisation

  • Separate translation files: Keep all translations in separate JSON files organised by language code

  • Use variables for dynamic content:

// Instead of concatenating strings
t('GREETING') + userName // BAD

// Use variables
t('GREETING_WITH_NAME', { name: userName }) // GOOD
  • Handle plurals properly:
// In your JSON file
{
  "ITEMS_COUNT": "8 item",
  "ITEMS_COUNT_plural": "8 items"
}

// In your code
t('ITEMS_COUNT', { count: itemCount })
  • Format dates and numbers according to locale:
import { format } from 'date-fns';
import { enGB, fr } from 'date-fns/locale';

// Map language codes to date-fns locales
const locales = {
  en: enGB,
  fr: fr
};

// In component
const dateStr = format(
  new Date(),
  'PPP', // Format pattern
  { locale: locales[i18n.language] || enGB }
);
  • Test with pseudo-localisation: Create a test translation file with extended characters or longer text to identify UI issues.

  • Cache translations to reduce API calls and work offline

  • Add RTL (Right-to-Left) support for languages like Arabic and Hebrew:

import { I18nManager } from 'react-native';

// In your app setup
const isRTL = I18nManager.isRTL;

// In your styles
const styles = StyleSheet.create({
  container: {
    flexDirection: isRTL ? 'row-reverse' : 'row'
  }
});

Complete Project Structure

my-multilingual-app/
├── src/
│   ├── translations/
│   │   ├── en.json
│   │   ├── fr.json
│   │   ├── es.json
│   │   ├── de.json
│   │   └── ja.json
│   ├── components/
│   │   ├── LanguageSwitcher.js
│   │   └── [other components]
│   ├── services/
│   │   └── HumanicerService.js
│   ├── i18n.js
│   └── App.js
├── scripts/
│   └── generate-translations.js
├── package.json
└── babel.config.js

Example Translation File (en.json)

{
  "APP_NAME": "My Multilingual App",
  "HELLO_WORLD": "Hello, World!",
  "WELCOME_MESSAGE": "Welcome to our app!",
  
  "ONBOARDING": {
    "SCREEN_1_TITLE": "Welcome",
    "SCREEN_1_TEXT": "Get started with our amazing features",
    "SCREEN_2_TITLE": "Discover",
    "SCREEN_2_TEXT": "Find what you need with our intuitive interface",
    "SCREEN_3_TITLE": "Connect",
    "SCREEN_3_TEXT": "Stay connected with friends and family",
    "NEXT_BUTTON": "Next",
    "SKIP_BUTTON": "Skip",
    "GET_STARTED": "Get Started"
  },
  
  "AUTH": {
    "LOGIN": "Log In",
    "SIGNUP": "Sign Up",
    "EMAIL": "Email",
    "PASSWORD": "Password",
    "FORGOT_PASSWORD": "Forgot Password?",
    "OR_CONTINUE_WITH": "Or continue with",
    "GOOGLE": "Google",
    "APPLE": "Apple",
    "FACEBOOK": "Facebook"
  },
  
  "SETTINGS": {
    "TITLE": "Settings",
    "ACCOUNT": "Account",
    "NOTIFICATIONS": "Notifications",
    "LANGUAGE": "Language",
    "THEME": "Theme",
    "HELP": "Help & Support",
    "LOGOUT": "Log Out"
  },
  
  "ERRORS": {
    "GENERIC": "Something went wrong. Please try again.",
    "NETWORK": "Network error. Please check your connection.",
    "NOT_FOUND": "The requested resource was not found."
  },
  
  "COMMON": {
    "SAVE": "Save",
    "CANCEL": "Cancel",
    "DONE": "Done",
    "EDIT": "Edit",
    "DELETE": "Delete",
    "LOADING": "Loading...",
    "SEARCH": "Search",
    "NO_RESULTS": "No results found",
    "RETRY": "Retry",
    "CONFIRM": "Confirm",
    "YES": "Yes",
    "NO": "No",
    "BACK": "Back",
    "NEXT": "Next",
    "ITEMS_COUNT": "8 item",
    "ITEMS_COUNT_plural": "8 items"
  },
  
  "DATES": {
    "TODAY": "Today",
    "YESTERDAY": "Yesterday",
    "TOMORROW": "Tomorrow",
    "DAYS_AGO": "8 day ago",
    "DAYS_AGO_plural": "8 days ago"
  }
}

CI/CD Integration with GitHub Actions

Add translation generation to your CI/CD pipeline:

name: Generate Translations

on:
  push:
    branches: [main]
    paths:
      - 'src/translations/en.json'
  workflow_dispatch:

jobs:
  generate-translations:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      
      - name: Set up Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '16'
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Generate translations
        run: npm run generate-translations
        env:
          HUMANICER_API_KEY: $
      
      - name: Commit and push if changed
        run: |
          git config --local user.email "github-actions@github.com"
          git config --local user.name "GitHub Actions"
          git add src/translations/*.json
          git diff --staged --quiet || (git commit -m "feat: update translations" && git push)

Step-by-Step Implementation Guide

  • Set up the basic React Native project:
npx create-expo-app my-multilingual-app
cd my-multilingual-app
  • Install the required packages:
npm install i18next react-i18next react-native-localize @react-native-async-storage/async-storage axios
  • Create the project structure:
mkdir -p src/translations src/components src/services scripts
  • Create the translation files:
    • Create src/translations/en.json with your base translations
    • Set up Humanicer API key in your environment
  • Set up i18n configuration:
    • Implement src/i18n.js using the code from our example
  • Create the translation generation script:
    • Add scripts/generate-translations.js using our example
    • Run it to generate initial translations: node scripts/generate-translations.js
  • Update package.json:
    • Add the script commands as shown in our example
  • Implement the language switcher component:
    • Create src/components/LanguageSwitcher.js
  • Update your App.js to use translations:
    • Import i18n and the language switcher
    • Use the t function for all text content
  • Optional: Set up CI/CD:

Getting Started with Humanicer

  • Sign up at Humanicer for your API key
  • Set up your API key in your environment variables or config
  • Run your translation script to generate all language files
  • Build and test your app to ensure translations work correctly

Localisation is now straightforward. Focus on building great features whilst Humanicer handles the translations. Your global users will thank you.