@@ -88,11 +88,25 @@ function getPath(template: string, language?: string, namespace?: string) {
88
88
return template ;
89
89
}
90
90
91
+ export type CollectedKeys = { [ language : string ] : { [ namespace : string ] : { [ key : string ] : string [ ] } } } ;
92
+
93
+ function removeMap < T > ( obj : _ . Dictionary < T > , keys : ( string | undefined ) [ ] ) {
94
+ for ( const emptyKey of keys ) {
95
+ if ( emptyKey !== undefined ) {
96
+ delete obj [ emptyKey ] ;
97
+ }
98
+ }
99
+
100
+ return obj ;
101
+ }
102
+
91
103
export default class I18nextPlugin {
92
104
protected compilation : wp . Compilation ;
93
105
protected option : InternalOption ;
94
106
protected context : string ;
95
- protected missingKeys : { [ language : string ] : { [ namespace : string ] : string [ ] } } ;
107
+ protected missingKeys : CollectedKeys = { } ;
108
+ protected startTime = Date . now ( ) ;
109
+ protected prevTimestamps : { [ file : string ] : number } = { } ;
96
110
97
111
public constructor ( option : Option ) {
98
112
this . option = _ . defaults ( option , {
@@ -132,14 +146,29 @@ export default class I18nextPlugin {
132
146
133
147
compiler . plugin ( "compilation" , ( compilation , data ) => {
134
148
// reset for new compliation
135
- this . missingKeys = { } ;
136
-
137
149
i18next . reloadResources ( this . option . languages ) ;
138
150
this . compilation = compilation ;
151
+ const changedFiles = _ . keys ( compilation . fileTimestamps ) . filter (
152
+ watchfile => ( this . prevTimestamps [ watchfile ] || this . startTime ) < ( compilation . fileTimestamps [ watchfile ] || Infinity )
153
+ ) ;
154
+
155
+ removeMap ( this . missingKeys , _ . map ( this . missingKeys , ( namespaces , lng ) =>
156
+ _ . size ( removeMap ( namespaces , _ . map ( namespaces , ( values , ns ) =>
157
+ _ . size ( removeMap ( values , _ . map ( values , ( deps , key ) => {
158
+ _ . remove ( deps , dep => _ . includes ( changedFiles , dep ) ) ;
159
+
160
+ return deps . length === 0 ? key : undefined ;
161
+ } ) ) ) === 0 ? ns : undefined
162
+ ) ) ) === 0 ? lng : undefined
163
+ ) ) ;
164
+
139
165
data . normalModuleFactory . plugin (
140
166
"parser" ,
141
167
( parser : any ) => {
142
- parser . plugin ( `call ${ this . option . functionName } ` , this . onTranslateFunctionCall . bind ( this ) ) ;
168
+ const that = this ;
169
+ parser . plugin ( `call ${ this . option . functionName } ` , function ( this : wp . Parser , arg : wp . Expression ) {
170
+ return I18nextPlugin . onTranslateFunctionCall . call ( this , that , arg ) ;
171
+ } ) ;
143
172
}
144
173
) ;
145
174
} ) ;
@@ -149,6 +178,8 @@ export default class I18nextPlugin {
149
178
150
179
protected async onEmit ( compilation : wp . Compilation , callback : ( err ?: Error ) => void ) {
151
180
// emit translation files
181
+ this . prevTimestamps = compilation . fileTimestamps ;
182
+
152
183
try {
153
184
await Promise . all ( _ . map ( this . option . languages , lng => {
154
185
const resourceTemplate = path . join ( this . context , getPath ( this . option . resourcePath , lng ) ) ;
@@ -204,20 +235,20 @@ export default class I18nextPlugin {
204
235
}
205
236
}
206
237
207
- return _ . map ( namespaces , async ( keys , ns ) => new Promise < void > ( resolve => {
238
+ return _ . map ( namespaces , async ( values , ns ) => new Promise < void > ( resolve => {
208
239
delete remains [ lng ] [ ns ] ;
209
240
const missingPath = getPath ( resourceTemplate , undefined , ns ) ;
210
241
const stream = fs . createWriteStream ( missingPath , {
211
242
defaultEncoding : "utf-8"
212
243
} ) ;
213
- keys = _ . sortedUniq ( _ . sortBy ( keys ) ) ;
244
+ const keys = _ . sortedUniq ( _ . sortBy ( _ . keys ( values ) ) ) ;
214
245
stream . write ( "{\n" ) ;
215
246
stream . write ( _ . map ( keys , key => `\t"${ key } ": "${ key } "` ) . join ( ",\n" ) ) ;
216
247
stream . write ( "\n}" ) ;
217
248
218
249
stream . on ( "close" , ( ) => resolve ( ) ) ;
219
250
220
- compilation . warnings . push ( `missing translation ${ keys . length } keys in ${ lng } /${ ns } ` ) ;
251
+ compilation . warnings . push ( `missing translation ${ _ . size ( values ) } keys in ${ lng } /${ ns } ` ) ;
221
252
} ) ) ;
222
253
} ) ) ;
223
254
// remove previous missings
@@ -235,27 +266,29 @@ export default class I18nextPlugin {
235
266
}
236
267
}
237
268
238
- protected onTranslateFunctionCall ( expr : any ) {
239
- const args = expr . arguments . map ( ( arg : any ) => extractArgs ( arg , this . warningOnCompilation . bind ( this ) ) ) ;
269
+ protected static onTranslateFunctionCall ( this : wp . Parser , plugin : I18nextPlugin , expr : wp . Expression ) {
270
+ const args = expr . arguments . map ( ( arg : any ) => extractArgs ( arg , plugin . warningOnCompilation . bind ( plugin ) ) ) ;
240
271
241
- for ( const lng of this . option . languages ) {
272
+ for ( const lng of plugin . option . languages ) {
242
273
const keyOrKeys : string | string [ ] = args [ 0 ] ;
243
274
const option : i18next . TranslationOptionsBase = Object . assign ( _ . defaults ( args [ 1 ] , { } ) , {
244
275
lng,
245
- defaultValue : null
246
- } ) ;
276
+ defaultValue : this . state . current . resource
277
+ } as i18next . TranslationOptionsBase ) ;
247
278
i18next . t ( keyOrKeys , option ) ;
248
279
}
249
280
}
250
281
251
- protected onKeyMissing ( lng : string , ns : string , key : string , __ : string ) {
252
- const p = [ lng , ns ] ;
282
+ protected onKeyMissing ( lng : string , ns : string , key : string , moduleName : string ) {
283
+ const p = [ lng , ns , key ] ;
253
284
let arr : string [ ] = _ . get ( this . missingKeys , p ) ;
254
285
if ( arr === undefined ) {
255
286
_ . set ( this . missingKeys , p , [ ] ) ;
256
287
arr = _ . get ( this . missingKeys , p ) ;
257
288
}
258
- arr . push ( key ) ;
289
+ if ( arr . indexOf ( moduleName ) === - 1 ) {
290
+ arr . push ( moduleName ) ;
291
+ }
259
292
}
260
293
261
294
protected warningOnCompilation ( msg : string ) {
0 commit comments