Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion dist/create-report/language-files.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/// <reference types="dot-object" />
import { SimpleFile, I18NLanguage, I18NItem } from '../types';
import { SimpleFile, I18NLanguage, I18NItem, I18NItemWithBounding } from '../types';
export declare function readLanguageFiles(src: string): SimpleFile[];
export declare function extractI18NItemsFromLanguageFiles(languageFiles: SimpleFile[]): I18NItemWithBounding[];
export declare function extractI18NLanguageFromLanguageFiles(languageFiles: SimpleFile[], dot?: DotObject.Dot): I18NLanguage;
export declare function writeMissingToLanguageFiles(parsedLanguageFiles: SimpleFile[], missingKeys: I18NItem[], dot?: DotObject.Dot, noEmptyTranslation?: string): void;
export declare function removeUnusedFromLanguageFiles(parsedLanguageFiles: SimpleFile[], unusedKeys: I18NItem[], dot?: DotObject.Dot): void;
Expand Down
47 changes: 41 additions & 6 deletions dist/vue-i18n-extract.modern.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ function readVueFiles(src) {
});
}

function* getMatches(file, regExp, captureGroup = 1) {
function* getMatches$1(file, regExp, captureGroup = 1) {
while (true) {
const match = regExp.exec(file.content);

Expand Down Expand Up @@ -136,17 +136,17 @@ function* getMatches(file, regExp, captureGroup = 1) {

function extractMethodMatches(file) {
const methodRegExp = /(?:[$\s.:"'`+\(\[\{]t[cm]?)\(\s*?(["'`])((?:[^\\]|\\.)*?)\1/g;
return [...getMatches(file, methodRegExp, 2)];
return [...getMatches$1(file, methodRegExp, 2)];
}

function extractComponentMatches(file) {
const componentRegExp = /(?:(?:<|h\()(?:i18n|Translation))(?:.|\n)*?(?:[^:]path(?:=|: )("|'))((?:[^\\]|\\.)*?)\1/gi;
return [...getMatches(file, componentRegExp, 2)];
return [...getMatches$1(file, componentRegExp, 2)];
}

function extractDirectiveMatches(file) {
const directiveRegExp = /\bv-t(?:\.[\w-]+)?="'((?:[^\\]|\\.)*?)'"/g;
return [...getMatches(file, directiveRegExp)];
return [...getMatches$1(file, directiveRegExp)];
}

function extractI18NItemsFromVueFiles(sourceFiles) {
Expand Down Expand Up @@ -200,6 +200,41 @@ function readLanguageFiles(src) {
};
});
}

function* getMatches(file, regExp, captureGroup = 1) {
while (true) {
const match = regExp.exec(file.content);

if (match === null) {
break;
}

const path = match[captureGroup];
const pathAtIndex = file.content.indexOf(path);
const previousCharacter = file.content.charAt(pathAtIndex - 1);
const nextCharacter = file.content.charAt(pathAtIndex + path.length);
const line = (file.content.substring(0, match.index).match(/\n/g) || []).length + 1;
yield {
path,
previousCharacter,
nextCharacter,
file: file.fileName,
line
};
}
}

function extractMessageLinkMatches(file) {
const messageLinkRegExp = /@:((?:[^\\]|\\.)*?)[\s"'`]/g;
return [...getMatches(file, messageLinkRegExp, 2)];
}

function extractI18NItemsFromLanguageFiles(languageFiles) {
return languageFiles.reduce((accumulator, file) => {
const messageLinkMatches = extractMessageLinkMatches(file);
return [...accumulator, ...messageLinkMatches];
}, []);
}
function extractI18NLanguageFromLanguageFiles(languageFiles, dot = Dot) {
return languageFiles.reduce((accumulator, file) => {
const language = file.fileName.substring(file.fileName.lastIndexOf('/') + 1, file.fileName.lastIndexOf('.'));
Expand Down Expand Up @@ -330,7 +365,7 @@ async function createI18NReport(options) {
const dot = typeof separator === 'string' ? new Dot(separator) : Dot;
const vueFiles = readVueFiles(path.resolve(process.cwd(), vueFilesGlob));
const languageFiles = readLanguageFiles(path.resolve(process.cwd(), languageFilesGlob));
const I18NItems = extractI18NItemsFromVueFiles(vueFiles);
const I18NItems = [...extractI18NItemsFromVueFiles(vueFiles), ...extractI18NItemsFromLanguageFiles(languageFiles)];
const I18NLanguage = extractI18NLanguageFromLanguageFiles(languageFiles, dot);
const report = extractI18NReport(I18NItems, I18NLanguage);
report.unusedKeys = report.unusedKeys.filter(key => !exclude.filter(excluded => key.path.startsWith(excluded)).length);
Expand Down Expand Up @@ -373,5 +408,5 @@ process.on('unhandledRejection', err => {
process.exit(1);
});

export { createI18NReport, extractI18NItemsFromVueFiles, extractI18NLanguageFromLanguageFiles, extractI18NReport, initCommand, parseVueFiles, parselanguageFiles, readLanguageFiles, readVueFiles, removeUnusedFromLanguageFiles, resolveConfig, writeMissingToLanguageFiles, writeReportToFile };
export { createI18NReport, extractI18NItemsFromLanguageFiles, extractI18NItemsFromVueFiles, extractI18NLanguageFromLanguageFiles, extractI18NReport, initCommand, parseVueFiles, parselanguageFiles, readLanguageFiles, readVueFiles, removeUnusedFromLanguageFiles, resolveConfig, writeMissingToLanguageFiles, writeReportToFile };
//# sourceMappingURL=vue-i18n-extract.modern.mjs.map
2 changes: 1 addition & 1 deletion dist/vue-i18n-extract.modern.mjs.map

Large diffs are not rendered by default.

46 changes: 41 additions & 5 deletions dist/vue-i18n-extract.umd.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/vue-i18n-extract.umd.js.map

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions src/create-report/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from 'path';
import { ReportOptions, I18NReport } from '../types';
import { readVueFiles, extractI18NItemsFromVueFiles } from './vue-files';
import { readLanguageFiles, extractI18NLanguageFromLanguageFiles, removeUnusedFromLanguageFiles, writeMissingToLanguageFiles } from './language-files';
import { readLanguageFiles, extractI18NItemsFromLanguageFiles, extractI18NLanguageFromLanguageFiles, removeUnusedFromLanguageFiles, writeMissingToLanguageFiles } from './language-files';
import { extractI18NReport, writeReportToFile } from './report';
import Dot from 'dot-object';

Expand All @@ -25,7 +25,10 @@ export async function createI18NReport (options: ReportOptions): Promise<I18NRep
const vueFiles = readVueFiles(path.resolve(process.cwd(), vueFilesGlob));
const languageFiles = readLanguageFiles(path.resolve(process.cwd(), languageFilesGlob));

const I18NItems = extractI18NItemsFromVueFiles(vueFiles);
const I18NItems = [
...extractI18NItemsFromVueFiles(vueFiles),
...extractI18NItemsFromLanguageFiles(languageFiles),
];
const I18NLanguage = extractI18NLanguageFromLanguageFiles(languageFiles, dot);

const report = extractI18NReport(I18NItems, I18NLanguage);
Expand Down
40 changes: 39 additions & 1 deletion src/create-report/language-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import glob from 'glob';
import Dot from 'dot-object';
import yaml from 'js-yaml';
import isValidGlob from 'is-valid-glob';
import { SimpleFile, I18NLanguage, I18NItem } from '../types';
import { SimpleFile, I18NLanguage, I18NItem, I18NItemWithBounding } from '../types';

export function readLanguageFiles (src: string): SimpleFile[] {
// Replace backslash path segments to make the path work with the glob package.
Expand Down Expand Up @@ -42,6 +42,44 @@ export function readLanguageFiles (src: string): SimpleFile[] {
});
}

function* getMatches (file: SimpleFile, regExp: RegExp, captureGroup = 1): IterableIterator<I18NItemWithBounding> {
while (true) {
const match = regExp.exec(file.content);
if (match === null) {
break;
}
const path = match[captureGroup];

const pathAtIndex = file.content.indexOf(path);
const previousCharacter = file.content.charAt(pathAtIndex - 1);
const nextCharacter = file.content.charAt(pathAtIndex + path.length);

const line = (file.content.substring(0, match.index).match(/\n/g) || []).length + 1;
yield {
path,
previousCharacter,
nextCharacter,
file: file.fileName,
line,
};
}
}

function extractMessageLinkMatches (file: SimpleFile): I18NItemWithBounding[] {
const messageLinkRegExp = /@:((?:[^\\]|\\.)*?)[\s"'`]/g;
return [ ...getMatches(file, messageLinkRegExp, 2) ];
}

export function extractI18NItemsFromLanguageFiles (languageFiles: SimpleFile[]): I18NItemWithBounding[] {
return languageFiles.reduce((accumulator, file) => {
const messageLinkMatches = extractMessageLinkMatches(file);
return [
...accumulator,
...messageLinkMatches,
];
}, [] as I18NItemWithBounding[]);
}

export function extractI18NLanguageFromLanguageFiles (languageFiles: SimpleFile[], dot: DotObject.Dot = Dot): I18NLanguage {
return languageFiles.reduce((accumulator, file) => {
const language = file.fileName.substring(file.fileName.lastIndexOf('/') + 1, file.fileName.lastIndexOf('.'));
Expand Down
45 changes: 34 additions & 11 deletions tests/fixtures/expected-values.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,81 +21,88 @@ export const expectedFromParsedVueFiles = [
line: 5
},
{
path: 'Key used as default translation. Second sentence.',
path: 'linked.composite',
previousCharacter: "'",
nextCharacter: "'",
file: './tests/fixtures/vue-files/Basic.vue',
line: 6
},
{
path: 'Key used as default translation. Second sentence.',
previousCharacter: "'",
nextCharacter: "'",
file: './tests/fixtures/vue-files/Basic.vue',
line: 7
},
{
path: 'content.paragraph.p.2',
previousCharacter: '`',
nextCharacter: '`',
file: './tests/fixtures/vue-files/Basic.vue',
line: 7
line: 8
},
{
path: 'content.link.b',
previousCharacter: "'",
nextCharacter: "'",
file: './tests/fixtures/vue-files/Basic.vue',
line: 9
line: 10
},
{
path: 'content.link.b',
previousCharacter: "'",
nextCharacter: "'",
file: './tests/fixtures/vue-files/Basic.vue',
line: 12
line: 13
},
{
path: 'content.link.b',
previousCharacter: "'",
nextCharacter: "'",
file: './tests/fixtures/vue-files/Basic.vue',
line: 15
line: 16
},
{
path: 'header.title',
previousCharacter: "'",
nextCharacter: "'",
file: './tests/fixtures/vue-files/Basic.vue',
line: 19
line: 20
},
{
path: 'content.link.a',
previousCharacter: '"',
nextCharacter: '"',
file: './tests/fixtures/vue-files/Basic.vue',
line: 8
line: 9
},
{
path: 'content.link.a',
previousCharacter: '"',
nextCharacter: '"',
file: './tests/fixtures/vue-files/Basic.vue',
line: 11
line: 12
},
{
path: 'content.link.a',
previousCharacter: '"',
nextCharacter: '"',
file: './tests/fixtures/vue-files/Basic.vue',
line: 14
line: 15
},
{
path: 'header.title',
previousCharacter: "'",
nextCharacter: "'",
file: './tests/fixtures/vue-files/Basic.vue',
line: 17
line: 18
},
{
path: 'header.title',
previousCharacter: "'",
nextCharacter: "'",
file: './tests/fixtures/vue-files/Basic.vue',
line: 18
line: 19
},
{
path: "single \\' quote",
Expand Down Expand Up @@ -282,6 +289,14 @@ export const expectedFromParsedLanguageFiles = {
path: 'content.link.b',
file: './tests/fixtures/lang/de_DE.js',
},
{
path: 'linked.referenced',
file: './tests/fixtures/lang/de_DE.js',
},
{
path: 'linked.composite',
file: './tests/fixtures/lang/de_DE.js',
},
{
path: 'Key used as default translation. Second sentence.',
file: './tests/fixtures/lang/de_DE.js',
Expand Down Expand Up @@ -332,6 +347,14 @@ export const expectedFromParsedLanguageFiles = {
path: 'content.link.b',
file: './tests/fixtures/lang/en_EN.json',
},
{
path: 'linked.referenced',
file: './tests/fixtures/lang/en_EN.json',
},
{
path: 'linked.composite',
file: './tests/fixtures/lang/en_EN.json',
},
{
path: 'Key used as default translation. Second sentence.',
file: './tests/fixtures/lang/en_EN.json',
Expand Down
Loading