This commit is contained in:
nettee
2026-05-13 11:44:31 +08:00
parent 714fe52593
commit c61b0f70bc
5 changed files with 51 additions and 67 deletions
+3
View File
@@ -61,6 +61,9 @@ describe('localized resource content', () => {
);
expect(localized.category).toBe('Infographie');
expect(localized.tags).toEqual(['3D', 'unknown-tag']);
expect(
localizePromptTemplateSummary('fr', { ...translatedTemplate, category: 'Unknown category' }).category,
).toBe('Unknown category');
const englishOnlyTemplate = {
...translatedTemplate,
+2 -2
View File
@@ -192,14 +192,14 @@ The `e2e/tests/localized-content.test.ts` test enforces that every directory und
For a non-featured skill, the cheap path is to keep the source metadata complete:
- [ ] **Ensure `SKILL.md` has complete English display copy**: title/name, description, example prompt, and any picker metadata required by the skill schema. The localized runtime uses these fields as the fallback display path.
- [ ] **Run `pnpm --filter @open-design/web test` and `pnpm --filter @open-design/e2e test tests/localized-content.test.ts`** locally before pushing. These suites catch missing localized dictionaries and undisplayable discovered resources.
- [ ] **Run `pnpm --filter @open-design/web test` and `pnpm --filter @open-design/e2e test tests/localized-content.test.ts`** locally before pushing. These suites catch undisplayable discovered resources and verify localized fallback behavior.
### Featured skills (optional path)
If you set `od.featured: 1`, also:
- [ ] **Add a screenshot** at `docs/screenshots/skills/<skill>.png`. PNG, ~1024×640 retina, captured from the real `example.html` at zoomed-out browser scale.
- [ ] **Add full localized display copy** in `content.ts` (DE), `content.fr.ts` (FR), `content.ru.ts` (RU) — title, summary, scenario tag. The featured row in the picker uses this copy; the default fallback path renders English everywhere.
- [ ] **Optionally add full localized display copy** in `content.ts` (DE), `content.fr.ts` (FR), `content.ru.ts` (RU) — title, summary, scenario tag. The featured row in the picker uses this copy when present; the default fallback path renders English everywhere.
### Forking
+2 -2
View File
@@ -65,8 +65,8 @@
| SET-040 | 在 Language 页面切换语言后,触发器文案会立即更新,同时把 locale 写入 `localStorage` 并同步 `html[lang]` | `SettingsDialog.execution.test.tsx` |
| SET-041 | 切换到 `fa` 等 RTL 语言后,会同步更新 `html[dir=rtl]`,且语言菜单支持 `Escape` 关闭 | `SettingsDialog.execution.test.tsx` |
| SET-042 | Language 页面不依赖全局保存按钮;语言切换即时生效,关闭 Settings 也不会回滚已应用 locale | `SettingsDialog.execution.test.tsx` |
| SET-043 | 每个 locale 都覆盖了所有 curated skill、design system、prompt template id | `localized-content.test.ts` |
| SET-044 | 每个 locale 都覆盖了要求的展示分类和 prompt tag | `localized-content.test.ts` |
| SET-043 | 多语言内容资源可通过翻译字典或英文 fallback 渲染为非空 skill、design system、prompt template 展示内容 | `localized-content.test.ts` |
| SET-044 | Prompt template category 和 tag 在缺少 locale 字典项时回退到源值,已有字典项仍可本地化 | `localized-content.test.ts` |
| SET-045 | Notifications 默认以 `offline` 展示;开启 completion sound 后才会显示成功/失败音选择器,并立即试听默认成功音 | `SettingsDialog.execution.test.tsx` |
| SET-046 | Notifications 支持切换 success / failure sound,并把声音选择保存到通知配置 | `SettingsDialog.execution.test.tsx` |
| SET-047 | Desktop notification 在授权成功后会切为 `active`,支持发送测试通知并展示发送结果文案 | `SettingsDialog.execution.test.tsx` |
+16 -43
View File
@@ -10,17 +10,7 @@ declare global {
}
}
type LocalizedContentIds = {
skills: string[];
designSystems: string[];
designSystemCategories: string[];
promptTemplates: string[];
promptTemplateCategories: string[];
promptTemplateTags: string[];
};
type LocalizedContentModule = {
LOCALIZED_CONTENT_IDS: Record<string, LocalizedContentIds>;
localizeDesignSystemSummary: (locale: string, system: DesignSystemResource) => string;
localizePromptTemplateSummary: (
locale: string,
@@ -44,12 +34,8 @@ if (localizedContentModule == null) {
throw new Error('Failed to load apps/web localized content ids');
}
const {
LOCALIZED_CONTENT_IDS,
localizeDesignSystemSummary,
localizePromptTemplateSummary,
localizeSkillDescription,
} = localizedContentModule;
const { localizeDesignSystemSummary, localizePromptTemplateSummary, localizeSkillDescription } =
localizedContentModule;
const COVERAGE_LOCALES = ['de', 'fr', 'ru'] as const;
const RESOURCE_ID_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
@@ -378,35 +364,22 @@ describe('localized display content coverage', () => {
});
for (const locale of COVERAGE_LOCALES) {
const ids = LOCALIZED_CONTENT_IDS[locale];
invariant(ids, `Localized content ids are missing for ${locale}`);
it(`falls back to source prompt-template category and tags for ${locale} when dictionary entries are missing`, () => {
const localized = localizePromptTemplateSummary(locale, {
id: 'missing-template-translation',
category: 'Untranslated Category',
tags: ['untranslated-tag', '3d'],
title: ' English title from source ',
summary: ' English summary from source ',
});
it(`covers every discovered design-system category and prompt tag for ${locale}`, async () => {
const [designSystems, promptTemplates] = await Promise.all([
readDesignSystemResources(),
readPromptTemplateResources(),
]);
const designSystemCategories = uniqueSorted(designSystems.map((system) => system.category));
const promptTemplateCategories = uniqueSorted(
promptTemplates.map((template) => template.category),
expect(localized.title).toBe(' English title from source ');
expect(localized.summary).toBe(' English summary from source ');
expect(localized.category).toBe('Untranslated Category');
expect(localized.tags[0]).toBe('untranslated-tag');
expect(normalizeText(localized.tags[1] ?? ''), `${locale} should still localize known tags`).not.toEqual(
'',
);
const promptTemplateTags = uniqueSorted(
promptTemplates.flatMap((template) => template.tags),
);
expect(
sorted(ids.designSystemCategories),
`${locale} is missing localized design-system category translations for: ${designSystemCategories.filter((category) => !ids.designSystemCategories.includes(category)).join(', ') || 'none'}`,
).toEqual(expect.arrayContaining(designSystemCategories));
expect(
sorted(ids.promptTemplateCategories),
`${locale} is missing localized prompt-template category translations for: ${promptTemplateCategories.filter((category) => !ids.promptTemplateCategories.includes(category)).join(', ') || 'none'}`,
).toEqual(expect.arrayContaining(promptTemplateCategories));
expect(
sorted(ids.promptTemplateTags),
`${locale} is missing localized prompt-template tag translations for: ${promptTemplateTags.filter((tag) => !ids.promptTemplateTags.includes(tag)).join(', ') || 'none'}`,
).toEqual(expect.arrayContaining(promptTemplateTags));
});
}
});
@@ -1,7 +1,7 @@
---
id: 20260513-optional-content-i18n
name: Optional Content I18n
status: designed
status: implemented
created: '2026-05-13'
---
@@ -148,30 +148,38 @@ Flow:
## Plan
- [ ] Step 1: 调整 localized-content 测试 gate
- [ ] Substep 1.1 Implement: 移除或改写 `LOCALIZED_CONTENT_IDS` 对 discovered category / tag 的全量覆盖断言。
- [ ] Substep 1.2 Implement: 保留真实资源在 `de` / `fr` / `ru` 下非空显示的 fallback smoke。
- [ ] Substep 1.3 Implement: 需要时增加 category / tag fallback 的直接断言,覆盖缺字典时返回原值。
- [ ] Substep 1.4 Verify: 运行 `pnpm --filter @open-design/e2e test tests/localized-content.test.ts`。
- [ ] Step 2: 同步贡献和覆盖文档
- [ ] Substep 2.1 Implement: 更新 `docs/skills-contributing.md`,把 featured localized copy 表达为可选增强路径。
- [ ] Substep 2.2 Implement: 更新 `docs/testing/e2e-coverage/settings.md` 中 SET-043 / SET-044 的覆盖描述。
- [ ] Substep 2.3 Implement: 复核 `docs/design-systems.md` 与新语义一致,必要时微调 wording。
- [ ] Substep 2.4 Verify: 人工检查文档中不再把 `de` / `fr` / `ru` 内容翻译描述为内容型贡献的硬性阻塞项。
- [ ] Step 3: 回归验证
- [ ] Substep 3.1 Verify: 运行 `pnpm --filter @open-design/web test`。
- [ ] Substep 3.2 Verify: 本地临时新增一个未补 `de` / `fr` / `ru` localized dictionary 的 probe 类内容资源,运行 CI 等价验证,确认通过后移除 probe 内容。
- [ ] Substep 3.3 Verify: 运行 `pnpm guard`。
- [ ] Substep 3.4 Verify: 运行 `pnpm typecheck`。
- [x] Step 1: 调整 localized-content 测试 gate
- [x] Substep 1.1 Implement: 移除或改写 `LOCALIZED_CONTENT_IDS` 对 discovered category / tag 的全量覆盖断言。
- [x] Substep 1.2 Implement: 保留真实资源在 `de` / `fr` / `ru` 下非空显示的 fallback smoke。
- [x] Substep 1.3 Implement: 需要时增加 category / tag fallback 的直接断言,覆盖缺字典时返回原值。
- [x] Substep 1.4 Verify: 运行 `pnpm --filter @open-design/e2e test tests/localized-content.test.ts`。
- [x] Step 2: 同步贡献和覆盖文档
- [x] Substep 2.1 Implement: 更新 `docs/skills-contributing.md`,把 featured localized copy 表达为可选增强路径。
- [x] Substep 2.2 Implement: 更新 `docs/testing/e2e-coverage/settings.md` 中 SET-043 / SET-044 的覆盖描述。
- [x] Substep 2.3 Implement: 复核 `docs/design-systems.md` 与新语义一致,必要时微调 wording。
- [x] Substep 2.4 Verify: 人工检查文档中不再把 `de` / `fr` / `ru` 内容翻译描述为内容型贡献的硬性阻塞项。
- [x] Step 3: 回归验证
- [x] Substep 3.1 Verify: 运行 `pnpm --filter @open-design/web test`。
- [x] Substep 3.2 Verify: 本地临时新增一个未补 `de` / `fr` / `ru` localized dictionary 的 probe 类内容资源,运行 CI 等价验证,确认通过后移除 probe 内容。
- [x] Substep 3.3 Verify: 运行 `pnpm guard`。
- [x] Substep 3.4 Verify: 运行 `pnpm typecheck`。
## Notes
<!-- Optional sections — add what's relevant. -->
### Implementation
<!-- Files created/modified, decisions made during coding, deviations from design -->
- `e2e/tests/localized-content.test.ts` - 移除 discovered category / tag 对 `LOCALIZED_CONTENT_IDS` 的全量覆盖 gate,保留真实资源可显示 smoke,并新增缺 prompt-template category / tag 字典项时回退源值的直接断言。
- `apps/web/tests/i18n/content.test.ts` - 补强 prompt-template 未知 category 的 fallback 单元断言。
- `docs/skills-contributing.md` - 将 localized display copy 调整为 featured skill 的可选增强路径,并说明测试关注可显示资源与 fallback 行为。
- `docs/testing/e2e-coverage/settings.md` - 将 SET-043 / SET-044 改写为 fallback 展示完整性和可选翻译行为覆盖。
- `docs/design-systems.md` - 现有 wording 已表达英文 fallback 和可选 localized summary,无需修改。
### Verification
<!-- How the feature was verified: tests written, manual testing steps, results -->
- `pnpm --filter @open-design/web test tests/i18n/content.test.ts` - passed。
- `pnpm --filter @open-design/e2e test tests/localized-content.test.ts` - 初次发现并清理前序 probe 空目录后 passed。
- 临时新增英文-only skill、design template、design system、prompt template probe,并运行 `pnpm --filter @open-design/e2e test tests/localized-content.test.ts` - passed;随后移除临时 probe 内容。
- `pnpm --filter @open-design/e2e test tests/localized-content.test.ts` - final passed。
- `pnpm --filter @open-design/web test` - passed,110 files / 1013 tests。
- `pnpm guard` - passed。
- `pnpm typecheck` - passed。