feat: internationalize error messages for custom error titles

- Added i18n support for error titles and messages in applyDiffTool, insertContentTool, and Task.ts
- Added English translations for new error messages in tools.json
- Translated error messages to all 18 supported languages (ca, de, es, fr, hi, id, it, ja, ko, nl, pl, pt-BR, ru, tr, vi, zh-CN, zh-TW)
- Updated code to use i18n keys instead of hardcoded strings
- Fixed tests to work with i18n keys
- All translations validated with find-missing-translations.js script
This commit is contained in:
Roo Code 2025-09-08 21:20:46 +00:00
parent eef6c0313c
commit 7e65f6f6af
22 changed files with 373 additions and 10 deletions

View file

@ -1164,18 +1164,21 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
}
async sayAndCreateMissingParamError(toolName: ToolName, paramName: string, relPath?: string) {
const relPathFormatted = relPath ? ` for '${relPath.toPosix()}'` : ""
await this.say(
"error",
`Roo tried to use ${toolName}${
relPath ? ` for '${relPath.toPosix()}'` : ""
} without value for required parameter '${paramName}'. Retrying...`,
t("tools:common.errors.missingParameterMessage", {
toolName,
relPath: relPathFormatted,
paramName,
}),
undefined,
undefined,
undefined,
undefined,
{
metadata: {
title: "Missing Parameter Error",
title: t("tools:common.errors.missingParameter"),
},
},
)

View file

@ -46,6 +46,22 @@ vi.mock("../../ignore/RooIgnoreController", () => ({
},
}))
vi.mock("../../../i18n", () => ({
t: vi.fn((key: string, params?: any) => {
// Return the key without the namespace prefix for testing
const keyWithoutNamespace = key.replace(/^[^:]+:/, "")
if (params) {
// Simple parameter replacement for testing
let result = keyWithoutNamespace
Object.entries(params).forEach(([key, value]) => {
result = result.replace(`{{${key}}}`, String(value))
})
return result
}
return keyWithoutNamespace
}),
}))
describe("insertContentTool", () => {
const testFilePath = "test/file.txt"
// Use a consistent mock absolute path for testing
@ -228,14 +244,14 @@ describe("insertContentTool", () => {
expect(mockCline.recordToolError).toHaveBeenCalledWith("insert_content")
expect(mockCline.say).toHaveBeenCalledWith(
"error",
expect.stringContaining("non-existent file"),
"insertContent.errors.cannotInsertIntoNonExistent",
undefined,
undefined,
undefined,
undefined,
expect.objectContaining({
metadata: expect.objectContaining({
title: "Invalid Line Number",
title: "insertContent.errors.invalidLineNumber",
}),
}),
)

View file

@ -13,6 +13,7 @@ import { fileExistsAtPath } from "../../utils/fs"
import { RecordSource } from "../context-tracking/FileContextTrackerTypes"
import { unescapeHtmlEntities } from "../../utils/text-normalization"
import { EXPERIMENT_IDS, experiments } from "../../shared/experiments"
import { t } from "../../i18n"
export async function applyDiffToolLegacy(
cline: Task,
@ -82,9 +83,9 @@ export async function applyDiffToolLegacy(
if (!fileExists) {
cline.consecutiveMistakeCount++
cline.recordToolError("apply_diff")
const formattedError = `File does not exist at path: ${absolutePath}\n\n<error_details>\nThe specified file could not be found. Please verify the file path and try again.\n</error_details>`
const formattedError = `${t("tools:applyDiff.errors.fileDoesNotExist", { path: absolutePath })}\n\n<error_details>\n${t("tools:applyDiff.errors.fileDoesNotExistDetails")}\n</error_details>`
await cline.say("error", formattedError, undefined, undefined, undefined, undefined, {
metadata: { title: "File Not Found" },
metadata: { title: t("tools:applyDiff.errors.fileNotFound") },
})
pushToolResult(formattedError)
return

View file

@ -12,6 +12,7 @@ import { fileExistsAtPath } from "../../utils/fs"
import { insertGroups } from "../diff/insert-groups"
import { DEFAULT_WRITE_DELAY_MS } from "@roo-code/types"
import { EXPERIMENT_IDS, experiments } from "../../shared/experiments"
import { t } from "../../i18n"
export async function insertContentTool(
cline: Task,
@ -86,9 +87,9 @@ export async function insertContentTool(
if (lineNumber > 1) {
cline.consecutiveMistakeCount++
cline.recordToolError("insert_content")
const formattedError = `Cannot insert content at line ${lineNumber} into a non-existent file. For new files, 'line' must be 0 (to append) or 1 (to insert at the beginning).`
const formattedError = t("tools:insertContent.errors.cannotInsertIntoNonExistent", { lineNumber })
await cline.say("error", formattedError, undefined, undefined, undefined, undefined, {
metadata: { title: "Invalid Line Number" },
metadata: { title: t("tools:insertContent.errors.invalidLineNumber") },
})
pushToolResult(formattedError)
return

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "No s'ha pogut crear una nova tasca a causa de restriccions de política."
}
},
"applyDiff": {
"errors": {
"fileNotFound": "Fitxer no trobat",
"fileDoesNotExist": "El fitxer no existeix al camí: {{path}}",
"fileDoesNotExistDetails": "No s'ha pogut trobar el fitxer especificat. Si us plau, verifica el camí del fitxer i torna-ho a provar."
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "Número de línia invàlid",
"cannotInsertIntoNonExistent": "No es pot inserir contingut a la línia {{lineNumber}} d'un fitxer inexistent. Per a fitxers nous, 'line' ha de ser 0 (per afegir al final) o 1 (per inserir al principi)."
}
},
"common": {
"errors": {
"missingParameter": "Paràmetre que falta",
"missingParameterMessage": "Roo ha intentat utilitzar {{toolName}}{{relPath}} sense valor per al paràmetre requerit '{{paramName}}'. Tornant a intentar..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "Neue Aufgabe konnte aufgrund von Richtlinienbeschränkungen nicht erstellt werden."
}
},
"applyDiff": {
"errors": {
"fileNotFound": "Datei nicht gefunden",
"fileDoesNotExist": "Datei existiert nicht unter dem Pfad: {{path}}",
"fileDoesNotExistDetails": "Die angegebene Datei konnte nicht gefunden werden. Bitte überprüfe den Dateipfad und versuche es erneut."
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "Ungültige Zeilennummer",
"cannotInsertIntoNonExistent": "Inhalt kann nicht in Zeile {{lineNumber}} einer nicht existierenden Datei eingefügt werden. Für neue Dateien muss 'line' 0 (zum Anhängen) oder 1 (zum Einfügen am Anfang) sein."
}
},
"common": {
"errors": {
"missingParameter": "Fehlender Parameter",
"missingParameterMessage": "Roo hat versucht, {{toolName}}{{relPath}} ohne Wert für den erforderlichen Parameter '{{paramName}}' zu verwenden. Versuche erneut..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "Failed to create new task due to policy restrictions."
}
},
"applyDiff": {
"errors": {
"fileNotFound": "File Not Found",
"fileDoesNotExist": "File does not exist at path: {{path}}",
"fileDoesNotExistDetails": "The specified file could not be found. Please verify the file path and try again."
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "Invalid Line Number",
"cannotInsertIntoNonExistent": "Cannot insert content at line {{lineNumber}} into a non-existent file. For new files, 'line' must be 0 (to append) or 1 (to insert at the beginning)."
}
},
"common": {
"errors": {
"missingParameter": "Missing Parameter Error",
"missingParameterMessage": "Roo tried to use {{toolName}}{{relPath}} without value for required parameter '{{paramName}}'. Retrying..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "No se pudo crear una nueva tarea debido a restricciones de política."
}
},
"applyDiff": {
"errors": {
"fileNotFound": "Archivo no encontrado",
"fileDoesNotExist": "El archivo no existe en la ruta: {{path}}",
"fileDoesNotExistDetails": "No se pudo encontrar el archivo especificado. Por favor, verifica la ruta del archivo e intenta de nuevo."
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "Número de línea inválido",
"cannotInsertIntoNonExistent": "No se puede insertar contenido en la línea {{lineNumber}} de un archivo inexistente. Para archivos nuevos, 'line' debe ser 0 (para añadir al final) o 1 (para insertar al principio)."
}
},
"common": {
"errors": {
"missingParameter": "Parámetro faltante",
"missingParameterMessage": "Roo intentó usar {{toolName}}{{relPath}} sin valor para el parámetro requerido '{{paramName}}'. Reintentando..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "Impossible de créer une nouvelle tâche en raison de restrictions de politique."
}
},
"applyDiff": {
"errors": {
"fileNotFound": "Fichier introuvable",
"fileDoesNotExist": "Le fichier n'existe pas au chemin : {{path}}",
"fileDoesNotExistDetails": "Le fichier spécifié n'a pas pu être trouvé. Veuillez vérifier le chemin du fichier et réessayer."
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "Numéro de ligne invalide",
"cannotInsertIntoNonExistent": "Impossible d'insérer du contenu à la ligne {{lineNumber}} dans un fichier inexistant. Pour les nouveaux fichiers, 'line' doit être 0 (pour ajouter à la fin) ou 1 (pour insérer au début)."
}
},
"common": {
"errors": {
"missingParameter": "Paramètre manquant",
"missingParameterMessage": "Roo a essayé d'utiliser {{toolName}}{{relPath}} sans valeur pour le paramètre requis '{{paramName}}'. Nouvelle tentative..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "नीति प्रतिबंधों के कारण नया कार्य बनाने में विफल।"
}
},
"applyDiff": {
"errors": {
"fileNotFound": "फ़ाइल नहीं मिली",
"fileDoesNotExist": "फ़ाइल पथ पर मौजूद नहीं है: {{path}}",
"fileDoesNotExistDetails": "निर्दिष्ट फ़ाइल नहीं मिल सकी। कृपया फ़ाइल पथ सत्यापित करें और पुनः प्रयास करें।"
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "अमान्य लाइन नंबर",
"cannotInsertIntoNonExistent": "गैर-मौजूद फ़ाइल की लाइन {{lineNumber}} में सामग्री नहीं डाली जा सकती। नई फ़ाइलों के लिए, 'line' 0 (अंत में जोड़ने के लिए) या 1 (शुरुआत में डालने के लिए) होनी चाहिए।"
}
},
"common": {
"errors": {
"missingParameter": "गुम पैरामीटर",
"missingParameterMessage": "Roo ने आवश्यक पैरामीटर '{{paramName}}' के लिए मान के बिना {{toolName}}{{relPath}} का उपयोग करने का प्रयास किया। पुनः प्रयास कर रहा है..."
}
}
}

View file

@ -17,5 +17,24 @@
"errors": {
"policy_restriction": "Gagal membuat tugas baru karena pembatasan kebijakan."
}
},
"applyDiff": {
"errors": {
"fileNotFound": "File Tidak Ditemukan",
"fileDoesNotExist": "File tidak ada di path: {{path}}",
"fileDoesNotExistDetails": "File yang ditentukan tidak dapat ditemukan. Silakan verifikasi path file dan coba lagi."
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "Nomor Baris Tidak Valid",
"cannotInsertIntoNonExistent": "Tidak dapat menyisipkan konten di baris {{lineNumber}} ke file yang tidak ada. Untuk file baru, 'line' harus 0 (untuk menambahkan di akhir) atau 1 (untuk menyisipkan di awal)."
}
},
"common": {
"errors": {
"missingParameter": "Parameter Hilang",
"missingParameterMessage": "Roo mencoba menggunakan {{toolName}}{{relPath}} tanpa nilai untuk parameter yang diperlukan '{{paramName}}'. Mencoba lagi..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "Impossibile creare una nuova attività a causa di restrizioni di policy."
}
},
"applyDiff": {
"errors": {
"fileNotFound": "File non trovato",
"fileDoesNotExist": "Il file non esiste nel percorso: {{path}}",
"fileDoesNotExistDetails": "Il file specificato non è stato trovato. Verifica il percorso del file e riprova."
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "Numero di riga non valido",
"cannotInsertIntoNonExistent": "Impossibile inserire contenuto alla riga {{lineNumber}} in un file inesistente. Per i nuovi file, 'line' deve essere 0 (per aggiungere alla fine) o 1 (per inserire all'inizio)."
}
},
"common": {
"errors": {
"missingParameter": "Parametro mancante",
"missingParameterMessage": "Roo ha tentato di usare {{toolName}}{{relPath}} senza valore per il parametro richiesto '{{paramName}}'. Nuovo tentativo..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "ポリシー制限により新しいタスクを作成できませんでした。"
}
},
"applyDiff": {
"errors": {
"fileNotFound": "ファイルが見つかりません",
"fileDoesNotExist": "ファイルがパスに存在しません: {{path}}",
"fileDoesNotExistDetails": "指定されたファイルが見つかりませんでした。ファイルパスを確認して、もう一度お試しください。"
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "無効な行番号",
"cannotInsertIntoNonExistent": "存在しないファイルの{{lineNumber}}行目にコンテンツを挿入できません。新しいファイルの場合、'line'は0末尾に追加または1先頭に挿入である必要があります。"
}
},
"common": {
"errors": {
"missingParameter": "パラメータ不足",
"missingParameterMessage": "Rooは必須パラメータ'{{paramName}}'の値なしで{{toolName}}{{relPath}}を使用しようとしました。再試行中..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "정책 제한으로 인해 새 작업을 생성하지 못했습니다."
}
},
"applyDiff": {
"errors": {
"fileNotFound": "파일을 찾을 수 없음",
"fileDoesNotExist": "파일이 경로에 존재하지 않습니다: {{path}}",
"fileDoesNotExistDetails": "지정된 파일을 찾을 수 없습니다. 파일 경로를 확인하고 다시 시도해 주세요."
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "잘못된 줄 번호",
"cannotInsertIntoNonExistent": "존재하지 않는 파일의 {{lineNumber}}번째 줄에 내용을 삽입할 수 없습니다. 새 파일의 경우 'line'은 0(끝에 추가) 또는 1(시작 부분에 삽입)이어야 합니다."
}
},
"common": {
"errors": {
"missingParameter": "누락된 매개변수",
"missingParameterMessage": "Roo가 필수 매개변수 '{{paramName}}'의 값 없이 {{toolName}}{{relPath}}를 사용하려고 했습니다. 다시 시도 중..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "Kan geen nieuwe taak aanmaken vanwege beleidsbeperkingen."
}
},
"applyDiff": {
"errors": {
"fileNotFound": "Bestand niet gevonden",
"fileDoesNotExist": "Bestand bestaat niet op pad: {{path}}",
"fileDoesNotExistDetails": "Het opgegeven bestand kon niet worden gevonden. Controleer het bestandspad en probeer het opnieuw."
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "Ongeldig regelnummer",
"cannotInsertIntoNonExistent": "Kan geen inhoud invoegen op regel {{lineNumber}} in een niet-bestaand bestand. Voor nieuwe bestanden moet 'line' 0 zijn (om toe te voegen aan het einde) of 1 (om in te voegen aan het begin)."
}
},
"common": {
"errors": {
"missingParameter": "Ontbrekende parameter",
"missingParameterMessage": "Roo probeerde {{toolName}}{{relPath}} te gebruiken zonder waarde voor de vereiste parameter '{{paramName}}'. Opnieuw proberen..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "Nie udało się utworzyć nowego zadania z powodu ograniczeń polityki."
}
},
"applyDiff": {
"errors": {
"fileNotFound": "Plik nie został znaleziony",
"fileDoesNotExist": "Plik nie istnieje w ścieżce: {{path}}",
"fileDoesNotExistDetails": "Nie można znaleźć określonego pliku. Sprawdź ścieżkę pliku i spróbuj ponownie."
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "Nieprawidłowy numer linii",
"cannotInsertIntoNonExistent": "Nie można wstawić treści w linii {{lineNumber}} do nieistniejącego pliku. Dla nowych plików 'line' musi być 0 (aby dodać na końcu) lub 1 (aby wstawić na początku)."
}
},
"common": {
"errors": {
"missingParameter": "Brakujący parametr",
"missingParameterMessage": "Roo próbował użyć {{toolName}}{{relPath}} bez wartości dla wymaganego parametru '{{paramName}}'. Ponawiam próbę..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "Falha ao criar nova tarefa devido a restrições de política."
}
},
"applyDiff": {
"errors": {
"fileNotFound": "Arquivo não encontrado",
"fileDoesNotExist": "O arquivo não existe no caminho: {{path}}",
"fileDoesNotExistDetails": "O arquivo especificado não pôde ser encontrado. Por favor, verifique o caminho do arquivo e tente novamente."
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "Número de linha inválido",
"cannotInsertIntoNonExistent": "Não é possível inserir conteúdo na linha {{lineNumber}} em um arquivo inexistente. Para novos arquivos, 'line' deve ser 0 (para adicionar ao final) ou 1 (para inserir no início)."
}
},
"common": {
"errors": {
"missingParameter": "Parâmetro ausente",
"missingParameterMessage": "Roo tentou usar {{toolName}}{{relPath}} sem valor para o parâmetro obrigatório '{{paramName}}'. Tentando novamente..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "Не удалось создать новую задачу из-за ограничений политики."
}
},
"applyDiff": {
"errors": {
"fileNotFound": "Файл не найден",
"fileDoesNotExist": "Файл не существует по пути: {{path}}",
"fileDoesNotExistDetails": "Указанный файл не найден. Пожалуйста, проверьте путь к файлу и попробуйте снова."
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "Недопустимый номер строки",
"cannotInsertIntoNonExistent": "Невозможно вставить содержимое в строку {{lineNumber}} несуществующего файла. Для новых файлов 'line' должна быть 0 (для добавления в конец) или 1 (для вставки в начало)."
}
},
"common": {
"errors": {
"missingParameter": "Отсутствующий параметр",
"missingParameterMessage": "Roo попытался использовать {{toolName}}{{relPath}} без значения для обязательного параметра '{{paramName}}'. Повторная попытка..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "Politika kısıtlamaları nedeniyle yeni görev oluşturulamadı."
}
},
"applyDiff": {
"errors": {
"fileNotFound": "Dosya Bulunamadı",
"fileDoesNotExist": "Dosya şu yolda mevcut değil: {{path}}",
"fileDoesNotExistDetails": "Belirtilen dosya bulunamadı. Lütfen dosya yolunu doğrulayın ve tekrar deneyin."
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "Geçersiz Satır Numarası",
"cannotInsertIntoNonExistent": "Var olmayan bir dosyanın {{lineNumber}}. satırına içerik eklenemez. Yeni dosyalar için 'line' 0 (sona eklemek için) veya 1 (başa eklemek için) olmalıdır."
}
},
"common": {
"errors": {
"missingParameter": "Eksik Parametre",
"missingParameterMessage": "Roo, gerekli '{{paramName}}' parametresi için değer olmadan {{toolName}}{{relPath}} kullanmaya çalıştı. Yeniden deneniyor..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "Không thể tạo nhiệm vụ mới do hạn chế chính sách."
}
},
"applyDiff": {
"errors": {
"fileNotFound": "Không tìm thấy tệp",
"fileDoesNotExist": "Tệp không tồn tại tại đường dẫn: {{path}}",
"fileDoesNotExistDetails": "Không thể tìm thấy tệp được chỉ định. Vui lòng xác minh đường dẫn tệp và thử lại."
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "Số dòng không hợp lệ",
"cannotInsertIntoNonExistent": "Không thể chèn nội dung vào dòng {{lineNumber}} của tệp không tồn tại. Đối với tệp mới, 'line' phải là 0 (để thêm vào cuối) hoặc 1 (để chèn vào đầu)."
}
},
"common": {
"errors": {
"missingParameter": "Thiếu tham số",
"missingParameterMessage": "Roo đã cố gắng sử dụng {{toolName}}{{relPath}} mà không có giá trị cho tham số bắt buộc '{{paramName}}'. Đang thử lại..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "由于策略限制,无法创建新任务。"
}
},
"applyDiff": {
"errors": {
"fileNotFound": "文件未找到",
"fileDoesNotExist": "文件不存在于路径:{{path}}",
"fileDoesNotExistDetails": "找不到指定的文件。请验证文件路径并重试。"
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "无效的行号",
"cannotInsertIntoNonExistent": "无法在不存在的文件的第 {{lineNumber}} 行插入内容。对于新文件,'line' 必须为 0追加到末尾或 1插入到开头。"
}
},
"common": {
"errors": {
"missingParameter": "缺少参数",
"missingParameterMessage": "Roo 尝试使用 {{toolName}}{{relPath}} 但缺少必需参数 '{{paramName}}' 的值。正在重试..."
}
}
}

View file

@ -14,5 +14,24 @@
"errors": {
"policy_restriction": "由於政策限制,無法建立新工作。"
}
},
"applyDiff": {
"errors": {
"fileNotFound": "找不到檔案",
"fileDoesNotExist": "檔案不存在於路徑:{{path}}",
"fileDoesNotExistDetails": "找不到指定的檔案。請驗證檔案路徑並重試。"
}
},
"insertContent": {
"errors": {
"invalidLineNumber": "無效的行號",
"cannotInsertIntoNonExistent": "無法在不存在的檔案的第 {{lineNumber}} 行插入內容。對於新檔案,'line' 必須為 0附加到結尾或 1插入到開頭。"
}
},
"common": {
"errors": {
"missingParameter": "缺少參數",
"missingParameterMessage": "Roo 嘗試使用 {{toolName}}{{relPath}} 但缺少必要參數 '{{paramName}}' 的值。正在重試..."
}
}
}