Skip to content

Commit 2363fe9

Browse files
ericyangpanclaude
andcommitted
refactor(i18n): update i18n infrastructure and utilities
Update i18n core infrastructure to support the new namespaced locale structure and add validation tools. Changes: - Update i18n configuration to use new locale structure (src/i18n/config.ts) - Add new i18n utilities: - src/i18n/lib-core.mjs - Core i18n utilities (ESM) - src/i18n/lib.ts - TypeScript i18n utilities - src/i18n/routing.ts - Routing configuration - Update i18n navigation and request handling - Add validation scripts: - scripts/validate/validate-locales-refs.mjs - Validate locale references - scripts/validate/validate-locales-structure.mjs - Validate locale file structure - scripts/refactor/sort-locales-fields.mjs - Sort locale file fields - Add npm script: validate:locales-structure - Remove deprecated script: scripts/i18n/map-locales.mjs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 6e69ddc commit 2363fe9

File tree

10 files changed

+1216
-10
lines changed

10 files changed

+1216
-10
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"validate:manifests": "node scripts/validate/index.mjs manifests",
2020
"validate:github-stars": "node scripts/validate/index.mjs github-stars",
2121
"validate:urls": "node scripts/validate/index.mjs urls",
22+
"validate:locales-structure": "node scripts/validate/index.mjs locales-structure",
2223
"generate": "node scripts/generate/index.mjs",
2324
"generate:manifests": "node scripts/generate/index.mjs manifest-indexes",
2425
"generate:metadata": "node scripts/generate/index.mjs metadata",
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Sort fields in all locales JSON files alphabetically
5+
* This script recursively processes all JSON files in the locales directory
6+
* and sorts their object keys alphabetically (including nested objects).
7+
*/
8+
9+
import fs from 'node:fs/promises'
10+
import path from 'node:path'
11+
import { fileURLToPath } from 'node:url'
12+
13+
const __filename = fileURLToPath(import.meta.url)
14+
const __dirname = path.dirname(__filename)
15+
const ROOT_DIR = path.resolve(__dirname, '../..')
16+
const LOCALES_DIR = path.join(ROOT_DIR, 'locales')
17+
18+
/**
19+
* Recursively sort object keys alphabetically
20+
* Arrays are preserved as-is, only object keys are sorted
21+
*/
22+
function sortObjectKeysRecursively(obj) {
23+
if (Array.isArray(obj)) {
24+
return obj.map(item => sortObjectKeysRecursively(item))
25+
}
26+
27+
if (obj && typeof obj === 'object') {
28+
const sorted = {}
29+
const keys = Object.keys(obj).sort()
30+
31+
for (const key of keys) {
32+
sorted[key] = sortObjectKeysRecursively(obj[key])
33+
}
34+
35+
return sorted
36+
}
37+
38+
return obj
39+
}
40+
41+
/**
42+
* Process a single JSON file
43+
*/
44+
async function processJsonFile(filePath, relativePath) {
45+
try {
46+
// Read the file
47+
const content = await fs.readFile(filePath, 'utf-8')
48+
const data = JSON.parse(content)
49+
50+
// Sort the data recursively
51+
const sortedData = sortObjectKeysRecursively(data)
52+
53+
// Write back to file with 2-space indentation
54+
const jsonContent = `${JSON.stringify(sortedData, null, 2)}\n`
55+
await fs.writeFile(filePath, jsonContent, 'utf-8')
56+
57+
console.log(` ✅ ${relativePath}`)
58+
} catch (error) {
59+
console.error(` ❌ Error processing ${relativePath}:`, error.message)
60+
}
61+
}
62+
63+
/**
64+
* Recursively find all JSON files in a directory
65+
*/
66+
async function findJsonFiles(dirPath, basePath = dirPath) {
67+
const jsonFiles = []
68+
69+
try {
70+
const entries = await fs.readdir(dirPath, { withFileTypes: true })
71+
72+
for (const entry of entries) {
73+
const fullPath = path.join(dirPath, entry.name)
74+
75+
if (entry.isDirectory()) {
76+
// Recursively search subdirectories
77+
const subFiles = await findJsonFiles(fullPath, basePath)
78+
jsonFiles.push(...subFiles)
79+
} else if (entry.isFile() && entry.name.endsWith('.json')) {
80+
// Calculate relative path from base
81+
const relativePath = path.relative(basePath, fullPath)
82+
jsonFiles.push({ fullPath, relativePath })
83+
}
84+
}
85+
} catch (error) {
86+
console.error(` ⚠️ Error reading directory ${dirPath}:`, error.message)
87+
}
88+
89+
return jsonFiles
90+
}
91+
92+
/**
93+
* Main function
94+
*/
95+
async function main() {
96+
console.log('🔄 Sorting locales JSON files alphabetically...\n')
97+
98+
// Find all JSON files in locales directory
99+
const jsonFiles = await findJsonFiles(LOCALES_DIR)
100+
101+
if (jsonFiles.length === 0) {
102+
console.log('⚠️ No JSON files found in locales directory')
103+
return
104+
}
105+
106+
console.log(`📁 Found ${jsonFiles.length} JSON file(s) to process\n`)
107+
108+
// Process each file
109+
for (const { fullPath, relativePath } of jsonFiles) {
110+
await processJsonFile(fullPath, relativePath)
111+
}
112+
113+
console.log('\n✨ Done!')
114+
}
115+
116+
main().catch(console.error)

0 commit comments

Comments
 (0)