Files
TREK/client/native-shell/i18n.ts
T
Maurice 2a6c771ad9 fix(native): the first screens fit a phone on its side, fill an upright iPad, and read right in Arabic and Russian
On a phone or a folded foldable turned landscape the welcome, address,
TREK Cloud and plan screens were taller than the glass: the second choice
and the main button sat below the edge and Back was cut at the top. There
the explanation and the choices now stand side by side, the explanation
pinned while a long plan list scrolls. Every screen centres while it fits
and starts at the top when it does not.

Upright on an iPad, half of one in Split View and an unfolded foldable,
the photo spans the full width and fades only downwards, and the choices
stand centred in the room below it. Buttons and fields are pills like the
app's, choice cards take the app's card radius, and headings and subtitles
balance their lines.

In Arabic (and Hebrew, which never ran right to left here) chevrons point
along the reading direction and sit at the far edge of their card, the
Cloud lockup stays unmirrored on the leading edge, prices and addresses
read left to right, and a plan's period no longer touches its price. The
slides follow the reading direction. Russian gets Cyrillic stand-ins under
the same family names, so the headline keeps a rounded face.
2026-11-07 23:25:15 +01:00

40 lines
1.6 KiB
TypeScript

import { SUPPORTED_LANGUAGE_CODES, isRtlLanguage } from '@trek/shared/i18n'
import type { TranslationStrings } from '@trek/shared/i18n'
// Only the native strings of every locale, not the whole UI: this page ships
// inside the app binary and shows three screens.
const bundles = import.meta.glob<TranslationStrings>('../../shared/src/i18n/*/native.ts', { eager: true, import: 'default' })
function bundleFor(code: string): TranslationStrings | undefined {
return bundles[`../../shared/src/i18n/${code}/native.ts`]
}
export function pickLocale(preferred: readonly string[]): string {
for (const lang of preferred) {
const lower = lang.toLowerCase()
if (lower === 'pt-br') return 'br'
if (lower.startsWith('zh-tw') || lower.startsWith('zh-hk') || lower.startsWith('zh-hant')) return 'zh-TW'
if (lower.startsWith('el')) return 'gr'
const prefix = lower.split('-')[0]
const match = SUPPORTED_LANGUAGE_CODES.find((code) => code.toLowerCase() === lower || code === prefix)
if (match) return match
}
return 'en'
}
export function translator(code: string) {
const strings = bundleFor(code) ?? {}
const fallback = bundleFor('en') ?? {}
return (key: string, params: Record<string, string> = {}): string => {
const template = strings[key] ?? fallback[key] ?? key
return typeof template === 'string'
? template.replace(/\{(\w+)\}/g, (whole, name: string) => params[name] ?? whole)
: key
}
}
/** Arabic and Hebrew run right to left. */
export function directionOf(code: string): 'rtl' | 'ltr' {
return isRtlLanguage(code) ? 'rtl' : 'ltr'
}