React Native SDK - Complete Integration Guide
Comprehensive guide for integrating GetTranslated.AI into your React Native applications
Table of Contents
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:
- Static Methods - Direct SDK access for simple use cases
- TranslationProvider - Context-based management for React applications
- 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 storagei18next- Core internationalization libraryintl-pluralrules- For pluralization supportreact-i18next- React integration for i18next
Note: Language detection uses React Native's built-in getLocales() API, so no additional language detection library is required.
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 keyuserId- Optional user ID for authenticated users (if not provided, creates anonymous user)logLevel- Optional log level for debugging (LogLevel enum). Defaults to LogLevel.WARNresources- Optional translation resources for bundled translations (required for synchronoust()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 resourcesoptions- Optional interpolation options (variables, count, etc.)
Returns: string - Translated text (synchronous, no async/await needed)
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');
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>;
}
- Always include
other: Theotherkey 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
oneandother - Russian: Uses
one,few,many, andother - Arabic: Uses
zero,one,two,few,many, andother
- English: Uses
- 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.
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
- Default namespace: The
translationnamespace 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 inerrors. - Consistency: Ensure all languages have the same namespaces. If you have
currenciesfor 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:submitanderrors:submitare 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:
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>
- 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
- 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>;
}
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-i18nextto@gettranslated/react-native-sdk - โ Replace
i18n.init()with<TranslationProvider> - โ Pass resources to
TranslationProvider - โ Update language change calls (add
awaitif needed) - โ Test all translations in your app
- โ Remove
react-i18nextandi18nextdependencies
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 --clearornpx 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 messagesLogLevel.WARN(1) - Warnings and errors (default)LogLevel.INFO(2) - Info, warnings, and errorsLogLevel.DEBUG(3) - Debug, info, warnings, and errorsLogLevel.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;
Next Steps
Need Help?
๐ง Email: [email protected]
๐ Docs: Full Documentation