Files
dsh_shenxian/test/locale-pref.test.mjs
T
admin 3efd68517f chore: 并入已删除会话的在途成果(防丢失;原会话已删,未做功能验收)
**背景**:这些改动原属本工作区另外几个会话(T01/T02 等),**那些会话已被用户删除** ⇒
工作树里的成果处于"无主"状态,一次错误 checkout / 覆盖即**永久丢失** ⇒ 代入库保全。
口径遵循本项目**先例**(`39a1f2e` / `b617cdb`:**别人的活,代入库并在提交信息里注明**)。

**内容**:档案 101「能力管理」改名 + 页内 tab 分页|档案 102 语言切换搬入「用户设置」|
`07-实例UI分区登记表.md`|`scripts/find-ui*.mjs`(UI 元素定位工具)|`poc/portal-entry/`(0.5.3)|
`src/web/locale-pref.ts` + `home-files.ts`(语言偏好持久化)|`test/locale-pref.test.mjs`|
`package.json`|`BRIEF.md` / `INDEX.md` / `docs-manifest.json` / `03-路线图与待办.md` / 档案 100 增量。

**已做最小健全性检查**(⚠️ **未跑完整构建 / 单测** —— 那是原会话的验收职责,本次只求"不丢"):
- JSON 合法:`package.json` / `poc/business-plugins/package.json` / `docs-manifest.json` ✓
- 4 个 TS 文件 `{}`/`()` 配平 ✓;新增文件均非空 ✓
- 规模:13 文件改动 +340/−210,新增 12 条

**未 push**(按 §4 提交边界:用户说"提交",未说"推送")。
2026-09-15 21:17:12 +08:00

80 lines
3.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* `src/web/locale-pref.ts` —— 语言偏好写进 `settings.yaml` 的**按行对账**逻辑。
*
* 为什么专门测它:这个函数**直接改用户的 `settings.yaml`** —— 写坏了 dsh 会拒绝加载整个文档
* (用户实例直接起不来)。所以这里钉的是三件事:
* · 只碰 `locale.preference` 那两行,**其它块 / 注释 / 顺序一律原样保留**;
* · 幂等(值相同 ⇒ `changed: false`,调用方据此跳过写盘);
* · 行尾风格跟着原文件走(CRLF 文件不会被写成混合行尾)。
*/
import { test } from 'node:test'
import assert from 'node:assert/strict'
import { LOCALE_IDS, isLocaleId, reconcileLocalePreference } from '../lib/web/locale-pref.js'
test('LOCALE_IDS 与官方 dsh-client-locale 一致(en 是官方 FALLBACK)', () => {
assert.deepEqual([...LOCALE_IDS], ['en', 'zh'])
assert.equal(isLocaleId('en'), true)
assert.equal(isLocaleId('zh'), true)
assert.equal(isLocaleId('ja'), false)
assert.equal(isLocaleId(''), false)
assert.equal(isLocaleId(undefined), false)
})
test('空文档 ⇒ 建出 locale 块', () => {
const r = reconcileLocalePreference('', 'zh')
assert.equal(r.changed, true)
assert.equal(r.text, 'locale:\n preference: zh\n')
})
test('没有 locale 块 ⇒ 追加,且不动已有内容', () => {
const src = 'llm-pi-ai:\n providers:\n my-gw:\n baseURL: https://x\n'
const r = reconcileLocalePreference(src, 'zh')
assert.equal(r.changed, true)
assert.ok(r.text.startsWith(src), '原有内容必须原样在前')
assert.ok(r.text.includes('locale:\n preference: zh'))
})
test('已有 locale 块但没有 preference ⇒ 紧跟块头插入一行', () => {
const src = 'locale:\n other: keep\nfoo: bar\n'
const r = reconcileLocalePreference(src, 'zh')
assert.equal(r.text, 'locale:\n preference: zh\n other: keep\nfoo: bar\n')
})
test('值不同 ⇒ 原地替换(只改那一行)', () => {
const src = 'a: 1\nlocale:\n preference: en\nb: 2\n'
const r = reconcileLocalePreference(src, 'zh')
assert.equal(r.changed, true)
assert.equal(r.text, 'a: 1\nlocale:\n preference: zh\nb: 2\n')
})
test('值相同 ⇒ 幂等(changed: false,文本一字不动)', () => {
const src = 'locale:\n preference: zh\n'
const r = reconcileLocalePreference(src, 'zh')
assert.equal(r.changed, false)
assert.equal(r.text, src)
})
test('注释与其它块一律保留', () => {
const src = '# 我自己的注释\nllm-pi-ai:\n # 内层注释\n providers: {}\nlocale:\n preference: en\n'
const r = reconcileLocalePreference(src, 'zh')
assert.ok(r.text.includes('# 我自己的注释'))
assert.ok(r.text.includes(' # 内层注释'))
assert.ok(r.text.includes(' preference: zh'))
assert.equal(r.text.split('\n').length, src.split('\n').length, '行数不变(没多写也没少写)')
})
test('CRLF 文档 ⇒ 保持 CRLF(不产生混合行尾)', () => {
const src = 'a: 1\r\nlocale:\r\n preference: en\r\n'
const r = reconcileLocalePreference(src, 'zh')
assert.ok(r.text.includes(' preference: zh\r\n'))
assert.equal(r.text.includes('\n\n'), false)
assert.equal(r.text.replace(/\r\n/g, '').includes('\n'), false, '不许出现裸 LF')
})
test('两次调用等价(第二次不再 changed)', () => {
const first = reconcileLocalePreference('x: 1\n', 'zh')
const second = reconcileLocalePreference(first.text, 'zh')
assert.equal(second.changed, false)
assert.equal(second.text, first.text)
})