Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion ui/src/components/IssuesBoard.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { cleanup, render, screen } from '@testing-library/react'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'

import type { IssueListItem, IssueSnapshot } from '../api/issues'
import { i18n } from '../i18n'
import { IssuesBoard } from './IssuesBoard'

const mocks = vi.hoisted(() => ({
Expand Down Expand Up @@ -52,7 +53,8 @@ function snapshot(issues: IssueListItem[]): IssueSnapshot {
}
}

beforeEach(() => {
beforeEach(async () => {
await i18n.changeLanguage('en')
mocks.useIssues.mockReturnValue({
data: snapshot([]),
error: null,
Expand Down Expand Up @@ -147,4 +149,36 @@ describe('IssuesBoard', () => {
expect(screen.getByText('Assign on first run')).toBeTruthy()
expect(screen.queryByText('@new')).toBeNull()
})

it('localizes board chrome, schedule health, and accessible metadata', async () => {
await i18n.changeLanguage('zh')
mocks.useIssues.mockReturnValue({
data: snapshot([
issue({
id: 'weekday-scan',
title: '工作日扫描',
status: 'in_progress',
priority: 'high',
assignee: '@new',
agent: 'claude',
when: { kind: 'cron', cron: '30 8 * * 1-5' },
automationHealth: { state: 'running', message: 'Run is active.' },
}),
]),
error: null,
loading: false,
})

render(<IssuesBoard />)

expect(screen.getByText('进行中')).toBeTruthy()
expect(screen.getAllByText('运行中')).toHaveLength(2)
expect(screen.getAllByText('每工作日 08:30')).toHaveLength(2)
expect(screen.getByText('首次运行时指派')).toBeTruthy()
expect(screen.getByText('claude 覆盖')).toBeTruthy()
expect(screen.getByLabelText('高优先级')).toBeTruthy()
expect(screen.getByLabelText('折叠“进行中”议题')).toBeTruthy()
expect(screen.getByTitle('打开 weekday-scan')).toBeTruthy()
expect(screen.getByTitle('工作区:market-desk(ws-1)')).toBeTruthy()
})
})
149 changes: 83 additions & 66 deletions ui/src/components/IssuesBoard.tsx

Large diffs are not rendered by default.

73 changes: 73 additions & 0 deletions ui/src/i18n/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,79 @@ export const en = {
collapseRail: 'Collapse activity bar',
expandRail: 'Expand activity bar',
},
issues: {
description: 'Work tracked across every workspace.',
settings: 'Issue settings',
loadError: 'Failed to load issues: {{error}}',
unknownError: 'Unknown error',
stale: 'Live refresh failing — showing the last known issues.',
emptyTitle: 'No workspace has any issues yet.',
emptyPrefix: 'A workspace tracks an issue by writing',
emptySuffixBeforeWhen: '. Add a ',
emptySuffixAfterWhen: ' field and it self-schedules.',
unreadableWorkspace: 'Issues are unreadable for this workspace.',
openIssue: 'Open {{id}}',
assignOnFirstRun: 'Assign on first run',
duplicateOne: 'Duplicate name — also used in 1 other workspace. A [[name]] is a global handle; resolve manually.',
duplicateMany: 'Duplicate name — also used in {{count}} other workspaces. A [[name]] is a global handle; resolve manually.',
duplicateLabel: 'Duplicate issue name across workspaces',
duplicateShort: 'dup',
workspaceTitle: 'Workspace: {{workspace}} ({{id}})',
issueIdTitle: 'Issue ID: {{id}}',
assigneeTitle: 'Assignee: {{assignee}}',
agentOverrideTitle: 'Agent runtime override: {{agent}}',
agentOverrideShort: '{{agent}} override',
collapseStatus: 'Collapse {{status}} issues',
expandStatus: 'Expand {{status}} issues',
status: {
in_progress: 'In Progress',
todo: 'Todo',
backlog: 'Backlog',
done: 'Done',
canceled: 'Canceled',
},
health: {
inactive: 'Inactive',
not_started: 'Not started',
due: 'Due',
running: 'Running',
healthy: 'Healthy',
interrupted: 'Interrupted',
failed: 'Failed',
blocked: 'Blocked',
},
priority: {
urgent: 'Urgent',
high: 'High',
medium: 'Medium',
low: 'Low',
none: 'No',
label: '{{priority}} priority',
},
cadence: {
custom: 'Every custom schedule',
customAt: 'Every custom schedule {{time}}',
everyMinute: 'Every minute',
everyHour: 'Every hour',
everyDuration: 'Every {{duration}}',
everyDayAt: 'Every {{day}} {{time}}',
everyMonthDayAt: 'Every month on day {{day}} {{time}}',
day: 'day',
weekday: 'weekday',
weekend: 'weekend',
local: 'local',
localTime: 'local time',
},
weekday: {
sun: 'Sun',
mon: 'Mon',
tue: 'Tue',
wed: 'Wed',
thu: 'Thu',
fri: 'Fri',
sat: 'Sat',
},
},
settings: {
title: 'Settings',
tab: {
Expand Down
73 changes: 73 additions & 0 deletions ui/src/i18n/locales/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,79 @@ export const ja: Resources = {
collapseRail: 'アクティビティバーを折りたたむ',
expandRail: 'アクティビティバーを展開',
},
issues: {
description: 'すべてのワークスペースで追跡中の作業です。',
settings: '課題設定',
loadError: '課題を読み込めませんでした:{{error}}',
unknownError: '不明なエラー',
stale: 'ライブ更新に失敗したため、最後に取得した課題を表示しています。',
emptyTitle: '課題のあるワークスペースはまだありません。',
emptyPrefix: 'ワークスペースは',
emptySuffixBeforeWhen: ' を書くことで課題を追跡できます。',
emptySuffixAfterWhen: ' フィールドを追加すると自動実行されます。',
unreadableWorkspace: 'このワークスペースの課題を読み取れません。',
openIssue: '{{id}} を開く',
assignOnFirstRun: '初回実行時に割り当て',
duplicateOne: '名前が重複しています。ほかの 1 件のワークスペースでも使用されています。[[name]] はグローバルハンドルです。手動で解決してください。',
duplicateMany: '名前が重複しています。ほかの {{count}} 件のワークスペースでも使用されています。[[name]] はグローバルハンドルです。手動で解決してください。',
duplicateLabel: 'ワークスペース間で課題名が重複',
duplicateShort: '重複',
workspaceTitle: 'ワークスペース:{{workspace}}({{id}})',
issueIdTitle: '課題 ID:{{id}}',
assigneeTitle: '担当:{{assignee}}',
agentOverrideTitle: 'エージェントランタイムの上書き:{{agent}}',
agentOverrideShort: '{{agent}} 上書き',
collapseStatus: '「{{status}}」の課題を折りたたむ',
expandStatus: '「{{status}}」の課題を展開',
status: {
in_progress: '進行中',
todo: 'ToDo',
backlog: 'バックログ',
done: '完了',
canceled: 'キャンセル済み',
},
health: {
inactive: '無効',
not_started: '未開始',
due: '実行待ち',
running: '実行中',
healthy: '正常',
interrupted: '中断',
failed: '失敗',
blocked: 'ブロック中',
},
priority: {
urgent: '緊急',
high: '高',
medium: '中',
low: '低',
none: 'なし',
label: '優先度:{{priority}}',
},
cadence: {
custom: 'カスタムスケジュールで繰り返し',
customAt: 'カスタムスケジュールで {{time}} に繰り返し',
everyMinute: '毎分',
everyHour: '毎時',
everyDuration: '{{duration}} ごと',
everyDayAt: '毎{{day}} {{time}}',
everyMonthDayAt: '毎月 {{day}} 日 {{time}}',
day: '日',
weekday: '平日',
weekend: '週末',
local: 'ローカル',
localTime: 'ローカル時刻',
},
weekday: {
sun: '日',
mon: '月',
tue: '火',
wed: '水',
thu: '木',
fri: '金',
sat: '土',
},
},
settings: {
title: '設定',
tab: {
Expand Down
73 changes: 73 additions & 0 deletions ui/src/i18n/locales/zh-Hant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,79 @@ export const zhHant: Resources = {
collapseRail: '收合活動列',
expandRail: '展開活動列',
},
issues: {
description: '集中查看所有工作區追蹤的工作。',
settings: '議題設定',
loadError: '議題載入失敗:{{error}}',
unknownError: '未知錯誤',
stale: '即時重新整理失敗,目前顯示上次已知的議題。',
emptyTitle: '還沒有工作區建立議題。',
emptyPrefix: '工作區可透過寫入',
emptySuffixBeforeWhen: ' 來追蹤議題;加入 ',
emptySuffixAfterWhen: ' 欄位後即可自動排程。',
unreadableWorkspace: '無法讀取此工作區的議題。',
openIssue: '開啟 {{id}}',
assignOnFirstRun: '首次執行時指派',
duplicateOne: '名稱重複——另有 1 個工作區也在使用。[[name]] 是全域控制代碼,請手動解決衝突。',
duplicateMany: '名稱重複——另有 {{count}} 個工作區也在使用。[[name]] 是全域控制代碼,請手動解決衝突。',
duplicateLabel: '多個工作區存在同名議題',
duplicateShort: '重複',
workspaceTitle: '工作區:{{workspace}}({{id}})',
issueIdTitle: '議題 ID:{{id}}',
assigneeTitle: '負責人:{{assignee}}',
agentOverrideTitle: 'Agent 執行環境覆寫:{{agent}}',
agentOverrideShort: '{{agent}} 覆寫',
collapseStatus: '摺疊「{{status}}」議題',
expandStatus: '展開「{{status}}」議題',
status: {
in_progress: '進行中',
todo: '待辦',
backlog: '待排程',
done: '已完成',
canceled: '已取消',
},
health: {
inactive: '未啟用',
not_started: '尚未開始',
due: '等待執行',
running: '執行中',
healthy: '正常',
interrupted: '已中斷',
failed: '失敗',
blocked: '受阻',
},
priority: {
urgent: '緊急',
high: '高',
medium: '中',
low: '低',
none: '無',
label: '{{priority}}優先級',
},
cadence: {
custom: '依自訂排程重複',
customAt: '依自訂排程於 {{time}} 重複',
everyMinute: '每分鐘',
everyHour: '每小時',
everyDuration: '每 {{duration}}',
everyDayAt: '每{{day}} {{time}}',
everyMonthDayAt: '每月 {{day}} 日 {{time}}',
day: '天',
weekday: '工作日',
weekend: '週末',
local: '本機',
localTime: '本機時間',
},
weekday: {
sun: '週日',
mon: '週一',
tue: '週二',
wed: '週三',
thu: '週四',
fri: '週五',
sat: '週六',
},
},
settings: {
title: '設定',
tab: {
Expand Down
73 changes: 73 additions & 0 deletions ui/src/i18n/locales/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,79 @@ export const zh: Resources = {
collapseRail: '折叠活动栏',
expandRail: '展开活动栏',
},
issues: {
description: '集中查看所有工作区追踪的工作。',
settings: '议题设置',
loadError: '议题加载失败:{{error}}',
unknownError: '未知错误',
stale: '实时刷新失败,当前显示上次已知的议题。',
emptyTitle: '还没有工作区创建议题。',
emptyPrefix: '工作区可通过写入',
emptySuffixBeforeWhen: ' 来追踪议题;添加 ',
emptySuffixAfterWhen: ' 字段后即可自动调度。',
unreadableWorkspace: '无法读取此工作区的议题。',
openIssue: '打开 {{id}}',
assignOnFirstRun: '首次运行时指派',
duplicateOne: '名称重复——另有 1 个工作区也在使用。[[name]] 是全局句柄,请手动解决冲突。',
duplicateMany: '名称重复——另有 {{count}} 个工作区也在使用。[[name]] 是全局句柄,请手动解决冲突。',
duplicateLabel: '多个工作区存在同名议题',
duplicateShort: '重复',
workspaceTitle: '工作区:{{workspace}}({{id}})',
issueIdTitle: '议题 ID:{{id}}',
assigneeTitle: '负责人:{{assignee}}',
agentOverrideTitle: 'Agent 运行时覆盖:{{agent}}',
agentOverrideShort: '{{agent}} 覆盖',
collapseStatus: '折叠“{{status}}”议题',
expandStatus: '展开“{{status}}”议题',
status: {
in_progress: '进行中',
todo: '待办',
backlog: '待排期',
done: '已完成',
canceled: '已取消',
},
health: {
inactive: '未启用',
not_started: '尚未开始',
due: '等待运行',
running: '运行中',
healthy: '正常',
interrupted: '已中断',
failed: '失败',
blocked: '受阻',
},
priority: {
urgent: '紧急',
high: '高',
medium: '中',
low: '低',
none: '无',
label: '{{priority}}优先级',
},
cadence: {
custom: '按自定义计划重复',
customAt: '按自定义计划于 {{time}} 重复',
everyMinute: '每分钟',
everyHour: '每小时',
everyDuration: '每 {{duration}}',
everyDayAt: '每{{day}} {{time}}',
everyMonthDayAt: '每月 {{day}} 日 {{time}}',
day: '天',
weekday: '工作日',
weekend: '周末',
local: '本地',
localTime: '本地时间',
},
weekday: {
sun: '周日',
mon: '周一',
tue: '周二',
wed: '周三',
thu: '周四',
fri: '周五',
sat: '周六',
},
},
settings: {
title: '设置',
tab: {
Expand Down
Loading
Loading