19
19
# show the translation status of all locales
20
20
$ php translation-status.php
21
21
22
- # show the translation status of all locales and all their missing translations
22
+ # only show the translation status of incomplete or erroneous locales
23
+ $ php translation-status.php --incomplete
24
+
25
+ # show the translation status of all locales, all their missing translations and mismatches between trans-unit id and source
23
26
$ php translation-status.php -v
24
27
25
28
# show the status of a single locale
26
29
$ php translation-status.php fr
27
30
28
- # show the status of a single locale and all its missing translations
31
+ # show the status of a single locale, missing translations and mismatches between trans-unit id and source
29
32
$ php translation-status.php fr -v
30
33
31
34
END ;
35
38
'verbose_output ' => false ,
36
39
// NULL = analyze all locales
37
40
'locale_to_analyze ' => null ,
41
+ // append --incomplete to only show incomplete languages
42
+ 'include_completed_languages ' => true ,
38
43
// the reference files all the other translations are compared to
39
44
'original_files ' => [
40
45
'src/Symfony/Component/Form/Resources/translations/validators.en.xlf ' ,
46
51
$ argc = $ _SERVER ['argc ' ];
47
52
$ argv = $ _SERVER ['argv ' ];
48
53
49
- if ($ argc > 3 ) {
54
+ if ($ argc > 4 ) {
50
55
echo str_replace ('translation-status.php ' , $ argv [0 ], $ usageInstructions );
51
56
exit (1 );
52
57
}
53
58
54
59
foreach (array_slice ($ argv , 1 ) as $ argumentOrOption ) {
60
+ if ('--incomplete ' === $ argumentOrOption ) {
61
+ $ config ['include_completed_languages ' ] = false ;
62
+ continue ;
63
+ }
64
+
55
65
if (str_starts_with ($ argumentOrOption , '- ' )) {
56
66
$ config ['verbose_output ' ] = true ;
57
67
} else {
67
77
}
68
78
69
79
$ totalMissingTranslations = 0 ;
80
+ $ totalTranslationMismatches = 0 ;
70
81
71
82
foreach ($ config ['original_files ' ] as $ originalFilePath ) {
72
83
$ translationFilePaths = findTranslationFiles ($ originalFilePath , $ config ['locale_to_analyze ' ]);
75
86
$ totalMissingTranslations += array_sum (array_map (function ($ translation ) {
76
87
return count ($ translation ['missingKeys ' ]);
77
88
}, array_values ($ translationStatus )));
89
+ $ totalTranslationMismatches += array_sum (array_map (function ($ translation ) {
90
+ return count ($ translation ['mismatches ' ]);
91
+ }, array_values ($ translationStatus )));
78
92
79
- printTranslationStatus ($ originalFilePath , $ translationStatus , $ config ['verbose_output ' ]);
93
+ printTranslationStatus ($ originalFilePath , $ translationStatus , $ config ['verbose_output ' ], $ config [ ' include_completed_languages ' ] );
80
94
}
81
95
82
- exit ($ totalMissingTranslations > 0 ? 1 : 0 );
96
+ exit ($ totalTranslationMismatches > 0 ? 1 : 0 );
83
97
84
98
function findTranslationFiles ($ originalFilePath , $ localeToAnalyze )
85
99
{
@@ -112,21 +126,29 @@ function calculateTranslationStatus($originalFilePath, $translationFilePaths)
112
126
foreach ($ translationFilePaths as $ locale => $ translationPath ) {
113
127
$ translatedKeys = extractTranslationKeys ($ translationPath );
114
128
$ missingKeys = array_diff_key ($ allTranslationKeys , $ translatedKeys );
129
+ $ mismatches = findTransUnitMismatches ($ allTranslationKeys , $ translatedKeys );
115
130
116
131
$ translationStatus [$ locale ] = [
117
132
'total ' => count ($ allTranslationKeys ),
118
133
'translated ' => count ($ translatedKeys ),
119
134
'missingKeys ' => $ missingKeys ,
135
+ 'mismatches ' => $ mismatches ,
120
136
];
137
+ $ translationStatus [$ locale ]['is_completed ' ] = isTranslationCompleted ($ translationStatus [$ locale ]);
121
138
}
122
139
123
140
return $ translationStatus ;
124
141
}
125
142
126
- function printTranslationStatus ($ originalFilePath , $ translationStatus , $ verboseOutput )
143
+ function isTranslationCompleted (array $ translationStatus ): bool
144
+ {
145
+ return $ translationStatus ['total ' ] === $ translationStatus ['translated ' ] && 0 === count ($ translationStatus ['mismatches ' ]);
146
+ }
147
+
148
+ function printTranslationStatus ($ originalFilePath , $ translationStatus , $ verboseOutput , $ includeCompletedLanguages )
127
149
{
128
150
printTitle ($ originalFilePath );
129
- printTable ($ translationStatus , $ verboseOutput );
151
+ printTable ($ translationStatus , $ verboseOutput, $ includeCompletedLanguages );
130
152
echo \PHP_EOL .\PHP_EOL ;
131
153
}
132
154
@@ -152,13 +174,35 @@ function extractTranslationKeys($filePath)
152
174
return $ translationKeys ;
153
175
}
154
176
177
+ /**
178
+ * Check whether the trans-unit id and source match with the base translation.
179
+ */
180
+ function findTransUnitMismatches (array $ baseTranslationKeys , array $ translatedKeys ): array
181
+ {
182
+ $ mismatches = [];
183
+
184
+ foreach ($ baseTranslationKeys as $ translationId => $ translationKey ) {
185
+ if (!isset ($ translatedKeys [$ translationId ])) {
186
+ continue ;
187
+ }
188
+ if ($ translatedKeys [$ translationId ] !== $ translationKey ) {
189
+ $ mismatches [$ translationId ] = [
190
+ 'found ' => $ translatedKeys [$ translationId ],
191
+ 'expected ' => $ translationKey ,
192
+ ];
193
+ }
194
+ }
195
+
196
+ return $ mismatches ;
197
+ }
198
+
155
199
function printTitle ($ title )
156
200
{
157
201
echo $ title .\PHP_EOL ;
158
202
echo str_repeat ('= ' , strlen ($ title )).\PHP_EOL .\PHP_EOL ;
159
203
}
160
204
161
- function printTable ($ translations , $ verboseOutput )
205
+ function printTable ($ translations , $ verboseOutput, bool $ includeCompletedLanguages )
162
206
{
163
207
if (0 === count ($ translations )) {
164
208
echo 'No translations found ' ;
@@ -168,24 +212,47 @@ function printTable($translations, $verboseOutput)
168
212
$ longestLocaleNameLength = max (array_map ('strlen ' , array_keys ($ translations )));
169
213
170
214
foreach ($ translations as $ locale => $ translation ) {
215
+ if (!$ includeCompletedLanguages && $ translation ['is_completed ' ]) {
216
+ continue ;
217
+ }
218
+
171
219
if ($ translation ['translated ' ] > $ translation ['total ' ]) {
172
220
textColorRed ();
173
- } elseif ($ translation ['translated ' ] === $ translation ['total ' ]) {
221
+ } elseif (count ($ translation ['mismatches ' ]) > 0 ) {
222
+ textColorRed ();
223
+ } elseif ($ translation ['is_completed ' ]) {
174
224
textColorGreen ();
175
225
}
176
226
177
- echo sprintf ('| Locale: %- ' .$ longestLocaleNameLength .'s | Translated: %d/%d ' , $ locale , $ translation ['translated ' ], $ translation ['total ' ]).\PHP_EOL ;
227
+ echo sprintf (
228
+ '| Locale: %- ' .$ longestLocaleNameLength .'s | Translated: %2d/%2d | Mismatches: %d | ' ,
229
+ $ locale ,
230
+ $ translation ['translated ' ],
231
+ $ translation ['total ' ],
232
+ count ($ translation ['mismatches ' ])
233
+ ).\PHP_EOL ;
178
234
179
235
textColorNormal ();
180
236
237
+ $ shouldBeClosed = false ;
181
238
if (true === $ verboseOutput && count ($ translation ['missingKeys ' ]) > 0 ) {
182
- echo str_repeat ('- ' , 80 ).\PHP_EOL ;
183
- echo '| Missing Translations: ' .\PHP_EOL ;
239
+ echo '| Missing Translations: ' .\PHP_EOL ;
184
240
185
241
foreach ($ translation ['missingKeys ' ] as $ id => $ content ) {
186
- echo sprintf ('| (id=%s) %s ' , $ id , $ content ).\PHP_EOL ;
242
+ echo sprintf ('| (id=%s) %s ' , $ id , $ content ).\PHP_EOL ;
187
243
}
244
+ $ shouldBeClosed = true ;
245
+ }
246
+ if (true === $ verboseOutput && count ($ translation ['mismatches ' ]) > 0 ) {
247
+ echo '| Mismatches between trans-unit id and source: ' .\PHP_EOL ;
188
248
249
+ foreach ($ translation ['mismatches ' ] as $ id => $ content ) {
250
+ echo sprintf ('| (id=%s) Expected: %s ' , $ id , $ content ['expected ' ]).\PHP_EOL ;
251
+ echo sprintf ('| Found: %s ' , $ content ['found ' ]).\PHP_EOL ;
252
+ }
253
+ $ shouldBeClosed = true ;
254
+ }
255
+ if ($ shouldBeClosed ) {
189
256
echo str_repeat ('- ' , 80 ).\PHP_EOL ;
190
257
}
191
258
}
0 commit comments