diff --git a/README.md b/README.md index 1783a7f..dd5add0 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Use all OpenCode features from a familiar sidebar chat UI. - Settings panel - Keyboard navigation for inline popups (Tab / Arrow keys) - Subtask display -- i18n support (English, Japanese) +- i18n support (English, Japanese, Simplified Chinese, Korean, Traditional Chinese, Spanish, Brazilian Portuguese, Russian) ### Requirements @@ -204,7 +204,7 @@ OpenCode の全機能をサイドバーのチャット UI から操作できま - 設定パネル - インラインポップアップのキーボードナビゲーション(Tab / 矢印キー) - サブタスク表示 -- 多言語対応(英語、日本語) +- 多言語対応(英語、日本語、簡体字中国語、韓国語、繁体字中国語、スペイン語、ブラジルポルトガル語、ロシア語) ### 必要条件 diff --git a/package.nls.es.json b/package.nls.es.json new file mode 100644 index 0000000..46c38af --- /dev/null +++ b/package.nls.es.json @@ -0,0 +1,4 @@ +{ + "displayName": "OpenCodeGUI", + "description": "[Experimental / No oficial] Una interfaz de chat en la barra lateral de VS Code para OpenCode. Esta extensión se desarrolla principalmente mediante codificación asistida por IA y se proporciona tal cual, sin garantía. No está afiliada ni respaldada por el proyecto OpenCode." +} diff --git a/package.nls.ko.json b/package.nls.ko.json new file mode 100644 index 0000000..d6fc043 --- /dev/null +++ b/package.nls.ko.json @@ -0,0 +1,4 @@ +{ + "displayName": "OpenCodeGUI", + "description": "【실험적·비공식】OpenCode용 VS Code 사이드바 채팅 인터페이스. 이 확장 프로그램은 주로 AI 보조 코딩을 통해 개발되었으며 어떠한 보증 없이 있는 그대로 제공됩니다. OpenCode 프로젝트와 제휴 또는 보증 관계가 없습니다." +} diff --git a/package.nls.pt-br.json b/package.nls.pt-br.json new file mode 100644 index 0000000..cdbb03f --- /dev/null +++ b/package.nls.pt-br.json @@ -0,0 +1,4 @@ +{ + "displayName": "OpenCodeGUI", + "description": "[Experimental / Não oficial] Uma interface de chat na barra lateral do VS Code para o OpenCode. Esta extensão é desenvolvida principalmente por meio de codificação assistida por IA e fornecida como está, sem garantia. Não é afiliada nem endossada pelo projeto OpenCode." +} diff --git a/package.nls.ru.json b/package.nls.ru.json new file mode 100644 index 0000000..4d33a80 --- /dev/null +++ b/package.nls.ru.json @@ -0,0 +1,4 @@ +{ + "displayName": "OpenCodeGUI", + "description": "[Экспериментальное / Неофициальное] Интерфейс чата в боковой панели VS Code для OpenCode. Это расширение разработано преимущественно с помощью ИИ и предоставляется «как есть» без каких-либо гарантий. Не связано с проектом OpenCode и не одобрено им." +} diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json new file mode 100644 index 0000000..0d9120b --- /dev/null +++ b/package.nls.zh-cn.json @@ -0,0 +1,4 @@ +{ + "displayName": "OpenCodeGUI", + "description": "【实验性·非官方】OpenCode 的 VS Code 侧边栏聊天界面。本扩展主要通过 AI 辅助编码开发,按原样提供,不含任何保证。与 OpenCode 项目无关联或背书关系。" +} diff --git a/package.nls.zh-tw.json b/package.nls.zh-tw.json new file mode 100644 index 0000000..965f482 --- /dev/null +++ b/package.nls.zh-tw.json @@ -0,0 +1,4 @@ +{ + "displayName": "OpenCodeGUI", + "description": "【實驗性·非官方】OpenCode 的 VS Code 側邊欄聊天介面。本擴充功能主要透過 AI 輔助編碼開發,按原樣提供,不含任何保證。與 OpenCode 專案無關聯或背書關係。" +} diff --git a/webview/__tests__/components/organisms/ToolConfigPanel.test.tsx b/webview/__tests__/components/organisms/ToolConfigPanel.test.tsx index 4e66f98..1e524a6 100644 --- a/webview/__tests__/components/organisms/ToolConfigPanel.test.tsx +++ b/webview/__tests__/components/organisms/ToolConfigPanel.test.tsx @@ -25,10 +25,10 @@ describe("ToolConfigPanel", () => { expect(container.querySelector(".muted.sm")).toBeInTheDocument(); }); - // renders language options + // renders language options (auto + 8 locales = 9) it("言語オプションをレンダリングすること", () => { const { container } = render(); - expect(container.querySelectorAll("input[name='locale']")).toHaveLength(3); + expect(container.querySelectorAll("input[name='locale']")).toHaveLength(9); }); }); diff --git a/webview/__tests__/hooks/useLocale.test.ts b/webview/__tests__/hooks/useLocale.test.ts index f7be8f1..95620e4 100644 --- a/webview/__tests__/hooks/useLocale.test.ts +++ b/webview/__tests__/hooks/useLocale.test.ts @@ -59,4 +59,109 @@ describe("useLocale", () => { expect(result.current.resolvedLocale).toBe("ja"); }); }); + + // resolveLocale for zh-cn + context("setVscodeLanguage で 'zh-cn' を設定した場合", () => { + // resolves to zh-cn + it("resolvedLocale が 'zh-cn' になること", () => { + const { result } = renderHook(() => useLocale()); + act(() => result.current.setVscodeLanguage("zh-cn")); + expect(result.current.resolvedLocale).toBe("zh-cn"); + }); + }); + + // resolveLocale for ko + context("setVscodeLanguage で 'ko' を設定した場合", () => { + // resolves to ko + it("resolvedLocale が 'ko' になること", () => { + const { result } = renderHook(() => useLocale()); + act(() => result.current.setVscodeLanguage("ko")); + expect(result.current.resolvedLocale).toBe("ko"); + }); + }); + + // resolveLocale for zh-tw + context("setVscodeLanguage で 'zh-tw' を設定した場合", () => { + // resolves to zh-tw + it("resolvedLocale が 'zh-tw' になること", () => { + const { result } = renderHook(() => useLocale()); + act(() => result.current.setVscodeLanguage("zh-tw")); + expect(result.current.resolvedLocale).toBe("zh-tw"); + }); + }); + + // resolveLocale for es + context("setVscodeLanguage で 'es' を設定した場合", () => { + // resolves to es + it("resolvedLocale が 'es' になること", () => { + const { result } = renderHook(() => useLocale()); + act(() => result.current.setVscodeLanguage("es")); + expect(result.current.resolvedLocale).toBe("es"); + }); + }); + + // resolveLocale for pt-br + context("setVscodeLanguage で 'pt-br' を設定した場合", () => { + // resolves to pt-br + it("resolvedLocale が 'pt-br' になること", () => { + const { result } = renderHook(() => useLocale()); + act(() => result.current.setVscodeLanguage("pt-br")); + expect(result.current.resolvedLocale).toBe("pt-br"); + }); + }); + + // resolveLocale for ru + context("setVscodeLanguage で 'ru' を設定した場合", () => { + // resolves to ru + it("resolvedLocale が 'ru' になること", () => { + const { result } = renderHook(() => useLocale()); + act(() => result.current.setVscodeLanguage("ru")); + expect(result.current.resolvedLocale).toBe("ru"); + }); + }); + + // handleLocaleSettingChange with new locales + context("handleLocaleSettingChange で直接ロケールを指定した場合", () => { + // sets zh-cn directly + it("resolvedLocale が 'zh-cn' になること", () => { + const { result } = renderHook(() => useLocale()); + act(() => result.current.handleLocaleSettingChange("zh-cn")); + expect(result.current.resolvedLocale).toBe("zh-cn"); + }); + + // sets ko directly + it("resolvedLocale が 'ko' になること", () => { + const { result } = renderHook(() => useLocale()); + act(() => result.current.handleLocaleSettingChange("ko")); + expect(result.current.resolvedLocale).toBe("ko"); + }); + + // sets zh-tw directly + it("resolvedLocale が 'zh-tw' になること", () => { + const { result } = renderHook(() => useLocale()); + act(() => result.current.handleLocaleSettingChange("zh-tw")); + expect(result.current.resolvedLocale).toBe("zh-tw"); + }); + + // sets es directly + it("resolvedLocale が 'es' になること", () => { + const { result } = renderHook(() => useLocale()); + act(() => result.current.handleLocaleSettingChange("es")); + expect(result.current.resolvedLocale).toBe("es"); + }); + + // sets pt-br directly + it("resolvedLocale が 'pt-br' になること", () => { + const { result } = renderHook(() => useLocale()); + act(() => result.current.handleLocaleSettingChange("pt-br")); + expect(result.current.resolvedLocale).toBe("pt-br"); + }); + + // sets ru directly + it("resolvedLocale が 'ru' になること", () => { + const { result } = renderHook(() => useLocale()); + act(() => result.current.handleLocaleSettingChange("ru")); + expect(result.current.resolvedLocale).toBe("ru"); + }); + }); }); diff --git a/webview/components/organisms/ToolConfigPanel/ToolConfigPanel.tsx b/webview/components/organisms/ToolConfigPanel/ToolConfigPanel.tsx index 62dbd1b..8a62516 100644 --- a/webview/components/organisms/ToolConfigPanel/ToolConfigPanel.tsx +++ b/webview/components/organisms/ToolConfigPanel/ToolConfigPanel.tsx @@ -30,9 +30,18 @@ export function ToolConfigPanel({ paths, onOpenConfigFile, onClose, localeSettin
{t["config.language"]}
- {(["auto", "en", "ja"] as const).map((opt) => { - const label = - opt === "auto" ? t["config.langAuto"] : opt === "en" ? t["config.langEn"] : t["config.langJa"]; + {(["auto", "en", "ja", "zh-cn", "ko", "zh-tw", "es", "pt-br", "ru"] as const).map((opt) => { + const labelMap = { + auto: t["config.langAuto"], + en: t["config.langEn"], + ja: t["config.langJa"], + "zh-cn": t["config.langZhCn"], + ko: t["config.langKo"], + "zh-tw": t["config.langZhTw"], + es: t["config.langEs"], + "pt-br": t["config.langPtBr"], + ru: t["config.langRu"], + } as const; return ( ); })} diff --git a/webview/locales/en.ts b/webview/locales/en.ts index d6c3f73..4dac4d1 100644 --- a/webview/locales/en.ts +++ b/webview/locales/en.ts @@ -105,6 +105,12 @@ export const en = { "config.langAuto": "Auto (VS Code)", "config.langEn": "English", "config.langJa": "日本語", + "config.langZhCn": "简体中文", + "config.langKo": "한국어", + "config.langZhTw": "繁體中文", + "config.langEs": "Español", + "config.langPtBr": "Português (Brasil)", + "config.langRu": "Русский", // FileChangesHeader "fileChanges.title": "File Changes", diff --git a/webview/locales/es.ts b/webview/locales/es.ts new file mode 100644 index 0000000..cf2cc65 --- /dev/null +++ b/webview/locales/es.ts @@ -0,0 +1,139 @@ +import type { en } from "./en"; + +export const es: typeof en = { + // ChatHeader + "header.sessions": "Sesiones", + "header.title.fallback": "OpenCode", + "header.newChat": "Nuevo chat", + + // EmptyState + "empty.title": "OpenCode", + "empty.description": "Inicia una nueva conversación para comenzar.", + "empty.newChat": "Nuevo chat", + + // InputArea + "input.addContext": "Añadir contexto", + "input.searchFiles": "Buscar archivos...", + "input.noFiles": "No se encontraron archivos", + "input.remove": "Eliminar", + "input.placeholder": "Pregunta a OpenCode... (escribe # para adjuntar archivos)", + "input.addFile": (name: string) => `Añadir ${name}`, + "input.openTerminal": "Abrir sesión en terminal", + "input.shellMode": "Modo Shell", + "input.placeholder.shell": "Ingresa un comando de shell...", + "input.settings": "Configuración", + "input.stop": "Detener", + "input.send": "Enviar", + + // MessageItem + "message.fileFallback": "archivo", + "message.clickToEdit": "Haz clic para editar", + "message.cancel": "Cancelar", + "message.send": "Enviar", + "message.thought": "Pensamiento", + "message.thinking": "Pensando…", + "message.toggleThought": "Alternar detalles de pensamiento", + + // MessagesArea + "checkpoint.revertTitle": "Revertir a este punto", + "checkpoint.retryFromHere": "Reintentar desde aquí", + "checkpoint.forkFromHere": "Bifurcar desde aquí", + + // Undo/Redo + "header.undo": "Deshacer", + "header.redo": "Rehacer", + + // PermissionView + "permission.allow": "Permitir", + "permission.once": "Solo una vez", + "permission.deny": "Denegar", + + // SessionList + "session.noSessions": "Sin sesiones", + "session.untitled": "Sin título", + "session.delete": "Eliminar", + "session.select": "Seleccionar sesión", + + // Time (relative) + "time.now": "ahora", + "time.minutes": (n: number) => `${n}min`, + "time.hours": (n: number) => `${n}h`, + "time.days": (n: number) => `${n}d`, + + // ToolPartView - category labels + "tool.read": "Leer", + "tool.edit": "Editar", + "tool.create": "Crear", + "tool.run": "Ejecutar", + "tool.search": "Buscar", + "tool.tool": "Herramienta", + "tool.toggleDetails": "Alternar detalles", + "tool.completed": (done: number, total: number) => `${done}/${total} completados`, + "tool.moreLines": (n: number) => `… +${n} líneas más`, + "tool.addLines": (n: number) => `+${n} líneas`, + "tool.todos": (done: number, total: number) => `${done}/${total} tareas`, + + // ModelSelector + "model.selectModel": "Seleccionar modelo", + "model.notConnected": "No conectado", + "model.connectedOnly": "Solo conectados", + "model.showAll": "Mostrar todos los proveedores", + "model.hideDisconnected": "Ocultar proveedores desconectados", + + // TodoHeader + "todo.label": "Tareas", + "todo.toggleList": "Alternar lista de tareas", + + // ContextIndicator + "context.title": (percent: number) => `Contexto: ${percent}% usado`, + "context.windowUsage": "Uso de ventana de contexto", + "context.inputTokens": "Tokens de entrada", + "context.contextLimit": "Límite de contexto", + "context.compressing": "Comprimiendo...", + "context.compress": "Comprimir conversación", + + // ShellResultView + "shell.title": "Shell", + + // ToolConfigPanel + "config.title": "Configuración", + "config.projectConfig": "Configuración del proyecto", + "config.globalConfig": "Configuración global", + + "config.close": "Cerrar", + + // Language setting + "config.language": "Idioma", + "config.langAuto": "Automático (VS Code)", + "config.langEn": "English", + "config.langJa": "日本語", + "config.langZhCn": "简体中文", + "config.langKo": "한국어", + "config.langZhTw": "繁體中文", + "config.langEs": "Español", + "config.langPtBr": "Português (Brasil)", + "config.langRu": "Русский", + + // FileChangesHeader + "fileChanges.title": "Cambios de archivos", + "fileChanges.noChanges": "Sin cambios de archivos", + "fileChanges.openDiff": "Abrir en editor de diferencias", + "fileChanges.toggle": "Cambios de archivos", + + // Share + "share.share": "Compartir sesión", + "share.unshare": "Dejar de compartir", + "share.copied": "URL de compartir copiada al portapapeles", + + // ChildSession + "childSession.agent": "Agente", + "childSession.backToParent": "Volver a la sesión principal", + + // Context menu sections + "input.section.files": "Archivos", + "input.section.agents": "Agentes", + "input.section.shell": "Modo Shell", + + // AgentMention + "input.noAgents": "No hay agentes disponibles", +}; diff --git a/webview/locales/index.ts b/webview/locales/index.ts index f34e0af..ab79986 100644 --- a/webview/locales/index.ts +++ b/webview/locales/index.ts @@ -1,16 +1,37 @@ import { createContext, useContext } from "react"; import { en } from "./en"; +import { es } from "./es"; import { ja } from "./ja"; +import { ko } from "./ko"; +import { ptBr } from "./pt-br"; +import { ru } from "./ru"; +import { zhCn } from "./zh-cn"; +import { zhTw } from "./zh-tw"; -export type SupportedLocale = "en" | "ja"; +export type SupportedLocale = "en" | "ja" | "zh-cn" | "ko" | "zh-tw" | "es" | "pt-br" | "ru"; export type LocaleSetting = "auto" | SupportedLocale; -const locales: Record = { en, ja }; +const locales: Record = { + en, + ja, + "zh-cn": zhCn, + ko, + "zh-tw": zhTw, + es, + "pt-br": ptBr, + ru, +}; export function resolveLocale(setting: LocaleSetting, vscodeLanguage: string): SupportedLocale { if (setting !== "auto") return setting; - // vscode.env.language は "ja", "en", "zh-cn" など + // vscode.env.language は "ja", "en", "zh-cn", "zh-tw", "ko", "es", "pt-br", "ru" など if (vscodeLanguage.startsWith("ja")) return "ja"; + if (vscodeLanguage === "zh-cn") return "zh-cn"; + if (vscodeLanguage === "zh-tw") return "zh-tw"; + if (vscodeLanguage.startsWith("ko")) return "ko"; + if (vscodeLanguage.startsWith("es")) return "es"; + if (vscodeLanguage === "pt-br") return "pt-br"; + if (vscodeLanguage.startsWith("ru")) return "ru"; return "en"; } diff --git a/webview/locales/ja.ts b/webview/locales/ja.ts index 010816c..77137d7 100644 --- a/webview/locales/ja.ts +++ b/webview/locales/ja.ts @@ -107,6 +107,12 @@ export const ja: typeof en = { "config.langAuto": "自動 (VS Code)", "config.langEn": "English", "config.langJa": "日本語", + "config.langZhCn": "简体中文", + "config.langKo": "한국어", + "config.langZhTw": "繁體中文", + "config.langEs": "Español", + "config.langPtBr": "Português (Brasil)", + "config.langRu": "Русский", // FileChangesHeader "fileChanges.title": "ファイル変更", diff --git a/webview/locales/ko.ts b/webview/locales/ko.ts new file mode 100644 index 0000000..92a1e8e --- /dev/null +++ b/webview/locales/ko.ts @@ -0,0 +1,139 @@ +import type { en } from "./en"; + +export const ko: typeof en = { + // ChatHeader + "header.sessions": "세션 목록", + "header.title.fallback": "OpenCode", + "header.newChat": "새 채팅", + + // EmptyState + "empty.title": "OpenCode", + "empty.description": "새 대화를 시작하세요.", + "empty.newChat": "새 채팅", + + // InputArea + "input.addContext": "컨텍스트 추가", + "input.searchFiles": "파일 검색...", + "input.noFiles": "파일을 찾을 수 없습니다", + "input.remove": "제거", + "input.placeholder": "OpenCode에 질문하기... (# 으로 파일 첨부)", + "input.addFile": (name: string) => `${name} 추가`, + "input.openTerminal": "터미널에서 세션 열기", + "input.shellMode": "셸 모드", + "input.placeholder.shell": "셸 명령어 입력...", + "input.settings": "설정", + "input.stop": "중지", + "input.send": "전송", + + // MessageItem + "message.fileFallback": "파일", + "message.clickToEdit": "클릭하여 편집", + "message.cancel": "취소", + "message.send": "전송", + "message.thought": "사고", + "message.thinking": "사고 중…", + "message.toggleThought": "사고 상세 전환", + + // MessagesArea + "checkpoint.revertTitle": "이 지점으로 되돌리기", + "checkpoint.retryFromHere": "여기서 다시 시도", + "checkpoint.forkFromHere": "여기서 분기", + + // Undo/Redo + "header.undo": "실행 취소", + "header.redo": "다시 실행", + + // PermissionView + "permission.allow": "허용", + "permission.once": "한 번만", + "permission.deny": "거부", + + // SessionList + "session.noSessions": "세션 없음", + "session.untitled": "제목 없음", + "session.delete": "삭제", + "session.select": "세션 선택", + + // Time (relative) + "time.now": "방금", + "time.minutes": (n: number) => `${n}분`, + "time.hours": (n: number) => `${n}시간`, + "time.days": (n: number) => `${n}일`, + + // ToolPartView - category labels + "tool.read": "읽기", + "tool.edit": "편집", + "tool.create": "생성", + "tool.run": "실행", + "tool.search": "검색", + "tool.tool": "도구", + "tool.toggleDetails": "상세 전환", + "tool.completed": (done: number, total: number) => `${done}/${total} 완료`, + "tool.moreLines": (n: number) => `… +${n}줄 더`, + "tool.addLines": (n: number) => `+${n}줄`, + "tool.todos": (done: number, total: number) => `${done}/${total} 할 일`, + + // ModelSelector + "model.selectModel": "모델 선택", + "model.notConnected": "연결 안 됨", + "model.connectedOnly": "연결됨만", + "model.showAll": "모든 제공자 표시", + "model.hideDisconnected": "연결 안 된 제공자 숨기기", + + // TodoHeader + "todo.label": "할 일", + "todo.toggleList": "할 일 목록 전환", + + // ContextIndicator + "context.title": (percent: number) => `컨텍스트: ${percent}% 사용 중`, + "context.windowUsage": "컨텍스트 윈도우 사용량", + "context.inputTokens": "입력 토큰", + "context.contextLimit": "컨텍스트 한도", + "context.compressing": "압축 중...", + "context.compress": "대화 압축", + + // ShellResultView + "shell.title": "셸", + + // ToolConfigPanel + "config.title": "설정", + "config.projectConfig": "프로젝트 설정", + "config.globalConfig": "전역 설정", + + "config.close": "닫기", + + // Language setting + "config.language": "언어", + "config.langAuto": "자동 (VS Code)", + "config.langEn": "English", + "config.langJa": "日本語", + "config.langZhCn": "简体中文", + "config.langKo": "한국어", + "config.langZhTw": "繁體中文", + "config.langEs": "Español", + "config.langPtBr": "Português (Brasil)", + "config.langRu": "Русский", + + // FileChangesHeader + "fileChanges.title": "파일 변경", + "fileChanges.noChanges": "파일 변경 없음", + "fileChanges.openDiff": "차이 편집기에서 열기", + "fileChanges.toggle": "파일 변경", + + // Share + "share.share": "세션 공유", + "share.unshare": "공유 해제", + "share.copied": "공유 URL이 클립보드에 복사되었습니다", + + // ChildSession + "childSession.agent": "에이전트", + "childSession.backToParent": "상위 세션으로 돌아가기", + + // Context menu sections + "input.section.files": "파일", + "input.section.agents": "에이전트", + "input.section.shell": "셸 모드", + + // AgentMention + "input.noAgents": "사용 가능한 에이전트가 없습니다", +}; diff --git a/webview/locales/pt-br.ts b/webview/locales/pt-br.ts new file mode 100644 index 0000000..1c530ad --- /dev/null +++ b/webview/locales/pt-br.ts @@ -0,0 +1,139 @@ +import type { en } from "./en"; + +export const ptBr: typeof en = { + // ChatHeader + "header.sessions": "Sessões", + "header.title.fallback": "OpenCode", + "header.newChat": "Novo chat", + + // EmptyState + "empty.title": "OpenCode", + "empty.description": "Inicie uma nova conversa para começar.", + "empty.newChat": "Novo chat", + + // InputArea + "input.addContext": "Adicionar contexto", + "input.searchFiles": "Pesquisar arquivos...", + "input.noFiles": "Nenhum arquivo encontrado", + "input.remove": "Remover", + "input.placeholder": "Pergunte ao OpenCode... (digite # para anexar arquivos)", + "input.addFile": (name: string) => `Adicionar ${name}`, + "input.openTerminal": "Abrir sessão no terminal", + "input.shellMode": "Modo Shell", + "input.placeholder.shell": "Digite um comando shell...", + "input.settings": "Configurações", + "input.stop": "Parar", + "input.send": "Enviar", + + // MessageItem + "message.fileFallback": "arquivo", + "message.clickToEdit": "Clique para editar", + "message.cancel": "Cancelar", + "message.send": "Enviar", + "message.thought": "Pensamento", + "message.thinking": "Pensando…", + "message.toggleThought": "Alternar detalhes do pensamento", + + // MessagesArea + "checkpoint.revertTitle": "Reverter para este ponto", + "checkpoint.retryFromHere": "Tentar novamente daqui", + "checkpoint.forkFromHere": "Ramificar daqui", + + // Undo/Redo + "header.undo": "Desfazer", + "header.redo": "Refazer", + + // PermissionView + "permission.allow": "Permitir", + "permission.once": "Apenas uma vez", + "permission.deny": "Negar", + + // SessionList + "session.noSessions": "Sem sessões", + "session.untitled": "Sem título", + "session.delete": "Excluir", + "session.select": "Selecionar sessão", + + // Time (relative) + "time.now": "agora", + "time.minutes": (n: number) => `${n}min`, + "time.hours": (n: number) => `${n}h`, + "time.days": (n: number) => `${n}d`, + + // ToolPartView - category labels + "tool.read": "Ler", + "tool.edit": "Editar", + "tool.create": "Criar", + "tool.run": "Executar", + "tool.search": "Pesquisar", + "tool.tool": "Ferramenta", + "tool.toggleDetails": "Alternar detalhes", + "tool.completed": (done: number, total: number) => `${done}/${total} concluídos`, + "tool.moreLines": (n: number) => `… +${n} linhas`, + "tool.addLines": (n: number) => `+${n} linhas`, + "tool.todos": (done: number, total: number) => `${done}/${total} tarefas`, + + // ModelSelector + "model.selectModel": "Selecionar modelo", + "model.notConnected": "Não conectado", + "model.connectedOnly": "Apenas conectados", + "model.showAll": "Mostrar todos os provedores", + "model.hideDisconnected": "Ocultar provedores desconectados", + + // TodoHeader + "todo.label": "Tarefas", + "todo.toggleList": "Alternar lista de tarefas", + + // ContextIndicator + "context.title": (percent: number) => `Contexto: ${percent}% usado`, + "context.windowUsage": "Uso da janela de contexto", + "context.inputTokens": "Tokens de entrada", + "context.contextLimit": "Limite de contexto", + "context.compressing": "Comprimindo...", + "context.compress": "Comprimir conversa", + + // ShellResultView + "shell.title": "Shell", + + // ToolConfigPanel + "config.title": "Configurações", + "config.projectConfig": "Configuração do projeto", + "config.globalConfig": "Configuração global", + + "config.close": "Fechar", + + // Language setting + "config.language": "Idioma", + "config.langAuto": "Automático (VS Code)", + "config.langEn": "English", + "config.langJa": "日本語", + "config.langZhCn": "简体中文", + "config.langKo": "한국어", + "config.langZhTw": "繁體中文", + "config.langEs": "Español", + "config.langPtBr": "Português (Brasil)", + "config.langRu": "Русский", + + // FileChangesHeader + "fileChanges.title": "Alterações de arquivos", + "fileChanges.noChanges": "Sem alterações de arquivos", + "fileChanges.openDiff": "Abrir no editor de diferenças", + "fileChanges.toggle": "Alterações de arquivos", + + // Share + "share.share": "Compartilhar sessão", + "share.unshare": "Deixar de compartilhar", + "share.copied": "URL de compartilhamento copiada para a área de transferência", + + // ChildSession + "childSession.agent": "Agente", + "childSession.backToParent": "Voltar à sessão principal", + + // Context menu sections + "input.section.files": "Arquivos", + "input.section.agents": "Agentes", + "input.section.shell": "Modo Shell", + + // AgentMention + "input.noAgents": "Nenhum agente disponível", +}; diff --git a/webview/locales/ru.ts b/webview/locales/ru.ts new file mode 100644 index 0000000..b9d5689 --- /dev/null +++ b/webview/locales/ru.ts @@ -0,0 +1,139 @@ +import type { en } from "./en"; + +export const ru: typeof en = { + // ChatHeader + "header.sessions": "Сессии", + "header.title.fallback": "OpenCode", + "header.newChat": "Новый чат", + + // EmptyState + "empty.title": "OpenCode", + "empty.description": "Начните новый разговор.", + "empty.newChat": "Новый чат", + + // InputArea + "input.addContext": "Добавить контекст", + "input.searchFiles": "Поиск файлов...", + "input.noFiles": "Файлы не найдены", + "input.remove": "Удалить", + "input.placeholder": "Спросите OpenCode... (введите # для прикрепления файлов)", + "input.addFile": (name: string) => `Добавить ${name}`, + "input.openTerminal": "Открыть сессию в терминале", + "input.shellMode": "Режим Shell", + "input.placeholder.shell": "Введите команду оболочки...", + "input.settings": "Настройки", + "input.stop": "Остановить", + "input.send": "Отправить", + + // MessageItem + "message.fileFallback": "файл", + "message.clickToEdit": "Нажмите для редактирования", + "message.cancel": "Отмена", + "message.send": "Отправить", + "message.thought": "Мысль", + "message.thinking": "Думаю…", + "message.toggleThought": "Переключить детали мысли", + + // MessagesArea + "checkpoint.revertTitle": "Вернуться к этой точке", + "checkpoint.retryFromHere": "Повторить отсюда", + "checkpoint.forkFromHere": "Ответвить отсюда", + + // Undo/Redo + "header.undo": "Отменить", + "header.redo": "Повторить", + + // PermissionView + "permission.allow": "Разрешить", + "permission.once": "Однократно", + "permission.deny": "Отклонить", + + // SessionList + "session.noSessions": "Нет сессий", + "session.untitled": "Без названия", + "session.delete": "Удалить", + "session.select": "Выбрать сессию", + + // Time (relative) + "time.now": "сейчас", + "time.minutes": (n: number) => `${n}мин`, + "time.hours": (n: number) => `${n}ч`, + "time.days": (n: number) => `${n}д`, + + // ToolPartView - category labels + "tool.read": "Чтение", + "tool.edit": "Редактирование", + "tool.create": "Создание", + "tool.run": "Запуск", + "tool.search": "Поиск", + "tool.tool": "Инструмент", + "tool.toggleDetails": "Переключить детали", + "tool.completed": (done: number, total: number) => `${done}/${total} завершено`, + "tool.moreLines": (n: number) => `… ещё ${n} строк`, + "tool.addLines": (n: number) => `+${n} строк`, + "tool.todos": (done: number, total: number) => `${done}/${total} задач`, + + // ModelSelector + "model.selectModel": "Выбрать модель", + "model.notConnected": "Не подключено", + "model.connectedOnly": "Только подключённые", + "model.showAll": "Показать всех провайдеров", + "model.hideDisconnected": "Скрыть отключённых провайдеров", + + // TodoHeader + "todo.label": "Задачи", + "todo.toggleList": "Переключить список задач", + + // ContextIndicator + "context.title": (percent: number) => `Контекст: использовано ${percent}%`, + "context.windowUsage": "Использование окна контекста", + "context.inputTokens": "Входные токены", + "context.contextLimit": "Лимит контекста", + "context.compressing": "Сжатие...", + "context.compress": "Сжать диалог", + + // ShellResultView + "shell.title": "Shell", + + // ToolConfigPanel + "config.title": "Настройки", + "config.projectConfig": "Настройки проекта", + "config.globalConfig": "Глобальные настройки", + + "config.close": "Закрыть", + + // Language setting + "config.language": "Язык", + "config.langAuto": "Автоматически (VS Code)", + "config.langEn": "English", + "config.langJa": "日本語", + "config.langZhCn": "简体中文", + "config.langKo": "한국어", + "config.langZhTw": "繁體中文", + "config.langEs": "Español", + "config.langPtBr": "Português (Brasil)", + "config.langRu": "Русский", + + // FileChangesHeader + "fileChanges.title": "Изменения файлов", + "fileChanges.noChanges": "Нет изменений файлов", + "fileChanges.openDiff": "Открыть в редакторе различий", + "fileChanges.toggle": "Изменения файлов", + + // Share + "share.share": "Поделиться сессией", + "share.unshare": "Отменить общий доступ", + "share.copied": "Ссылка скопирована в буфер обмена", + + // ChildSession + "childSession.agent": "Агент", + "childSession.backToParent": "Вернуться к родительской сессии", + + // Context menu sections + "input.section.files": "Файлы", + "input.section.agents": "Агенты", + "input.section.shell": "Режим Shell", + + // AgentMention + "input.noAgents": "Нет доступных агентов", +}; diff --git a/webview/locales/zh-cn.ts b/webview/locales/zh-cn.ts new file mode 100644 index 0000000..9dfb6c0 --- /dev/null +++ b/webview/locales/zh-cn.ts @@ -0,0 +1,139 @@ +import type { en } from "./en"; + +export const zhCn: typeof en = { + // ChatHeader + "header.sessions": "会话列表", + "header.title.fallback": "OpenCode", + "header.newChat": "新建聊天", + + // EmptyState + "empty.title": "OpenCode", + "empty.description": "开始新的对话吧。", + "empty.newChat": "新建聊天", + + // InputArea + "input.addContext": "添加上下文", + "input.searchFiles": "搜索文件...", + "input.noFiles": "未找到文件", + "input.remove": "移除", + "input.placeholder": "向 OpenCode 提问...(输入 # 附加文件)", + "input.addFile": (name: string) => `添加 ${name}`, + "input.openTerminal": "在终端中打开会话", + "input.shellMode": "Shell 模式", + "input.placeholder.shell": "输入 Shell 命令...", + "input.settings": "设置", + "input.stop": "停止", + "input.send": "发送", + + // MessageItem + "message.fileFallback": "文件", + "message.clickToEdit": "点击编辑", + "message.cancel": "取消", + "message.send": "发送", + "message.thought": "思考", + "message.thinking": "思考中…", + "message.toggleThought": "切换思考详情", + + // MessagesArea + "checkpoint.revertTitle": "回退到此处", + "checkpoint.retryFromHere": "从此处重试", + "checkpoint.forkFromHere": "从此处分支", + + // Undo/Redo + "header.undo": "撤销", + "header.redo": "重做", + + // PermissionView + "permission.allow": "允许", + "permission.once": "仅一次", + "permission.deny": "拒绝", + + // SessionList + "session.noSessions": "暂无会话", + "session.untitled": "无标题", + "session.delete": "删除", + "session.select": "选择会话", + + // Time (relative) + "time.now": "刚刚", + "time.minutes": (n: number) => `${n}分钟`, + "time.hours": (n: number) => `${n}小时`, + "time.days": (n: number) => `${n}天`, + + // ToolPartView - category labels + "tool.read": "读取", + "tool.edit": "编辑", + "tool.create": "创建", + "tool.run": "运行", + "tool.search": "搜索", + "tool.tool": "工具", + "tool.toggleDetails": "切换详情", + "tool.completed": (done: number, total: number) => `${done}/${total} 已完成`, + "tool.moreLines": (n: number) => `… 还有 ${n} 行`, + "tool.addLines": (n: number) => `+${n} 行`, + "tool.todos": (done: number, total: number) => `${done}/${total} 待办`, + + // ModelSelector + "model.selectModel": "选择模型", + "model.notConnected": "未连接", + "model.connectedOnly": "仅已连接", + "model.showAll": "显示所有提供者", + "model.hideDisconnected": "隐藏未连接的提供者", + + // TodoHeader + "todo.label": "待办", + "todo.toggleList": "切换待办列表", + + // ContextIndicator + "context.title": (percent: number) => `上下文:已使用 ${percent}%`, + "context.windowUsage": "上下文窗口使用量", + "context.inputTokens": "输入 Token", + "context.contextLimit": "上下文上限", + "context.compressing": "压缩中...", + "context.compress": "压缩对话", + + // ShellResultView + "shell.title": "Shell", + + // ToolConfigPanel + "config.title": "设置", + "config.projectConfig": "项目配置", + "config.globalConfig": "全局配置", + + "config.close": "关闭", + + // Language setting + "config.language": "语言", + "config.langAuto": "自动(VS Code)", + "config.langEn": "English", + "config.langJa": "日本語", + "config.langZhCn": "简体中文", + "config.langKo": "한국어", + "config.langZhTw": "繁體中文", + "config.langEs": "Español", + "config.langPtBr": "Português (Brasil)", + "config.langRu": "Русский", + + // FileChangesHeader + "fileChanges.title": "文件更改", + "fileChanges.noChanges": "无文件更改", + "fileChanges.openDiff": "在差异编辑器中打开", + "fileChanges.toggle": "文件更改", + + // Share + "share.share": "共享会话", + "share.unshare": "取消共享", + "share.copied": "共享链接已复制到剪贴板", + + // ChildSession + "childSession.agent": "智能体", + "childSession.backToParent": "返回父会话", + + // Context menu sections + "input.section.files": "文件", + "input.section.agents": "智能体", + "input.section.shell": "Shell 模式", + + // AgentMention + "input.noAgents": "没有可用的智能体", +}; diff --git a/webview/locales/zh-tw.ts b/webview/locales/zh-tw.ts new file mode 100644 index 0000000..c83135f --- /dev/null +++ b/webview/locales/zh-tw.ts @@ -0,0 +1,139 @@ +import type { en } from "./en"; + +export const zhTw: typeof en = { + // ChatHeader + "header.sessions": "工作階段列表", + "header.title.fallback": "OpenCode", + "header.newChat": "新建聊天", + + // EmptyState + "empty.title": "OpenCode", + "empty.description": "開始新的對話吧。", + "empty.newChat": "新建聊天", + + // InputArea + "input.addContext": "新增上下文", + "input.searchFiles": "搜尋檔案...", + "input.noFiles": "找不到檔案", + "input.remove": "移除", + "input.placeholder": "向 OpenCode 提問...(輸入 # 附加檔案)", + "input.addFile": (name: string) => `新增 ${name}`, + "input.openTerminal": "在終端機中開啟工作階段", + "input.shellMode": "Shell 模式", + "input.placeholder.shell": "輸入 Shell 命令...", + "input.settings": "設定", + "input.stop": "停止", + "input.send": "傳送", + + // MessageItem + "message.fileFallback": "檔案", + "message.clickToEdit": "點擊編輯", + "message.cancel": "取消", + "message.send": "傳送", + "message.thought": "思考", + "message.thinking": "思考中…", + "message.toggleThought": "切換思考詳情", + + // MessagesArea + "checkpoint.revertTitle": "回退到此處", + "checkpoint.retryFromHere": "從此處重試", + "checkpoint.forkFromHere": "從此處分支", + + // Undo/Redo + "header.undo": "復原", + "header.redo": "重做", + + // PermissionView + "permission.allow": "允許", + "permission.once": "僅一次", + "permission.deny": "拒絕", + + // SessionList + "session.noSessions": "沒有工作階段", + "session.untitled": "無標題", + "session.delete": "刪除", + "session.select": "選擇工作階段", + + // Time (relative) + "time.now": "剛剛", + "time.minutes": (n: number) => `${n}分鐘`, + "time.hours": (n: number) => `${n}小時`, + "time.days": (n: number) => `${n}天`, + + // ToolPartView - category labels + "tool.read": "讀取", + "tool.edit": "編輯", + "tool.create": "建立", + "tool.run": "執行", + "tool.search": "搜尋", + "tool.tool": "工具", + "tool.toggleDetails": "切換詳情", + "tool.completed": (done: number, total: number) => `${done}/${total} 已完成`, + "tool.moreLines": (n: number) => `… 還有 ${n} 行`, + "tool.addLines": (n: number) => `+${n} 行`, + "tool.todos": (done: number, total: number) => `${done}/${total} 待辦`, + + // ModelSelector + "model.selectModel": "選擇模型", + "model.notConnected": "未連線", + "model.connectedOnly": "僅已連線", + "model.showAll": "顯示所有提供者", + "model.hideDisconnected": "隱藏未連線的提供者", + + // TodoHeader + "todo.label": "待辦", + "todo.toggleList": "切換待辦列表", + + // ContextIndicator + "context.title": (percent: number) => `上下文:已使用 ${percent}%`, + "context.windowUsage": "上下文視窗使用量", + "context.inputTokens": "輸入 Token", + "context.contextLimit": "上下文上限", + "context.compressing": "壓縮中...", + "context.compress": "壓縮對話", + + // ShellResultView + "shell.title": "Shell", + + // ToolConfigPanel + "config.title": "設定", + "config.projectConfig": "專案設定", + "config.globalConfig": "全域設定", + + "config.close": "關閉", + + // Language setting + "config.language": "語言", + "config.langAuto": "自動(VS Code)", + "config.langEn": "English", + "config.langJa": "日本語", + "config.langZhCn": "简体中文", + "config.langKo": "한국어", + "config.langZhTw": "繁體中文", + "config.langEs": "Español", + "config.langPtBr": "Português (Brasil)", + "config.langRu": "Русский", + + // FileChangesHeader + "fileChanges.title": "檔案變更", + "fileChanges.noChanges": "沒有檔案變更", + "fileChanges.openDiff": "在差異編輯器中開啟", + "fileChanges.toggle": "檔案變更", + + // Share + "share.share": "分享工作階段", + "share.unshare": "取消分享", + "share.copied": "分享連結已複製到剪貼簿", + + // ChildSession + "childSession.agent": "智慧代理", + "childSession.backToParent": "返回上層工作階段", + + // Context menu sections + "input.section.files": "檔案", + "input.section.agents": "智慧代理", + "input.section.shell": "Shell 模式", + + // AgentMention + "input.noAgents": "沒有可用的智慧代理", +};