Skip to content

Commit 8ffba03

Browse files
committed
write missing with occurrences
1 parent d9a7656 commit 8ffba03

File tree

2 files changed

+35
-16
lines changed

2 files changed

+35
-16
lines changed

index.ts

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import util = require('util');
55
import _ = require("lodash");
66
import i18next = require('i18next');
77
import Backend = require('i18next-node-fs-backend');
8+
import { SourceMapConsumer } from 'source-map';
89
const VirtualModulePlugin = require('virtual-module-webpack-plugin');
910

1011
const readFile = util.promisify(fs.readFile);
@@ -88,7 +89,7 @@ function getPath(template: string, language?: string, namespace?: string) {
8889
return template;
8990
}
9091

91-
export type CollectedKeys = {[language: string]: {[namespace: string]: {[key: string]: string[]}}};
92+
export type CollectedKeys = {[language: string]: {[namespace: string]: {[key: string]: {[module: string]: [number, number]}}}};
9293

9394
function removeMap<T>(obj: _.Dictionary<T>, keys: (string | undefined)[]) {
9495
for (const emptyKey of keys) {
@@ -107,6 +108,7 @@ export default class I18nextPlugin {
107108
protected missingKeys: CollectedKeys = {};
108109
protected startTime = Date.now();
109110
protected prevTimestamps: {[file: string]: number} = {};
111+
protected sourceMaps: {[key: string]: SourceMapConsumer} = {};
110112

111113
public constructor(option: Option) {
112114
this.option = _.defaults(option, {
@@ -152,14 +154,19 @@ export default class I18nextPlugin {
152154
watchfile => (this.prevTimestamps[watchfile] || this.startTime) < (compilation.fileTimestamps[watchfile] || Infinity)
153155
);
154156

157+
for (const changed of changedFiles) {
158+
delete this.sourceMaps[changed];
159+
}
155160
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
161+
_.isEmpty(removeMap(namespaces, _.map(namespaces, (values, ns) =>
162+
_.isEmpty(removeMap(values, _.map(values, (deps, key) => {
163+
for (const changed of changedFiles) {
164+
delete deps[changed];
165+
}
166+
167+
return _.isEmpty(deps) ? key : undefined;
168+
}))) ? ns : undefined
169+
))) ? lng : undefined
163170
));
164171

165172
data.normalModuleFactory.plugin(
@@ -243,7 +250,12 @@ export default class I18nextPlugin {
243250
});
244251
const keys = _.sortedUniq(_.sortBy(_.keys(values)));
245252
stream.write("{\n");
246-
stream.write(_.map(keys, key => `\t"${key}": "${key}"`).join(",\n"));
253+
stream.write(_.map(
254+
keys,
255+
key => `\t"${key}": [\n${_.map(
256+
values[key], (pos, module) => `\t\t"${_.trim(JSON.stringify(path.relative(this.context, module)), '"')}(${pos})"`).join("\n")
257+
}\n\t]`).join(",\n")
258+
);
247259
stream.end("\n}");
248260
stream.on("close", () => resolve());
249261

@@ -267,27 +279,32 @@ export default class I18nextPlugin {
267279

268280
protected static onTranslateFunctionCall(this: wp.Parser, plugin: I18nextPlugin, expr: wp.Expression) {
269281
const args = expr.arguments.map((arg: any) => extractArgs(arg, plugin.warningOnCompilation.bind(plugin)));
282+
const resource = this.state.current.resource;
283+
if (plugin.sourceMaps[resource] === undefined) {
284+
plugin.sourceMaps[resource] = new SourceMapConsumer(this.state.current._source._sourceMap);
285+
}
286+
const sourceMap = plugin.sourceMaps[resource];
287+
const startPos = sourceMap.originalPositionFor(expr.loc.start);
288+
const pos = [resource, startPos.line, startPos.column];
270289

271290
for (const lng of plugin.option.languages) {
272291
const keyOrKeys: string | string[] = args[0];
273292
const option: i18next.TranslationOptionsBase = Object.assign(_.defaults(args[1], {}), {
274293
lng,
275-
defaultValue: this.state.current.resource
294+
defaultValue: pos
276295
} as i18next.TranslationOptionsBase);
277296
i18next.t(keyOrKeys, option);
278297
}
279298
}
280299

281-
protected onKeyMissing(lng: string, ns: string, key: string, moduleName: string) {
282-
const p = [lng, ns, key];
283-
let arr: string[] = _.get(this.missingKeys, p);
300+
protected onKeyMissing(lng: string, ns: string, key: string, pos: [string, number, number]) {
301+
const p = [lng, ns, key, pos[0]];
302+
let arr: [number, number][] = _.get(this.missingKeys, p);
284303
if (arr === undefined) {
285304
_.set(this.missingKeys, p, []);
286305
arr = _.get(this.missingKeys, p);
287306
}
288-
if (arr.indexOf(moduleName) === -1) {
289-
arr.push(moduleName);
290-
}
307+
arr.push([pos[1], pos[2]]);
291308
}
292309

293310
protected warningOnCompilation(msg: string) {

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@
2828
"@types/i18next-node-fs-backend": "0.0.29",
2929
"@types/lodash": "^4.14.74",
3030
"@types/node": "^8.0.26",
31+
"@types/source-map": "^0.5.1",
3132
"@types/webpack": "^3.0.10",
3233
"typescript": "^2.4.2"
3334
},
3435
"dependencies": {
3536
"i18next": "^9.0.0",
3637
"i18next-node-fs-backend": "^1.0.0",
3738
"lodash": "^4.17.4",
39+
"source-map": "^0.5.7",
3840
"virtual-module-webpack-plugin": "^0.3.0"
3941
}
4042
}

0 commit comments

Comments
 (0)