Files
zeekay 2bf05441ce t takes elements and isolates arguments; English keys are extracted
t(source, values) returns a node once a value is an element, so a link
or a styled figure stays inside the one sentence a translator reorders.
In a right-to-left locale every argument is isolated (U+2068..U+2069 in
a string, <bdi> around an element): 1,150–1,400 no longer reads
1,400–1,150 in Arabic. English output is unchanged byte for byte.

phrase(source) marks English written as data, for t(item.label) where
it is drawn. i18n-extract --catalogs reads t and phrase literals from
the syntax tree into en-US.json; --prune drops what no reader asks for.
i18n-translate --jobs n asks several locales at once.

@hanzo/i18n 0.4.0.

Claude-Session: https://claude.ai/code/session_01BLLMyBFSvAfCt7ZGqYuiEz
2026-10-22 13:50:15 -07:00

37 lines
1.5 KiB
TypeScript

import assert from 'node:assert/strict'
import test from 'node:test'
import { catalogue, english } from '../src/english.ts'
test('a sentence is its own key, with apostrophes, colons and either quote', () => {
const code = `
const a = t("Hanzo's Terms of Service")
const b = t('Note: {n} tasks', { n })
const c = i18n.t(\`Sign in\`)
const d = phrase('About Us')
`
assert.deepEqual(english(code, 'a.ts'), ["Hanzo's Terms of Service", 'Note: {n} tasks', 'Sign in', 'About Us'])
})
test('JSX attributes and children are read; a comment or doc example is not', () => {
const code = `
// t('in a comment')
/** \`t('in a doc example')\` */
export const A = () => <a aria-label={t('Open the menu')}>{t('Menu')}</a>
`
assert.deepEqual(english(code, 'a.tsx'), ['Open the menu', 'Menu'])
})
test('both arms of a choice, and the literal side of a fallback', () => {
assert.deepEqual(english(`t(open ? 'Close' : 'Open'); t(name ?? 'Untitled')`, 'a.ts'), ['Close', 'Open', 'Untitled'])
})
test('a key built at runtime, or a template with a substitution, is not extracted', () => {
assert.deepEqual(english('t(label); t(`Hello ${name}`); format("x"); at("y")', 'a.ts'), [])
})
test('the catalog adds what is found; pruning keeps only what is found', () => {
assert.deepEqual(catalogue({ Old: 'Old', Kept: 'Kept' }, ['Kept', 'New'], false), { Old: 'Old', Kept: 'Kept', New: 'New' })
assert.deepEqual(catalogue({ Old: 'Old', Kept: 'Kept' }, ['Kept', 'New'], true), { Kept: 'Kept', New: 'New' })
})