mirror of
https://github.com/hanzoai/i18n.git
synced 2026-10-30 14:24:32 +00:00
Arabic under Zen is drawn by a companion @font-face with a unicode-range, which a browser fetches only once an Arabic letter is laid out. The provider showed a catalog first, so its words were laid out invisibly in the platform's metrics for the face's block period, and every box after them moved when the face landed: the page changed twice, once for the words and once for the face. select now awaits faces(messages) before it shows a catalog: the body's families in order, document.fonts.load with the catalog's letters, stopping at the first family that has a face for them, which is the face the browser draws them in. Asking the whole stack would also fetch a later copy of the same companion. Capped at 3 s, the block period, so a face that never comes holds the words no longer than it would have hidden them. English loads no catalog and costs nothing. Claude-Session: https://claude.ai/code/session_015XYKLjZtDTJEnMo4eK3AFH
64 lines
2.1 KiB
TypeScript
64 lines
2.1 KiB
TypeScript
import assert from 'node:assert/strict'
|
|
import { afterEach, test } from 'node:test'
|
|
|
|
import { faces, letters } from '../src/faces.ts'
|
|
|
|
const g = globalThis as Record<string, unknown>
|
|
afterEach(() => {
|
|
delete g.document
|
|
delete g.getComputedStyle
|
|
})
|
|
|
|
/** A page whose body is set in `stack`, and a font set that holds faces for `held`. */
|
|
function page(stack: string, held: Record<string, RegExp>, delay = 0) {
|
|
const asked: string[] = []
|
|
g.getComputedStyle = () => ({ fontFamily: stack, fontWeight: '400' })
|
|
g.document = {
|
|
body: {},
|
|
fonts: {
|
|
load: async (font: string, text: string) => {
|
|
asked.push(font)
|
|
const family = font.replace(/^400 16px /, '').replace(/"/g, '')
|
|
if (delay) await new Promise((done) => setTimeout(done, delay))
|
|
return held[family]?.test(text) ? [{ family }] : []
|
|
},
|
|
},
|
|
}
|
|
return asked
|
|
}
|
|
|
|
const ARABIC = { a: 'كل ما يحتاجه', b: 'Hanzo' }
|
|
|
|
test('letters: each character once', () => {
|
|
assert.equal(letters({ a: 'aab', b: 'ba' }), 'ab')
|
|
assert.equal(letters({}), '')
|
|
})
|
|
|
|
test('asks the stack in order and stops at the first family with a face for the words', async () => {
|
|
const asked = page('"Noto Kufi Arabic", Zen, sans-serif', { 'Noto Kufi Arabic': /[-ۿ]/, Zen: /./ })
|
|
await faces(ARABIC)
|
|
assert.deepEqual(asked, ['400 16px "Noto Kufi Arabic"'])
|
|
})
|
|
|
|
test('passes over a family with no face for these letters', async () => {
|
|
const asked = page('"Noto Kufi Arabic", Zen, sans-serif', { 'Noto Kufi Arabic': /[-ۿ]/, Zen: /./ })
|
|
await faces({ a: 'Bonjour' })
|
|
assert.deepEqual(asked, ['400 16px "Noto Kufi Arabic"', '400 16px Zen'])
|
|
})
|
|
|
|
test('holds the words no longer than the block period', async () => {
|
|
page('"Noto Kufi Arabic", Zen', { 'Noto Kufi Arabic': /./ }, 1500)
|
|
const start = Date.now()
|
|
await faces(ARABIC, 50)
|
|
assert.ok(Date.now() - start < 1000, 'returned on the wait, not the face')
|
|
})
|
|
|
|
test('costs nothing without a document, the Font Loading API, or words', async () => {
|
|
await faces(ARABIC)
|
|
g.document = { body: {} }
|
|
await faces(ARABIC)
|
|
const asked = page('Zen', { Zen: /./ })
|
|
await faces({})
|
|
assert.deepEqual(asked, [])
|
|
})
|