i99dash docs
Recipes

Locale-aware rendering

Read the host's locale, flip RTL, render translations, react to mid-session locale changes. ~5 minutes.

The i99dash host runs in en or ar. Arabic flips the page direction to RTL — and gets it wrong if you forget. This recipe is the smallest correct version: read the locale, set lang + dir, render the right strings, refresh on change.

Step 1 — read locale once on mount

import { MiniAppClient } from '@i99dash/sdk';

const client = MiniAppClient.fromWindow();
const ctx = await client.getContext();

document.documentElement.lang = ctx.locale;
document.documentElement.dir = ctx.locale === 'ar' ? 'rtl' : 'ltr';

Setting lang and dir on <html> cascades:

  • CSS [dir="rtl"] selectors flip layout.
  • Logical properties (margin-inline-start, padding-inline-end) resolve correctly.
  • <input> text alignment matches the language without any code.

Step 2 — translation table

const STRINGS = {
  en: {
    title: 'Fuel near you',
    loading: 'Loading…',
    empty: 'No stations.',
    retry: 'Retry',
  },
  ar: {
    title: 'الوقود قريب منك',
    loading: 'جارٍ التحميل…',
    empty: 'لا توجد محطات.',
    retry: 'إعادة المحاولة',
  },
} as const;

type Locale = keyof typeof STRINGS;

export function t(locale: Locale, key: keyof typeof STRINGS.en): string {
  return STRINGS[locale][key] ?? STRINGS.en[key];
}

Why a flat table not i18next / react-intl for this size: bundles ship to constrained head-units. A 50-key flat table is < 1 KB; a proper i18n library is 30–200 KB. Use the library only when you have hundreds of strings and pluralisation rules.

Step 3 — react to mid-session locale changes

Currently, getContext() is the only way to read locale, and the host doesn't push an event when the user changes it system-wide. The next launch picks up the new value.

For dev-mode iteration: the dev-server's control panel (http://127.0.0.1:5173/_sdk/ui) lets you flip locale live. Your code re-reads getContext() on the next call, so a refresh shows the updated language.

async function refreshLocale() {
  const ctx = await client.getContext();
  document.documentElement.lang = ctx.locale;
  document.documentElement.dir = ctx.locale === 'ar' ? 'rtl' : 'ltr';
  rerender(ctx.locale);
}

// Re-read on every visibility change (cheap; one bridge call)
document.addEventListener('visibilitychange', () => {
  if (!document.hidden) void refreshLocale();
});

Step 4 — RTL-friendly CSS

Logical properties make almost everything flip automatically:

.station {
  /* ❌ Will not flip in RTL */
  /* margin-left: 12px; padding-right: 8px; text-align: left; */

  /* ✅ Flips in RTL */
  margin-inline-start: 12px;
  padding-inline-end: 8px;
  text-align: start;
}

Use direction-aware utilities for icons and arrows:

.chevron {
  /* ❌ Always points right */
  /* transform: rotate(0); */

  /* ✅ Points "forward" in both languages */
  transform: rotate(0);
}
[dir="rtl"] .chevron { transform: rotate(180deg); }

Or with logical properties:

.chevron::after {
  content: "›";  /* unicode handles direction in fonts that support it */
}

Tailwind shortcut: ltr: / rtl: variants for things logical properties can't express:

<button class="ltr:rounded-l-md rtl:rounded-r-md">Continue</button>

Step 5 — number, date, currency

Always use the platform Intl APIs with the locale you read from getContext(). They handle digit shaping (Latin vs Arabic-Indic), decimal separator (. vs ٫), and direction:

const fmt = new Intl.NumberFormat(ctx.locale, {
  style: 'currency',
  currency: 'SAR',
  minimumFractionDigits: 2,
});

fmt.format(2.33);
// en: "SAR 2.33"
// ar: "٢٫٣٣ ر.س.‏"

Common mistakes

MistakeWhy it bites
Using margin-left instead of margin-inline-startLayout doesn't flip in RTL; site looks broken on Arabic
Hard-coding text-align: leftSame — text goes the wrong way
Forgetting dir attribute on <html>Browser doesn't know the direction; logical properties fall back to LTR
Concatenating translated stringst('greet') + ' ' + name works in English but Arabic word order is different. Use template strings with positional placeholders, or a real i18n library
Using toLocaleString() without localeDefaults to runtime locale, which may differ from the host's UI locale

Test it

Open the dev-server's control panel (http://127.0.0.1:5173/_sdk/ui), flip Locale: enar, refresh your page. Verify:

  • <html dir> is now rtl.
  • Layout flipped (text on the right, icons mirrored).
  • Numbers render with Arabic digits (٢ not 2) where the currency style includes them.
  • No left/right wording in copy ("see below" beats "see right" — "right" doesn't translate predictably).

On this page