Skip to content

feat: implement trilingual i18n and locale export pipeline - #23

Merged
BlackishGreen33 merged 6 commits into
mainfrom
codex/i18n-trilingual-ui
Mar 10, 2026
Merged

feat: implement trilingual i18n and locale export pipeline#23
BlackishGreen33 merged 6 commits into
mainfrom
codex/i18n-trilingual-ui

Conversation

@BlackishGreen33

@BlackishGreen33 BlackishGreen33 commented Mar 10, 2026

Copy link
Copy Markdown
Owner

Summary

  • add ui.language (auto|zh-TW|zh-CN|en) across web/extension config schema, normalization, and sync
  • implement shared i18n core (resolveLocale, useI18n) and apply to dashboard/settings/trend/list/detail/loading flows
  • add export locale pipeline (/api/export locale, csv/markdown/pdf localized, json/sarif schema unchanged)
  • add locale-related tests and sync steering + AGENTS docs

Validation

  • pnpm lint
  • pnpm build
  • pnpm --filter web test
  • pnpm --filter confession-extension test

Copilot AI review requested due to automatic review settings March 10, 2026 16:06
@BlackishGreen33
BlackishGreen33 merged commit 47dcd81 into main Mar 10, 2026
9 checks passed
@BlackishGreen33
BlackishGreen33 deleted the codex/i18n-trilingual-ui branch March 10, 2026 16:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

此 PR 在 Confession 的 Webview/Extension/Backend 之間導入三語系(zh-TW / zh-CN / en)i18n,並讓匯出流程(CSV/Markdown/PDF)可依 locale 在後端產生本地化內容,同時把 ui.language 納入設定 schema、正規化與同步管線。

Changes:

  • 新增 PluginConfig.ui.language(含 auto)並貫穿 web/extension 的 default、schema、normalize、同步寫入 VS Code settings 與 .confession/config.json
  • 新增 shared i18n core(locale resolve + date/time formatter + options),並套用到 dashboard/settings/trend/list/detail/loading 等 UI 流程。
  • /api/export 新增 locale?;CSV/Markdown/PDF 渲染器支援在後端輸出本地化標題/文案(JSON/SARIF schema 維持不變),並補齊對應測試與文件規範。

Reviewed changes

Copilot reviewed 42 out of 42 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
web/src/server/storage/snapshot-codec.ts DEFAULT_CONFIG 與 config normalize 新增 ui.language
web/src/server/storage.test.ts 測試預設 config 補上 ui.language
web/src/server/routes/export.ts /api/export 支援 locale,並在未指定時由 config 解析 locale。
web/src/server/routes/export.test.ts 匯出測試新增 locale 覆蓋與 config fallback 情境;改用 TextDecoder
web/src/server/routes/config.ts config API schema/normalize/merge 支援 ui.language
web/src/server/export/renderers.ts CSV/Markdown 依 locale 本地化欄位標題/章節文案。
web/src/server/export/printable-text.ts 新增可列印 HTML 的三語系文案表。
web/src/server/export/printable-html.ts PDF(HTML) 輸出依 locale 本地化並套用 html lang
web/src/server/export/common.ts groupBySeverity 支援 locale 化的 section label。
web/src/server/agents/messages.pbt.test.ts PBT config arb 補上 ui.language
web/src/common/libs/ui-messages.ts sync phase / engine mode / more-info 文案支援 locale。
web/src/common/libs/types.ts 新增 UiLanguagePluginConfig.ui;export_pdf message 加入 locale?
web/src/common/libs/i18n.ts 新增 locale resolve/detect 與日期時間格式化工具。
web/src/common/libs/i18n.test.ts i18n resolver 單元測試。
web/src/common/libs/dashboard-insights.ts 趨勢洞察/總結卡等文案支援 locale;新增 getPresetLabel
web/src/common/libs/dashboard-insights.test.ts dashboard insights 新增 en/zh-CN 覆蓋測試。
web/src/common/libs/atoms.ts configAtom 預設值補上 ui.language
web/src/common/hooks/use-i18n.ts 新增 i18n hook,從 config 解析 locale 並提供 t/formatters/options。
web/src/common/hooks/use-config.ts 更新 config merge 將 ui 納入。
web/src/common/components/vulnerability-list/main.tsx 列表日期格式化與 preset label locale 化。
web/src/common/components/vulnerability-detail/main.tsx 事件時間顯示改用 locale formatter。
web/src/common/components/trend-chart.tsx 趨勢圖文案/tooltip/preset label locale 化。
web/src/common/components/settings/main.tsx 設定頁新增「介面語言」選項並讓各區塊文案 locale 化。
web/src/common/components/dashboard/main.tsx dashboard 匯出與 preset label/時間顯示 locale 化;export request 帶 locale。
web/src/app/vulnerability-detail/loading.tsx Loading 文案 locale 化。
web/src/app/vulnerabilities/loading.tsx Loading 文案 locale 化。
web/src/app/settings/loading.tsx Loading 文案 locale 化。
web/src/app/loading.tsx Loading 文案 locale 化。
extension/src/webview.ts export_pdf request body 轉送 locale;寫入 settings 補上 ui.language
extension/src/webview.test.ts 測試 config/arb 補上 ui.language
extension/src/types.ts extension 端 PluginConfig/WebToExtMsg 補上 ui.language/locale?
extension/src/ignore-file.ts .confession/config.json normalize/default 補上 ui.language
extension/src/ignore-file.test.ts ignore-file 測試 default config 補上 ui.language
extension/src/extension.ts 從 VS Code settings 與 scoped config 合併讀取 ui.language
extension/package.json 新增 confession.ui.language 設定項宣告。
AGENTS.md 更新 export locale 規範與 config 同步規範;文件樹新增 printable-text。
.kiro/steering/structure.md 文件樹新增 printable-text;標註 i18n core/hook 位置。
.kiro/steering/product.md 補充 Webview 三語系與 auto 行為。
.kiro/steering/language-preferences.md 補充 Webview 三語系與 auto 行為。
.kiro/steering/extension-guide.md 補充 confession.ui.languageauto 持續跟隨宿主語系。
.kiro/steering/code-conventions.md PluginConfig 定義補充 ui 設定。
.kiro/steering/api-standards.md /api/export/api/config 規範補上 locale / ui.language

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +410 to +413
const VulnCard: React.FC<VulnCardProps> = ({ vuln, onClick, onMore }) => {
const { formatDate } = useI18n()
return (
<div

Copilot AI Mar 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VulnCard calls useI18n() per card render. In a large list/grid this creates many hook subscriptions to config state and can amplify re-render cost when language changes. Consider calling useI18n() once in the parent and passing formatDate (or locale) down as a prop to VulnCard.

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +10
import { type ResolvedLocale,resolveLocale } from '@/libs/i18n'
import type { UiLanguage } from '@/libs/types'

Copilot AI Mar 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import { type ResolvedLocale,resolveLocale } ... is missing a space after the comma and will likely fail formatting/lint. Consider reformatting to keep imports consistent (e.g. resolveLocale before type ResolvedLocale and ensure proper spacing).

Copilot uses AI. Check for mistakes.
Comment on lines +22 to +28
export function useI18n() {
const config = useConfig()
const language: UiLanguage = config.ui?.language ?? 'auto'
const locale: ResolvedLocale = useMemo(
() => resolveLocale(language),
[language],
)

Copilot AI Mar 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ui.language=auto is supposed to keep following the host locale, but this hook memoizes resolveLocale(language) and only re-computes when language changes. If the host locale changes while language stays auto, locale won’t update; consider subscribing to languagechange (or tracking navigator.language/languages) and including it in the dependencies.

Copilot uses AI. Check for mistakes.
Comment on lines +150 to 174
function getPresetLabel(
preset: VulnerabilityFilterPreset,
locale: ResolvedLocale,
): string {
switch (preset) {
case 'critical_open':
return lt(locale, {
'zh-TW': '嚴重級待處理',
'zh-CN': '严重级待处理',
en: 'Open Critical',
})
case 'high_open':
return lt(locale, {
'zh-TW': '高風險待處理',
'zh-CN': '高风险待处理',
en: 'Open High Risk',
})
default:
return lt(locale, {
'zh-TW': '全部待處理',
'zh-CN': '全部待处理',
en: 'All Open',
})
}
}

Copilot AI Mar 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file re-implements getPresetLabel(...) locally even though an equivalent helper already exists in @/libs/dashboard-insights. Duplicating preset label logic risks drift across UI surfaces; consider importing and reusing the shared helper instead of maintaining a second copy here.

Copilot uses AI. Check for mistakes.
analysis: { triggerMode: 'manual', depth: 'standard', debounceMs: 500 },
ignore: { paths: [], types: [] },
api: { baseUrl: 'http://localhost:3000', mode: 'local' },
ui: { language: 'auto' },

Copilot AI Mar 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ui is mis-indented in this object literal (it’s not aligned with the other top-level config keys). This likely indicates a formatting issue that will either fail linting or make future diffs noisy; please run the formatter so the ui block aligns with llm/analysis/ignore/api.

Suggested change
ui: { language: 'auto' },
ui: { language: 'auto' },

Copilot uses AI. Check for mistakes.
analysis: { triggerMode: 'manual', depth: 'standard', debounceMs: 500 },
ignore: { paths: [], types: [] },
api: { baseUrl: 'http://localhost:3000', mode: 'local' },
ui: { language: 'auto' },

Copilot AI Mar 10, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same indentation/formatting issue here: ui is not aligned with the other keys in mockConfig. Running the formatter (or fixing whitespace) will avoid lint failures and keep object literals consistent.

Suggested change
ui: { language: 'auto' },
ui: { language: 'auto' },

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants