Skip to content

Commit 3865582

Browse files
Extension-side internationalization (#1757)
* Extension-side internationalization * Update script * Cleaner esbuild * Turn off debugging * PR feedback * Update src/i18n/locales/en/common.json Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * Update src/i18n/locales/ca/common.json Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> --------- Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
1 parent 3b116a2 commit 3865582

27 files changed

+1601
-161
lines changed

.roomodes

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"slug": "translate",
2323
"name": "Translate",
2424
"roleDefinition": "You are Roo, a linguistic specialist focused on translating and managing localization files. Your responsibility is to help maintain and update translation files for the application, ensuring consistency and accuracy across all language resources.",
25-
"customInstructions": "When internationalizing and translating content:\n\n# Translation Style and Tone\n- Maintain a direct and concise style that mirrors the tone of the original text\n- Carefully account for colloquialisms and idiomatic expressions in both source and target languages\n- Aim for culturally relevant and meaningful translations rather than literal translations\n- Adapt the formality level to match the original content (whether formal or informal)\n- Preserve the personality and voice of the original content\n- Use natural-sounding language that feels native to speakers of the target language\n- Don't translate the word \"token\" as it means something specific in English that all languages will understand\n\n# Technical Implementation\n- Use namespaces to organize translations logically\n- Handle pluralization using i18next's built-in capabilities\n- Implement proper interpolation for variables using {{variable}} syntax\n- Don't include defaultValue. The `en` translations are the fallback.\n- Always use apply_diff instead of write_to_file when editing existing translation files as it's much faster and more reliable\n- When using apply_diff, make sure to carefully identify the exact JSON structure to edit to avoid syntax errors\n- Always use the Trans component for text with embedded components\n- Internationalize and add English strings first, and then ask the user to confirm the approach before translating into all other languages\n\n# Quality Assurance\n- Maintain consistent terminology across all translations\n- Respect the JSON structure of translation files\n- Watch for placeholders and preserve them in translations\n- Be mindful of text length in UI elements when translating to languages that might require more characters\n- Use context-aware translations when the same string has different meanings\n- Always validate your translation work by running the missing translations script:\n ```\n node scripts/find-missing-translations.js\n ```\n- Before completing any translation task, ensure there are no missing translations by running the script with the target locale(s):\n ```\n node scripts/find-missing-translations.js --locale=<locale-code>\n ```\n- Address any missing translations identified by the script to ensure complete coverage across all locales\n\n# Supported Languages\n- Localize all strings into the following locale files: ca, de, en, es, fr, hi, it, ja, ko, pl, pt-BR, tr, vi, zh-CN, zh-TW\n- The translation files are under webview-ui/src/i18n/locales/",
25+
"customInstructions": "# 1. SUPPORTED LANGUAGES AND LOCATION\n- Localize all strings into the following locale files: ca, de, en, es, fr, hi, it, ja, ko, pl, pt-BR, tr, vi, zh-CN, zh-TW\n- The VSCode extension has two main areas that require localization:\n * Core Extension: src/i18n/locales/ (extension backend)\n * WebView UI: webview-ui/src/i18n/locales/ (user interface)\n\n# 2. VOICE, STYLE AND TONE\n- Maintain a direct and concise style that mirrors the tone of the original text\n- Carefully account for colloquialisms and idiomatic expressions in both source and target languages\n- Aim for culturally relevant and meaningful translations rather than literal translations\n- Adapt the formality level to match the original content (whether formal or informal)\n- Preserve the personality and voice of the original content\n- Use natural-sounding language that feels native to speakers of the target language\n- Don't translate the word \"token\" as it means something specific in English that all languages will understand\n\n# 3. CORE EXTENSION LOCALIZATION (src/)\n- Located in src/i18n/locales/\n- NOT ALL strings in core source need internationalization - only user-facing messages\n- Internal error messages, debugging logs, and developer-facing messages should remain in English\n- The t() function is used with namespaces like 'core:errors.missingToolParameter'\n- Be careful when modifying interpolation variables; they must remain consistent across all translations\n- Some strings in formatResponse.ts are intentionally not internationalized since they're internal\n- When updating strings in core.json, maintain all existing interpolation variables\n- Check string usages in the codebase before making changes to ensure you're not breaking functionality\n\n# 4. WEBVIEW UI LOCALIZATION (webview-ui/src/)\n- Located in webview-ui/src/i18n/locales/\n- Uses standard React i18next patterns with the useTranslation hook\n- All user interface strings should be internationalized\n- Always use the Trans component for text with embedded components\n\n# 5. TECHNICAL IMPLEMENTATION\n- Use namespaces to organize translations logically\n- Handle pluralization using i18next's built-in capabilities\n- Implement proper interpolation for variables using {{variable}} syntax\n- Don't include defaultValue. The `en` translations are the fallback\n- Always use apply_diff instead of write_to_file when editing existing translation files (much faster and more reliable)\n- When using apply_diff, carefully identify the exact JSON structure to edit to avoid syntax errors\n\n# 6. WORKFLOW AND APPROACH\n- First add or modify English strings, then ask for confirmation before translating to all other languages\n- Use this process for each localization task:\n 1. Identify where the string appears in the UI/codebase\n 2. Understand the context and purpose of the string\n 3. Update English translation first\n 4. Create appropriate translations for all other supported languages\n 5. Validate your changes with the missing translations script\n\n# 7. QUALITY ASSURANCE\n- Maintain consistent terminology across all translations\n- Respect the JSON structure of translation files\n- Watch for placeholders and preserve them in translations\n- Be mindful of text length in UI elements when translating to languages that might require more characters\n- Use context-aware translations when the same string has different meanings\n- Always validate your translation work by running the missing translations script:\n ```\n node scripts/find-missing-translations.js\n ```\n- Address any missing translations identified by the script to ensure complete coverage across all locales",
2626
"groups": [
2727
"read",
2828
"command",

.vscodeignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ demo.gif
2828
.roomodes
2929
cline_docs/**
3030
coverage/**
31+
locales/**
3132

3233
# Ignore all webview-ui files except the build directory (https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/frameworks/hello-world-react-cra/.vscodeignore)
3334
webview-ui/src/**

esbuild.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,111 @@ const copyWasmFiles = {
6363
},
6464
}
6565

66+
// Simple function to copy locale files
67+
function copyLocaleFiles() {
68+
const srcDir = path.join(__dirname, "src", "i18n", "locales")
69+
const destDir = path.join(__dirname, "dist", "i18n", "locales")
70+
const outDir = path.join(__dirname, "out", "i18n", "locales")
71+
72+
// Ensure source directory exists before proceeding
73+
if (!fs.existsSync(srcDir)) {
74+
console.warn(`Source locales directory does not exist: ${srcDir}`)
75+
return // Exit early if source directory doesn't exist
76+
}
77+
78+
// Create destination directories
79+
fs.mkdirSync(destDir, { recursive: true })
80+
try {
81+
fs.mkdirSync(outDir, { recursive: true })
82+
} catch (e) {}
83+
84+
// Function to copy directory recursively
85+
function copyDir(src, dest) {
86+
const entries = fs.readdirSync(src, { withFileTypes: true })
87+
88+
for (const entry of entries) {
89+
const srcPath = path.join(src, entry.name)
90+
const destPath = path.join(dest, entry.name)
91+
92+
if (entry.isDirectory()) {
93+
// Create directory and copy contents
94+
fs.mkdirSync(destPath, { recursive: true })
95+
copyDir(srcPath, destPath)
96+
} else {
97+
// Copy the file
98+
fs.copyFileSync(srcPath, destPath)
99+
}
100+
}
101+
}
102+
103+
// Copy files to dist directory
104+
copyDir(srcDir, destDir)
105+
console.log("Copied locale files to dist/i18n/locales")
106+
107+
// Copy to out directory for debugging
108+
try {
109+
copyDir(srcDir, outDir)
110+
console.log("Copied locale files to out/i18n/locales")
111+
} catch (e) {
112+
console.warn("Could not copy to out directory:", e.message)
113+
}
114+
}
115+
116+
// Set up file watcher if in watch mode
117+
function setupLocaleWatcher() {
118+
if (!watch) return
119+
120+
const localesDir = path.join(__dirname, "src", "i18n", "locales")
121+
122+
// Ensure the locales directory exists before setting up watcher
123+
if (!fs.existsSync(localesDir)) {
124+
console.warn(`Cannot set up watcher: Source locales directory does not exist: ${localesDir}`)
125+
return
126+
}
127+
128+
console.log(`Setting up watcher for locale files in ${localesDir}`)
129+
130+
// Use a debounce mechanism
131+
let debounceTimer = null
132+
const debouncedCopy = () => {
133+
if (debounceTimer) clearTimeout(debounceTimer)
134+
debounceTimer = setTimeout(() => {
135+
console.log("Locale files changed, copying...")
136+
copyLocaleFiles()
137+
}, 300) // Wait 300ms after last change before copying
138+
}
139+
140+
// Watch the locales directory
141+
try {
142+
fs.watch(localesDir, { recursive: true }, (eventType, filename) => {
143+
if (filename && filename.endsWith(".json")) {
144+
console.log(`Locale file ${filename} changed, triggering copy...`)
145+
debouncedCopy()
146+
}
147+
})
148+
console.log("Watcher for locale files is set up")
149+
} catch (error) {
150+
console.error(`Error setting up watcher for ${localesDir}:`, error.message)
151+
}
152+
}
153+
154+
const copyLocalesFiles = {
155+
name: "copy-locales-files",
156+
setup(build) {
157+
build.onEnd(() => {
158+
copyLocaleFiles()
159+
})
160+
},
161+
}
162+
66163
const extensionConfig = {
67164
bundle: true,
68165
minify: production,
69166
sourcemap: !production,
70167
logLevel: "silent",
71168
plugins: [
72169
copyWasmFiles,
170+
copyLocalesFiles,
73171
/* add to the end of plugins array */
74172
esbuildProblemMatcherPlugin,
75173
{
@@ -91,8 +189,17 @@ const extensionConfig = {
91189

92190
async function main() {
93191
const extensionCtx = await esbuild.context(extensionConfig)
192+
94193
if (watch) {
194+
// Start the esbuild watcher
95195
await extensionCtx.watch()
196+
197+
// Copy and watch locale files
198+
console.log("Copying locale files initially...")
199+
copyLocaleFiles()
200+
201+
// Set up the watcher for locale files
202+
setupLocaleWatcher()
96203
} else {
97204
await extensionCtx.rebuild()
98205
await extensionCtx.dispose()

package-lock.json

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@
345345
"fastest-levenshtein": "^1.0.16",
346346
"get-folder-size": "^5.0.0",
347347
"globby": "^14.0.2",
348+
"i18next": "^24.2.2",
348349
"isbinaryfile": "^5.0.2",
349350
"js-tiktoken": "^1.0.19",
350351
"mammoth": "^1.8.0",

0 commit comments

Comments
 (0)