UI: localize Logs tab labels (#92820)

Repair #61080 by routing Logs tab user-facing labels through Control UI locale keys while keeping export filename suffixes stable.

Validation:
- pnpm ui:i18n:check
- pnpm check:changed
- ui/src/ui/views/logs.test.ts
- Codex /review
- GitHub PR checks

Source PR credit: continues @rubensfox20's work from https://github.com/openclaw/openclaw/pull/61080.

Co-authored-by: rubensfox20 <111531429+rubensfox20@users.noreply.github.com>
This commit is contained in:
openclaw-clownfish[bot]
2026-06-14 09:23:00 +08:00
committed by GitHub
parent b3dc274034
commit 971542b7f6
40 changed files with 659 additions and 117 deletions
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:38.611Z",
"generatedAt": "2026-06-14T00:56:11.191Z",
"locale": "ar",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:38.187Z",
"generatedAt": "2026-06-14T00:56:10.731Z",
"locale": "de",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:38.275Z",
"generatedAt": "2026-06-14T00:56:10.822Z",
"locale": "es",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:39.387Z",
"generatedAt": "2026-06-14T00:56:12.036Z",
"locale": "fa",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:38.527Z",
"generatedAt": "2026-06-14T00:56:11.096Z",
"locale": "fr",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:38.953Z",
"generatedAt": "2026-06-14T00:56:11.562Z",
"locale": "id",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:38.697Z",
"generatedAt": "2026-06-14T00:56:11.279Z",
"locale": "it",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:38.361Z",
"generatedAt": "2026-06-14T00:56:10.912Z",
"locale": "ja-JP",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:38.446Z",
"generatedAt": "2026-06-14T00:56:11.005Z",
"locale": "ko",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:39.305Z",
"generatedAt": "2026-06-14T00:56:11.940Z",
"locale": "nl",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:39.039Z",
"generatedAt": "2026-06-14T00:56:11.653Z",
"locale": "pl",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:38.104Z",
"generatedAt": "2026-06-14T00:56:10.631Z",
"locale": "pt-BR",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
-49
View File
@@ -3984,55 +3984,6 @@
"path": "ui/src/ui/views/login-gate.ts",
"text": "OpenClaw"
},
{
"count": 1,
"kind": "html-attribute",
"name": "placeholder",
"path": "ui/src/ui/views/logs.ts",
"text": "Search logs"
},
{
"count": 1,
"kind": "html-text",
"name": "text",
"path": "ui/src/ui/views/logs.ts",
"text": "Auto-follow"
},
{
"count": 1,
"kind": "html-text",
"name": "text",
"path": "ui/src/ui/views/logs.ts",
"text": "Filter"
},
{
"count": 1,
"kind": "html-text",
"name": "text",
"path": "ui/src/ui/views/logs.ts",
"text": "Gateway file logs (JSONL)."
},
{
"count": 1,
"kind": "html-text",
"name": "text",
"path": "ui/src/ui/views/logs.ts",
"text": "Log output truncated; showing latest chunk."
},
{
"count": 1,
"kind": "html-text",
"name": "text",
"path": "ui/src/ui/views/logs.ts",
"text": "Logs"
},
{
"count": 1,
"kind": "html-text",
"name": "text",
"path": "ui/src/ui/views/logs.ts",
"text": "No log entries."
},
{
"count": 1,
"kind": "html-attribute",
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:39.135Z",
"generatedAt": "2026-06-14T00:56:11.747Z",
"locale": "th",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:38.778Z",
"generatedAt": "2026-06-14T00:56:11.372Z",
"locale": "tr",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:38.861Z",
"generatedAt": "2026-06-14T00:56:11.468Z",
"locale": "uk",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:39.223Z",
"generatedAt": "2026-06-14T00:56:11.843Z",
"locale": "vi",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:37.909Z",
"generatedAt": "2026-06-14T00:56:10.441Z",
"locale": "zh-CN",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+14 -3
View File
@@ -11,6 +11,17 @@
"chat.workspaceFiles.workspace",
"cron.jobDetail.command",
"cron.jobDetail.cwd",
"logsView.autoFollow",
"logsView.empty",
"logsView.exportButton",
"logsView.exportLabels.filtered",
"logsView.exportLabels.visible",
"logsView.file",
"logsView.filter",
"logsView.searchPlaceholder",
"logsView.subtitle",
"logsView.title",
"logsView.truncated",
"skillWorkshop.header.useCurrentChat",
"skillWorkshop.header.useCurrentChatAria",
"skillWorkshop.header.useCurrentChatTooltip",
@@ -43,12 +54,12 @@
"workboard.unknownStatus",
"workboard.viewDetails"
],
"generatedAt": "2026-06-13T21:58:38.020Z",
"generatedAt": "2026-06-14T00:56:10.535Z",
"locale": "zh-TW",
"model": "claude-opus-4-8",
"provider": "anthropic",
"sourceHash": "642a382824b6637e6eea0d3fbccd04b135194675db6bb9a0a1bacbf6424bd870",
"totalKeys": 1345,
"sourceHash": "d0b2c5f7e87d471ad2373c4ea8875db08c9bab459b4c4c5573e5eff03ee5be12",
"totalKeys": 1356,
"translatedKeys": 1303,
"workflow": 1
}
+15
View File
@@ -493,6 +493,21 @@ export const ar: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "لوحة العمل معطّلة. فعّل",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -498,6 +498,21 @@ export const de: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard ist deaktiviert. Aktivieren Sie",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -492,6 +492,21 @@ export const en: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard is disabled. Enable",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -495,6 +495,21 @@ export const es: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard está desactivado. Activa",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -495,6 +495,21 @@ export const fa: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard غیرفعال است. فعال کنید",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -497,6 +497,21 @@ export const fr: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Le tableau de travail est désactivé. Activez",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -494,6 +494,21 @@ export const id: TranslationMap = {
minutes: "{minutes}m {seconds}dtk",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard dinonaktifkan. Aktifkan",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -496,6 +496,21 @@ export const it: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard è disabilitata. Abilita",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -497,6 +497,21 @@ export const ja_JP: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard は無効になっています。有効にするには",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -493,6 +493,21 @@ export const ko: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard가 비활성화되어 있습니다. 활성화하려면",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -496,6 +496,21 @@ export const nl: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard is uitgeschakeld. Schakel",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -495,6 +495,21 @@ export const pl: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard jest wyłączony. Włącz",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -494,6 +494,21 @@ export const pt_BR: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "O Workboard está desativado. Ative",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -492,6 +492,21 @@ export const th: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard ถูกปิดใช้งาน เปิดใช้งาน",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -497,6 +497,21 @@ export const tr: TranslationMap = {
minutes: "{minutes} dk {seconds} sn",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard devre dışı. Etkinleştirin",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -496,6 +496,21 @@ export const uk: TranslationMap = {
minutes: "{minutes}хв {seconds}с",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard вимкнено. Увімкніть",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -495,6 +495,21 @@ export const vi: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard đã bị tắt. Bật",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -491,6 +491,21 @@ export const zh_CN: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard 已禁用。启用",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+15
View File
@@ -491,6 +491,21 @@ export const zh_TW: TranslationMap = {
minutes: "{minutes}m {seconds}s",
},
},
logsView: {
title: "Logs",
subtitle: "Gateway file logs (JSONL).",
exportButton: "Export {label}",
exportLabels: {
filtered: "filtered",
visible: "visible",
},
filter: "Filter",
searchPlaceholder: "Search logs",
autoFollow: "Auto-follow",
file: "File: {file}",
truncated: "Log output truncated; showing latest chunk.",
empty: "No log entries.",
},
workboard: {
disabledHelpStart: "Workboard 已停用。啟用",
enableConfigKey: "plugins.entries.workboard.enabled = true",
+106
View File
@@ -0,0 +1,106 @@
/* @vitest-environment jsdom */
import { render } from "lit";
import { afterEach, describe, expect, it, vi } from "vitest";
import { i18n } from "../../i18n/index.ts";
import { pt_BR } from "../../i18n/locales/pt-BR.ts";
import type { LogLevel } from "../types.ts";
import { renderLogs, type LogsProps } from "./logs.ts";
function createLevelFilters(overrides: Partial<Record<LogLevel, boolean>> = {}) {
return {
trace: true,
debug: true,
info: true,
warn: true,
error: true,
fatal: true,
...overrides,
};
}
function createProps(overrides: Partial<LogsProps> = {}): LogsProps {
return {
loading: false,
error: null,
file: null,
entries: [
{
raw: '{"level":"info","message":"matched line"}',
time: "2026-06-14T12:00:00Z",
level: "info",
subsystem: "gateway",
message: "matched line",
},
],
filterText: "",
levelFilters: createLevelFilters(),
autoFollow: true,
truncated: false,
onFilterTextChange: vi.fn(),
onLevelToggle: vi.fn(),
onToggleAutoFollow: vi.fn(),
onRefresh: vi.fn(),
onExport: vi.fn(),
onScroll: vi.fn(),
...overrides,
};
}
function buttonByText(container: Element, text: string): HTMLButtonElement {
const button = Array.from(container.querySelectorAll("button")).find(
(candidate) => candidate.textContent?.replace(/\s+/g, " ").trim() === text,
);
if (!(button instanceof HTMLButtonElement)) {
throw new Error(`Expected ${text} button`);
}
return button;
}
async function useTestPortugueseLogsLabels() {
i18n.registerTranslation("pt-BR", {
logsView: {
title: "Registros",
subtitle: "Registros do Gateway em JSONL.",
exportButton: "Exportar {label}",
exportLabels: {
filtered: "filtrado",
visible: "visivel",
},
filter: "Filtro",
searchPlaceholder: "Pesquisar registros",
autoFollow: "Acompanhar automaticamente",
file: "Arquivo: {file}",
truncated: "Saida truncada.",
empty: "Nenhuma entrada.",
},
});
await i18n.setLocale("pt-BR");
}
afterEach(async () => {
i18n.registerTranslation("pt-BR", pt_BR);
await i18n.setLocale("en");
});
describe("renderLogs", () => {
it.each([
{ buttonText: "Exportar visivel", expectedLabel: "visible", filterText: "" },
{ buttonText: "Exportar filtrado", expectedLabel: "filtered", filterText: "matched" },
])(
"keeps the $expectedLabel export filename suffix stable when labels are localized",
async ({ buttonText, expectedLabel, filterText }) => {
await useTestPortugueseLogsLabels();
const onExport = vi.fn();
const container = document.createElement("div");
render(renderLogs(createProps({ filterText, onExport })), container);
buttonByText(container, buttonText).click();
expect(onExport).toHaveBeenCalledWith(
['{"level":"info","message":"matched line"}'],
expectedLabel,
);
},
);
});
+16 -14
View File
@@ -5,6 +5,7 @@ import { normalizeLowercaseStringOrEmpty } from "../string-coerce.ts";
import type { LogEntry, LogLevel } from "../types.ts";
const LEVELS: LogLevel[] = ["trace", "debug", "info", "warn", "error", "fatal"];
type ExportFileLabel = "filtered" | "visible";
export type LogsProps = {
loading: boolean;
@@ -53,14 +54,15 @@ export function renderLogs(props: LogsProps) {
}
return matchesFilter(entry, needle);
});
const exportLabel = needle || levelFiltered ? "filtered" : "visible";
const exportFileLabel: ExportFileLabel = needle || levelFiltered ? "filtered" : "visible";
const exportDisplayLabel = t(`logsView.exportLabels.${exportFileLabel}`);
return html`
<section class="card card--fill-height">
<div class="row" style="justify-content: space-between;">
<div>
<div class="card-title">Logs</div>
<div class="card-sub">Gateway file logs (JSONL).</div>
<div class="card-title">${t("logsView.title")}</div>
<div class="card-sub">${t("logsView.subtitle")}</div>
</div>
<div class="row" style="gap: 8px;">
<button class="btn" ?disabled=${props.loading} @click=${props.onRefresh}>
@@ -72,25 +74,25 @@ export function renderLogs(props: LogsProps) {
@click=${() =>
props.onExport(
filtered.map((entry) => entry.raw),
exportLabel,
exportFileLabel,
)}
>
Export ${exportLabel}
${t("logsView.exportButton", { label: exportDisplayLabel })}
</button>
</div>
</div>
<div class="filters" style="margin-top: 14px;">
<label class="field" style="min-width: 220px;">
<span>Filter</span>
<span>${t("logsView.filter")}</span>
<input
.value=${props.filterText}
@input=${(e: Event) => props.onFilterTextChange((e.target as HTMLInputElement).value)}
placeholder="Search logs"
placeholder=${t("logsView.searchPlaceholder")}
/>
</label>
<label class="field checkbox">
<span>Auto-follow</span>
<span>${t("logsView.autoFollow")}</span>
<input
type="checkbox"
.checked=${props.autoFollow}
@@ -117,22 +119,22 @@ export function renderLogs(props: LogsProps) {
</div>
${props.file
? html`<div class="muted" style="margin-top: 10px;">File: ${props.file}</div>`
: nothing}
${props.truncated
? html`
<div class="callout" style="margin-top: 10px">
Log output truncated; showing latest chunk.
<div class="muted" style="margin-top: 10px;">
${t("logsView.file", { file: props.file })}
</div>
`
: nothing}
${props.truncated
? html` <div class="callout" style="margin-top: 10px">${t("logsView.truncated")}</div> `
: nothing}
${props.error
? html`<div class="callout danger" style="margin-top: 10px;">${props.error}</div>`
: nothing}
<div class="log-stream" style="margin-top: 12px;" @scroll=${props.onScroll}>
${filtered.length === 0
? html` <div class="muted" style="padding: 12px">No log entries.</div> `
? html` <div class="muted" style="padding: 12px">${t("logsView.empty")}</div> `
: filtered.map(
(entry) => html`
<div class="log-row">