Skip to content

A lightweight, professional localization package for React and React Native applications built on top of i18next and react-i18next. This package provides a clean, type-safe API for managing translations with built-in language switching, variable injection, and component interpolation capabilities.

Notifications You must be signed in to change notification settings

weprodev/ui-localization

Repository files navigation

@weprodev/ui-localization

A lightweight, professional localization package for React and React Native applications built on top of i18next and react-i18next. This package provides a clean, type-safe API for managing translations with built-in language switching, variable injection, and component interpolation capabilities.

✨ Features

  • 🌐 Simple React Hooks - Clean, intuitive hooks for translations and language management
  • πŸ”„ Language Switching - Built-in language switching with persistence
  • πŸ“ Variable Injection - Dynamic content insertion in translations
  • 🧩 Component Interpolation - Embed React components within translations
  • πŸ” Translation Validation - CLI tools to ensure translation consistency
  • πŸ”„ Translation Sync - Automated synchronization of translation files
  • πŸ“± React Native Support - Full compatibility with React Native applications
  • πŸ›‘οΈ Type Safety - Full TypeScript support with comprehensive type definitions
  • ⚑ Performance Optimized - Lightweight wrapper with minimal overhead

πŸ“¦ Installation

npm install @weprodev/ui-localization

πŸš€ Quick Start

React Applications

1. Create Translation Files

Create a translations directory in your project with language files:

// translations/en.ts
const en = {
  common: {
    hello: "Hello",
    welcome: "Welcome to our app",
    goodbye: "Goodbye"
  },
  auth: {
    login: "Login",
    signup: "Sign Up",
    forgotPassword: "Forgot Password"
  },
  dashboard: {
    title: "Dashboard",
    summary: "Summary",
    recentActivity: "Recent Activity"
  }
};

export default en;
// translations/es.ts
const es = {
  common: {
    hello: "Hola",
    welcome: "Bienvenido a nuestra aplicaciΓ³n",
    goodbye: "AdiΓ³s"
  },
  auth: {
    login: "Iniciar sesiΓ³n",
    signup: "Registrarse",
    forgotPassword: "ContraseΓ±a olvidada"
  },
  dashboard: {
    title: "Panel de control",
    summary: "Resumen",
    recentActivity: "Actividad reciente"
  }
};

export default es;

2. Create Localization Configuration

// src/localizationConfig.ts
import { LocalizationConfig, LanguageStore } from '@weprodev/ui-localization';
import en from '../translations/en';
import es from '../translations/es';

// Optional: Create a custom language store for persistence
class CustomLanguageStore implements LanguageStore {
  getLanguage(): string | null {
    return localStorage.getItem("app-language") || null;
  }

  setLanguage(language: string): void {
    localStorage.setItem("app-language", language);
  }
}

export const localizationConfig: LocalizationConfig = {
  resources: {
    en: { translation: en },
    es: { translation: es }
  },
  fallbackLng: 'en',
  languageStore: new CustomLanguageStore()
};

3. Initialize Localization

// src/index.tsx
import React, { StrictMode } from 'react';
import ReactDOM from 'react-dom/client';
import { initLocalization } from '@weprodev/ui-localization';
import { localizationConfig } from './localizationConfig';
import App from './App';

const rootElement = document.getElementById('root');

// Initialize localization before rendering the app
initLocalization(localizationConfig).then(() => {
  ReactDOM.createRoot(rootElement).render(
    <StrictMode>
      <App />
    </StrictMode>
  );
});

4. Use Translations in Components

// src/components/Welcome.tsx
import React from 'react';
import { useTranslation } from '@weprodev/ui-localization';
import en from '../translations/en';

const Welcome: React.FC = () => {
  // Type-safe translation hook with intellisense
  const t = useTranslation<typeof en>(en);
  
  return (
    <div>
      <h1>{t.common.welcome}</h1>
      <p>{t.common.hello}</p>
    </div>
  );
};

export default Welcome;

Alternative: Create a custom hook for better reusability

// src/hooks/useAppTranslation.ts
import { useTranslation } from '@weprodev/ui-localization';
import en from '../translations/en';

export const useAppTranslation = () => {
  return useTranslation<typeof en>(en);
};

// Usage in components
import { useAppTranslation } from '../hooks/useAppTranslation';

const Welcome: React.FC = () => {
  const t = useAppTranslation();
  
  return (
    <div>
      <h1>{t.common.welcome}</h1> {/* Full intellisense support */}
      <p>{t.common.hello}</p>
    </div>
  );
};

Troubleshooting: If you encounter TypeScript errors with the type-safe hook, you can use useTranslationFallback() as an escape hatch. See the API Reference for details.

5. Language Switching

// src/components/LanguageSwitcher.tsx
import React from 'react';
import { useLanguage } from '@weprodev/ui-localization';

const LanguageSwitcher: React.FC = () => {
  const { currentLanguage, changeLanguage, availableLanguages } = useLanguage();
  
  return (
    <select 
      value={currentLanguage} 
      onChange={(e) => changeLanguage(e.target.value)}
    >
      {availableLanguages.map(lang => (
        <option key={lang} value={lang}>
          {lang.toUpperCase()}
        </option>
      ))}
    </select>
  );
};

export default LanguageSwitcher;

React Native Applications

1. Create Translation Files

Same structure as React applications (see above).

2. Create Localization Configuration

// src/localizationConfig.ts
import { LocalizationConfig, LanguageStore } from '@weprodev/ui-localization';
import AsyncStorage from '@react-native-async-storage/async-storage';
import en from '../translations/en';
import es from '../translations/es';

// React Native language store using AsyncStorage
class ReactNativeLanguageStore implements LanguageStore {
  async getLanguage(): Promise<string | null> {
    try {
      return await AsyncStorage.getItem("app-language");
    } catch {
      return null;
    }
  }

  async setLanguage(language: string): Promise<void> {
    try {
      await AsyncStorage.setItem("app-language", language);
    } catch {
      // Handle storage error silently
    }
  }
}

export const localizationConfig: LocalizationConfig = {
  resources: {
    en: { translation: en },
    es: { translation: es }
  },
  fallbackLng: 'en',
  languageStore: new ReactNativeLanguageStore()
};

3. Initialize Localization

// src/App.tsx
import React, { useEffect, useState } from 'react';
import { View, Text } from 'react-native';
import { initLocalization } from '@weprodev/ui-localization';
import { localizationConfig } from './localizationConfig';

const App: React.FC = () => {
  const [isInitialized, setIsInitialized] = useState(false);

  useEffect(() => {
    initLocalization(localizationConfig).then(() => {
      setIsInitialized(true);
    });
  }, []);

  if (!isInitialized) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Text>Loading...</Text>
      </View>
    );
  }

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      {/* Your app content */}
    </View>
  );
};

export default App;

4. Use Translations in React Native Components

// src/components/Welcome.tsx
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { useTranslation } from '@weprodev/ui-localization';
import en from '../translations/en';

const Welcome: React.FC = () => {
  // Type-safe translation hook with intellisense
  const t = useTranslation<typeof en>(en);
  
  return (
    <View style={styles.container}>
      <Text style={styles.title}>{t.common.welcome}</Text>
      <Text style={styles.subtitle}>{t.common.hello}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 10,
  },
  subtitle: {
    fontSize: 16,
    color: '#666',
  },
});

export default Welcome;

5. Language Switching in React Native

// src/components/LanguageSwitcher.tsx
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { useLanguage } from '@weprodev/ui-localization';

const LanguageSwitcher: React.FC = () => {
  const { currentLanguage, changeLanguage, availableLanguages } = useLanguage();
  
  return (
    <View style={styles.container}>
      <Text style={styles.label}>Language:</Text>
      <View style={styles.buttonContainer}>
        {availableLanguages.map(lang => (
          <TouchableOpacity
            key={lang}
            style={[
              styles.button,
              currentLanguage === lang && styles.activeButton
            ]}
            onPress={() => changeLanguage(lang)}
          >
            <Text style={[
              styles.buttonText,
              currentLanguage === lang && styles.activeButtonText
            ]}>
              {lang.toUpperCase()}
            </Text>
          </TouchableOpacity>
        ))}
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    padding: 20,
  },
  label: {
    fontSize: 16,
    fontWeight: 'bold',
    marginBottom: 10,
  },
  buttonContainer: {
    flexDirection: 'row',
    gap: 10,
  },
  button: {
    paddingHorizontal: 16,
    paddingVertical: 8,
    borderRadius: 4,
    borderWidth: 1,
    borderColor: '#ddd',
  },
  activeButton: {
    backgroundColor: '#007AFF',
    borderColor: '#007AFF',
  },
  buttonText: {
    fontSize: 14,
    color: '#333',
  },
  activeButtonText: {
    color: '#fff',
  },
});

export default LanguageSwitcher;

πŸ”§ Advanced Usage

Translation with Variables

import { useTranslation, useTranslationInjection } from '@weprodev/ui-localization';
import en from '../translations/en';

const Greeting: React.FC<{ name: string }> = ({ name }) => {
  const t = useTranslation<typeof en>(en);
  
  // Translation key: "greeting": "Hello, {{name}}!"
  const greeting = useTranslationInjection(t.common.greeting, { name });
  
  return <p>{greeting}</p>;
};

Translation with Components

import { useTranslation, useTranslationWithInterpolation } from '@weprodev/ui-localization';
import en from '../translations/en';

const TermsAgreement: React.FC<{ name: string }> = ({ name }) => {
  const t = useTranslation<typeof en>(en);
  
  // Translation key: "welcome": "Welcome <strong>{{name}}</strong>"
  const welcomeElement = useTranslationWithInterpolation(
    t.common.welcome, 
    { name }, 
    {
      strong: <strong style={{ color: "red" }} />
    }
  );
  
  return <div>{welcomeElement}</div>;
};

πŸ› οΈ Translation Management Tools

The package includes powerful CLI tools to help manage your translations. You can use these tools in multiple ways:

Option 1: Using NPM Scripts (Recommended)

Add these commands to your project's package.json scripts:

{
  "scripts": {
    "translation:validate": "wpd-translation-validate --dir ./translations --source en",
    "translation:sync": "wpd-translation-sync --dir ./translations --source en"
  }
}

Then run:

npm run translation:validate
npm run translation:sync

Customizing paths:

Modify the scripts in your package.json to use different directories or source language:

{
  "scripts": {
    "translation:validate": "wpd-translation-validate --dir ./src/translations --source es",
    "translation:sync": "wpd-translation-sync --dir ./src/translations --source es"
  }
}

Option 2: Using npx (Direct CLI)

Run the CLI tools directly via npx:

# Validate translations
npx wpd-translation-validate --dir ./translations --source en

# Sync translations
npx wpd-translation-sync --dir ./translations --source en

What These Tools Do

Validate Translations (validate-translations)

  • Checks if all language files have the same keys as the source language
  • Reports missing keys for each language file
  • Exits with error code if inconsistencies are found
  • Perfect for CI/CD integration

Sync Translations (sync-translations)

  • Adds missing keys from the source language to all other language files
  • Preserves existing translations
  • Sets empty string values for new keys (ready for translation)
  • Updates translation files automatically

CI/CD Integration

We recommend running translation:validate as part of your CI pipeline to ensure translation consistency:

# .github/workflows/ci.yml
- name: Validate Translations
  run: npm run translation:validate

πŸ“š API Reference

Hooks

useTranslation<T>(translationLanguage: object)

Returns a type-safe translation proxy object with intellisense support.

Parameters:

  • translationLanguage: The translation object to provide type safety for

Returns: Type-safe translation proxy object

import en from '../translations/en';

const t = useTranslation<typeof en>(en);
const translatedText = t.common.hello; // Type-safe with intellisense

Note: For better reusability, consider creating a custom hook:

// src/hooks/useAppTranslation.ts
import { useTranslation } from '@weprodev/ui-localization';
import en from '../translations/en';

export const useAppTranslation = () => {
  return useTranslation<typeof en>(en);
};

useLanguage()

Provides language management functionality.

const { currentLanguage, changeLanguage, availableLanguages } = useLanguage();

useTranslationFallback()

⚠️ Escape hatch hook - use only when the main useTranslation hook has TypeScript issues.

Returns the raw i18next translation function without type safety. This should only be used in rare edge cases where the type-safe hook encounters problems.

// Only use when useTranslation has TypeScript errors
const t = useTranslationFallback();
const text = t('common.hello'); // No type safety - standard i18next usage
const withVars = t('greeting', { name: 'John' });

Note: The main useTranslation hook should be preferred in 99% of cases.

useTranslationInjection(key, variables)

Injects variables into translation strings.

const result = useTranslationInjection('greeting', { name: 'John' });

useTranslationWithInterpolation(key, variables, components)

Interpolates React components into translations.

const element = useTranslationWithInterpolation(
  'welcome', 
  { name: 'John' }, 
  { strong: <strong /> }
);

Core Functions

initLocalization(config)

Initializes the localization system.

await initLocalization({
  resources: { en: { translation: enTranslations } },
  fallbackLng: 'en',
  languageStore: new CustomLanguageStore()
});

Types

LanguageStore

Interface for custom language storage implementations.

interface LanguageStore {
  getLanguage(): string | null;
  setLanguage(language: string): void;
}

LocalizationConfig

Configuration object for localization initialization.

interface LocalizationConfig {
  resources: Resource;
  fallbackLng?: string;
  compatibilityJSON?: "v4";
  interpolation?: {
    escapeValue?: boolean;
  };
  languageStore?: LanguageStore;
}

πŸ†˜ Support

For support, bug reports, or feature requests, please contact the WeProDev team or create an issue in our internal repository.

πŸ“„ License

This project is licensed under the MIT License.

πŸ”— Links


@weprodev/ui-localization - Professional localization solution by WeProDev

About

A lightweight, professional localization package for React and React Native applications built on top of i18next and react-i18next. This package provides a clean, type-safe API for managing translations with built-in language switching, variable injection, and component interpolation capabilities.

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •