UI: localize command palette labels (#72378)

This commit is contained in:
Vincent Koc
2026-04-26 14:58:16 -07:00
committed by GitHub
parent 364d49889e
commit 070b55f336
31 changed files with 472 additions and 78 deletions

View File

@@ -31,6 +31,7 @@ Docs: https://docs.openclaw.ai
- WhatsApp/Web: keep quiet but healthy linked-device sessions connected by basing the watchdog on WhatsApp Web transport activity, while retaining a longer app-silence cap so frame activity cannot mask a stuck session forever. Fixes #70678; carries forward the focused #71466 approach and keeps #63939 as related configurable-timeout follow-up. Thanks @vincentkoc and @oromeis.
- Discord/gateway: count failed health-monitor restart attempts toward cooldown and hourly caps, and evict stale account lifecycle state during channel reloads so repeated Discord gateway recovery cannot loop on old status. Fixes #38596. (#40413) Thanks @jellyAI-dev and @vashquez.
- Cron/context engine: run isolated cron jobs under run-scoped context-engine session keys so prior runs of the same job are not inherited unless the job is explicitly session-bound. (#72292) Thanks @jalehman.
- Control UI: localize command palette labels, categories, skill shortcuts, footer hints, and connect-command copy labels while preserving localized command palette search matching. (#61130, #61119) Thanks @rubensfox20.
## 2026.4.26

View File

@@ -1,11 +1,11 @@
{
"fallbackKeys": [],
"generatedAt": "2026-04-25T07:56:05.494Z",
"generatedAt": "2026-04-26T21:47:11.631Z",
"locale": "de",
"model": "gpt-5.5",
"provider": "openai",
"sourceHash": "2af900ae253948aab69216e38e0fce2dfde89801d178dee0ebb8dd28df2e11ef",
"totalKeys": 734,
"translatedKeys": 734,
"sourceHash": "0b1690213c6431759bd87ed8a231c4f523c79bac42dfac74028698fb18e7ebba",
"totalKeys": 752,
"translatedKeys": 752,
"workflow": 1
}

View File

@@ -1,11 +1,11 @@
{
"fallbackKeys": [],
"generatedAt": "2026-04-25T07:56:33.676Z",
"generatedAt": "2026-04-26T21:47:11.941Z",
"locale": "es",
"model": "gpt-5.5",
"provider": "openai",
"sourceHash": "2af900ae253948aab69216e38e0fce2dfde89801d178dee0ebb8dd28df2e11ef",
"totalKeys": 734,
"translatedKeys": 734,
"sourceHash": "0b1690213c6431759bd87ed8a231c4f523c79bac42dfac74028698fb18e7ebba",
"totalKeys": 752,
"translatedKeys": 752,
"workflow": 1
}

View File

@@ -1,11 +1,11 @@
{
"fallbackKeys": [],
"generatedAt": "2026-04-25T07:56:45.086Z",
"generatedAt": "2026-04-26T21:47:12.883Z",
"locale": "fr",
"model": "gpt-5.5",
"provider": "openai",
"sourceHash": "2af900ae253948aab69216e38e0fce2dfde89801d178dee0ebb8dd28df2e11ef",
"totalKeys": 734,
"translatedKeys": 734,
"sourceHash": "0b1690213c6431759bd87ed8a231c4f523c79bac42dfac74028698fb18e7ebba",
"totalKeys": 752,
"translatedKeys": 752,
"workflow": 1
}

View File

@@ -1,11 +1,11 @@
{
"fallbackKeys": [],
"generatedAt": "2026-04-25T07:57:25.463Z",
"generatedAt": "2026-04-26T21:47:13.865Z",
"locale": "id",
"model": "gpt-5.5",
"provider": "openai",
"sourceHash": "2af900ae253948aab69216e38e0fce2dfde89801d178dee0ebb8dd28df2e11ef",
"totalKeys": 734,
"translatedKeys": 734,
"sourceHash": "0b1690213c6431759bd87ed8a231c4f523c79bac42dfac74028698fb18e7ebba",
"totalKeys": 752,
"translatedKeys": 752,
"workflow": 1
}

View File

@@ -1,11 +1,11 @@
{
"fallbackKeys": [],
"generatedAt": "2026-04-25T07:56:47.425Z",
"generatedAt": "2026-04-26T21:47:12.252Z",
"locale": "ja-JP",
"model": "gpt-5.5",
"provider": "openai",
"sourceHash": "2af900ae253948aab69216e38e0fce2dfde89801d178dee0ebb8dd28df2e11ef",
"totalKeys": 734,
"translatedKeys": 734,
"sourceHash": "0b1690213c6431759bd87ed8a231c4f523c79bac42dfac74028698fb18e7ebba",
"totalKeys": 752,
"translatedKeys": 752,
"workflow": 1
}

View File

@@ -1,11 +1,11 @@
{
"fallbackKeys": [],
"generatedAt": "2026-04-25T07:56:44.197Z",
"generatedAt": "2026-04-26T21:47:12.563Z",
"locale": "ko",
"model": "gpt-5.5",
"provider": "openai",
"sourceHash": "2af900ae253948aab69216e38e0fce2dfde89801d178dee0ebb8dd28df2e11ef",
"totalKeys": 734,
"translatedKeys": 734,
"sourceHash": "0b1690213c6431759bd87ed8a231c4f523c79bac42dfac74028698fb18e7ebba",
"totalKeys": 752,
"translatedKeys": 752,
"workflow": 1
}

View File

@@ -1,11 +1,11 @@
{
"fallbackKeys": [],
"generatedAt": "2026-04-25T07:57:26.422Z",
"generatedAt": "2026-04-26T21:47:14.204Z",
"locale": "pl",
"model": "gpt-5.5",
"provider": "openai",
"sourceHash": "2af900ae253948aab69216e38e0fce2dfde89801d178dee0ebb8dd28df2e11ef",
"totalKeys": 734,
"translatedKeys": 734,
"sourceHash": "0b1690213c6431759bd87ed8a231c4f523c79bac42dfac74028698fb18e7ebba",
"totalKeys": 752,
"translatedKeys": 752,
"workflow": 1
}

View File

@@ -1,11 +1,11 @@
{
"fallbackKeys": [],
"generatedAt": "2026-04-25T07:56:04.004Z",
"generatedAt": "2026-04-26T21:47:11.305Z",
"locale": "pt-BR",
"model": "gpt-5.5",
"provider": "openai",
"sourceHash": "2af900ae253948aab69216e38e0fce2dfde89801d178dee0ebb8dd28df2e11ef",
"totalKeys": 734,
"translatedKeys": 734,
"sourceHash": "0b1690213c6431759bd87ed8a231c4f523c79bac42dfac74028698fb18e7ebba",
"totalKeys": 752,
"translatedKeys": 752,
"workflow": 1
}

View File

@@ -1,11 +1,11 @@
{
"fallbackKeys": [],
"generatedAt": "2026-04-25T07:57:38.352Z",
"generatedAt": "2026-04-26T21:47:14.524Z",
"locale": "th",
"model": "gpt-5.5",
"provider": "openai",
"sourceHash": "2af900ae253948aab69216e38e0fce2dfde89801d178dee0ebb8dd28df2e11ef",
"totalKeys": 734,
"translatedKeys": 734,
"sourceHash": "0b1690213c6431759bd87ed8a231c4f523c79bac42dfac74028698fb18e7ebba",
"totalKeys": 752,
"translatedKeys": 752,
"workflow": 1
}

View File

@@ -1,11 +1,11 @@
{
"fallbackKeys": [],
"generatedAt": "2026-04-25T07:57:03.203Z",
"generatedAt": "2026-04-26T21:47:13.204Z",
"locale": "tr",
"model": "gpt-5.5",
"provider": "openai",
"sourceHash": "2af900ae253948aab69216e38e0fce2dfde89801d178dee0ebb8dd28df2e11ef",
"totalKeys": 734,
"translatedKeys": 734,
"sourceHash": "0b1690213c6431759bd87ed8a231c4f523c79bac42dfac74028698fb18e7ebba",
"totalKeys": 752,
"translatedKeys": 752,
"workflow": 1
}

View File

@@ -1,11 +1,11 @@
{
"fallbackKeys": [],
"generatedAt": "2026-04-25T07:57:11.008Z",
"generatedAt": "2026-04-26T21:47:13.531Z",
"locale": "uk",
"model": "gpt-5.5",
"provider": "openai",
"sourceHash": "2af900ae253948aab69216e38e0fce2dfde89801d178dee0ebb8dd28df2e11ef",
"totalKeys": 734,
"translatedKeys": 734,
"sourceHash": "0b1690213c6431759bd87ed8a231c4f523c79bac42dfac74028698fb18e7ebba",
"totalKeys": 752,
"translatedKeys": 752,
"workflow": 1
}

View File

@@ -1,11 +1,11 @@
{
"fallbackKeys": [],
"generatedAt": "2026-04-25T07:56:08.786Z",
"generatedAt": "2026-04-26T21:47:10.673Z",
"locale": "zh-CN",
"model": "gpt-5.5",
"provider": "openai",
"sourceHash": "2af900ae253948aab69216e38e0fce2dfde89801d178dee0ebb8dd28df2e11ef",
"totalKeys": 734,
"translatedKeys": 734,
"sourceHash": "0b1690213c6431759bd87ed8a231c4f523c79bac42dfac74028698fb18e7ebba",
"totalKeys": 752,
"translatedKeys": 752,
"workflow": 1
}

View File

@@ -1,11 +1,11 @@
{
"fallbackKeys": [],
"generatedAt": "2026-04-25T07:56:00.104Z",
"generatedAt": "2026-04-26T21:47:10.990Z",
"locale": "zh-TW",
"model": "gpt-5.5",
"provider": "openai",
"sourceHash": "2af900ae253948aab69216e38e0fce2dfde89801d178dee0ebb8dd28df2e11ef",
"totalKeys": 734,
"translatedKeys": 734,
"sourceHash": "0b1690213c6431759bd87ed8a231c4f523c79bac42dfac74028698fb18e7ebba",
"totalKeys": 752,
"translatedKeys": 752,
"workflow": 1
}

View File

@@ -280,6 +280,8 @@ export const de: TranslationMap = {
tailscaleDocsLink: "Docs: Tailscale Serve",
insecureHttpDocsTitle: "Dokumentation zu unsicherem HTTP (öffnet sich in neuem Tab)",
insecureHttpDocsLink: "Docs: Unsicheres HTTP",
copyCommand: "Befehl kopieren",
copyCommandAria: "Befehl kopieren: {command}",
},
cards: {
cost: "Kosten",
@@ -316,6 +318,30 @@ export const de: TranslationMap = {
palette: {
placeholder: "Befehl eingeben…",
noResults: "Keine Ergebnisse",
categories: {
search: "Suchen",
navigation: "Navigation",
skills: "Skills",
},
items: {
overview: "Übersicht",
sessions: "Sitzungen",
scheduled: "Geplant",
skills: "Skills",
settings: "Einstellungen",
agents: "Agenten",
shellCommand: "Shell-Befehl",
debugMode: "Debug-Modus",
},
descriptions: {
shellCommand: "Shell ausführen",
debugMode: "Debug umschalten",
},
footer: {
navigate: "navigieren",
select: "auswählen",
close: "schließen",
},
},
},
dreaming: {

View File

@@ -271,6 +271,8 @@ export const en: TranslationMap = {
tailscaleDocsLink: "Docs: Tailscale Serve",
insecureHttpDocsTitle: "Insecure HTTP docs (opens in new tab)",
insecureHttpDocsLink: "Docs: Insecure HTTP",
copyCommand: "Copy command",
copyCommandAria: "Copy command: {command}",
},
cards: {
cost: "Cost",
@@ -306,6 +308,30 @@ export const en: TranslationMap = {
palette: {
placeholder: "Type a command…",
noResults: "No results",
categories: {
search: "Search",
navigation: "Navigation",
skills: "Skills",
},
items: {
overview: "Overview",
sessions: "Sessions",
scheduled: "Scheduled",
skills: "Skills",
settings: "Settings",
agents: "Agents",
shellCommand: "Shell Command",
debugMode: "Debug Mode",
},
descriptions: {
shellCommand: "Run shell",
debugMode: "Toggle debug",
},
footer: {
navigate: "navigate",
select: "select",
close: "close",
},
},
},
dreaming: {

View File

@@ -275,6 +275,8 @@ export const es: TranslationMap = {
tailscaleDocsLink: "Documentación: Tailscale Serve",
insecureHttpDocsTitle: "Documentación de HTTP inseguro (se abre en una pestaña nueva)",
insecureHttpDocsLink: "Documentación: HTTP inseguro",
copyCommand: "Copiar comando",
copyCommandAria: "Copiar comando: {command}",
},
cards: {
cost: "Costo",
@@ -310,6 +312,30 @@ export const es: TranslationMap = {
palette: {
placeholder: "Escribe un comando…",
noResults: "Sin resultados",
categories: {
search: "Buscar",
navigation: "Navegación",
skills: "Skills",
},
items: {
overview: "Resumen",
sessions: "Sesiones",
scheduled: "Programado",
skills: "Skills",
settings: "Configuración",
agents: "Agentes",
shellCommand: "Comando de shell",
debugMode: "Modo de depuración",
},
descriptions: {
shellCommand: "Ejecutar shell",
debugMode: "Alternar depuración",
},
footer: {
navigate: "navegar",
select: "seleccionar",
close: "cerrar",
},
},
},
dreaming: {

View File

@@ -279,6 +279,8 @@ export const fr: TranslationMap = {
tailscaleDocsLink: "Documentation : Tailscale Serve",
insecureHttpDocsTitle: "Documentation sur HTTP non sécurisé (souvre dans un nouvel onglet)",
insecureHttpDocsLink: "Documentation : HTTP non sécurisé",
copyCommand: "Copier la commande",
copyCommandAria: "Copier la commande : {command}",
},
cards: {
cost: "Coût",
@@ -314,6 +316,30 @@ export const fr: TranslationMap = {
palette: {
placeholder: "Saisissez une commande…",
noResults: "Aucun résultat",
categories: {
search: "Recherche",
navigation: "Navigation",
skills: "Skills",
},
items: {
overview: "Vue densemble",
sessions: "Sessions",
scheduled: "Planifié",
skills: "Skills",
settings: "Paramètres",
agents: "Agents",
shellCommand: "Commande shell",
debugMode: "Mode débogage",
},
descriptions: {
shellCommand: "Exécuter le shell",
debugMode: "Basculer le débogage",
},
footer: {
navigate: "naviguer",
select: "sélectionner",
close: "fermer",
},
},
},
dreaming: {

View File

@@ -275,6 +275,8 @@ export const id: TranslationMap = {
tailscaleDocsLink: "Dokumentasi: Tailscale Serve",
insecureHttpDocsTitle: "Dokumentasi HTTP tidak aman (dibuka di tab baru)",
insecureHttpDocsLink: "Dokumentasi: HTTP tidak aman",
copyCommand: "Salin perintah",
copyCommandAria: "Salin perintah: {command}",
},
cards: {
cost: "Biaya",
@@ -310,6 +312,30 @@ export const id: TranslationMap = {
palette: {
placeholder: "Ketik perintah…",
noResults: "Tidak ada hasil",
categories: {
search: "Cari",
navigation: "Navigasi",
skills: "Skills",
},
items: {
overview: "Ikhtisar",
sessions: "Sesi",
scheduled: "Terjadwal",
skills: "Skills",
settings: "Pengaturan",
agents: "Agen",
shellCommand: "Perintah shell",
debugMode: "Mode debug",
},
descriptions: {
shellCommand: "Jalankan shell",
debugMode: "Alihkan debug",
},
footer: {
navigate: "navigasi",
select: "pilih",
close: "tutup",
},
},
},
dreaming: {

View File

@@ -279,6 +279,8 @@ export const ja_JP: TranslationMap = {
tailscaleDocsLink: "ドキュメント: Tailscale Serve",
insecureHttpDocsTitle: "安全でない HTTP に関するドキュメント(新しいタブで開きます)",
insecureHttpDocsLink: "ドキュメント: 安全でない HTTP",
copyCommand: "コマンドをコピー",
copyCommandAria: "コマンドをコピー: {command}",
},
cards: {
cost: "コスト",
@@ -314,6 +316,30 @@ export const ja_JP: TranslationMap = {
palette: {
placeholder: "コマンドを入力…",
noResults: "結果がありません",
categories: {
search: "検索",
navigation: "ナビゲーション",
skills: "Skills",
},
items: {
overview: "概要",
sessions: "セッション",
scheduled: "スケジュール済み",
skills: "Skills",
settings: "設定",
agents: "エージェント",
shellCommand: "シェルコマンド",
debugMode: "デバッグモード",
},
descriptions: {
shellCommand: "シェルを実行",
debugMode: "デバッグを切り替え",
},
footer: {
navigate: "移動",
select: "選択",
close: "閉じる",
},
},
},
dreaming: {

View File

@@ -274,6 +274,8 @@ export const ko: TranslationMap = {
tailscaleDocsLink: "문서: Tailscale Serve",
insecureHttpDocsTitle: "안전하지 않은 HTTP 문서(새 탭에서 열림)",
insecureHttpDocsLink: "문서: 안전하지 않은 HTTP",
copyCommand: "명령 복사",
copyCommandAria: "명령 복사: {command}",
},
cards: {
cost: "비용",
@@ -309,6 +311,30 @@ export const ko: TranslationMap = {
palette: {
placeholder: "명령을 입력하세요…",
noResults: "결과 없음",
categories: {
search: "검색",
navigation: "탐색",
skills: "Skills",
},
items: {
overview: "개요",
sessions: "세션",
scheduled: "예약됨",
skills: "Skills",
settings: "설정",
agents: "에이전트",
shellCommand: "셸 명령",
debugMode: "디버그 모드",
},
descriptions: {
shellCommand: "셸 실행",
debugMode: "디버그 전환",
},
footer: {
navigate: "탐색",
select: "선택",
close: "닫기",
},
},
},
dreaming: {

View File

@@ -276,6 +276,8 @@ export const pl: TranslationMap = {
tailscaleDocsLink: "Dokumentacja: Tailscale Serve",
insecureHttpDocsTitle: "Dokumentacja niezabezpieczonego HTTP (otwiera się w nowej karcie)",
insecureHttpDocsLink: "Dokumentacja: Niezabezpieczone HTTP",
copyCommand: "Kopiuj polecenie",
copyCommandAria: "Kopiuj polecenie: {command}",
},
cards: {
cost: "Koszt",
@@ -312,6 +314,30 @@ export const pl: TranslationMap = {
palette: {
placeholder: "Wpisz polecenie…",
noResults: "Brak wyników",
categories: {
search: "Szukaj",
navigation: "Nawigacja",
skills: "Skills",
},
items: {
overview: "Przegląd",
sessions: "Sesje",
scheduled: "Zaplanowane",
skills: "Skills",
settings: "Ustawienia",
agents: "Agenci",
shellCommand: "Polecenie powłoki",
debugMode: "Tryb debugowania",
},
descriptions: {
shellCommand: "Uruchom powłokę",
debugMode: "Przełącz debugowanie",
},
footer: {
navigate: "nawiguj",
select: "wybierz",
close: "zamknij",
},
},
},
dreaming: {

View File

@@ -275,6 +275,8 @@ export const pt_BR: TranslationMap = {
tailscaleDocsLink: "Docs: Tailscale Serve",
insecureHttpDocsTitle: "Documentação de HTTP inseguro (abre em nova aba)",
insecureHttpDocsLink: "Docs: HTTP inseguro",
copyCommand: "Copiar comando",
copyCommandAria: "Copiar comando: {command}",
},
cards: {
cost: "Custo",
@@ -310,6 +312,30 @@ export const pt_BR: TranslationMap = {
palette: {
placeholder: "Digite um comando…",
noResults: "Sem resultados",
categories: {
search: "Pesquisar",
navigation: "Navegação",
skills: "Skills",
},
items: {
overview: "Visão geral",
sessions: "Sessões",
scheduled: "Agendado",
skills: "Skills",
settings: "Configurações",
agents: "Agentes",
shellCommand: "Comando de shell",
debugMode: "Modo de depuração",
},
descriptions: {
shellCommand: "Executar shell",
debugMode: "Alternar depuração",
},
footer: {
navigate: "navegar",
select: "selecionar",
close: "fechar",
},
},
},
dreaming: {

View File

@@ -268,6 +268,8 @@ export const th: TranslationMap = {
tailscaleDocsLink: "เอกสาร: Tailscale Serve",
insecureHttpDocsTitle: "เอกสาร HTTP ที่ไม่ปลอดภัย (เปิดในแท็บใหม่)",
insecureHttpDocsLink: "เอกสาร: HTTP ที่ไม่ปลอดภัย",
copyCommand: "คัดลอกคำสั่ง",
copyCommandAria: "คัดลอกคำสั่ง: {command}",
},
cards: {
cost: "ค่าใช้จ่าย",
@@ -303,6 +305,30 @@ export const th: TranslationMap = {
palette: {
placeholder: "พิมพ์คำสั่ง…",
noResults: "ไม่พบผลลัพธ์",
categories: {
search: "ค้นหา",
navigation: "การนำทาง",
skills: "ทักษะ",
},
items: {
overview: "ภาพรวม",
sessions: "เซสชัน",
scheduled: "กำหนดเวลาแล้ว",
skills: "ทักษะ",
settings: "การตั้งค่า",
agents: "เอเจนต์",
shellCommand: "คำสั่งเชลล์",
debugMode: "โหมดดีบัก",
},
descriptions: {
shellCommand: "เรียกใช้เชลล์",
debugMode: "สลับดีบัก",
},
footer: {
navigate: "นำทาง",
select: "เลือก",
close: "ปิด",
},
},
},
dreaming: {

View File

@@ -279,6 +279,8 @@ export const tr: TranslationMap = {
tailscaleDocsLink: "Belgeler: Tailscale Serve",
insecureHttpDocsTitle: "Güvenli olmayan HTTP belgeleri (yeni sekmede açılır)",
insecureHttpDocsLink: "Belgeler: Güvenli olmayan HTTP",
copyCommand: "Komutu kopyala",
copyCommandAria: "Komutu kopyala: {command}",
},
cards: {
cost: "Maliyet",
@@ -315,6 +317,30 @@ export const tr: TranslationMap = {
palette: {
placeholder: "Bir komut yazın…",
noResults: "Sonuç yok",
categories: {
search: "Arama",
navigation: "Navigation",
skills: "Skills",
},
items: {
overview: "Genel Bakış",
sessions: "Oturumlar",
scheduled: "Zamanlanmış",
skills: "Skills",
settings: "Ayarlar",
agents: "Ajanlar",
shellCommand: "Shell Komutu",
debugMode: "Hata Ayıklama Modu",
},
descriptions: {
shellCommand: "Shell çalıştır",
debugMode: "Hata ayıklamayı değiştir",
},
footer: {
navigate: "gezin",
select: "seç",
close: "kapat",
},
},
},
dreaming: {

View File

@@ -277,6 +277,8 @@ export const uk: TranslationMap = {
tailscaleDocsLink: "Документація: Tailscale Serve",
insecureHttpDocsTitle: "Документація щодо незахищеного HTTP (відкривається в новій вкладці)",
insecureHttpDocsLink: "Документація: незахищений HTTP",
copyCommand: "Копіювати команду",
copyCommandAria: "Копіювати команду: {command}",
},
cards: {
cost: "Вартість",
@@ -313,6 +315,30 @@ export const uk: TranslationMap = {
palette: {
placeholder: "Введіть команду…",
noResults: "Немає результатів",
categories: {
search: "Пошук",
navigation: "Навігація",
skills: "Навички",
},
items: {
overview: "Огляд",
sessions: "Сеанси",
scheduled: "Заплановано",
skills: "Навички",
settings: "Налаштування",
agents: "Агенти",
shellCommand: "Команда оболонки",
debugMode: "Режим налагодження",
},
descriptions: {
shellCommand: "Запустити оболонку",
debugMode: "Перемкнути налагодження",
},
footer: {
navigate: "навігація",
select: "вибрати",
close: "закрити",
},
},
},
dreaming: {

View File

@@ -268,6 +268,8 @@ export const zh_CN: TranslationMap = {
tailscaleDocsLink: "文档Tailscale Serve",
insecureHttpDocsTitle: "不安全 HTTP 文档(在新标签页中打开)",
insecureHttpDocsLink: "文档:不安全 HTTP",
copyCommand: "复制命令",
copyCommandAria: "复制命令:{command}",
},
cards: {
cost: "费用",
@@ -303,6 +305,30 @@ export const zh_CN: TranslationMap = {
palette: {
placeholder: "输入命令…",
noResults: "无结果",
categories: {
search: "搜索",
navigation: "导航",
skills: "技能",
},
items: {
overview: "概览",
sessions: "会话",
scheduled: "已计划",
skills: "技能",
settings: "设置",
agents: "代理",
shellCommand: "Shell 命令",
debugMode: "调试模式",
},
descriptions: {
shellCommand: "运行 shell",
debugMode: "切换调试",
},
footer: {
navigate: "导航",
select: "选择",
close: "关闭",
},
},
},
dreaming: {

View File

@@ -268,6 +268,8 @@ export const zh_TW: TranslationMap = {
tailscaleDocsLink: "文件Tailscale Serve",
insecureHttpDocsTitle: "不安全 HTTP 文件(在新分頁中開啟)",
insecureHttpDocsLink: "文件:不安全 HTTP",
copyCommand: "複製指令",
copyCommandAria: "複製指令:{command}",
},
cards: {
cost: "費用",
@@ -303,6 +305,30 @@ export const zh_TW: TranslationMap = {
palette: {
placeholder: "輸入指令…",
noResults: "無結果",
categories: {
search: "搜尋",
navigation: "導覽",
skills: "技能",
},
items: {
overview: "概覽",
sessions: "工作階段",
scheduled: "已排程",
skills: "技能",
settings: "設定",
agents: "代理",
shellCommand: "Shell 指令",
debugMode: "偵錯模式",
},
descriptions: {
shellCommand: "執行 shell",
debugMode: "切換偵錯",
},
footer: {
navigate: "導覽",
select: "選取",
close: "關閉",
},
},
},
dreaming: {

View File

@@ -1,9 +1,11 @@
import { afterEach, describe, expect, it } from "vitest";
import { i18n } from "../../i18n/index.ts";
import { refreshSlashCommands, resetSlashCommandsForTest } from "../chat/slash-commands.ts";
import { getPaletteItems } from "./command-palette.ts";
import { getFilteredPaletteItems, getPaletteItems } from "./command-palette.ts";
afterEach(() => {
afterEach(async () => {
resetSlashCommandsForTest();
await i18n.setLocale("en");
});
describe("command palette", () => {
@@ -51,4 +53,20 @@ describe("command palette", () => {
}),
);
});
it("matches localized base item labels and descriptions", async () => {
await i18n.setLocale("zh-CN");
expect(getPaletteItems()).toContainEqual(
expect.objectContaining({
id: "nav-config",
label: "设置",
}),
);
expect(getFilteredPaletteItems("切换调试")).toContainEqual(
expect.objectContaining({
id: "skill-debug",
}),
);
});
});

View File

@@ -29,61 +29,61 @@ function getPaletteBaseItems(): PaletteItem[] {
return [
{
id: "nav-overview",
label: "Overview",
label: t("overview.palette.items.overview"),
icon: "barChart",
category: "navigation",
action: "nav:overview",
},
{
id: "nav-sessions",
label: "Sessions",
label: t("overview.palette.items.sessions"),
icon: "fileText",
category: "navigation",
action: "nav:sessions",
},
{
id: "nav-cron",
label: "Scheduled",
label: t("overview.palette.items.scheduled"),
icon: "scrollText",
category: "navigation",
action: "nav:cron",
},
{
id: "nav-skills",
label: "Skills",
label: t("overview.palette.items.skills"),
icon: "zap",
category: "navigation",
action: "nav:skills",
},
{
id: "nav-config",
label: "Settings",
label: t("overview.palette.items.settings"),
icon: "settings",
category: "navigation",
action: "nav:config",
},
{
id: "nav-agents",
label: "Agents",
label: t("overview.palette.items.agents"),
icon: "folder",
category: "navigation",
action: "nav:agents",
},
{
id: "skill-shell",
label: "Shell Command",
label: t("overview.palette.items.shellCommand"),
icon: "monitor",
category: "skills",
action: "/skill shell",
description: "Run shell",
description: t("overview.palette.descriptions.shellCommand"),
},
{
id: "skill-debug",
label: "Debug Mode",
label: t("overview.palette.items.debugMode"),
icon: "bug",
category: "skills",
action: "/verbose full",
description: "Toggle debug",
description: t("overview.palette.descriptions.debugMode"),
},
];
}
@@ -120,6 +120,10 @@ function filteredItems(query: string): PaletteItem[] {
);
}
export function getFilteredPaletteItems(query: string): readonly PaletteItem[] {
return filteredItems(query);
}
function groupItems(items: PaletteItem[]): Array<[string, PaletteItem[]]> {
const map = new Map<string, PaletteItem[]>();
for (const item of items) {
@@ -190,11 +194,18 @@ function handleKeydown(e: KeyboardEvent, props: CommandPaletteProps) {
}
}
const CATEGORY_LABELS: Record<string, string> = {
search: "Search",
navigation: "Navigation",
skills: "Skills",
};
function getCategoryLabel(category: string): string {
switch (category) {
case "search":
return t("overview.palette.categories.search");
case "navigation":
return t("overview.palette.categories.navigation");
case "skills":
return t("overview.palette.categories.skills");
default:
return category;
}
}
function focusInput(el: Element | undefined) {
if (el) {
@@ -244,9 +255,7 @@ export function renderCommandPalette(props: CommandPaletteProps) {
</div>`
: grouped.map(
([category, groupedItems]) => html`
<div class="cmd-palette__group-label">
${CATEGORY_LABELS[category] ?? category}
</div>
<div class="cmd-palette__group-label">${getCategoryLabel(category)}</div>
${groupedItems.map((item) => {
const globalIndex = items.indexOf(item);
const isActive = globalIndex === props.activeIndex;
@@ -273,9 +282,9 @@ export function renderCommandPalette(props: CommandPaletteProps) {
)}
</div>
<div class="cmd-palette__footer">
<span><kbd>↑↓</kbd> navigate</span>
<span><kbd>↵</kbd> select</span>
<span><kbd>esc</kbd> close</span>
<span><kbd>↑↓</kbd> ${t("overview.palette.footer.navigate")}</span>
<span><kbd>↵</kbd> ${t("overview.palette.footer.select")}</span>
<span><kbd>esc</kbd> ${t("overview.palette.footer.close")}</span>
</div>
</div>
</div>

View File

@@ -1,4 +1,5 @@
import { html } from "lit";
import { t } from "../../i18n/index.ts";
import { renderCopyButton } from "../chat/copy-as-markdown.ts";
async function copyCommand(command: string) {
@@ -10,13 +11,14 @@ async function copyCommand(command: string) {
}
export function renderConnectCommand(command: string) {
const copyLabel = t("overview.connection.copyCommand");
return html`
<div
class="login-gate__command"
role="button"
tabindex="0"
title="Copy command"
aria-label=${`Copy command: ${command}`}
title=${copyLabel}
aria-label=${t("overview.connection.copyCommandAria", { command })}
@click=${async (e: Event) => {
if ((e.target as HTMLElement | null)?.closest(".chat-copy-btn")) {
return;
@@ -32,7 +34,7 @@ export function renderConnectCommand(command: string) {
}}
>
<code>${command}</code>
${renderCopyButton(command, "Copy command")}
${renderCopyButton(command, copyLabel)}
</div>
`;
}