94 lines
3.9 KiB
JavaScript
94 lines
3.9 KiB
JavaScript
// The dictionaries and the translator. The key sets are asserted equal because
|
|
// the translator falls back to whichever dictionary has a key: an asymmetric key
|
|
// would silently switch language instead of failing, and a key nobody reads is a
|
|
// defect this repository has removed once already.
|
|
import { test } from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
|
|
import { createTranslator, dictionaries, registerDictionaries } from '../../src/client/i18n/index.js'
|
|
import { zh } from '../../src/client/i18n/zh.js'
|
|
import { en } from '../../src/client/i18n/en.js'
|
|
|
|
test('both dictionaries carry exactly the same keys', () => {
|
|
assert.deepEqual(Object.keys(zh).sort(), Object.keys(en).sort())
|
|
assert.deepEqual(Object.keys(dictionaries).sort(), ['en', 'zh'])
|
|
})
|
|
|
|
test('every key carries copy in both languages', () => {
|
|
for (const [key, value] of Object.entries(zh)) {
|
|
assert.equal(typeof value, 'string', `${key} is not a string in zh`)
|
|
assert.notEqual(value, '', `${key} is empty in zh`)
|
|
}
|
|
for (const [key, value] of Object.entries(en)) {
|
|
assert.equal(typeof value, 'string', `${key} is not a string in en`)
|
|
assert.notEqual(value, '', `${key} is empty in en`)
|
|
}
|
|
})
|
|
|
|
test('the seat translation wins, and a key it does not know falls back to the dictionary', () => {
|
|
const locale = {
|
|
bind: (namespace) => {
|
|
assert.equal(namespace, 'session-notify')
|
|
return (key, params) => (key === 'notification.completion' ? `seat:${params?.title ?? ''}` : key)
|
|
},
|
|
getSnapshot: () => ({ active: 'zh' }),
|
|
}
|
|
const t = createTranslator(locale)
|
|
assert.equal(t('notification.completion', { title: 'X' }), 'seat:X')
|
|
assert.equal(t('body.untitled'), '未命名会话')
|
|
})
|
|
|
|
test('the active language selects the dictionary, and an unknown key renders itself', () => {
|
|
const t = createTranslator({ bind: () => undefined, getSnapshot: () => ({ active: 'zh-CN' }) })
|
|
assert.equal(t('body.untitled'), '未命名会话')
|
|
|
|
const english = createTranslator(undefined)
|
|
assert.equal(english('body.untitled'), 'Untitled conversation')
|
|
assert.equal(english('nope.not.a.key'), 'nope.not.a.key')
|
|
})
|
|
|
|
test('interpolation replaces every known placeholder and leaves unknown ones alone', () => {
|
|
const t = createTranslator({ getSnapshot: () => ({ active: 'en' }) })
|
|
assert.equal(t('body.approval', { title: 'A', tool: 'Bash' }), 'A: Bash is waiting for your approval')
|
|
assert.equal(t('body.approval', { title: 'A' }), 'A: {tool} is waiting for your approval')
|
|
assert.equal(t('body.untitled', { unused: 'x' }), 'Untitled conversation')
|
|
})
|
|
|
|
test('a locale service that throws on every call keeps the copy renderable', () => {
|
|
const t = createTranslator({
|
|
bind: () => {
|
|
throw new Error('no such namespace')
|
|
},
|
|
getSnapshot: () => {
|
|
throw new Error('no snapshot')
|
|
},
|
|
})
|
|
assert.equal(t('settings.title'), 'Session notifications')
|
|
})
|
|
|
|
test('registration prefers the typed form and falls back to one call per locale', () => {
|
|
const typed = []
|
|
const disposeTyped = registerDictionaries({ register: (ns, dict) => { typed.push([ns, dict]); return () => {} } })
|
|
assert.deepEqual(typed, [['session-notify', dictionaries]])
|
|
assert.equal(typeof disposeTyped, 'function')
|
|
|
|
const single = []
|
|
let disposed = 0
|
|
const disposeSingle = registerDictionaries({
|
|
register: (ns, id, dict) => {
|
|
if (typeof id === 'object') throw new Error('typed form unsupported')
|
|
single.push([ns, id, dict])
|
|
return () => { disposed += 1 }
|
|
},
|
|
})
|
|
assert.deepEqual(single.map(([ns, id]) => [ns, id]), [['session-notify', 'zh'], ['session-notify', 'en']])
|
|
disposeSingle()
|
|
assert.equal(disposed, 2)
|
|
})
|
|
|
|
test('a profile without a locale service is not an error', () => {
|
|
assert.equal(typeof registerDictionaries(undefined), 'function')
|
|
assert.doesNotThrow(() => registerDictionaries(undefined)())
|
|
assert.equal(createTranslator(undefined)('body.untitled'), 'Untitled conversation')
|
|
})
|