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
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.
| Feature | LTR (English) | RTL (Arabic) |
|---|---|---|
| <html dir> | ltr | rtl |
| <html lang> | en | ar |
| <body class> | font-english | font-arabic |
| Text alignment | text-left | text-right |
| Sidebar position | Left | Right |
| Icon direction | → | ← |
| Number format | 1,234.56 | ١٬٢٣٤٫٥٦ |
Adding New Translation Keys
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. Register with useModuleLocales
In your view component, call useModuleLocales(() => import('../../../locales'), 'module-name') before useI18n() to lazy-load the module's translations.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.