GetTranslated.AI

React Native SDK - Complete Integration Guide

Comprehensive guide for integrating GetTranslated.AI into your React Native applications

Overview

The GetTranslated React Native SDK provides real-time, AI-powered translations for React Native applications. It offers seamless integration with automatic language detection, offline caching, and support for both anonymous and authenticated users.

Key Features

  • Real-time Translation: Get translations on-demand with automatic caching
  • Anonymous User Support: Automatic user ID generation with seamless login transition
  • Language Management: Automatic language detection based on system preferences and overrides (manual setting optional for custom selectors)
  • Offline Caching: Persistent translation cache using AsyncStorage
  • TypeScript Support: Full TypeScript definitions included
  • Cross-platform: Works on both iOS and Android
  • React Integration: Hooks and providers for easy React integration

Architecture

The SDK provides three integration approaches:

  1. Static Methods - Direct SDK access for simple use cases
  2. TranslationProvider - Context-based management for React applications
  3. Default i18n Context - Integration with existing react-i18next setups

Installation

Prerequisites

  • React Native 0.60+
  • iOS 10.0+ / Android API 21+
  • Node.js 14+

Install the SDK

npm install @gettranslated/react-native-sdk
# or
yarn add @gettranslated/react-native-sdk

iOS Setup

For iOS, install the required native dependencies:

cd ios && pod install

Android Setup

No additional setup required for Android. The SDK uses react-i18next for language management.

Dependencies

The SDK automatically installs these dependencies:

  • @react-native-async-storage/async-storage - For persistent storage
  • i18next - Core internationalization library
  • intl-pluralrules - For pluralization support
  • react-i18next - React integration for i18next

Note: Language detection uses React Native's built-in getLocales() API, so no additional language detection library is required.

๐Ÿš€ New to GetTranslated? Check out our Quick Start Guide to get up and running in under 5 minutes!

API Reference

Static Methods

init(key: string, userId?: string, logLevel?: LogLevel, resources?: Record<string, Record<string, Record<string, any>>>): Promise<void>

Initializes the SDK with optional user ID, log level, and translation resources. Supports multiple namespaces (e.g., translation, currencies, errors).

Parameters:

  • key - Your GetTranslated API key
  • userId - Optional user ID for authenticated users (if not provided, creates anonymous user)
  • logLevel - Optional log level for debugging (LogLevel enum). Defaults to LogLevel.WARN
  • resources - Optional translation resources for bundled translations (required for synchronous t() function). Supports multiple namespaces (e.g., translation, currencies, errors). See Multiple Language Files (Namespaces) for details.
import { LogLevel } from '@gettranslated/react-native-sdk';

// Anonymous user (uses default WARN log level)
await GetTranslated.init('your-ck-api-key');

// Anonymous user with debug logging
await GetTranslated.init('your-ck-api-key', undefined, LogLevel.DEBUG);

// Specific user ID (uses default WARN log level)
await GetTranslated.init('your-ck-api-key', 'user-123');

// Specific user ID with debug logging
await GetTranslated.init('your-ck-api-key', 'user-123', LogLevel.DEBUG);

// With translation resources for synchronous translations
// Import translation files (generated by CLI)
import enTranslations from './locales/en.json';
import esTranslations from './locales/es.json';

const resources = {
  en: { translation: enTranslations },
  es: { translation: esTranslations }
};
await GetTranslated.init('your-ck-api-key', 'user-123', LogLevel.DEBUG, resources);

// Verbose logging for development
await GetTranslated.init('your-ck-api-key', 'user-123', LogLevel.VERBOSE);

t(text: string, options?: any): string

Primary method - Gets translation synchronously from bundled/extracted resources. Use this for all UI strings, button labels, screen titles, and any strings known at build time.

Parameters:

  • text - Text key from your extracted resources
  • options - Optional interpolation options (variables, count, etc.)

Returns: string - Translated text (synchronous, no async/await needed)

Loading State Behavior: The t() function returns an empty string when translations are not yet loaded or when a translation key is not found. This prevents translation keys from flashing in the UI during initialization. Components will automatically re-render when translations become available. You can check isInitialized from the useTranslation() hook if you need to show loading states or fallback content.
// In React components - use t() from hook (preferred)
function MyComponent() {
  const { t } = useTranslation();
  
  return (
    <View>
      {/* Basic usage */}
      <Text>{t('Welcome')}</Text>
      
      {/* With interpolation */}
      <Text>{t('Hello, !', { name: 'John' })}</Text>
      {/* Result: "Hello, John!" */}
      
      {/* With count (pluralization) */}
      <Text>{t(' item', { count: 5 })}</Text>
      {/* Result: "5 items" (if plural form exists) */}
      
      {/* With structured plural object */}
      <Text>{t('item_count', { count: 5 })}</Text>
      {/* Result: "5 items" (automatically selects correct plural form) */}
      
      {/* In button titles */}
      <Button title={t('Submit')} />
      
      {/* Accessing translations from different namespaces */}
      <Text>{t('currencies:usd')}</Text>
      <Text>{t('errors:network_error')}</Text>
      
      {/* Or using ns option */}
      <Text>{t('usd', { ns: 'currencies' })}</Text>
    </View>
  );
}

// Static method (for utility functions outside components)
const greeting = GetTranslated.t('Welcome');
const currency = GetTranslated.t('currencies:usd');
๐Ÿ“ Multiple Namespaces: The SDK supports multiple language files (namespaces). Access translations from different namespaces using namespace:key syntax (e.g., t('currencies:usd')) or the ns option. See the Multiple Language Files (Namespaces) section for complete documentation.
Pluralization with Structured Objects

The SDK supports i18next's structured plural object format for proper plural handling. This format allows you to define different plural forms based on quantity rules (zero, one, two, few, many, other).

Plural Format in JSON Files:

Use a structured object with plural quantity keys:

{
  "item_count": {
    "zero": "No items",
    "one": " item",
    "other": " items"
  }
}

Supported Plural Quantities:

  • zero - For zero quantity (e.g., "No items")
  • one - For singular (e.g., "1 item")
  • two - For exactly two (used in some languages like Slovenian)
  • few - For small quantities (used in languages like Russian, Polish)
  • many - For large quantities (used in some languages)
  • other - Default/fallback form (required in all plural objects)

Usage in Code:

function ItemList({ count }: { count: number }) {
  const { t } = useTranslation();
  
  return (
    <View>
      {/* i18next automatically selects the correct plural form based on count */}
      <Text>{t('item_count', { count })}</Text>
    </View>
  );
}

// Examples:
// count = 0  โ†’ "No items" (zero)
// count = 1  โ†’ "1 item" (one)
// count = 5  โ†’ "5 items" (other)

Complete Example:

// en.json
{
  "message_count": {
    "zero": "No messages",
    "one": "One message",
    "other": " messages"
  }
}
function MessageCounter({ count }: { count: number }) {
  const { t } = useTranslation();
  return <Text>{t('message_count', { count })}</Text>;
}
Important Notes:
  • Always include other: The other key is required and serves as the fallback for quantities that don't match other rules.
  • Language-specific rules: i18next automatically applies the correct plural rules for each language. For example:
    • English: Uses one and other
    • Russian: Uses one, few, many, and other
    • Arabic: Uses zero, one, two, few, many, and other
  • Count interpolation: Use in your plural strings to include the actual number.
  • Legacy suffix format: The SDK also supports the legacy suffix-based format (key, key_plural, key_one, etc.), but the structured object format is recommended for better language support.
๐Ÿ’ก Resources are extracted via CLI: Run translate sync to generate en.json, es.json, etc. files that you import into your app.

getDynamicTranslation(text: string): Promise<string>

Advanced use case - Gets translation asynchronously for dynamic strings not in bundled resources. Use this only for server-side error messages, user-generated content, or strings from external APIs.

Parameters:

  • text - Dynamic text to translate (not in bundled resources)

Returns: Promise<string> - Translated text

// Translate server error message (not in bundled resources)
const errorMessage = await GetTranslated.getDynamicTranslation('Connection timeout');

// With error handling
try {
  const translation = await GetTranslated.getDynamicTranslation(serverError);
  console.log('Translation:', translation);
} catch (error) {
  console.error('Translation failed:', error);
  // Use fallback text
}

When to Use Each Method

Method Use Case Example
t() Primary method - All UI strings, button labels, screen titles, etc. (extracted via CLI and bundled into your app) <Text>{t('Welcome')}</Text>
getDynamicTranslation() Advanced - Server error messages, user-generated content, external API responses const error = await getDynamicTranslation(serverError);

TranslationProvider

Props

Prop Type Required Description
children ReactNode Yes Your app components
apiKey string Yes GetTranslated API key
userId string No User ID for authenticated users
onError (error: Error) => void No Error handler callback
resources Record<string, Record<string, Record<string, any>>> No Translation resources with support for multiple namespaces. Structure: { language: { namespace: translations } }. See Multiple Language Files (Namespaces) for details.
logLevel LogLevel No Log level for debugging (defaults to LogLevel.WARN)

useTranslation Hook

Returns an object with the following properties:

Property Type Description
currentLanguage string Current language code (read-only)
changeLanguage (language: string) => Promise<void> Function to change language
availableLanguages LanguageInfo[] Array of available languages
isInitialized boolean Whether the SDK is initialized
getDynamicTranslation (text: string) => Promise<string> Function to get translations
login (userId: string) => Promise<void> Function to login authenticated user
logout () => Promise<void> Function to logout and return to anonymous state
t (text: string, options?: any) => string Synchronous translation function with interpolation support

Multiple Language Files (Namespaces)

The SDK supports organizing translations into multiple namespaces (language files), allowing you to separate translations by feature, module, or purpose. This is useful for large applications where you want to organize translations into logical groups like translation (general UI), currencies, errors, notifications, etc.

Setting Up Multiple Namespaces

To use multiple namespaces, structure your resources object with multiple namespace keys for each language:

// Import your translation files (generated by CLI)
import enTranslations from './locales/en/translation.json';
import enCurrencies from './locales/en/currencies.json';
import enErrors from './locales/en/errors.json';

import esTranslations from './locales/es/translation.json';
import esCurrencies from './locales/es/currencies.json';
import esErrors from './locales/es/errors.json';

// Structure resources with multiple namespaces
const resources = {
  en: {
    translation: enTranslations,    // General UI strings
    currencies: enCurrencies,        // Currency names and symbols
    errors: enErrors,                // Error messages
  },
  es: {
    translation: esTranslations,
    currencies: esCurrencies,
    errors: esErrors,
  },
};

// Pass to TranslationProvider
<TranslationProvider apiKey="your-ck-api-key" resources={resources}>
  <App />
</TranslationProvider>

Example Translation Files

Here's how your translation files might be structured:

// locales/en/translation.json (default namespace)
{
  "welcome": "Welcome",
  "hello": "Hello, !",
  "submit": "Submit",
  "cancel": "Cancel"
}

// locales/en/currencies.json
{
  "usd": "US Dollar",
  "eur": "Euro",
  "gbp": "British Pound",
  "symbol_usd": "$",
  "symbol_eur": "โ‚ฌ",
  "symbol_gbp": "ยฃ"
}

// locales/en/errors.json
{
  "network_error": "Network connection failed",
  "invalid_input": "Please check your input",
  "server_error": "Server error. Please try again later"
}

Accessing Translations with Namespaces

There are two ways to access translations from different namespaces:

Method 1: Namespace Prefix Syntax (Recommended)

Use the namespace:key syntax directly in the translation key:

function MyComponent() {
  const { t } = useTranslation();
  
  return (
    <View>
      {/* Default namespace (translation) */}
      <Text>{t('welcome')}</Text>
      <Text>{t('hello', { name: 'John' })}</Text>
      
      {/* Access currencies namespace */}
      <Text>{t('currencies:usd')}</Text>
      <Text>{t('currencies:symbol_usd')}</Text>
      
      {/* Access errors namespace */}
      <Text>{t('errors:network_error')}</Text>
      <Text>{t('errors:invalid_input')}</Text>
    </View>
  );
}

Method 2: Namespace Option

Use the ns option in the options parameter:

function MyComponent() {
  const { t } = useTranslation();
  
  return (
    <View>
      {/* Default namespace */}
      <Text>{t('welcome')}</Text>
      
      {/* Specify namespace in options */}
      <Text>{t('usd', { ns: 'currencies' })}</Text>
      <Text>{t('network_error', { ns: 'errors' })}</Text>
      
      {/* Combine with interpolation */}
      <Text>{t('hello', { name: 'John', ns: 'translation' })}</Text>
    </View>
  );
}

Complete Example

Here's a complete example showing multiple namespaces in action:

import React from 'react';
import { View, Text, Button } from 'react-native';
import { TranslationProvider, useTranslation } from '@gettranslated/react-native-sdk';

// Import translation files for each namespace
import enTranslation from './locales/en/translation.json';
import enCurrencies from './locales/en/currencies.json';
import enErrors from './locales/en/errors.json';

import esTranslation from './locales/es/translation.json';
import esCurrencies from './locales/es/currencies.json';
import esErrors from './locales/es/errors.json';

// Structure resources with multiple namespaces
const resources = {
  en: {
    translation: enTranslation,
    currencies: enCurrencies,
    errors: enErrors,
  },
  es: {
    translation: esTranslation,
    currencies: esCurrencies,
    errors: esErrors,
  },
};

export default function App() {
  return (
    <TranslationProvider apiKey="your-ck-api-key" resources={resources}>
      <MainScreen />
    </TranslationProvider>
  );
}

function MainScreen() {
  const { t } = useTranslation();
  
  return (
    <View>
      {/* Default namespace (translation) */}
      <Text>{t('welcome')}</Text>
      
      {/* Currencies namespace */}
      <Text>Price: {t('currencies:symbol_usd')}100</Text>
      <Text>Currency: {t('currencies:usd')}</Text>
      
      {/* Errors namespace */}
      <Text style={{ color: 'red' }}>
        {t('errors:network_error')}
      </Text>
    </View>
  );
}

Using with CLI

The GetTranslated CLI supports extracting translations into multiple namespaces. When you run translate sync, you can organize your translations into separate files:

# Your project structure after CLI sync
locales/
โ”œโ”€โ”€ en/
โ”‚   โ”œโ”€โ”€ translation.json    # General UI strings
โ”‚   โ”œโ”€โ”€ currencies.json    # Currency-related translations
โ”‚   โ””โ”€โ”€ errors.json        # Error messages
โ”œโ”€โ”€ es/
โ”‚   โ”œโ”€โ”€ translation.json
โ”‚   โ”œโ”€โ”€ currencies.json
โ”‚   โ””โ”€โ”€ errors.json
โ””โ”€โ”€ fr/
    โ”œโ”€โ”€ translation.json
    โ”œโ”€โ”€ currencies.json
    โ””โ”€โ”€ errors.json
๐Ÿ’ก Best Practices:
  • Default namespace: The translation namespace is the default. Keys without a namespace prefix will use this namespace.
  • Namespace naming: Use descriptive, lowercase names for namespaces (e.g., currencies, errors, notifications).
  • Organization: Group related translations together. For example, all currency-related strings go in currencies, all error messages in errors.
  • Consistency: Ensure all languages have the same namespaces. If you have currencies for English, you should have it for all other languages too.
  • Key naming: Keep keys unique within a namespace, but you can reuse keys across namespaces (e.g., translation:submit and errors:submit are different).

Benefits of Using Namespaces

  • Organization: Keep related translations together, making it easier to manage large translation sets
  • Performance: Load only the namespaces you need, reducing initial bundle size
  • Maintainability: Easier to find and update translations when organized by feature
  • Team Collaboration: Different teams can work on different namespaces without conflicts
  • Lazy Loading: Load namespaces on-demand for better performance (future feature)

Advanced Usage

Choosing the Right Integration Approach

The SDK provides four different integration approaches. Choose based on your needs:

1. TranslationProvider + useTranslation (Recommended)

Best for: Modern React apps with functional components

  • โœ… Automatic re-rendering on language changes
  • โœ… Full SDK features (dynamic translations, user management)
  • โœ… React hooks pattern
  • โœ… Error handling built-in

2. Static Methods

Best for: Simple use cases, utility functions, or non-React contexts

  • โœ… Direct SDK access
  • โœ… No React dependencies
  • โœ… Full control over initialization
  • โŒ Manual re-rendering required

3. withTranslations HOC

Best for: Class components or teams preferring HOC pattern

  • โœ… Works with class components
  • โœ… react-i18next compatible
  • โœ… Synchronous translations
  • โŒ Limited to t() function only

4. Default i18n Context

Best for: Existing react-i18next apps

  • โœ… Drop-in replacement for react-i18next
  • โœ… No code changes required
  • โœ… Synchronous translations
  • โŒ Limited to bundled resources

Resources for Synchronous Translations

When using the synchronous t() function for bundled resources, you must provide the resources prop to the TranslationProvider. The SDK now passes these resources directly to the init() method for better integration:

const resources = {
  en: { 
    translation: { 
      'Welcome': 'Welcome',
      'Hello': 'Hello',
      'Goodbye': 'Goodbye'
    } 
  },
  es: { 
    translation: { 
      'Welcome': 'Bienvenido',
      'Hello': 'Hola',
      'Goodbye': 'Adiรณs'
    } 
  },
  fr: { 
    translation: { 
      'Welcome': 'Bienvenue',
      'Hello': 'Bonjour',
      'Goodbye': 'Au revoir'
    } 
  }
};

<TranslationProvider
  apiKey="your-ck-api-key"
  resources={resources}
>
  <App />
</TranslationProvider>
How resources work:
  • Resources are passed to GetTranslated.init() during SDK initialization
  • i18next is initialized with these resources for synchronous lookups
  • The t() function works immediately after initialization
  • Resources are bundled with your app and available offline

Advanced TranslationProvider Patterns

Here are some advanced patterns for using TranslationProvider in complex applications:

Custom HOC with TranslationProvider

import React from 'react';
import { TranslationProvider, useTranslation } from '@gettranslated/react-native-sdk';

// Custom HOC that wraps components with TranslationProvider
export function withTranslationProvider<P extends object>(
  WrappedComponent: React.ComponentType<P>,
  apiKey: string,
  options?: {
    userId?: string;
    resources?: Record<string, any>;
    onError?: (error: Error) => void;
  }
) {
  const WithTranslationProvider = (props: P) => {
    return (
      <TranslationProvider
        apiKey={apiKey}
        userId={options?.userId}
        resources={options?.resources}
        onError={options?.onError}
      >
        <WrappedComponent {...props} />
      </TranslationProvider>
    );
  };

  WithTranslationProvider.displayName = `withTranslationProvider(${WrappedComponent.displayName || WrappedComponent.name})`;
  return WithTranslationProvider;
}

// Usage
const MyApp = withTranslationProvider(App, 'your-ck-api-key', {
  userId: 'user-123',
  onError: (error) => console.error('Translation error:', error)
});

Nested TranslationProviders

import React from 'react';
import { TranslationProvider, useTranslation } from '@gettranslated/react-native-sdk';

// Parent app with main translations
function App() {
  return (
    <TranslationProvider apiKey="main-api-key">
      <MainContent />
    </TranslationProvider>
  );
}

// Nested provider for specific features
function FeatureSection() {
  return (
    <TranslationProvider 
      apiKey="feature-api-key"
      userId="feature-user"
    >
      <FeatureContent />
    </TranslationProvider>
  );
}

function FeatureContent() {
  const { getDynamicTranslation } = useTranslation();
  // This will use the nested provider's context
  return <Text>Feature-specific translations</Text>;
}

TranslationProvider with Custom Context

import React, { createContext, useContext } from 'react';
import { TranslationProvider, useTranslation } from '@gettranslated/react-native-sdk';

// Custom context for app-specific state
const AppContext = createContext<{
  theme: 'light' | 'dark';
  user: { id: string; name: string };
}>({ theme: 'light', user: { id: '', name: '' } });

// Combined provider
export function AppProvider({ children, apiKey }: { children: React.ReactNode; apiKey: string }) {
  const [theme, setTheme] = React.useState<'light' | 'dark'>('light');
  const [user, setUser] = React.useState<{ id: string; name: string }>({ id: '', name: '' });

  return (
    <AppContext.Provider value={{ theme, user }}>
      <TranslationProvider apiKey={apiKey}>
        {children}
      </TranslationProvider>
    </AppContext.Provider>
  );
}

// Custom hook that combines both contexts
export function useAppTranslations() {
  const translations = useTranslation();
  const appContext = useContext(AppContext);
  
  return {
    ...translations,
    theme: appContext.theme,
    user: appContext.user,
  };
}

Error Boundary with TranslationProvider

import React from 'react';
import { View, Text } from 'react-native';
import { TranslationProvider } from '@gettranslated/react-native-sdk';

class TranslationErrorBoundary extends React.Component<
  { children: React.ReactNode; fallback?: React.ReactNode },
  { hasError: boolean; error?: Error }
> {
  constructor(props: any) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error: Error) {
    return { hasError: true, error };
  }

  componentDidCatch(error: Error, errorInfo: any) {
    console.error('Translation Error Boundary caught an error:', error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback || (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
          <Text>Something went wrong with translations.</Text>
        </View>
      );
    }

    return this.props.children;
  }
}

// Usage
function App() {
  return (
    <TranslationErrorBoundary>
      <TranslationProvider apiKey="your-ck-api-key">
        <YourAppContent />
      </TranslationProvider>
    </TranslationErrorBoundary>
  );
}

withTranslations HOC

Higher-Order Component that provides translation functionality to class components. This is perfect for teams using class components or preferring the HOC pattern.

Basic Usage

import React from 'react';
import { View, Text, Button } from 'react-native';
import { withTranslations, TranslationProvider } from '@gettranslated/react-native-sdk';

// Define component with translation props
interface MyComponentProps {
  title: string;
  t: (key: string) => string;
}

class MyComponent extends React.Component<MyComponentProps> {
  render() {
    const { title, t } = this.props;
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Text style={{ fontSize: 24, marginBottom: 20 }}>
          {t('Welcome, !', { name: title })}
        </Text>
        <Text style={{ fontSize: 16, marginBottom: 20 }}>
          {t('This is a translated message')}
        </Text>
        <Button title={t('Click Me')} onPress={() => console.log('Button pressed')} />
      </View>
    );
  }
}

// Wrap with withTranslations HOC
export default withTranslations(MyComponent);

Complete Example

import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { withTranslations, TranslationProvider } from '@gettranslated/react-native-sdk';

// Define component props including translation functions
interface WelcomeScreenProps {
  userName: string;
  t: (key: string) => string;
}

class WelcomeScreen extends React.Component<WelcomeScreenProps> {
  render() {
    const { userName, t } = this.props;
    
    return (
      <View style={styles.container}>
        <Text style={styles.title}>
          {t('Welcome, !', { name: userName })}
        </Text>
        
        <Text style={styles.subtitle}>
          {t('We are glad to have you here')}
        </Text>
        
        <View style={styles.buttonContainer}>
          <TouchableOpacity style={styles.button} onPress={this.handleGetStarted}>
            <Text style={styles.buttonText}>
              {t('Get Started')}
            </Text>
          </TouchableOpacity>
          
          <TouchableOpacity style={styles.secondaryButton} onPress={this.handleLearnMore}>
            <Text style={styles.secondaryButtonText}>
              {t('Learn More')}
            </Text>
          </TouchableOpacity>
        </View>
      </View>
    );
  }

  private handleGetStarted = () => {
    console.log('Get Started pressed');
  };

  private handleLearnMore = () => {
    console.log('Learn More pressed');
  };
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
    backgroundColor: '#f5f5f5',
  },
  title: {
    fontSize: 28,
    fontWeight: 'bold',
    textAlign: 'center',
    marginBottom: 16,
    color: '#333',
  },
  subtitle: {
    fontSize: 16,
    textAlign: 'center',
    marginBottom: 32,
    color: '#666',
  },
  buttonContainer: {
    width: '100%',
    maxWidth: 300,
  },
  button: {
    backgroundColor: '#007AFF',
    paddingVertical: 12,
    paddingHorizontal: 24,
    borderRadius: 8,
    marginBottom: 12,
  },
  buttonText: {
    color: 'white',
    fontSize: 16,
    fontWeight: '600',
    textAlign: 'center',
  },
  secondaryButton: {
    backgroundColor: 'transparent',
    paddingVertical: 12,
    paddingHorizontal: 24,
    borderRadius: 8,
    borderWidth: 1,
    borderColor: '#007AFF',
  },
  secondaryButtonText: {
    color: '#007AFF',
    fontSize: 16,
    fontWeight: '600',
    textAlign: 'center',
  },
});

// Wrap with withTranslations HOC
export default withTranslations(WelcomeScreen);

// Use in your app
function App() {
  return (
    <TranslationProvider apiKey="your-ck-api-key">
      <WelcomeScreen userName="John" />
    </TranslationProvider>
  );
}

HOC Benefits

  • Class Component Support: Works seamlessly with React class components
  • react-i18next Compatible: Uses the same patterns as react-i18next
  • Synchronous Translations: No async/await needed for basic translations
  • Automatic Re-rendering: Components update automatically when language changes
  • TypeScript Support: Full type safety with proper prop interfaces

When to Use HOC

Choose withTranslations HOC when:
  • You're using class components
  • Your team prefers HOC patterns over hooks
  • You're migrating from react-i18next
  • You need synchronous translations without async complexity

Migration from react-i18next

The GetTranslated SDK is designed as a drop-in replacement for react-i18next. The t() function and most APIs work identically, requiring minimal code changes.

What Stays the Same

Most of your existing code doesn't need to change:

  • โœ… The t() function works identically
  • โœ… Interpolation syntax is the same: t('Hello, !', { name: 'John' })
  • โœ… Pluralization with structured objects: t('item_count', { count: 5 })
  • โœ… Component usage remains unchanged
  • โœ… Translation resource format is identical

What Changes

Only initialization and provider setup need to be updated:

Before (react-i18next)

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import enTranslations from './locales/en.json';
import esTranslations from './locales/es.json';

i18n
  .use(initReactI18next)
  .init({
    resources: {
      en: { translation: enTranslations },
      es: { translation: esTranslations },
    },
    lng: 'en',
    fallbackLng: 'en',
  });

// In your app
import { useTranslation } from 'react-i18next';

function MyComponent() {
  const { t } = useTranslation();
  return {t('Welcome')};
}

After (GetTranslated SDK)

import { TranslationProvider, useTranslation } from '@gettranslated/react-native-sdk';
import enTranslations from './locales/en.json';
import esTranslations from './locales/es.json';

const resources = {
  en: { translation: enTranslations },
  es: { translation: esTranslations },
};

// In your app root
export default function App() {
  return (
    <TranslationProvider apiKey="your-ck-api-key" resources={resources}>
      <MyComponent />
    </TranslationProvider>
  );
}

// In your components - NO CHANGES NEEDED!
function MyComponent() {
  const { t } = useTranslation(); // Same hook name, same API
  return <Text>{t('Welcome')}</Text>;
}
๐Ÿ’ก Key Point: Your component code using t() doesn't need to change at all! The function signature, interpolation, and pluralization all work exactly the same.

Step-by-Step Migration

Step 1: Install GetTranslated SDK

npm install @gettranslated/react-native-sdk
# Remove react-i18next if you're fully migrating
npm uninstall react-i18next i18next

Step 2: Update Imports

// โŒ Old
import { useTranslation } from 'react-i18next';

// โœ… New
import { useTranslation } from '@gettranslated/react-native-sdk';

Step 3: Replace i18n Initialization

// โŒ Old - Remove this
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';

i18n.use(initReactI18next).init({ /* config */ });

// โœ… New - Wrap your app with TranslationProvider
import { TranslationProvider } from '@gettranslated/react-native-sdk';

export default function App() {
  return (
    <TranslationProvider apiKey="your-ck-api-key" resources={resources}>
      <YourApp />
    </TranslationProvider>
  );
}

Step 4: Update Resource Loading

If you're using the GetTranslated CLI, your resources are already in the correct format. Just import and pass them to the provider:

// Load your translation resources (same format as before)
import enTranslations from './locales/en.json';
import esTranslations from './locales/es.json';
import frTranslations from './locales/fr.json';

const resources = {
  en: { translation: enTranslations },
  es: { translation: esTranslations },
  fr: { translation: frTranslations },
};

<TranslationProvider apiKey="your-ck-api-key" resources={resources}>
  <App />
</TranslationProvider>

Step 5: Update Language Changes

// โŒ Old
import { useTranslation } from 'react-i18next';
const { i18n } = useTranslation();
i18n.changeLanguage('es');

// โœ… New - Same API!
import { useTranslation } from '@gettranslated/react-native-sdk';
const { changeLanguage } = useTranslation();
await changeLanguage('es');

Component Migration Examples

Functional Components

// โŒ Before (react-i18next)
import { useTranslation } from 'react-i18next';

function WelcomeScreen() {
  const { t } = useTranslation();
  return (
    <View>
      <Text>{t('Welcome')}</Text>
      <Text>{t('Hello, !', { name: 'John' })}</Text>
    </View>
  );
}

// โœ… After (GetTranslated SDK) - NO CHANGES!
import { useTranslation } from '@gettranslated/react-native-sdk';

function WelcomeScreen() {
  const { t } = useTranslation(); // Same hook, same API
  return (
    <View>
      <Text>{t('Welcome')}</Text>
      <Text>{t('Hello, !', { name: 'John' })}</Text>
    </View>
  );
}

Class Components

// โŒ Before (react-i18next)
import { withTranslation } from 'react-i18next';

class WelcomeScreen extends React.Component {
  render() {
    const { t } = this.props;
    return <Text>{t('Welcome')}</Text>;
  }
}

export default withTranslation()(WelcomeScreen);

// โœ… After (GetTranslated SDK) - Minimal changes
import { withTranslations } from '@gettranslated/react-native-sdk';

class WelcomeScreen extends React.Component {
  render() {
    const { t } = this.props; // Same prop name
    return <Text>{t('Welcome')}</Text>;
  }
}

export default withTranslations(WelcomeScreen);

Advanced Features

Namespaces

If you were using namespaces in react-i18next, you can organize your resources similarly:

// Organize resources by namespace
const resources = {
  en: {
    translation: enCommon,
    errors: enErrors,
    validation: enValidation,
  },
  es: {
    translation: esCommon,
    errors: esErrors,
    validation: esValidation,
  },
};

// Use with namespace
const { t } = useTranslation();
<Text>{t('errors:not_found')}</Text>

Language Detection

GetTranslated SDK automatically detects the device language, but you can override it programmatically or via the dashboard:

// GetTranslated automatically detects device language
// But you can override it programmatically:
const { changeLanguage } = useTranslation();
await changeLanguage('es');

// Or set per-user overrides from your project's User Overrides settings
// in the GetTranslated dashboard

Benefits of Migration

  • โœ… AI-Powered Translations - Automatic translation of new strings
  • โœ… Dynamic Translations - Translate server-side messages on the fly
  • โœ… Unified Platform - Manage translations across all platforms in one place
  • โœ… CLI Integration - Sync translations automatically via CLI
  • โœ… Same API - Minimal code changes required

Migration Checklist

  • โ˜ Install @gettranslated/react-native-sdk
  • โ˜ Update imports from react-i18next to @gettranslated/react-native-sdk
  • โ˜ Replace i18n.init() with <TranslationProvider>
  • โ˜ Pass resources to TranslationProvider
  • โ˜ Update language change calls (add await if needed)
  • โ˜ Test all translations in your app
  • โ˜ Remove react-i18next and i18next dependencies
๐Ÿ’ก Need Help? If you encounter any issues during migration, check our Troubleshooting section or reach out to [email protected].

Troubleshooting

Common Issues

โŒ "useTranslation must be used within a TranslationProvider"

Solution: Wrap your component with TranslationProvider

// โŒ Wrong
function MyComponent() {
  const { getDynamicTranslation } = useTranslation(); // Error!
  return Hello;
}

// โœ… Correct
function App() {
  return (
    
      
    
  );
}

โŒ Translations not updating

Solution: Check initialization and language state

const { isInitialized, currentLanguage, getDynamicTranslation } = useTranslation();

useEffect(() => {
  const loadTranslation = async () => {
    if (isInitialized) { // โœ… Check initialization
      const translation = await getDynamicTranslation('Hello');
      setText(translation);
    }
  };
  loadTranslation();
}, [isInitialized, currentLanguage]); // โœ… Include dependencies

โŒ Cannot directly set currentLanguage

Problem: Trying to set currentLanguage directly

// โŒ Wrong - currentLanguage is read-only
currentLanguage = 'es'; // Error!

Solution: Use the changeLanguage function

// โœ… Correct - use the provided function
await changeLanguage('es');

โŒ iOS build fails

Solution: Run cd ios && pod install after installing the SDK

โŒ Android build fails

Solution: Clean and rebuild: npx react-native clean && npx react-native run-android

โŒ Debug logs not appearing

Problem: Setting logLevel={LogLevel.DEBUG} but not seeing debug messages

Solution: Debug logs use console.log instead of console.debug for better visibility:

// โœ… This will show debug logs
<TranslationProvider 
  apiKey="your-ck-api-key" 
  logLevel={LogLevel.DEBUG}
>
  <App />
</TranslationProvider>

If you still don't see logs:

  • Clear Metro cache: npx expo start --clear or npx react-native start --reset-cache
  • Check browser console settings: Ensure "Verbose" or "All" log levels are enabled
  • Verify log level: Make sure you're using LogLevel.DEBUG (not a string)
// โŒ Wrong - using string instead of enum
logLevel="DEBUG"

// โœ… Correct - using LogLevel enum
logLevel={LogLevel.DEBUG}

Debug Logging

Enable Debug Logging

Enable debug logging by setting the logLevel parameter to LogLevel.DEBUG:

import { LogLevel } from '@gettranslated/react-native-sdk';

// Enable debug logging in TranslationProvider
<TranslationProvider 
  apiKey="your-ck-api-key" 
  logLevel={LogLevel.DEBUG}
>
  <App />
</TranslationProvider>

// Or enable debug logging in static initialization
await GetTranslated.init('your-ck-api-key', undefined, LogLevel.DEBUG);

Debug Log Output

When debug logging is enabled, you'll see messages in the console like:

[2024-01-01T12:00:00.000Z | GetTranslated] DEBUG: Available languages: ["en", "es", "fr"]
[2024-01-01T12:00:00.000Z | GetTranslated] DEBUG: Selected default language: en
[2024-01-01T12:00:00.000Z | GetTranslated] INFO: GetTranslated: Starting initialization

Log Levels Available

  • LogLevel.ERROR (0) - Only error messages
  • LogLevel.WARN (1) - Warnings and errors (default)
  • LogLevel.INFO (2) - Info, warnings, and errors
  • LogLevel.DEBUG (3) - Debug, info, warnings, and errors
  • LogLevel.VERBOSE (4) - All log messages

Examples

Complete App Example

Here's a complete React Native app using the GetTranslated SDK:

import React, { useState, useEffect } from 'react';
import {
  View,
  Text,
  TouchableOpacity,
  StyleSheet,
  Alert,
  ActivityIndicator
} from 'react-native';
import { TranslationProvider, useTranslation } from '@gettranslated/react-native-sdk';

// Main App Component
function App() {
  return (
    <TranslationProvider
      apiKey="your-ck-api-key"
      onError={(error) => Alert.alert('Translation Error', error.message)}
    >
    <MainScreen />
      </TranslationProvider>
  );
}

// Main Screen Component
function MainScreen() {
  const {
    getDynamicTranslation,
    currentLanguage,
    changeLanguage,
    availableLanguages,
    isInitialized,
    login,
    logout
  } = useTranslations();

  const [translatedText, setTranslatedText] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const [isAuthenticated, setIsAuthenticated] = useState(false);

  // Load translations when component mounts or language changes
  useEffect(() => {
    const loadTranslations = async () => {
      if (isInitialized) {
        setIsLoading(true);
        try {
          const welcome = await getDynamicTranslation('Welcome to our app!');
          const description = await getDynamicTranslation('This is a sample translation app.');
          setTranslatedText(`{welcome}\n\n{description}`);
        } catch (error) {
          console.error('Failed to load translations:', error);
        } finally {
          setIsLoading(false);
        }
      }
    };

    loadTranslations();
  }, [isInitialized, currentLanguage]);

  const handleLanguageChange = async (languageCode: string) => {
    try {
      await changeLanguage(languageCode);
    } catch (error) {
      Alert.alert('Error', 'Failed to change language');
    }
  };

  const handleLogin = async () => {
    try {
      await login('user-123');
      setIsAuthenticated(true);
      Alert.alert('Success', 'Logged in successfully!');
    } catch (error) {
      Alert.alert('Error', 'Login failed');
    }
  };

  const handleLogout = async () => {
    try {
      await logout();
      setIsAuthenticated(false);
      Alert.alert('Success', 'Logged out successfully!');
    } catch (error) {
      Alert.alert('Error', 'Logout failed');
    }
  };

  if (!isInitialized) {
    return (
      <View style={styles.centerContainer}>
        <ActivityIndicator size="large" />
        <Text style={styles.loadingText}>Initializing translations...</Text>
      </View>
    );
  }

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Translation App</Text>
      
      <View style={styles.content}>
        <Text style={styles.translatedText}>
          {isLoading ? 'Loading...' : translatedText}
        </Text>
        
        <Text style={styles.languageInfo}>
          Current Language: {currentLanguage}
        </Text>
      </View>

      <View style={styles.languageSection}>
        <Text style={styles.sectionTitle}>Available Languages:</Text>
        <View style={styles.languageButtons}>
          {availableLanguages.map((language) => (
            <TouchableOpacity
              key={language.code}
              style={[
                styles.languageButton,
                currentLanguage === language.code && styles.activeLanguageButton
              ]}
              onPress={() => handleLanguageChange(language.code)}
            >
              <Text style={styles.languageButtonText}>
                {language.name}
              </Text>
            </TouchableOpacity>
          ))}
        </View>
      </View>

      <View style={styles.authSection}>
        {!isAuthenticated ? (
          <TouchableOpacity style={styles.loginButton} onPress={handleLogin}>
            <Text style={styles.loginButtonText}>Login as User</Text>
          </TouchableOpacity>
        ) : (
          <View style={styles.authenticatedContainer}>
            <Text style={styles.authenticatedText}>โœ“ Authenticated</Text>
            <TouchableOpacity style={styles.logoutButton} onPress={handleLogout}>
              <Text style={styles.logoutButtonText}>Logout</Text>
            </TouchableOpacity>
          </View>
        )}
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: '#f5f5f5',
  },
  centerContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  title: {
    fontSize: 28,
    fontWeight: 'bold',
    textAlign: 'center',
    marginBottom: 30,
    color: '#333',
  },
  content: {
    flex: 1,
    justifyContent: 'center',
  },
  translatedText: {
    fontSize: 18,
    textAlign: 'center',
    marginBottom: 20,
    lineHeight: 24,
    color: '#555',
  },
  languageInfo: {
    fontSize: 16,
    textAlign: 'center',
    color: '#666',
    marginBottom: 30,
  },
  languageSection: {
    marginBottom: 30,
  },
  sectionTitle: {
    fontSize: 18,
    fontWeight: '600',
    marginBottom: 15,
    color: '#333',
  },
  languageButtons: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    justifyContent: 'center',
  },
  languageButton: {
    paddingHorizontal: 16,
    paddingVertical: 8,
    margin: 5,
    backgroundColor: '#e0e0e0',
    borderRadius: 20,
  },
  activeLanguageButton: {
    backgroundColor: '#007AFF',
  },
  languageButtonText: {
    fontSize: 14,
    color: '#333',
    fontWeight: '500',
  },
  authSection: {
    alignItems: 'center',
  },
  loginButton: {
    backgroundColor: '#007AFF',
    paddingHorizontal: 20,
    paddingVertical: 12,
    borderRadius: 8,
  },
  loginButtonText: {
    color: 'white',
    fontSize: 16,
    fontWeight: '600',
  },
  authenticatedContainer: {
    alignItems: 'center',
  },
  logoutButton: {
    backgroundColor: '#FF3B30',
    paddingHorizontal: 20,
    paddingVertical: 12,
    borderRadius: 8,
    marginTop: 10,
  },
  logoutButtonText: {
    color: 'white',
    fontSize: 16,
    fontWeight: '600',
  },
  authenticatedText: {
    color: '#4CAF50',
    fontSize: 16,
    fontWeight: '600',
  },
  loadingText: {
    marginTop: 10,
    fontSize: 16,
    color: '#666',
  },
});

export default App;

Need Help?