From cf487fbfae55a128bfdb938f274b370ae29e00d5 Mon Sep 17 00:00:00 2001 From: feifei <46489071+feifei325@users.noreply.github.com> Date: Sun, 30 Mar 2025 23:42:48 +0800 Subject: [PATCH] i18n Add translations for task pinning and unpinning (#2109) Signed-off-by: feifei --- scripts/find-missing-i18n-key.js | 82 +++++++++++++------ src/core/webview/ClineProvider.ts | 2 +- .../webview/__tests__/ClineProvider.test.ts | 2 +- webview-ui/src/i18n/locales/ca/chat.json | 2 + webview-ui/src/i18n/locales/de/chat.json | 2 + webview-ui/src/i18n/locales/en/chat.json | 2 + webview-ui/src/i18n/locales/es/chat.json | 2 + webview-ui/src/i18n/locales/fr/chat.json | 2 + webview-ui/src/i18n/locales/hi/chat.json | 2 + webview-ui/src/i18n/locales/it/chat.json | 2 + webview-ui/src/i18n/locales/ja/chat.json | 2 + webview-ui/src/i18n/locales/ko/chat.json | 2 + webview-ui/src/i18n/locales/pl/chat.json | 2 + webview-ui/src/i18n/locales/pt-BR/chat.json | 2 + webview-ui/src/i18n/locales/tr/chat.json | 2 + webview-ui/src/i18n/locales/vi/chat.json | 2 + webview-ui/src/i18n/locales/zh-CN/chat.json | 2 + webview-ui/src/i18n/locales/zh-TW/chat.json | 2 + 18 files changed, 87 insertions(+), 29 deletions(-) diff --git a/scripts/find-missing-i18n-key.js b/scripts/find-missing-i18n-key.js index 3c21dfb410..87d160d490 100644 --- a/scripts/find-missing-i18n-key.js +++ b/scripts/find-missing-i18n-key.js @@ -34,9 +34,17 @@ Output: process.exit(0) } -// Directory to traverse -const TARGET_DIR = path.join(__dirname, "../webview-ui/src/components") -const LOCALES_DIR = path.join(__dirname, "../webview-ui/src/i18n/locales") +// Directories to traverse and their corresponding locales +const DIRS = { + components: { + path: path.join(__dirname, "../webview-ui/src/components"), + localesDir: path.join(__dirname, "../webview-ui/src/i18n/locales"), + }, + src: { + path: path.join(__dirname, "../src"), + localesDir: path.join(__dirname, "../src/i18n/locales"), + }, +} // Regular expressions to match i18n keys const i18nPatterns = [ @@ -45,15 +53,23 @@ const i18nPatterns = [ /t\("([a-zA-Z][a-zA-Z0-9_]*[:.][a-zA-Z0-9_.]+)"\)/g, // Match t("key") format, where key contains a colon or dot ] -// Get all language directories -function getLocaleDirs() { - const allLocales = fs.readdirSync(LOCALES_DIR).filter((file) => { - const stats = fs.statSync(path.join(LOCALES_DIR, file)) - return stats.isDirectory() // Do not exclude any language directories - }) +// Get all language directories for a specific locales directory +function getLocaleDirs(localesDir) { + try { + const allLocales = fs.readdirSync(localesDir).filter((file) => { + const stats = fs.statSync(path.join(localesDir, file)) + return stats.isDirectory() // Do not exclude any language directories + }) - // Filter to a specific language if specified - return args.locale ? allLocales.filter((locale) => locale === args.locale) : allLocales + // Filter to a specific language if specified + return args.locale ? allLocales.filter((locale) => locale === args.locale) : allLocales + } catch (error) { + if (error.code === "ENOENT") { + console.warn(`Warning: Locales directory not found: ${localesDir}`) + return [] + } + throw error + } } // Get the value from JSON by path @@ -72,14 +88,14 @@ function getValueByPath(obj, path) { } // Check if the key exists in all language files, return a list of missing language files -function checkKeyInLocales(key, localeDirs) { +function checkKeyInLocales(key, localeDirs, localesDir) { const [file, ...pathParts] = key.split(":") const jsonPath = pathParts.join(".") const missingLocales = [] localeDirs.forEach((locale) => { - const filePath = path.join(LOCALES_DIR, locale, `${file}.json`) + const filePath = path.join(localesDir, locale, `${file}.json`) if (!fs.existsSync(filePath)) { missingLocales.push(`${locale}/${file}.json`) return @@ -96,21 +112,20 @@ function checkKeyInLocales(key, localeDirs) { // Recursively traverse the directory function findMissingI18nKeys() { - const localeDirs = getLocaleDirs() const results = [] - function walk(dir) { + function walk(dir, baseDir, localeDirs, localesDir) { const files = fs.readdirSync(dir) for (const file of files) { const filePath = path.join(dir, file) const stat = fs.statSync(filePath) - // Exclude test files - if (filePath.includes(".test.")) continue + // Exclude test files and __mocks__ directory + if (filePath.includes(".test.") || filePath.includes("__mocks__")) continue if (stat.isDirectory()) { - walk(filePath) // Recursively traverse subdirectories + walk(filePath, baseDir, localeDirs, localesDir) // Recursively traverse subdirectories } else if (stat.isFile() && [".ts", ".tsx", ".js", ".jsx"].includes(path.extname(filePath))) { const content = fs.readFileSync(filePath, "utf8") @@ -119,12 +134,12 @@ function findMissingI18nKeys() { let match while ((match = pattern.exec(content)) !== null) { const key = match[1] - const missingLocales = checkKeyInLocales(key, localeDirs) + const missingLocales = checkKeyInLocales(key, localeDirs, localesDir) if (missingLocales.length > 0) { results.push({ key, missingLocales, - file: path.relative(TARGET_DIR, filePath), + file: path.relative(baseDir, filePath), }) } } @@ -133,20 +148,33 @@ function findMissingI18nKeys() { } } - walk(TARGET_DIR) + // Walk through all directories + Object.entries(DIRS).forEach(([name, config]) => { + const localeDirs = getLocaleDirs(config.localesDir) + if (localeDirs.length > 0) { + console.log(`\nChecking ${name} directory with ${localeDirs.length} languages: ${localeDirs.join(", ")}`) + walk(config.path, config.path, localeDirs, config.localesDir) + } + }) + return results } // Execute and output the results function main() { try { - const localeDirs = getLocaleDirs() - if (args.locale && localeDirs.length === 0) { - console.error(`Error: Language '${args.locale}' not found in ${LOCALES_DIR}`) - process.exit(1) - } + if (args.locale) { + // Check if the specified locale exists in any of the locales directories + const localeExists = Object.values(DIRS).some((config) => { + const localeDirs = getLocaleDirs(config.localesDir) + return localeDirs.includes(args.locale) + }) - console.log(`Checking ${localeDirs.length} non-English languages: ${localeDirs.join(", ")}`) + if (!localeExists) { + console.error(`Error: Language '${args.locale}' not found in any locales directory`) + process.exit(1) + } + } const missingKeys = findMissingI18nKeys() diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 0487d1bb98..f0027b322a 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -1250,7 +1250,7 @@ export class ClineProvider extends EventEmitter implements } case "openProjectMcpSettings": { if (!vscode.workspace.workspaceFolders?.length) { - vscode.window.showErrorMessage(t("common:no_workspace")) + vscode.window.showErrorMessage(t("common:errors.no_workspace")) return } diff --git a/src/core/webview/__tests__/ClineProvider.test.ts b/src/core/webview/__tests__/ClineProvider.test.ts index ea0677b010..059dca72de 100644 --- a/src/core/webview/__tests__/ClineProvider.test.ts +++ b/src/core/webview/__tests__/ClineProvider.test.ts @@ -2031,7 +2031,7 @@ describe("Project MCP Settings", () => { await messageHandler({ type: "openProjectMcpSettings" }) // Verify error message was shown - expect(vscode.window.showErrorMessage).toHaveBeenCalledWith("no_workspace") + expect(vscode.window.showErrorMessage).toHaveBeenCalledWith("errors.no_workspace") }) test.skip("handles openProjectMcpSettings file creation error", async () => { diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json index 1d29d269fd..7225e45c59 100644 --- a/webview-ui/src/i18n/locales/ca/chat.json +++ b/webview-ui/src/i18n/locales/ca/chat.json @@ -12,6 +12,8 @@ "export": "Exportar historial de tasques", "delete": "Eliminar tasca (Shift + Clic per ometre confirmació)" }, + "unpin": "desancorar", + "pin": "ancorar", "tokenProgress": { "availableSpace": "Espai disponible: {{amount}} tokens", "tokensUsed": "Tokens utilitzats: {{used}} de {{total}}", diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json index 5dd572796d..5aa623810c 100644 --- a/webview-ui/src/i18n/locales/de/chat.json +++ b/webview-ui/src/i18n/locales/de/chat.json @@ -12,6 +12,8 @@ "export": "Aufgabenverlauf exportieren", "delete": "Aufgabe löschen (Shift + Klick zum Überspringen der Bestätigung)" }, + "unpin": "lösen", + "pin": "anheften", "tokenProgress": { "availableSpace": "Verfügbarer Speicher: {{amount}} Tokens", "tokensUsed": "Verwendete Tokens: {{used}} von {{total}}", diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json index 3e3e5ecfac..0fa6520ec7 100644 --- a/webview-ui/src/i18n/locales/en/chat.json +++ b/webview-ui/src/i18n/locales/en/chat.json @@ -12,6 +12,8 @@ "export": "Export task history", "delete": "Delete Task (Shift + Click to skip confirmation)" }, + "unpin": "unpin", + "pin": "pin", "retry": { "title": "Retry", "tooltip": "Try the operation again" diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json index fdaa5a69b0..ddb09122aa 100644 --- a/webview-ui/src/i18n/locales/es/chat.json +++ b/webview-ui/src/i18n/locales/es/chat.json @@ -12,6 +12,8 @@ "export": "Exportar historial de tareas", "delete": "Eliminar tarea (Shift + Clic para omitir confirmación)" }, + "unpin": "desanclar", + "pin": "anclar", "retry": { "title": "Reintentar", "tooltip": "Intenta la operación de nuevo" diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json index 5aa3490b9a..6577f275ce 100644 --- a/webview-ui/src/i18n/locales/fr/chat.json +++ b/webview-ui/src/i18n/locales/fr/chat.json @@ -12,6 +12,8 @@ "export": "Exporter l'historique des tâches", "delete": "Supprimer la tâche (Shift + Clic pour ignorer la confirmation)" }, + "unpin": "détacher", + "pin": "épingler", "tokenProgress": { "availableSpace": "Espace disponible : {{amount}} tokens", "tokensUsed": "Tokens utilisés : {{used}} sur {{total}}", diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index 0d00d2fd8d..2b85828b08 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -12,6 +12,8 @@ "export": "कार्य इतिहास निर्यात करें", "delete": "कार्य हटाएं (पुष्टि को छोड़ने के लिए Shift + क्लिक)" }, + "unpin": "पिन हटाएं", + "pin": "पिन करें", "tokenProgress": { "availableSpace": "उपलब्ध स्थान: {{amount}} tokens", "tokensUsed": "प्रयुक्त tokens: {{used}} / {{total}}", diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json index e21a82da0d..d14ff9d051 100644 --- a/webview-ui/src/i18n/locales/it/chat.json +++ b/webview-ui/src/i18n/locales/it/chat.json @@ -12,6 +12,8 @@ "export": "Esporta cronologia attività", "delete": "Elimina attività (Shift + Clic per saltare la conferma)" }, + "unpin": "sblocca", + "pin": "blocca", "tokenProgress": { "availableSpace": "Spazio disponibile: {{amount}} tokens", "tokensUsed": "Tokens utilizzati: {{used}} di {{total}}", diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json index 9b82e56001..7f4fdd7e32 100644 --- a/webview-ui/src/i18n/locales/ja/chat.json +++ b/webview-ui/src/i18n/locales/ja/chat.json @@ -12,6 +12,8 @@ "export": "タスク履歴をエクスポート", "delete": "タスクを削除(Shift + クリックで確認をスキップ)" }, + "unpin": "固定解除", + "pin": "固定", "tokenProgress": { "availableSpace": "利用可能な空き容量: {{amount}} トークン", "tokensUsed": "使用トークン: {{used}} / {{total}}", diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json index c1b288e39b..4aa5960b6a 100644 --- a/webview-ui/src/i18n/locales/ko/chat.json +++ b/webview-ui/src/i18n/locales/ko/chat.json @@ -12,6 +12,8 @@ "export": "작업 기록 내보내기", "delete": "작업 삭제 (Shift + 클릭으로 확인 생략)" }, + "unpin": "고정 해제", + "pin": "고정", "tokenProgress": { "availableSpace": "사용 가능한 공간: {{amount}} 토큰", "tokensUsed": "사용된 토큰: {{used}} / {{total}}", diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json index 846534c559..8157d91db0 100644 --- a/webview-ui/src/i18n/locales/pl/chat.json +++ b/webview-ui/src/i18n/locales/pl/chat.json @@ -12,6 +12,8 @@ "export": "Eksportuj historię zadań", "delete": "Usuń zadanie (Shift + Kliknięcie, aby pominąć potwierdzenie)" }, + "unpin": "odepnij", + "pin": "przypnij", "tokenProgress": { "availableSpace": "Dostępne miejsce: {{amount}} tokenów", "tokensUsed": "Wykorzystane tokeny: {{used}} z {{total}}", diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json index 560e9b9bff..5c52c8bea9 100644 --- a/webview-ui/src/i18n/locales/pt-BR/chat.json +++ b/webview-ui/src/i18n/locales/pt-BR/chat.json @@ -12,6 +12,8 @@ "export": "Exportar histórico de tarefas", "delete": "Excluir tarefa (Shift + Clique para pular confirmação)" }, + "unpin": "desafixar", + "pin": "fixar", "tokenProgress": { "availableSpace": "Espaço disponível: {{amount}} tokens", "tokensUsed": "Tokens usados: {{used}} de {{total}}", diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json index b415524f92..d14b7a3ee2 100644 --- a/webview-ui/src/i18n/locales/tr/chat.json +++ b/webview-ui/src/i18n/locales/tr/chat.json @@ -12,6 +12,8 @@ "export": "Görev geçmişini dışa aktar", "delete": "Görevi sil (Onayı atlamak için Shift + Tıkla)" }, + "unpin": "sabitlemeyi kaldır", + "pin": "sabitle", "tokenProgress": { "availableSpace": "Kullanılabilir alan: {{amount}} token", "tokensUsed": "Kullanılan tokenlar: {{used}} / {{total}}", diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index f0f3221069..eabc7bb746 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -12,6 +12,8 @@ "export": "Xuất lịch sử nhiệm vụ", "delete": "Xóa nhiệm vụ (Shift + Click để bỏ qua xác nhận)" }, + "unpin": "bỏ ghim", + "pin": "ghim", "tokenProgress": { "availableSpace": "Không gian khả dụng: {{amount}} tokens", "tokensUsed": "Tokens đã sử dụng: {{used}} trong {{total}}", diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json index be20601e9b..7d6205dc70 100644 --- a/webview-ui/src/i18n/locales/zh-CN/chat.json +++ b/webview-ui/src/i18n/locales/zh-CN/chat.json @@ -12,6 +12,8 @@ "export": "导出任务历史", "delete": "删除任务(Shift + 点击跳过确认)" }, + "unpin": "取消置顶", + "pin": "置顶", "tokenProgress": { "availableSpace": "可用空间: {{amount}} tokens", "tokensUsed": "已使用tokens: {{used}} / {{total}}", diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json index 1e22877355..bfd69270e8 100644 --- a/webview-ui/src/i18n/locales/zh-TW/chat.json +++ b/webview-ui/src/i18n/locales/zh-TW/chat.json @@ -12,6 +12,8 @@ "export": "匯出任務歷史", "delete": "刪除任務(Shift + 點擊跳過確認)" }, + "unpin": "取消置頂", + "pin": "置頂", "tokenProgress": { "availableSpace": "可用空間: {{amount}} tokens", "tokensUsed": "已使用tokens: {{used}} / {{total}}",