Skip to content

Commit 5df4ed8

Browse files
committed
feat(i18n): migrate UI components to use i18next for localization
- Updated ContextPage, DashboardPage, DependenciesPage, ProjectsPage, SpecDetailPage, SpecsPage, and StatsPage to utilize i18next for translations. - Added translation keys for various UI elements, error messages, and empty states across multiple pages. - Enhanced user experience by providing localized content for different languages, including English and Chinese. - Improved error handling messages and descriptions for better clarity and user guidance.
1 parent e83231d commit 5df4ed8

File tree

12 files changed

+404
-125
lines changed

12 files changed

+404
-125
lines changed

packages/ui-vite/src/locales/en/common.json

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,11 @@
5757
"loading": "Loading...",
5858
"search": "Search",
5959
"backToTop": "Back to top",
60-
"openSidebar": "Open sidebar"
60+
"openSidebar": "Open sidebar",
61+
"validate": "Validate",
62+
"remove": "Remove",
63+
"report": "Report",
64+
"open": "Open"
6165
},
6266
"spec": {
6367
"spec": "Spec",
@@ -88,15 +92,19 @@
8892
"switchProject": "Switch Project",
8993
"createProject": "Create Project",
9094
"manageProjects": "Manage Projects",
91-
"selectProject": "Select Project"
95+
"selectProject": "Select Project",
96+
"description": "Manage your LeanSpec workspaces.",
97+
"colorLabel": "Color",
98+
"validationFailed": "Validation failed"
9299
},
93100
"quickSearch": {
94101
"button": "Quick search...",
95102
"placeholder": "Search specs by title, number, or tags...",
96103
"recentSearches": "Recent Searches",
97104
"filterHeading": "Filter by Tag",
98105
"filterPrefix": "Filter by:",
99-
"open": "Open quick search"
106+
"open": "Open quick search",
107+
"noResults": "No results found"
100108
},
101109
"projectSwitcher": {
102110
"switching": "Switching...",
@@ -232,6 +240,18 @@
232240
"toasts": {
233241
"statusUpdated": "Moved {{spec}} to {{status}}",
234242
"statusError": "Unable to update status. Please try again."
243+
},
244+
"state": {
245+
"errorTitle": "Unable to load specs",
246+
"errorDescription": "Please try again or refresh your project.",
247+
"noSpecsTitle": "No specs yet",
248+
"noSpecsDescription": "We could not find any specs for this project. Add a spec in your LeanSpec workspace, then refresh to see it here.",
249+
"noFiltersTitle": "No specs match your filters",
250+
"noFiltersDescription": "Try clearing filters or adjusting your search to see more specs."
251+
},
252+
"buttons": {
253+
"refreshList": "Refresh list",
254+
"reloadData": "Reload data"
235255
}
236256
},
237257
"specDetail": {
@@ -263,7 +283,17 @@
263283
},
264284
"state": {
265285
"loading": "Loading...",
266-
"error": "Error loading spec"
286+
"error": "Error loading spec",
287+
"unavailableTitle": "Spec unavailable",
288+
"unavailableDescription": "This spec could not be found. It may have been moved or deleted."
289+
},
290+
"dependencies": {
291+
"dependsOn": "Depends on",
292+
"requiredBy": "Required by"
293+
},
294+
"links": {
295+
"backToSpecs": "Back to specs",
296+
"reportIssue": "Report issue"
267297
}
268298
},
269299
"statsPage": {
@@ -305,6 +335,11 @@
305335
"description": "Most frequently used tags"
306336
},
307337
"label": "{{name}}: {{value}}"
338+
},
339+
"state": {
340+
"errorTitle": "Unable to load statistics",
341+
"errorDescription": "Please try again or refresh your project.",
342+
"unknownError": "Unknown error"
308343
}
309344
},
310345
"dashboard": {
@@ -327,7 +362,11 @@
327362
"quickActions": "Quick Actions",
328363
"viewAllSpecs": "View All Specs",
329364
"viewStats": "View Stats",
330-
"actionUpdated": "updated"
365+
"actionUpdated": "updated",
366+
"state": {
367+
"errorTitle": "Unable to load dashboard",
368+
"errorDescription": "Please refresh or try again."
369+
}
331370
},
332371
"contextPage": {
333372
"title": "Project Context",
@@ -440,6 +479,9 @@
440479
"dependenciesPage": {
441480
"header": {
442481
"title": "Dependency Graph",
482+
"specTitle": "Dependencies for {{specName}}",
483+
"allTitle": "All Dependencies",
484+
"countSummary": "{{specs}} specs, {{relationships}} relationships",
443485
"summary": {
444486
"connected": "{{count}} specs with dependencies",
445487
"standalone": "{{count}} standalone",
@@ -459,18 +501,40 @@
459501
"clear": "Clear",
460502
"count": "({{count}})"
461503
},
504+
"view": {
505+
"graph": "Graph",
506+
"list": "List"
507+
},
508+
"state": {
509+
"loading": "Loading dependencies...",
510+
"errorTitle": "Unable to load dependencies",
511+
"errorDescription": "Please check your connection and try again."
512+
},
462513
"empty": {
463514
"title": "No dependencies to display",
464515
"filters": "No specs match the current filters",
465-
"standaloneHint": "Enable \"Show Standalone\" to see specs without dependencies"
516+
"standaloneHint": "Enable \"Show Standalone\" to see specs without dependencies",
517+
"noDependencies": "No dependencies yet",
518+
"noDependenciesDescription": "Specs are present but no dependency relationships were found. Add depends_on links to see the graph."
466519
},
467520
"legend": {
468521
"dependsOn": "Depends On (arrow shows direction)",
469522
"instructions": "Click: select • Double-click: open • Drag to rearrange"
470523
},
471524
"graph": {
472525
"levelTitle": "Level {{depth}}",
473-
"levelBadge": "L{{depth}}"
526+
"levelBadge": "L{{depth}}",
527+
"instructions": "Click on a node to view spec details. Use mouse wheel to zoom, drag to pan."
528+
},
529+
"list": {
530+
"specsTitle": "Specs ({{count}})",
531+
"relationshipsTitle": "Relationships ({{count}})",
532+
"noRelationships": "No relationships yet. Add depends_on or required_by references in your specs to visualize them here.",
533+
"dependsOn": "↓ depends on",
534+
"requiredBy": "↑ required by"
535+
},
536+
"actions": {
537+
"goToSpecs": "Go to specs"
474538
},
475539
"sidebar": {
476540
"emptyTitle": "Select a spec",

packages/ui-vite/src/locales/zh-CN/common.json

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
"collapse": "收起",
99
"closeMenu": "关闭菜单",
1010
"dashboard": "仪表板",
11-
"filteredCount": "{{filtered}} / {{total}} 个 Spec",
1211
"allSpecifications": "所有 Spec",
1312
"dependencyGraph": "依赖图",
1413
"analytics": "数据分析",
@@ -58,7 +57,11 @@
5857
"loading": "加载中...",
5958
"search": "搜索",
6059
"backToTop": "返回顶部",
61-
"openSidebar": "打开侧边栏"
60+
"openSidebar": "打开侧边栏",
61+
"validate": "校验",
62+
"remove": "移除",
63+
"report": "报告",
64+
"open": "打开"
6265
},
6366
"spec": {
6467
"spec": "Spec",
@@ -89,15 +92,19 @@
8992
"switchProject": "切换项目",
9093
"createProject": "创建项目",
9194
"manageProjects": "管理项目",
92-
"selectProject": "选择项目"
95+
"selectProject": "选择项目",
96+
"description": "管理你的 LeanSpec 工作区。",
97+
"colorLabel": "颜色",
98+
"validationFailed": "校验失败"
9399
},
94100
"quickSearch": {
95101
"button": "快速搜索...",
96102
"placeholder": "按标题、编号或标签搜索 Spec...",
97103
"recentSearches": "最近搜索",
98104
"filterHeading": "按标签筛选",
99105
"filterPrefix": "筛选:",
100-
"open": "打开快速搜索"
106+
"open": "打开快速搜索",
107+
"noResults": "未找到结果"
101108
},
102109
"projectSwitcher": {
103110
"switching": "正在切换...",
@@ -208,6 +215,7 @@
208215
"sort": "排序",
209216
"statusAll": "全部状态",
210217
"priorityAll": "全部优先级",
218+
"filteredCount": "{{filtered}} / {{total}} 个 Spec",
211219
"sortOptions": {
212220
"id-desc": "最新优先",
213221
"id-asc": "最旧优先",
@@ -232,6 +240,18 @@
232240
"toasts": {
233241
"statusUpdated": "已将 {{spec}} 移动到 {{status}}",
234242
"statusError": "无法更新状态,请稍后重试。"
243+
},
244+
"state": {
245+
"errorTitle": "无法加载 Spec",
246+
"errorDescription": "请重试或刷新项目。",
247+
"noSpecsTitle": "暂无 Spec",
248+
"noSpecsDescription": "未找到任何 Spec。请在 LeanSpec 工作区添加后刷新。",
249+
"noFiltersTitle": "没有匹配当前筛选条件的 Spec",
250+
"noFiltersDescription": "尝试清除筛选条件或调整搜索。"
251+
},
252+
"buttons": {
253+
"refreshList": "刷新列表",
254+
"reloadData": "重新加载"
235255
}
236256
},
237257
"specDetail": {
@@ -263,7 +283,17 @@
263283
},
264284
"state": {
265285
"loading": "正在加载...",
266-
"error": "无法加载 Spec"
286+
"error": "无法加载 Spec",
287+
"unavailableTitle": "Spec 无法访问",
288+
"unavailableDescription": "无法找到该 Spec,可能已被移动或删除。"
289+
},
290+
"dependencies": {
291+
"dependsOn": "依赖",
292+
"requiredBy": "被依赖"
293+
},
294+
"links": {
295+
"backToSpecs": "返回 Spec 列表",
296+
"reportIssue": "报告问题"
267297
}
268298
},
269299
"statsPage": {
@@ -276,9 +306,7 @@
276306
},
277307
"completed": {
278308
"title": "已完成",
279-
"modified": "修改于 {{date}}",
280-
"size": "{{size}} KB",
281-
"selectFile": "选择文件以查看内容"
309+
"subtitle": "完成率"
282310
},
283311
"inProgress": {
284312
"title": "进行中",
@@ -307,6 +335,11 @@
307335
"description": "使用最频繁的标签"
308336
},
309337
"label": "{{name}}:{{value}}"
338+
},
339+
"state": {
340+
"errorTitle": "无法加载统计数据",
341+
"errorDescription": "请重试或刷新项目。",
342+
"unknownError": "未知错误"
310343
}
311344
},
312345
"dashboard": {
@@ -329,7 +362,11 @@
329362
"quickActions": "快捷操作",
330363
"viewAllSpecs": "查看所有 Spec",
331364
"viewStats": "查看统计",
332-
"actionUpdated": "已更新"
365+
"actionUpdated": "已更新",
366+
"state": {
367+
"errorTitle": "无法加载仪表板",
368+
"errorDescription": "请刷新页面或稍后再试。"
369+
}
333370
},
334371
"contextPage": {
335372
"title": "项目上下文",
@@ -442,6 +479,9 @@
442479
"dependenciesPage": {
443480
"header": {
444481
"title": "依赖关系图",
482+
"specTitle": "{{specName}} 的依赖",
483+
"allTitle": "所有依赖",
484+
"countSummary": "{{specs}} 个 Spec,{{relationships}} 条关系",
445485
"summary": {
446486
"connected": "{{count}} 个 Spec 存在依赖",
447487
"standalone": "{{count}} 个独立项",
@@ -461,18 +501,40 @@
461501
"clear": "重置",
462502
"count": "({{count}})"
463503
},
504+
"view": {
505+
"graph": "",
506+
"list": "列表"
507+
},
508+
"state": {
509+
"loading": "正在加载依赖...",
510+
"errorTitle": "无法加载依赖",
511+
"errorDescription": "请检查网络后重试。"
512+
},
464513
"empty": {
465514
"title": "暂无依赖可显示",
466515
"filters": "没有 Spec 满足当前筛选条件",
467-
"standaloneHint": "开启「显示独立项」即可查看未建立依赖的 Spec"
516+
"standaloneHint": "开启「显示独立项」即可查看未建立依赖的 Spec",
517+
"noDependencies": "暂无依赖",
518+
"noDependenciesDescription": "找到了 Spec,但尚未设置依赖关系。添加 depends_on 以查看依赖图。"
468519
},
469520
"legend": {
470521
"dependsOn": "依赖方向(箭头表示指向)",
471522
"instructions": "点击:选中 • 双击:打开 • 拖动:重新布局"
472523
},
473524
"graph": {
474525
"levelTitle": "第 {{depth}} 层",
475-
"levelBadge": "L{{depth}}"
526+
"levelBadge": "L{{depth}}",
527+
"instructions": "单击节点查看详情;滚轮缩放,拖拽平移。"
528+
},
529+
"list": {
530+
"specsTitle": "Spec 列表 ({{count}})",
531+
"relationshipsTitle": "关系 ({{count}})",
532+
"noRelationships": "尚无依赖或被依赖关系。添加 depends_on 或 required_by 来可视化。",
533+
"dependsOn": "↓ 依赖",
534+
"requiredBy": "↑ 被依赖"
535+
},
536+
"actions": {
537+
"goToSpecs": "前往 Spec 列表"
476538
},
477539
"sidebar": {
478540
"emptyTitle": "请选择一个 Spec",

packages/ui-vite/src/pages/ContextPage.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import { Card, CardContent } from '@leanspec/ui-components';
33
import { ContextClient } from '../components/context/ContextClient';
44
import { ContextPageSkeleton } from '../components/shared/Skeletons';
55
import { useProject } from '../contexts';
6+
import { useTranslation } from 'react-i18next';
67

78
export function ContextPage() {
89
const { currentProject, loading, error } = useProject();
10+
const { t } = useTranslation(['common', 'errors']);
911

1012
if (loading) {
1113
return <ContextPageSkeleton />;
@@ -18,8 +20,8 @@ export function ContextPage() {
1820
<div className="flex justify-center">
1921
<AlertCircle className="h-6 w-6 text-destructive" />
2022
</div>
21-
<div className="text-lg font-semibold">Project unavailable</div>
22-
<p className="text-sm text-muted-foreground">{error}</p>
23+
<div className="text-lg font-semibold">{t('projectNotFound', { ns: 'errors' })}</div>
24+
<p className="text-sm text-muted-foreground">{error || t('errors.loadingError', { ns: 'errors' })}</p>
2325
</CardContent>
2426
</Card>
2527
);
@@ -28,9 +30,9 @@ export function ContextPage() {
2830
return (
2931
<div className="space-y-6">
3032
<div className="space-y-1">
31-
<h1 className="text-3xl sm:text-4xl font-bold tracking-tight">Project Context</h1>
33+
<h1 className="text-3xl sm:text-4xl font-bold tracking-tight">{t('contextPage.title')}</h1>
3234
<p className="text-muted-foreground text-sm">
33-
Browse contextual files from .lean-spec/context with search, preview, and markdown rendering.
35+
{t('contextPage.description')}
3436
</p>
3537
</div>
3638

packages/ui-vite/src/pages/DashboardPage.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ import { useProject } from '../contexts';
66
import { DashboardClient } from '../components/dashboard/DashboardClient';
77
import type { DashboardSpec } from '../components/dashboard/SpecListItem';
88
import { DashboardSkeleton } from '../components/shared/Skeletons';
9+
import { useTranslation } from 'react-i18next';
910

1011
export function DashboardPage() {
1112
const { currentProject } = useProject();
1213
const [specs, setSpecs] = useState<DashboardSpec[]>([]);
1314
const [stats, setStats] = useState<Stats | null>(null);
1415
const [loading, setLoading] = useState(true);
1516
const [error, setError] = useState<string | null>(null);
17+
const { t } = useTranslation('common');
1618
const projectColor = currentProject && 'color' in currentProject ? (currentProject as { color?: string }).color : undefined;
1719
const basePath = currentProject?.id ? `/projects/${currentProject.id}` : '/projects/default';
1820

@@ -49,10 +51,10 @@ export function DashboardPage() {
4951
<div className="flex justify-center">
5052
<AlertCircle className="h-6 w-6 text-destructive" />
5153
</div>
52-
<div className="text-lg font-semibold">Unable to load dashboard</div>
53-
<p className="text-sm text-muted-foreground">{error}</p>
54+
<div className="text-lg font-semibold">{t('dashboard.state.errorTitle')}</div>
55+
<p className="text-sm text-muted-foreground">{error || t('dashboard.state.errorDescription')}</p>
5456
<Button variant="secondary" size="sm" onClick={loadData} className="mt-2">
55-
Retry
57+
{t('actions.retry')}
5658
</Button>
5759
</CardContent>
5860
</Card>

0 commit comments

Comments
 (0)