1111 * 5. Preserves JSON structure and formatting
1212 */
1313
14- import fs from 'fs' ;
15- import path from 'path' ;
16- import { fileURLToPath } from 'url' ;
14+ import fs from 'node: fs'
15+ import path from 'node: path'
16+ import { fileURLToPath } from 'node: url'
1717
18- const __filename = fileURLToPath ( import . meta. url ) ;
19- const __dirname = path . dirname ( __filename ) ;
18+ const __filename = fileURLToPath ( import . meta. url )
19+ const __dirname = path . dirname ( __filename )
2020
2121// ANSI color codes for terminal output
2222const colors = {
@@ -26,12 +26,12 @@ const colors = {
2626 yellow : '\x1b[33m' ,
2727 blue : '\x1b[34m' ,
2828 cyan : '\x1b[36m' ,
29- } ;
29+ }
3030
3131// Get project root (4 levels up from .claude/skills/i18n/scripts/)
32- const PROJECT_ROOT = path . resolve ( __dirname , '../../../../' ) ;
33- const MESSAGES_DIR = path . join ( PROJECT_ROOT , 'messages' ) ;
34- const EN_FILE = path . join ( MESSAGES_DIR , 'en.json' ) ;
32+ const PROJECT_ROOT = path . resolve ( __dirname , '../../../../' )
33+ const MESSAGES_DIR = path . join ( PROJECT_ROOT , 'messages' )
34+ const EN_FILE = path . join ( MESSAGES_DIR , 'en.json' )
3535
3636/**
3737 * Recursively get all keys from a nested object
@@ -40,19 +40,19 @@ const EN_FILE = path.join(MESSAGES_DIR, 'en.json');
4040 * @returns {string[] } Array of dot-notation key paths
4141 */
4242function getAllKeys ( obj , prefix = '' ) {
43- const keys = [ ] ;
43+ const keys = [ ]
4444
4545 for ( const [ key , value ] of Object . entries ( obj ) ) {
46- const fullKey = prefix ? `${ prefix } .${ key } ` : key ;
46+ const fullKey = prefix ? `${ prefix } .${ key } ` : key
4747
4848 if ( value !== null && typeof value === 'object' && ! Array . isArray ( value ) ) {
49- keys . push ( ...getAllKeys ( value , fullKey ) ) ;
49+ keys . push ( ...getAllKeys ( value , fullKey ) )
5050 } else {
51- keys . push ( fullKey ) ;
51+ keys . push ( fullKey )
5252 }
5353 }
5454
55- return keys ;
55+ return keys
5656}
5757
5858/**
@@ -62,7 +62,7 @@ function getAllKeys(obj, prefix = '') {
6262 * @returns {* } The value at the path
6363 */
6464function getValueByPath ( obj , path ) {
65- return path . split ( '.' ) . reduce ( ( current , key ) => current ?. [ key ] , obj ) ;
65+ return path . split ( '.' ) . reduce ( ( current , key ) => current ?. [ key ] , obj )
6666}
6767
6868/**
@@ -72,15 +72,15 @@ function getValueByPath(obj, path) {
7272 * @param {* } value - Value to set
7373 */
7474function setValueByPath ( obj , path , value ) {
75- const keys = path . split ( '.' ) ;
76- const lastKey = keys . pop ( ) ;
75+ const keys = path . split ( '.' )
76+ const lastKey = keys . pop ( )
7777 const target = keys . reduce ( ( current , key ) => {
7878 if ( ! ( key in current ) ) {
79- current [ key ] = { } ;
79+ current [ key ] = { }
8080 }
81- return current [ key ] ;
82- } , obj ) ;
83- target [ lastKey ] = value ;
81+ return current [ key ]
82+ } , obj )
83+ target [ lastKey ] = value
8484}
8585
8686/**
@@ -89,16 +89,16 @@ function setValueByPath(obj, path, value) {
8989 * @param {string } path - Dot notation path
9090 */
9191function deleteValueByPath ( obj , path ) {
92- const keys = path . split ( '.' ) ;
93- const lastKey = keys . pop ( ) ;
94- const target = keys . reduce ( ( current , key ) => current ?. [ key ] , obj ) ;
92+ const keys = path . split ( '.' )
93+ const lastKey = keys . pop ( )
94+ const target = keys . reduce ( ( current , key ) => current ?. [ key ] , obj )
9595
9696 if ( target && lastKey in target ) {
97- delete target [ lastKey ] ;
97+ delete target [ lastKey ]
9898
9999 // Clean up empty parent objects
100100 if ( Object . keys ( target ) . length === 0 && keys . length > 0 ) {
101- deleteValueByPath ( obj , keys . join ( '.' ) ) ;
101+ deleteValueByPath ( obj , keys . join ( '.' ) )
102102 }
103103 }
104104}
@@ -110,114 +110,123 @@ function deleteValueByPath(obj, path) {
110110 * @returns {Object } Sync report
111111 */
112112function syncLanguageFile ( targetFile , enData ) {
113- const targetData = JSON . parse ( fs . readFileSync ( targetFile , 'utf-8' ) ) ;
114- const enKeys = getAllKeys ( enData ) ;
115- const targetKeys = getAllKeys ( targetData ) ;
113+ const targetData = JSON . parse ( fs . readFileSync ( targetFile , 'utf-8' ) )
114+ const enKeys = getAllKeys ( enData )
115+ const targetKeys = getAllKeys ( targetData )
116116
117- const added = [ ] ;
118- const removed = [ ] ;
117+ const added = [ ]
118+ const removed = [ ]
119119
120120 // Add missing keys from en.json
121121 for ( const key of enKeys ) {
122122 if ( ! targetKeys . includes ( key ) ) {
123- const enValue = getValueByPath ( enData , key ) ;
124- setValueByPath ( targetData , key , enValue ) ;
125- added . push ( key ) ;
123+ const enValue = getValueByPath ( enData , key )
124+ setValueByPath ( targetData , key , enValue )
125+ added . push ( key )
126126 }
127127 }
128128
129129 // Remove extra keys not in en.json
130130 for ( const key of targetKeys ) {
131131 if ( ! enKeys . includes ( key ) ) {
132- deleteValueByPath ( targetData , key ) ;
133- removed . push ( key ) ;
132+ deleteValueByPath ( targetData , key )
133+ removed . push ( key )
134134 }
135135 }
136136
137137 // Write back with consistent formatting (2 spaces indentation)
138138 if ( added . length > 0 || removed . length > 0 ) {
139- fs . writeFileSync ( targetFile , JSON . stringify ( targetData , null , 2 ) + '\n' , 'utf-8' ) ;
139+ fs . writeFileSync ( targetFile , ` ${ JSON . stringify ( targetData , null , 2 ) } \n` , 'utf-8' )
140140 }
141141
142- return { added, removed } ;
142+ return { added, removed }
143143}
144144
145145/**
146146 * Main sync function
147147 */
148148function main ( ) {
149- console . log ( `${ colors . cyan } 🔄 Syncing language files with en.json...${ colors . reset } \n` ) ;
149+ console . log ( `${ colors . cyan } 🔄 Syncing language files with en.json...${ colors . reset } \n` )
150150
151151 // Check if messages directory exists
152152 if ( ! fs . existsSync ( MESSAGES_DIR ) ) {
153- console . error ( `${ colors . red } ✗ Messages directory not found: ${ MESSAGES_DIR } ${ colors . reset } ` ) ;
154- process . exit ( 1 ) ;
153+ console . error ( `${ colors . red } ✗ Messages directory not found: ${ MESSAGES_DIR } ${ colors . reset } ` )
154+ process . exit ( 1 )
155155 }
156156
157157 // Read English reference file
158158 if ( ! fs . existsSync ( EN_FILE ) ) {
159- console . error ( `${ colors . red } ✗ English reference file not found: ${ EN_FILE } ${ colors . reset } ` ) ;
160- process . exit ( 1 ) ;
159+ console . error ( `${ colors . red } ✗ English reference file not found: ${ EN_FILE } ${ colors . reset } ` )
160+ process . exit ( 1 )
161161 }
162162
163- const enData = JSON . parse ( fs . readFileSync ( EN_FILE , 'utf-8' ) ) ;
163+ const enData = JSON . parse ( fs . readFileSync ( EN_FILE , 'utf-8' ) )
164164
165165 // Get all language files except en.json
166- const files = fs . readdirSync ( MESSAGES_DIR )
166+ const files = fs
167+ . readdirSync ( MESSAGES_DIR )
167168 . filter ( file => file . endsWith ( '.json' ) && file !== 'en.json' )
168- . map ( file => path . join ( MESSAGES_DIR , file ) ) ;
169+ . map ( file => path . join ( MESSAGES_DIR , file ) )
169170
170171 if ( files . length === 0 ) {
171- console . log ( `${ colors . yellow } ⚠ No other language files found to sync${ colors . reset } ` ) ;
172- return ;
172+ console . log ( `${ colors . yellow } ⚠ No other language files found to sync${ colors . reset } ` )
173+ return
173174 }
174175
175- let totalAdded = 0 ;
176- let totalRemoved = 0 ;
177- let filesModified = 0 ;
176+ let totalAdded = 0
177+ let totalRemoved = 0
178+ let filesModified = 0
178179
179180 // Sync each language file
180181 for ( const file of files ) {
181- const locale = path . basename ( file , '.json' ) ;
182- const { added, removed } = syncLanguageFile ( file , enData ) ;
182+ const locale = path . basename ( file , '.json' )
183+ const { added, removed } = syncLanguageFile ( file , enData )
183184
184185 if ( added . length > 0 || removed . length > 0 ) {
185- filesModified ++ ;
186- console . log ( `${ colors . green } ✓${ colors . reset } Synced ${ colors . blue } ${ locale } .json${ colors . reset } ` ) ;
186+ filesModified ++
187+ console . log (
188+ `${ colors . green } ✓${ colors . reset } Synced ${ colors . blue } ${ locale } .json${ colors . reset } `
189+ )
187190
188191 if ( added . length > 0 ) {
189- console . log ( ` ${ colors . green } +${ colors . reset } Added ${ added . length } key${ added . length > 1 ? 's' : '' } ` ) ;
190- totalAdded += added . length ;
192+ console . log (
193+ ` ${ colors . green } +${ colors . reset } Added ${ added . length } key${ added . length > 1 ? 's' : '' } `
194+ )
195+ totalAdded += added . length
191196 }
192197
193198 if ( removed . length > 0 ) {
194- console . log ( ` ${ colors . red } -${ colors . reset } Removed ${ removed . length } key${ removed . length > 1 ? 's' : '' } ` ) ;
195- totalRemoved += removed . length ;
199+ console . log (
200+ ` ${ colors . red } -${ colors . reset } Removed ${ removed . length } key${ removed . length > 1 ? 's' : '' } `
201+ )
202+ totalRemoved += removed . length
196203 }
197204
198- console . log ( '' ) ;
205+ console . log ( '' )
199206 } else {
200- console . log ( `${ colors . green } ✓${ colors . reset } ${ colors . blue } ${ locale } .json${ colors . reset } already in sync` ) ;
207+ console . log (
208+ `${ colors . green } ✓${ colors . reset } ${ colors . blue } ${ locale } .json${ colors . reset } already in sync`
209+ )
201210 }
202211 }
203212
204213 // Summary
205- console . log ( `${ colors . cyan } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${ colors . reset } ` ) ;
214+ console . log ( `${ colors . cyan } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${ colors . reset } ` )
206215
207216 if ( filesModified > 0 ) {
208- console . log ( `${ colors . green } ✓ Sync complete!${ colors . reset } ` ) ;
209- console . log ( ` Modified: ${ filesModified } file${ filesModified > 1 ? 's' : '' } ` ) ;
210- console . log ( ` Added: ${ totalAdded } key${ totalAdded > 1 ? 's' : '' } ` ) ;
211- console . log ( ` Removed: ${ totalRemoved } key${ totalRemoved > 1 ? 's' : '' } ` ) ;
217+ console . log ( `${ colors . green } ✓ Sync complete!${ colors . reset } ` )
218+ console . log ( ` Modified: ${ filesModified } file${ filesModified > 1 ? 's' : '' } ` )
219+ console . log ( ` Added: ${ totalAdded } key${ totalAdded > 1 ? 's' : '' } ` )
220+ console . log ( ` Removed: ${ totalRemoved } key${ totalRemoved > 1 ? 's' : '' } ` )
212221 } else {
213- console . log ( `${ colors . green } ✓ All language files are already in sync${ colors . reset } ` ) ;
222+ console . log ( `${ colors . green } ✓ All language files are already in sync${ colors . reset } ` )
214223 }
215224}
216225
217226// Run the script
218227try {
219- main ( ) ;
228+ main ( )
220229} catch ( error ) {
221- console . error ( `${ colors . red } ✗ Error: ${ error . message } ${ colors . reset } ` ) ;
222- process . exit ( 1 ) ;
230+ console . error ( `${ colors . red } ✗ Error: ${ error . message } ${ colors . reset } ` )
231+ process . exit ( 1 )
223232}
0 commit comments