Localization (i18n)

LanguageProvider, module-scoped locales, useModuleLocales hook, t() function, RTL support, and adding new translation keys.

SCRIPE uses a module-scoped localization system. Shared keys (~1,156) live in core/locales/. Each module owns its translations in a co-located locales/ directory, loaded lazily via the useModuleLocales() hook. Supports Arabic (RTL) and English (LTR) with automatic direction switching, font changes, and localStorage persistence.

Architecture

Localization Architecture
LanguageProvider — React Context + localStorage
Language() Hook — language, direction, t()
en.ts Dictionary
ar.ts Dictionary
<html> Element — dir, lang attributes
<body> Element — font-class

Dictionary Structure

src/core/locales/en.ts — SampleTypeScript
export const en = {
  common: {
    loading: "Loading...",
    save: "Save",
    cancel: "Cancel",
    delete: "Delete",
    edit: "Edit",
    create: "Create",
    search: "Search",
    noData: "No data available",
    confirm: "Confirm",
    back: "Back",
  },
  auth: {
    login: "Login",
    logout: "Logout",
    email: "Email",
    password: "Password",
    forgotPassword: "Forgot Password?",
    register: "Register",
  },
  admins: {
    title: "Admin Management",
    create: "Create Admin",
    searchPlaceholder: "Search by name or email...",
    form: {
      firstName: "First Name",
      lastName: "Last Name",
      email: "Email Address",
      role: "Role",
    },
  },
  errors: {
    required: "This field is required",
    minLength: "Must be at least {{min}} characters",
    invalidEmail: "Invalid email address",
    serverError: "An error occurred. Please try again.",
  },
};

Using the t() Function

t() Function — Usage ExamplesTypeScript
import { Language } from '@core/providers/LanguageProvider';

/**
 * Presentation UI component rendering the admin form.
 * Arranges layout boundaries and accessibility targets (WCAG, tab index) using the core design library (@core/ui/*). Coordinates text fields, submit indicators, and validation warning messages.
 */
export function AdminForm() {
  const { t, language, direction } = Language();

  // Simple key access (dot notation)
  const title = t('admins.title');            // "Admin Management"

  // Nested key access
  const label = t('admins.form.firstName');   // "First Name"

  // With variable interpolation
  const error = t('errors.minLength', { min: '8' });
  // → "Must be at least 8 characters"

  // RTL-aware layout
  const align = direction === 'rtl' ? 'text-right' : 'text-left';

  // Language-specific logic
  const dateLocale = language === 'ar' ? 'ar-EG' : 'en-GB';

  return (
    <form dir={direction}>
      <label className={align}>{label}</label>
      <input placeholder={t('common.search')} />
    </form>
  );
}

RTL/LTR Support

When the language switches to Arabic, the system automatically sets dir='rtl' and lang='ar' on the HTML element, adds the font-arabic CSS class to the body, and updates the CSS direction for all layout components.

FeatureLTR (English)RTL (Arabic)
<html dir>ltrrtl
<html lang>enar
<body class>font-englishfont-arabic
Text alignmenttext-lefttext-right
Sidebar positionLeftRight
Icon direction→←
Number format1,234.56١٬٢٣٤٫٥٦

Adding New Translation Keys

  1. 1. Create or Update Module Locale

    Add new keys to your module's locales/{module}.en.ts and {module}.ar.ts files. Only add to core/locales/ if the key is truly shared (validation, navigation, common UI).
  2. 2. Register with useModuleLocales

    In your view component, call useModuleLocales(() => import('../../../locales'), 'module-name') before useI18n() to lazy-load the module's translations.
  3. 3. Use t() with Module Namespace

    Call t('moduleName.keyPath') using the namespace from your locale file. For interpolation, use {{variable}} syntax and pass variables as the second argument.