mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
impl
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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` |
|
||||
|
||||
@@ -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。
|
||||
|
||||
Reference in New Issue
Block a user