Skip to content

Commit cf487fb

Browse files
authored
i18n Add translations for task pinning and unpinning (#2109)
Signed-off-by: feifei <[email protected]>
1 parent 2303f67 commit cf487fb

File tree

18 files changed

+87
-29
lines changed

18 files changed

+87
-29
lines changed

scripts/find-missing-i18n-key.js

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,17 @@ Output:
3434
process.exit(0)
3535
}
3636

37-
// Directory to traverse
38-
const TARGET_DIR = path.join(__dirname, "../webview-ui/src/components")
39-
const LOCALES_DIR = path.join(__dirname, "../webview-ui/src/i18n/locales")
37+
// Directories to traverse and their corresponding locales
38+
const DIRS = {
39+
components: {
40+
path: path.join(__dirname, "../webview-ui/src/components"),
41+
localesDir: path.join(__dirname, "../webview-ui/src/i18n/locales"),
42+
},
43+
src: {
44+
path: path.join(__dirname, "../src"),
45+
localesDir: path.join(__dirname, "../src/i18n/locales"),
46+
},
47+
}
4048

4149
// Regular expressions to match i18n keys
4250
const i18nPatterns = [
@@ -45,15 +53,23 @@ const i18nPatterns = [
4553
/t\("([a-zA-Z][a-zA-Z0-9_]*[:.][a-zA-Z0-9_.]+)"\)/g, // Match t("key") format, where key contains a colon or dot
4654
]
4755

48-
// Get all language directories
49-
function getLocaleDirs() {
50-
const allLocales = fs.readdirSync(LOCALES_DIR).filter((file) => {
51-
const stats = fs.statSync(path.join(LOCALES_DIR, file))
52-
return stats.isDirectory() // Do not exclude any language directories
53-
})
56+
// Get all language directories for a specific locales directory
57+
function getLocaleDirs(localesDir) {
58+
try {
59+
const allLocales = fs.readdirSync(localesDir).filter((file) => {
60+
const stats = fs.statSync(path.join(localesDir, file))
61+
return stats.isDirectory() // Do not exclude any language directories
62+
})
5463

55-
// Filter to a specific language if specified
56-
return args.locale ? allLocales.filter((locale) => locale === args.locale) : allLocales
64+
// Filter to a specific language if specified
65+
return args.locale ? allLocales.filter((locale) => locale === args.locale) : allLocales
66+
} catch (error) {
67+
if (error.code === "ENOENT") {
68+
console.warn(`Warning: Locales directory not found: ${localesDir}`)
69+
return []
70+
}
71+
throw error
72+
}
5773
}
5874

5975
// Get the value from JSON by path
@@ -72,14 +88,14 @@ function getValueByPath(obj, path) {
7288
}
7389

7490
// Check if the key exists in all language files, return a list of missing language files
75-
function checkKeyInLocales(key, localeDirs) {
91+
function checkKeyInLocales(key, localeDirs, localesDir) {
7692
const [file, ...pathParts] = key.split(":")
7793
const jsonPath = pathParts.join(".")
7894

7995
const missingLocales = []
8096

8197
localeDirs.forEach((locale) => {
82-
const filePath = path.join(LOCALES_DIR, locale, `${file}.json`)
98+
const filePath = path.join(localesDir, locale, `${file}.json`)
8399
if (!fs.existsSync(filePath)) {
84100
missingLocales.push(`${locale}/${file}.json`)
85101
return
@@ -96,21 +112,20 @@ function checkKeyInLocales(key, localeDirs) {
96112

97113
// Recursively traverse the directory
98114
function findMissingI18nKeys() {
99-
const localeDirs = getLocaleDirs()
100115
const results = []
101116

102-
function walk(dir) {
117+
function walk(dir, baseDir, localeDirs, localesDir) {
103118
const files = fs.readdirSync(dir)
104119

105120
for (const file of files) {
106121
const filePath = path.join(dir, file)
107122
const stat = fs.statSync(filePath)
108123

109-
// Exclude test files
110-
if (filePath.includes(".test.")) continue
124+
// Exclude test files and __mocks__ directory
125+
if (filePath.includes(".test.") || filePath.includes("__mocks__")) continue
111126

112127
if (stat.isDirectory()) {
113-
walk(filePath) // Recursively traverse subdirectories
128+
walk(filePath, baseDir, localeDirs, localesDir) // Recursively traverse subdirectories
114129
} else if (stat.isFile() && [".ts", ".tsx", ".js", ".jsx"].includes(path.extname(filePath))) {
115130
const content = fs.readFileSync(filePath, "utf8")
116131

@@ -119,12 +134,12 @@ function findMissingI18nKeys() {
119134
let match
120135
while ((match = pattern.exec(content)) !== null) {
121136
const key = match[1]
122-
const missingLocales = checkKeyInLocales(key, localeDirs)
137+
const missingLocales = checkKeyInLocales(key, localeDirs, localesDir)
123138
if (missingLocales.length > 0) {
124139
results.push({
125140
key,
126141
missingLocales,
127-
file: path.relative(TARGET_DIR, filePath),
142+
file: path.relative(baseDir, filePath),
128143
})
129144
}
130145
}
@@ -133,21 +148,34 @@ function findMissingI18nKeys() {
133148
}
134149
}
135150

136-
walk(TARGET_DIR)
151+
// Walk through all directories
152+
Object.entries(DIRS).forEach(([name, config]) => {
153+
const localeDirs = getLocaleDirs(config.localesDir)
154+
if (localeDirs.length > 0) {
155+
console.log(`\nChecking ${name} directory with ${localeDirs.length} languages: ${localeDirs.join(", ")}`)
156+
walk(config.path, config.path, localeDirs, config.localesDir)
157+
}
158+
})
159+
137160
return results
138161
}
139162

140163
// Execute and output the results
141164
function main() {
142165
try {
143-
const localeDirs = getLocaleDirs()
144-
if (args.locale && localeDirs.length === 0) {
145-
console.error(`Error: Language '${args.locale}' not found in ${LOCALES_DIR}`)
146-
process.exit(1)
166+
if (args.locale) {
167+
// Check if the specified locale exists in any of the locales directories
168+
const localeExists = Object.values(DIRS).some((config) => {
169+
const localeDirs = getLocaleDirs(config.localesDir)
170+
return localeDirs.includes(args.locale)
171+
})
172+
173+
if (!localeExists) {
174+
console.error(`Error: Language '${args.locale}' not found in any locales directory`)
175+
process.exit(1)
176+
}
147177
}
148178

149-
console.log(`Checking ${localeDirs.length} non-English languages: ${localeDirs.join(", ")}`)
150-
151179
const missingKeys = findMissingI18nKeys()
152180

153181
if (missingKeys.length === 0) {

src/core/webview/ClineProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1250,7 +1250,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
12501250
}
12511251
case "openProjectMcpSettings": {
12521252
if (!vscode.workspace.workspaceFolders?.length) {
1253-
vscode.window.showErrorMessage(t("common:no_workspace"))
1253+
vscode.window.showErrorMessage(t("common:errors.no_workspace"))
12541254
return
12551255
}
12561256

src/core/webview/__tests__/ClineProvider.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2031,7 +2031,7 @@ describe("Project MCP Settings", () => {
20312031
await messageHandler({ type: "openProjectMcpSettings" })
20322032

20332033
// Verify error message was shown
2034-
expect(vscode.window.showErrorMessage).toHaveBeenCalledWith("no_workspace")
2034+
expect(vscode.window.showErrorMessage).toHaveBeenCalledWith("errors.no_workspace")
20352035
})
20362036

20372037
test.skip("handles openProjectMcpSettings file creation error", async () => {

webview-ui/src/i18n/locales/ca/chat.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
"export": "Exportar historial de tasques",
1313
"delete": "Eliminar tasca (Shift + Clic per ometre confirmació)"
1414
},
15+
"unpin": "desancorar",
16+
"pin": "ancorar",
1517
"tokenProgress": {
1618
"availableSpace": "Espai disponible: {{amount}} tokens",
1719
"tokensUsed": "Tokens utilitzats: {{used}} de {{total}}",

webview-ui/src/i18n/locales/de/chat.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
"export": "Aufgabenverlauf exportieren",
1313
"delete": "Aufgabe löschen (Shift + Klick zum Überspringen der Bestätigung)"
1414
},
15+
"unpin": "lösen",
16+
"pin": "anheften",
1517
"tokenProgress": {
1618
"availableSpace": "Verfügbarer Speicher: {{amount}} Tokens",
1719
"tokensUsed": "Verwendete Tokens: {{used}} von {{total}}",

webview-ui/src/i18n/locales/en/chat.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
"export": "Export task history",
1313
"delete": "Delete Task (Shift + Click to skip confirmation)"
1414
},
15+
"unpin": "unpin",
16+
"pin": "pin",
1517
"retry": {
1618
"title": "Retry",
1719
"tooltip": "Try the operation again"

webview-ui/src/i18n/locales/es/chat.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
"export": "Exportar historial de tareas",
1313
"delete": "Eliminar tarea (Shift + Clic para omitir confirmación)"
1414
},
15+
"unpin": "desanclar",
16+
"pin": "anclar",
1517
"retry": {
1618
"title": "Reintentar",
1719
"tooltip": "Intenta la operación de nuevo"

webview-ui/src/i18n/locales/fr/chat.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
"export": "Exporter l'historique des tâches",
1313
"delete": "Supprimer la tâche (Shift + Clic pour ignorer la confirmation)"
1414
},
15+
"unpin": "détacher",
16+
"pin": "épingler",
1517
"tokenProgress": {
1618
"availableSpace": "Espace disponible : {{amount}} tokens",
1719
"tokensUsed": "Tokens utilisés : {{used}} sur {{total}}",

webview-ui/src/i18n/locales/hi/chat.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
"export": "कार्य इतिहास निर्यात करें",
1313
"delete": "कार्य हटाएं (पुष्टि को छोड़ने के लिए Shift + क्लिक)"
1414
},
15+
"unpin": "पिन हटाएं",
16+
"pin": "पिन करें",
1517
"tokenProgress": {
1618
"availableSpace": "उपलब्ध स्थान: {{amount}} tokens",
1719
"tokensUsed": "प्रयुक्त tokens: {{used}} / {{total}}",

webview-ui/src/i18n/locales/it/chat.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
"export": "Esporta cronologia attività",
1313
"delete": "Elimina attività (Shift + Clic per saltare la conferma)"
1414
},
15+
"unpin": "sblocca",
16+
"pin": "blocca",
1517
"tokenProgress": {
1618
"availableSpace": "Spazio disponibile: {{amount}} tokens",
1719
"tokensUsed": "Tokens utilizzati: {{used}} di {{total}}",

0 commit comments

Comments
 (0)