1- // Update the language files with the new keys from the English file
2- // Usage:
3- // npx tsx extract-i18n-lang.ts src/i18n/messages.json src/i18n/messages.fr.json > src/i18n/messages.fr-updated.json
4- // npx tsx extract-i18n-lang.ts src/i18n/messages.json src/i18n/messages.es.json > src/i18n/messages.es-updated.json
5- // and then manually inspect the results, translate the new keys and copy the
6- // updated files back to the original files.
7-
81import fs from "fs" ;
92import process from "process" ;
3+ import { parseArgs } from "node:util" ;
104
11- // Get the messages file from the command line
12- const englishMessagesFile = process . argv [ 2 ] ;
13- const languageMessagesFile = process . argv [ 3 ] ;
5+ function showHelp ( ) {
6+ console . log ( `Update the language files with the new keys from the English file.
147
15- // Check if filename is provided
16- if ( ! englishMessagesFile || ! languageMessagesFile ) {
17- console . error (
18- "Please provide the English message file and translated message file as first and second CLI argument" ,
19- ) ;
20- process . exit ( 1 ) ;
8+ Then manually inspect the results, translate the new keys and copy the
9+ updated files back to the original files.
10+
11+ Usage:
12+ npx tsx extract-i18n-lang.ts [options] englishFile otherLanguageFile
13+
14+ Options:
15+ --output filePath writes the utf-8 encoded data to the specified output file
16+ -i, --inplace overwrites the translated language file
17+ -h, --help displays this message
18+
19+ Examples:
20+ npx tsx extract-i18n-lang.ts src/i18n/messages.json src/i18n/messages.fr.json > src/i18n/messages.fr-updated.json
21+ npx tsx extract-i18n-lang.ts src/i18n/messages.json src/i18n/messages.es.json > src/i18n/messages.es-updated.json
22+
23+ npx tsx extract-i18n-lang.ts --output src/i18n/messages.es-updated.json src/i18n/messages.json src/i18n/messages.es.json
24+ npx tsx extract-i18n-lang.ts --inplace src/i18n/messages.json src/i18n/messages.es.json
25+
26+ Note:
27+ In a Windows PowerShell environment, please use either the --output or the --inplace flags.
28+ ` ) ;
29+ }
30+
31+ function parseCommandLine ( ) {
32+ const { values : flags , positionals : args } = parseArgs ( {
33+ args : process . argv . slice ( 2 ) ,
34+ options : {
35+ output : {
36+ type : "string" ,
37+ default : "-" ,
38+ } ,
39+ inplace : { type : "boolean" , short : "i" } ,
40+ help : { type : "boolean" , short : "h" } ,
41+ } ,
42+ allowPositionals : true ,
43+ } ) ;
44+
45+ // show help message
46+ if ( flags . help ) {
47+ showHelp ( ) ;
48+ process . exit ( 0 ) ;
49+ }
50+
51+ // Check if filenames are provided
52+ if ( args . length < 2 ) {
53+ console . error (
54+ "Please provide the English message file and translated message file as first and second CLI argument" ,
55+ ) ;
56+ process . exit ( 1 ) ;
57+ }
58+
59+ // In-place implementation, replace the output file with the
60+ // source of the translated data, but only if the user has not
61+ // specified an output file path.
62+ if ( flags . output === "-" && flags . inplace ) {
63+ flags . output = args [ 1 ] ;
64+ }
65+
66+ // If a Windows user is using stdout, provide a warning message. This is really targeted
67+ // at PowerShell users but we cannot reliably determine which shell is being used.
68+ if ( process . platform === "win32" && flags . output === "-" ) {
69+ console . error (
70+ "Windows warning: please provide either the --output or --inplace flags to generate a valid utf-8 file" ,
71+ ) ;
72+ }
73+
74+ return { flags, args } ;
75+ }
76+
77+ interface TranslationFile {
78+ locale : string ;
79+ translations : {
80+ [ key : string ] : string ;
81+ } ;
82+ }
83+
84+ function readJSON ( filePath : string ) : TranslationFile {
85+ try {
86+ const rawData = fs . readFileSync ( filePath , "utf8" ) ;
87+ return JSON . parse ( rawData ) ;
88+ } catch ( err : any ) {
89+ console . error (
90+ `An error occurred while reading "${ filePath } ":\n ${ "message" in err ? err . message : err } ` ,
91+ ) ;
92+ process . exit ( 1 ) ;
93+ }
2194}
2295
23- // Read the English file synchronously
24- const englishDataRaw = fs . readFileSync ( englishMessagesFile , "utf8" ) ;
25- const englishData = JSON . parse ( englishDataRaw ) ;
26- //console.log(englishDataParsed);
96+ // Get the arguments from the command line
97+ const { flags, args } = parseCommandLine ( ) ;
98+
99+ const englishMessagesFile = args [ 0 ] ;
100+ const languageMessagesFile = args [ 1 ] ;
27101
28- // Read the language file synchronously
29- const languageDataRaw = fs . readFileSync ( languageMessagesFile , "utf8" ) ;
30- let languageData = JSON . parse ( languageDataRaw ) ;
31- //assert(englishData, 'English data is null');
32- //assert(languageData, 'Language data is null');
102+ const englishData = readJSON ( englishMessagesFile ) ;
103+ const languageData = readJSON ( languageMessagesFile ) ;
33104
34105for ( const key in englishData . translations ) {
35106 if ( ! languageData . translations [ key ] ) {
@@ -46,12 +117,28 @@ for (const key in languageData.translations) {
46117 delete languageData . translations [ key ] ;
47118 }
48119}
49- //console.log(languageData)
50120
51- let sortedTranslations : any = { } ;
121+ const sortedTranslations : any = { } ;
52122for ( const key in englishData . translations ) {
53123 sortedTranslations [ key ] = languageData . translations [ key ] ;
54124}
55- //console.log(sortedTranslations);
56125languageData . translations = sortedTranslations ;
57- console . log ( JSON . stringify ( languageData , null , 2 ) ) ;
126+
127+ // Save the new translated file to the user provided output path.
128+ try {
129+ const writer =
130+ flags . output !== "-" ? fs . openSync ( flags . output , "w" ) : process . stdout . fd ;
131+
132+ fs . writeSync (
133+ writer ,
134+ Buffer . from ( JSON . stringify ( languageData , null , 2 ) , "utf-8" ) ,
135+ ) ;
136+
137+ fs . closeSync ( writer ) ;
138+ } catch ( err : any ) {
139+ console . error (
140+ `An error occurred while saving the new translation file:\n` +
141+ ` ${ "message" in err ? err . message : err } ` ,
142+ ) ;
143+ process . exit ( 1 ) ;
144+ }
0 commit comments