Files
zeekay 595bb3b930 79 locales: right-to-left by script, regional variants in resolve
Add 43 locales to the registry, their loaders and catalogs: Persian,
Dari, Hebrew, Urdu, Pashto, Central Kurdish, Sindhi, Uyghur, Punjabi in
both scripts, four regional Arabics, Hong Kong Chinese, Mexican and
Argentine Spanish, European Portuguese, Canadian French, and 24 more.
34 wait for a native reader in review.json; ti, qu, gn, ay, bo and dv
are not shipped.

Every locale in Arabic or Hebrew script is rtl, and the registry test
derives the script from the tag. rtl.css selects on :dir(rtl), so it
holds inside a right-to-left region of a left-to-right page.

resolve no longer leans on registry order: after the exact tag and the
script, a request takes its own region, then the variant that serves it
(CLDR parents for es-419 and pt-PT, Macau to zh-HK, the Arabic dialect
areas), then the variant with no region, then the language's own region.
pnb reaches pa-PK.
2026-10-22 05:30:36 -07:00

45 lines
1.8 KiB
TypeScript

import assert from 'node:assert/strict'
import { test } from 'node:test'
import { loadAccountLocale, saveAccountLocale } from '../src/account.ts'
type Call = { url: string } & RequestInit
function serve(answer: unknown): Call[] {
const calls: Call[] = []
globalThis.fetch = (async (url: string, init: RequestInit) => {
calls.push({ url, ...init })
return { ok: true, status: 200, json: async () => answer } as Response
}) as typeof fetch
return calls
}
const original = globalThis.fetch
test.afterEach(() => {
globalThis.fetch = original
})
test('IAM sync reads with an empty merge and writes only the locale', async () => {
const calls = serve({ status: 'ok', data: { locale: 'ar', appearance: { density: 'compact' } } })
const account = { base: 'https://identity.example/', token: 'test-only' }
assert.equal(await loadAccountLocale(account), 'ar')
await saveAccountLocale(account, 'ar-IQ') // saved as the locale it reaches
assert.equal(calls[0].body, '{}')
assert.deepEqual(JSON.parse(String(calls[1].body)), { locale: 'ar' })
assert.equal(calls[1].credentials, 'omit')
assert.equal((calls[1].headers as Record<string, string>).Authorization, 'Bearer test-only')
assert.equal(calls[1].url, 'https://identity.example/v1/iam/preferences')
})
test('a locale IAM holds that we do not ship is no locale', async () => {
serve({ status: 'ok', data: { locale: 'xx-YY' } })
assert.equal(await loadAccountLocale({ base: 'https://identity.example', token: 't' }), undefined)
})
test('an error inside HTTP 200, and a write IAM did not keep, are refused', async () => {
serve({ status: 'error' })
await assert.rejects(saveAccountLocale({ base: 'https://identity.example', token: 't' }, 'ar'))
serve({ status: 'ok', data: { locale: 'en-US' } })
await assert.rejects(saveAccountLocale({ base: 'https://identity.example', token: 't' }, 'ar'))
})