iSpeaker Live iSpeaker Live / Docs
Internationalization

🌐 Localization (AR / EN)

How iSpeaker Live delivers a true Arabic-first experience without compromising the English version.

Overview

iSpeaker Live ships in two languages from day one:

🇸🇦 Arabic — العربية

Default language, right-to-left, primary target audience. All UI text, emails, push notifications, and PDF invoices localised. Stored as locale code ar.

🇬🇧 English

Left-to-right alternative, full parity with Arabic. Useful for non-Arabic-speaking speakers and the diaspora. Locale code en.

🌐

Locale parity rule: if a string exists in one language, it must exist in the other. CI checks for missing keys per build.

Strategy

  • Default to user profile: the user's preferred language is stored in user_profiles.language (ar by default).
  • Override per request: mobile and web can send Accept-Language or a ?lang= parameter; the backend's localization middleware switches the application locale accordingly.
  • Persistence: the chosen language is stored locally (cookie on web, secure storage on Flutter) so the experience is consistent on next launch.
  • Notifications & emails use the recipient's stored language, not the sender's.
  • Server-rendered content (invoice PDFs, transactional emails) renders in the user's locale.

RTL Handling

What flips in RTL

Page direction

<html dir="rtl"> on Arabic. All blocks flow right-to-left.

Layout

Sidebar moves to the right; back arrows flip; chevrons point left-to-right (←) instead of right-to-left.

Margins / padding

Use logical properties (margin-inline-start) or duplicate styles per direction selector.

Lists & indentation

Bullets & numbers appear on the right.

Text alignment

Default to start; manually right-align Arabic content blocks where intentional.

Form fields

Labels right-aligned; icons inside inputs flip side.

What does NOT flip in RTL

  • Numbers — always LTR (e.g. price 120.50 ر.س).
  • Code & technical strings — URLs, file paths, slugs.
  • Brand logo — stays as-is.
  • Progress bars — fill direction stays meaningful (left-to-right for English, right-to-left for Arabic when the metaphor matches).
  • Media players — playback controls stay LTR-style to match Western media conventions users are familiar with.
⚠️

Test every screen in both directions. Mixed content (Arabic with embedded English / numbers) is where bugs hide — use the Unicode direction marks if needed.

Backend (Laravel 11)

Lang files

Located at lang/ar/*.php and lang/en/*.php. Current files:

  • auth.php — login & throttle messages.
  • validation.php — Laravel validator messages.
  • passwords.php — password reset.
  • pagination.php — next / previous labels.
  • wallet.php — invoice headers, currency symbol, VAT label.

Middleware

A custom localization middleware (applied to all API groups) sets app()->setLocale($lang) from:

  1. X-Lang request header (highest priority).
  2. Authenticated user's user_profiles.language.
  3. Default ar.
// Sample translated response
return response()->json([
    'message' => __('wallet.transaction_completed'),
    'amount'  => 120.50,
    'currency'=> __('wallet.currency'),
]);

Sample Arabic wallet strings

KeyEnglishArabic
invoiceInvoiceفاتورة
invoice_numberInvoice Numberرقم الفاتورة
bill_toBill Toفاتورة إلى
subtotalSubtotalالمجموع الفرعي
vatVATضريبة القيمة المضافة
grand_totalGrand Totalالمجموع الكلي
currencySARر.س

Web (Next.js 15)

  • Locale state managed via React context + persisted to cookie / localStorage.
  • The root layout sets <html lang dir> based on context.
  • All UI strings live in dictionary maps; no inline literals in components.
  • API requests carry X-Lang header so server-side validation and notifications also localise.
  • Tailwind rtl: variants used selectively; logical CSS properties preferred globally.
  • Date/time/number formatting via Intl (e.g. Intl.DateTimeFormat('ar-SA')).

Mobile (Flutter)

Implementation lives in lib/core/localization/:

  • app_localizations.dartAppLocalizations class with translate(key).
  • app_localizations_delegate.dart — registered LocalizationsDelegate supporting en and ar.
  • languages/ar.dart & languages/en.dart — flat Map<String, String> of keys.
// Usage
final t = AppLocalizations.of(context);
Text(t.translate('login.welcome_back'));
  • App-level locale persisted via secure storage.
  • MaterialApp.locale rebuilt on change; the directionality follows automatically.
  • Text style uses Tajawal for Arabic, Inter for English (selected per locale in theme).

Localized Data

Some content needs to exist in both languages in the database:

Table.fieldStrategy
categories.name_en / categories.name_arTwin columns. API serves the field matching current locale.
courses.languageEnum ar / en — declares the course's content language (not the UI).
user_profiles.languagePer-user UI preference.
user_profiles.timezoneDefault Asia/Riyadh.
User-generated content (posts, reviews, etc.)Stored as written. We don't auto-translate — users see content in the author's language.
ℹ️

Course / book marketplace filters offer a language filter so students can show only content in their preferred language.

Formatting

DataArabic exampleEnglish example
Numbers1,234.56 (Arabic-Indic digits optional)1,234.56
Currency120.50 ر.سSAR 120.50
Date13 يناير 2026Jan 13, 2026
Time02:30 م2:30 PM
Relative timeمنذ 5 دقائق5 minutes ago
Phone‎+966 5X XXX XXXX+966 5X XXX XXXX
Addressالرياض، السعوديةRiyadh, Saudi Arabia

Time zones

  • Default: Asia/Riyadh (UTC+3).
  • Live rooms and consultations show the speaker's tz and the viewer's local tz.
  • All timestamps stored in UTC; conversion happens at the edges.

Translation Workflow

  1. Developer adds a new key to lang/en/<file>.php + languages/en.dart + the web dictionary.
  2. CI fails if a key exists in one locale and not the other.
  3. Translator (or AI assist + human review) fills in the Arabic value.
  4. PR review checks for tone, length (Arabic ~20% longer typically), and gender-neutral phrasing where applicable.
  5. Merged → deployed → tested visually in both directions.

Tone & voice

  • Arabic: formal MSA, polite, gender-neutral when possible.
  • English: clear and friendly, sentence case for buttons, title case for headings.
  • Avoid idioms that don't translate. Avoid country-specific slang.

Localization QA

See dedicated test cases in Test Cases. Quick checklist:

  • ☐ Switch language from settings — UI updates immediately without restart.
  • ☐ Every page passes visual review in both ar and en.
  • ☐ Arabic text uses Tajawal font and renders crisply.
  • ☐ Numbers, prices, and phone numbers stay LTR in Arabic context.
  • ☐ Dates and times match the selected locale.
  • ☐ Toasts, dialogs, and validation errors are translated.
  • ☐ Invoice PDF and emails render in the recipient's language.
  • ☐ FCM push notifications are in the user's language.
  • ☐ Right-side icons flip in RTL (back arrow, chevrons).
  • ☐ Mixed Arabic + English strings (e.g. brand names) render with correct bidi.
  • ☐ Long Arabic strings don't overflow buttons or table cells.
  • ☐ No untranslated keys leaking as foo.bar.baz in the UI.