44
55use Illuminate \Console \Command ;
66use Illuminate \Support \Arr ;
7- use Illuminate \Support \Facades \File ;
7+ use ProcessMaker \Helpers \SyncJsonTranslations ;
8+ use ProcessMaker \Helpers \SyncPhpTranslations ;
9+ use Symfony \Component \Console \Helper \Table ;
10+ use Symfony \Component \Console \Helper \TableSeparator ;
811
912class SyncTranslations extends Command
1013{
@@ -31,231 +34,133 @@ class SyncTranslations extends Command
3134 */
3235 public function handle ()
3336 {
34- // Check if exists resources core
35- $ translationsCore = base_path () . '/resources-core ' ;
36- $ existsLangOrig = $ this ->fileExists (lang_path () . '.orig ' );
37+ $ this ->info ('Starting translation synchronization... ' );
38+ $ this ->newLine ();
3739
38- if (!$ this ->fileExists ($ translationsCore )) {
39- $ this ->error ('The folder resources-core not exists. ' );
40+ $ jsonResults = (new SyncJsonTranslations ())->sync ();
41+ // dump("JSON Results: ", $jsonResults);
42+ $ phpResults = (new SyncPhpTranslations ())->sync ();
4043
41- return ;
42- }
43- //Search files
44- $ this ->listFiles ($ translationsCore . '/lang ' );
45-
46- // updating languages by default
47- foreach ($ this ->files as $ pathFile ) {
48- if (!(str_contains ($ pathFile , '.json ' ) || str_contains ($ pathFile , '.php ' )) || str_contains ($ pathFile , '.bak. ' )) {
49- continue ;
50- }
51- // updating resources/lang
52- $ this ->syncFile (str_replace ('/resources-core/ ' , '/resources/ ' , $ pathFile ), $ pathFile );
53- if ($ existsLangOrig ) {
54- // updating resources/lang.orig
55- $ this ->syncFile (str_replace (['/resources-core/ ' , '/lang/ ' ], ['/resources/ ' , '/lang.orig/ ' ], $ pathFile ), $ pathFile );
56- }
57- }
44+ $ this ->displayJsonResults ($ jsonResults );
45+ $ this ->newLine ();
46+ $ this ->displayPhpResults ($ phpResults );
5847
59- // updating all languages with new labels
60- $ this ->files = [];
61- $ translationsCore = lang_path ();
62- $ this ->listFiles ($ translationsCore );
63- foreach ($ this ->files as $ pathFile ) {
64- if (!(str_contains ($ pathFile , '.json ' ) || str_contains ($ pathFile , '.php ' )) || str_contains ($ pathFile , '.bak. ' )) {
65- continue ;
66- }
67- // updating resources/lang
68- $ backup = str_replace ('/resources/ ' , '/resources-core/ ' , preg_replace ('/(?<=lang).+?(?=json)/ ' , '/en. ' , $ pathFile ));
69- $ path1 = explode ('/lang/ ' , $ backup );
70- $ path2 = explode ('/ ' , $ path1 [1 ]);
71- if (is_array ($ path2 )) {
72- $ backup = str_replace ('/ ' . $ path2 [0 ] . '/ ' , '/en/ ' , $ backup );
73- }
48+ $ this ->newLine ();
49+ $ this ->info ('Translation synchronization completed! ' );
7450
75- $ this ->syncFile ($ pathFile , $ backup );
76- if ($ existsLangOrig ) {
77- // updating resources/lang.orig
78- $ this ->syncFile (str_replace ('/lang/ ' , '/lang.orig/ ' , $ pathFile ), $ backup );
79- }
80- }
51+ return 0 ;
8152 }
8253
83- private function listFiles ($ dir )
54+ /**
55+ * Display JSON translation results in a table format
56+ *
57+ * @param array $results
58+ * @return void
59+ */
60+ private function displayJsonResults (array $ results ): void
8461 {
85- $ files = scandir ( $ dir );
62+ $ this -> info ( ' JSON Translation Files: ' );
8663
87- foreach ($ files as $ value ) {
88- $ path = $ dir . '/ ' . $ value ;
89- if (!is_dir ($ path )) {
90- $ this ->files [] = $ path ;
91- } elseif ($ value != '. ' && $ value != '.. ' ) {
92- $ this ->listFiles ($ path );
64+ $ table = new Table ($ this ->output );
65+ $ table ->setHeaders (['Language ' , 'File ' , 'Action ' , 'New Keys ' , 'Total Keys ' , 'Backup ' , 'Status ' ]);
66+ $ additionalChanges = Arr::get ($ results , 'en.otherLanguageResults ' );
67+
68+ foreach ($ results as $ language => $ result ) {
69+ if (isset ($ additionalChanges [$ language ])) {
70+ if ($ result ['action ' ] !== 'no_changes ' ) {
71+ $ this ->addRowToTable ($ table , $ result , $ language );
72+ }
73+ $ this ->addRowToTable ($ table , $ additionalChanges [$ language ], $ language );
74+ } else {
75+ $ this ->addRowToTable ($ table , $ result , $ language );
9376 }
9477 }
95- }
9678
97- private function fileExists ($ path )
98- {
99- return File::exists ($ path );
79+ $ table ->render ();
10080 }
10181
102- private function parseFile ( $ path )
82+ private function addRowToTable ( Table $ table , array $ result , string $ language )
10383 {
104- $ pathInfo = pathinfo ($ path );
105-
106- $ lines = [];
107-
108- try {
109- if ($ pathInfo ['extension ' ] === 'json ' ) {
110- $ lines = json_decode (file_get_contents ($ path ), true );
111- } elseif ($ pathInfo ['extension ' ] === 'php ' ) {
112- $ lines = include $ path ;
113- }
114- } catch (\Exception $ e ) {
115- $ lines = [];
116- $ this ->error ($ path . '. Not found. ' );
84+ $ status = $ result ['error ' ] ? '<error>Error</error> ' : '<info>Success</info> ' ;
85+ $ action = $ this ->formatAction ($ result ['action ' ]);
86+ $ backup = $ result ['backup_created ' ] ? '<comment>Yes</comment> ' : 'No ' ;
87+
88+ $ table ->addRow ([
89+ $ language ,
90+ $ result ['filename ' ],
91+ $ action ,
92+ $ result ['new_keys ' ],
93+ $ result ['total_keys ' ],
94+ $ backup ,
95+ $ status ,
96+ ]);
97+
98+ if ($ result ['error ' ]) {
99+ $ table ->addRow (new TableSeparator ());
100+ $ table ->addRow (['' , '' , '' , '' , '' , '' , '<error> ' . $ result ['error ' ] . '</error> ' ]);
117101 }
118-
119- $ lines = Arr::dot ($ lines );
120-
121- return collect ($ lines );
122102 }
123103
124104 /**
125- * Synchronize translations between target and backup files
105+ * Display PHP translation results in a table format
126106 *
127- * @param string $target Path to target file
128- * @param string $backup Path to backup file
129- * @return bool
130- * @throws \Exception
107+ * @param array $results
108+ * @return void
131109 */
132- private function syncFile ( $ target , $ backup )
110+ private function displayPhpResults ( array $ results ): void
133111 {
134- if (str_contains ($ target , '.bak. ' )) {
135- // Clean up old backup if everything succeeded
136- if (file_exists ($ target )) {
137- unlink ($ target );
138- $ this ->info ('Removed bak: ' . $ target );
139- }
140- $ this ->info ("Skipping backup file: {$ target }" );
141-
142- return true ;
143- }
144- // Create backup before modifications
145- $ backupPath = $ target . '.bak. ' . date ('Y-m-d-His ' );
146- try {
147- if (!copy ($ target , $ backupPath )) {
148- $ this ->error ("Failed to create backup file: {$ backupPath }" );
149-
150- return false ;
112+ $ this ->info ('PHP Translation Files: ' );
113+
114+ $ table = new Table ($ this ->output );
115+ $ table ->setHeaders (['Language ' , 'Files Processed ' , 'Copied ' , 'Merged ' , 'No Changes ' , 'Errors ' , 'Status ' ]);
116+
117+ foreach ($ results as $ language => $ result ) {
118+ $ errorCount = count ($ result ['errors ' ]);
119+ $ status = $ errorCount > 0 ? '<error>Errors</error> ' : '<info>Success</info> ' ;
120+
121+ $ table ->addRow ([
122+ $ language ,
123+ $ result ['files_processed ' ],
124+ $ result ['files_copied ' ],
125+ $ result ['files_merged ' ],
126+ $ result ['files_no_changes ' ],
127+ $ errorCount ,
128+ $ status ,
129+ ]);
130+
131+ // Add error details if any
132+ if ($ errorCount > 0 ) {
133+ $ table ->addRow (new TableSeparator ());
134+ foreach ($ result ['errors ' ] as $ error ) {
135+ $ table ->addRow (['' , '' , '' , '' , '' , '' , '<error> ' . $ error . '</error> ' ]);
136+ }
151137 }
152- $ this ->info ("Backup created: {$ backupPath }" );
153- } catch (\Exception $ e ) {
154- $ this ->error ('Error creating backup: ' . $ e ->getMessage ());
155-
156- return false ;
157- }
158-
159- $ pathInfo = pathinfo ($ target );
160-
161- try {
162- $ targetTranslations = $ this ->parseFile ($ target );
163- $ origin = $ this ->parseFile ($ backup );
164- } catch (\Exception $ e ) {
165- $ this ->error ('Error parsing files: ' . $ e ->getMessage ());
166-
167- return false ;
168138 }
169139
170- // Get keys that are in origin but not in target
171- $ diff = $ origin ->diffKeys ($ targetTranslations );
172-
173- if ($ diff ->isNotEmpty ()) {
174- $ this ->info ('Found ' . $ diff ->count () . " new translations to add in {$ target }" );
175-
176- // only files en.json to en.json have translations others are empty
177- $ clear = true ;
178- if (str_contains ($ target , 'en.json ' ) && str_contains ($ backup , 'en.json ' )) {
179- $ clear = false ;
180- }
181-
182- // Add new keys to targetTranslations
183- foreach ($ diff as $ key => $ value ) {
184- $ targetTranslations [$ key ] = $ clear ? '' : $ value ;
185- }
186- }
187-
188- try {
189- $ contents = $ this ->generateFile ($ targetTranslations , $ pathInfo ['extension ' ]);
190-
191- // Validate content before saving
192- if (empty ($ contents )) {
193- throw new \Exception ('Generated content is empty ' );
194- }
195-
196- // Use atomic file writing
197- $ tempFile = $ target . '.tmp ' ;
198- if (file_put_contents ($ tempFile , $ contents ) === false ) {
199- throw new \Exception ('Failed to write temporary file ' );
200- }
201-
202- if (!rename ($ tempFile , $ target )) {
203- unlink ($ tempFile );
204- throw new \Exception ('Failed to move temporary file ' );
205- }
206-
207- $ this ->info ("Successfully updated: {$ target }" );
208-
209- // Clean up old backup if everything succeeded
210- if (file_exists ($ backupPath )) {
211- unlink ($ backupPath );
212- $ this ->info ('Removed backup file after successful update ' );
213- }
214-
215- if ($ pathInfo ['extension ' ] == 'php ' ) {
216- $ this ->clearCache ();
217- }
218-
219- return true ;
220- } catch (\Exception $ e ) {
221- // Restore from backup if something went wrong
222- if (file_exists ($ backupPath )) {
223- copy ($ backupPath , $ target );
224- $ this ->info ('Restored from backup due to error ' );
225- }
226- $ this ->error ('Error saving file: ' . $ e ->getMessage ());
227-
228- return false ;
229- }
140+ $ table ->render ();
230141 }
231142
232- private function generateFile ($ lines , $ type )
233- {
234- $ array = [];
235-
236- foreach ($ lines as $ key => $ line ) {
237- $ array [$ key ] = $ line ;
238- }
239-
240- if ($ type === 'json ' ) {
241- return json_encode ($ array , JSON_PRETTY_PRINT );
242- } elseif ($ type === 'php ' ) {
243- $ contents = "<?php \n\nreturn [ \n\n" ;
244- foreach ($ array as $ key => $ value ) {
245- $ key = addslashes ($ key );
246- $ value = addslashes ($ value );
247- $ contents .= "\t' $ key' => ' $ value', \n" ;
248- }
249- $ contents .= ']; ' ;
250-
251- return $ contents ;
252- }
253- }
254-
255- private function clearCache ()
143+ /**
144+ * Format action for display
145+ *
146+ * @param string $action
147+ * @return string
148+ */
149+ private function formatAction (string $ action ): string
256150 {
257- if (function_exists ('opcache_reset ' )) {
258- return opcache_reset ();
151+ switch ($ action ) {
152+ case 'copied ' :
153+ return '<comment>Copied</comment> ' ;
154+ case 'merged ' :
155+ return '<info>Merged</info> ' ;
156+ case 'updated ' :
157+ return '<fg=cyan>Updated</fg=cyan> ' ;
158+ case 'no_changes ' :
159+ return '<fg=gray>No Changes</fg=gray> ' ;
160+ case 'error ' :
161+ return '<error>Error</error> ' ;
162+ default :
163+ return $ action ;
259164 }
260165 }
261166}
0 commit comments