diff --git a/Changelog.md b/Changelog.md
index a43adf8..a0408bc 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,3 +1,20 @@
+
+# [0.4.0](https://github.com/martinroob/ngx-i18nsupport/compare/v0.3.1...v0.4.0) (2017-05-03)
+
+### Bug Fixes
+
+* **xliffmerge:** xliffmerge creates empty json files ([#18](https://github.com/martinroob/ngx-i18nsupport/issues/18))
+
+### Features
+
+* **xliffmerge:** create an API to access parsing functionality. ([#11](https://github.com/martinroob/ngx-i18nsupport/issues/11)).
+The API is in a separate npm package [ngx-i18nsupport-lib](https://github.com/martinroob/ngx-i18nsupport-lib).
+
+* **xliffmerge:** use explicitly set IDs for ngx-translate data generation. ([#15](https://github.com/martinroob/ngx-i18nsupport/issues/15))
+For detail have a look at the Wiki page [ngx translate usage](https://github.com/martinroob/ngx-i18nsupport/wiki/ngx-translate-usage).
+
+* **xliffmerge:** Handle new source element introduced with Angular 4. ([#21](https://github.com/martinroob/ngx-i18nsupport/issues/21))
+
# [0.3.1](https://github.com/martinroob/ngx-i18nsupport/compare/v0.3.0...v0.3.1) (2017-04-25)
diff --git a/ngx-i18nsupport.d.ts b/ngx-i18nsupport.d.ts
deleted file mode 100644
index 4aaf8f9..0000000
--- a/ngx-i18nsupport.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './public_api';
diff --git a/package.json b/package.json
index 5aa2ab1..034c78c 100644
--- a/package.json
+++ b/package.json
@@ -1,11 +1,10 @@
{
"name": "ngx-i18nsupport",
- "version": "0.3.1",
+ "version": "0.4.0",
"description": "Some tooling to be used with the Angular 2 i18n workflow",
"main": "index.js",
"module": "./src",
"es2015": "./src",
- "typings": "./ngx-i18nsupport.d.ts",
"bin": {
"xliffmerge": "./dist/xliffmerge/xliffmerge"
},
@@ -18,7 +17,8 @@
"pretest": "npm run build",
"test": "./node_modules/.bin/jasmine-node dist",
"precover": "npm run build",
- "cover": "./node_modules/.bin/istanbul cover --root dist --include-all-sources ./node_modules/jasmine-node/bin/jasmine-node -- dist"
+ "cover": "./node_modules/.bin/istanbul cover --root dist --include-all-sources ./node_modules/jasmine-node/bin/jasmine-node -- dist",
+ "prepublish": "npm run build"
},
"repository": {
"type": "git",
@@ -28,7 +28,8 @@
"i18n",
"tooling",
"angular",
- "xliff"
+ "xliff",
+ "xmb"
],
"author": "Martin Roob (www.roobsoft.de)",
"license": "MIT",
@@ -37,7 +38,6 @@
},
"homepage": "https://github.com/martinroob/ngx-i18nsupport#readme",
"devDependencies": {
- "@types/cheerio": "^0.17.31",
"@types/jasmine": "^2.5.43",
"@types/node": "^7.0.5",
"coveralls": "^2.11.16",
@@ -48,7 +48,7 @@
},
"dependencies": {
"chalk": "^1.1.3",
- "cheerio": "^0.22.0",
- "commander": "^2.9.0"
+ "commander": "^2.9.0",
+ "ngx-i18nsupport-lib": "^0.0.8"
}
}
diff --git a/public_api.d.ts b/public_api.d.ts
deleted file mode 100644
index 7da5242..0000000
--- a/public_api.d.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * @module
- * @description
- * Entry point for all public APIs of the package.
- */
-export * from './src/index';
diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json
index a460644..e2a914c 100644
--- a/spec/support/jasmine.json
+++ b/spec/support/jasmine.json
@@ -1,5 +1,5 @@
{
- "spec_dir": "dist/out-tsc",
+ "spec_dir": "dist",
"spec_files": [
"**/*[sS]pec.js"
],
diff --git a/src/common/command-output.js b/src/common/command-output.js
deleted file mode 100644
index 29c51ad..0000000
--- a/src/common/command-output.js
+++ /dev/null
@@ -1,124 +0,0 @@
-/**
- * Created by martin on 17.02.2017.
- * Very simple class to control the output of a command.
- * Output can be errors, warnings, infos and debug-Outputs.
- * The output can be controlled via 2 flags, quiet and verbose.
- * If quit is enabled only error messages are shown.
- * If verbose is enabled, everything is shown.
- * If both are not enabled (the default) errors, warnings and infos are shown.
- * If not are enabled (strange), we assumed the default.
- */
-"use strict";
-var chalk = require("chalk");
-var util = require("util");
-var LogLevel;
-(function (LogLevel) {
- LogLevel[LogLevel["ERROR"] = 0] = "ERROR";
- LogLevel[LogLevel["WARN"] = 1] = "WARN";
- LogLevel[LogLevel["INFO"] = 2] = "INFO";
- LogLevel[LogLevel["DEBUG"] = 3] = "DEBUG";
-})(LogLevel || (LogLevel = {}));
-var CommandOutput = (function () {
- function CommandOutput(stdout) {
- this._quiet = false;
- this._verbose = false;
- if (stdout) {
- this.outputStream = stdout;
- }
- else {
- this.outputStream = process.stdout;
- }
- }
- CommandOutput.prototype.setVerbose = function () {
- this._verbose = true;
- };
- CommandOutput.prototype.setQuiet = function () {
- this._quiet = true;
- };
- /**
- * Test, wether verbose is enabled.
- * @return {boolean}
- */
- CommandOutput.prototype.verbose = function () {
- return this._verbose;
- };
- /**
- * Test, wether queit is enabled.
- * @return {boolean}
- */
- CommandOutput.prototype.quiet = function () {
- return this._quiet;
- };
- CommandOutput.prototype.error = function (msg) {
- var params = [];
- for (var _i = 1; _i < arguments.length; _i++) {
- params[_i - 1] = arguments[_i];
- }
- this.log(LogLevel.ERROR, msg, params);
- };
- CommandOutput.prototype.warn = function (msg) {
- var params = [];
- for (var _i = 1; _i < arguments.length; _i++) {
- params[_i - 1] = arguments[_i];
- }
- this.log(LogLevel.WARN, msg, params);
- };
- CommandOutput.prototype.info = function (msg) {
- var params = [];
- for (var _i = 1; _i < arguments.length; _i++) {
- params[_i - 1] = arguments[_i];
- }
- this.log(LogLevel.INFO, msg, params);
- };
- CommandOutput.prototype.debug = function (msg) {
- var params = [];
- for (var _i = 1; _i < arguments.length; _i++) {
- params[_i - 1] = arguments[_i];
- }
- this.log(LogLevel.DEBUG, msg, params);
- };
- CommandOutput.prototype.log = function (level, msg, params) {
- if (!this.isOutputEnabled(level)) {
- return;
- }
- var coloredMessage;
- switch (level) {
- case LogLevel.ERROR:
- coloredMessage = chalk.red('ERROR: ' + msg);
- break;
- case LogLevel.WARN:
- coloredMessage = chalk.magenta('WARNING: ' + msg);
- break;
- default:
- coloredMessage = chalk.gray('* ' + msg);
- break;
- }
- var outMsg = util.format.apply(util, [coloredMessage].concat(params));
- this.outputStream.write(outMsg + '\n');
- };
- CommandOutput.prototype.isOutputEnabled = function (level) {
- var quietEnabled, verboseEnabled;
- if (this._quiet && this._verbose) {
- quietEnabled = false;
- verboseEnabled = false;
- }
- else {
- quietEnabled = this._quiet;
- verboseEnabled = this._verbose;
- }
- switch (level) {
- case LogLevel.ERROR:
- return true; // always output errors
- case LogLevel.WARN:
- return (!quietEnabled);
- case LogLevel.INFO:
- return (verboseEnabled && !quietEnabled);
- case LogLevel.DEBUG:
- return verboseEnabled;
- default:
- return true;
- }
- };
- return CommandOutput;
-}());
-exports.CommandOutput = CommandOutput;
diff --git a/src/common/command-output.ts b/src/common/command-output.ts
index 3b3c366..a73630a 100644
--- a/src/common/command-output.ts
+++ b/src/common/command-output.ts
@@ -11,7 +11,7 @@
import * as chalk from "chalk";
import WritableStream = NodeJS.WritableStream;
-import util = require('util');
+import * as util from "util";
enum LogLevel {
"ERROR",
diff --git a/src/common/file-util.js b/src/common/file-util.js
deleted file mode 100644
index fe9b06b..0000000
--- a/src/common/file-util.js
+++ /dev/null
@@ -1,96 +0,0 @@
-"use strict";
-var fs = require("fs");
-/**
- * Created by martin on 17.02.2017.
- * Some (a few) simple utils for file operations.
- * Just for convenience.
- */
-var FileUtil = (function () {
- function FileUtil() {
- }
- /**
- * Check for existence.
- * @param filename
- * @return {boolean}
- */
- FileUtil.exists = function (filename) {
- return fs.existsSync(filename);
- };
- /**
- * Read a file.
- * @param filename
- * @param encoding
- * @return {string}
- */
- FileUtil.read = function (filename, encoding) {
- return fs.readFileSync(filename, encoding);
- };
- /**
- * Write a file with given content.
- * @param filename
- * @param newContent
- * @param encoding
- */
- FileUtil.replaceContent = function (filename, newContent, encoding) {
- fs.writeFileSync(filename, newContent, { encoding: encoding });
- };
- FileUtil.copy = function (srcFile, destFile) {
- var BUF_LENGTH = 64 * 1024;
- var buff = new Buffer(BUF_LENGTH);
- var fdr = fs.openSync(srcFile, 'r');
- var fdw = fs.openSync(destFile, 'w');
- var bytesRead = 1;
- var pos = 0;
- while (bytesRead > 0) {
- bytesRead = fs.readSync(fdr, buff, 0, BUF_LENGTH, pos);
- fs.writeSync(fdw, buff, 0, bytesRead);
- pos += bytesRead;
- }
- fs.closeSync(fdr);
- fs.closeSync(fdw);
- };
- /**
- * Delete the folder and all of its content (rm -rf).
- * @param path
- */
- FileUtil.deleteFolderRecursive = function (path) {
- var files = [];
- if (fs.existsSync(path)) {
- files = fs.readdirSync(path);
- files.forEach(function (file, index) {
- var curPath = path + "/" + file;
- if (fs.lstatSync(curPath).isDirectory()) {
- FileUtil.deleteFolderRecursive(curPath);
- }
- else {
- fs.unlinkSync(curPath);
- }
- });
- fs.rmdirSync(path);
- }
- };
- ;
- /**
- * Delete folders content recursively, but do not delete folder.
- * Folder is left empty at the end.
- * @param path
- */
- FileUtil.deleteFolderContentRecursive = function (path) {
- var files = [];
- if (fs.existsSync(path)) {
- files = fs.readdirSync(path);
- files.forEach(function (file, index) {
- var curPath = path + "/" + file;
- if (fs.lstatSync(curPath).isDirectory()) {
- FileUtil.deleteFolderRecursive(curPath);
- }
- else {
- fs.unlinkSync(curPath);
- }
- });
- }
- };
- ;
- return FileUtil;
-}());
-exports.FileUtil = FileUtil;
diff --git a/src/common/file-util.ts b/src/common/file-util.ts
index ed811e2..a74dce2 100644
--- a/src/common/file-util.ts
+++ b/src/common/file-util.ts
@@ -1,4 +1,5 @@
-import fs = require("fs");
+import * as fs from "fs";
+
/**
* Created by martin on 17.02.2017.
* Some (a few) simple utils for file operations.
@@ -92,4 +93,11 @@ export class FileUtil {
}
};
+ /**
+ * Delete a file.
+ * @param path
+ */
+ public static deleteFile(path: string) {
+ fs.unlinkSync(path);
+ }
}
\ No newline at end of file
diff --git a/src/common/writer-to-string.js b/src/common/writer-to-string.js
deleted file mode 100644
index 1373cef..0000000
--- a/src/common/writer-to-string.js
+++ /dev/null
@@ -1,45 +0,0 @@
-"use strict";
-var __extends = (this && this.__extends) || function (d, b) {
- for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
- function __() { this.constructor = d; }
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
-};
-var stream_1 = require("stream");
-var util_1 = require("util");
-/**
- * Created by martin on 20.02.2017.
- * A helper class for testing.
- * Can be used as a WritableStream and writes everything (synchronously) into a string,
- * that can easily be read by the tests.
- */
-var WriterToString = (function (_super) {
- __extends(WriterToString, _super);
- function WriterToString() {
- var _this = _super.call(this) || this;
- _this.resultString = '';
- return _this;
- }
- WriterToString.prototype._write = function (chunk, encoding, callback) {
- var chunkString;
- if (util_1.isString(chunk)) {
- chunkString = chunk;
- }
- else if (chunk instanceof Buffer) {
- chunkString = chunk.toString();
- }
- else {
- chunkString = new Buffer(chunk).toString(encoding);
- }
- this.resultString = this.resultString + chunkString;
- callback();
- };
- /**
- * Returns a string of everything, that was written to the stream so far.
- * @return {string}
- */
- WriterToString.prototype.writtenData = function () {
- return this.resultString;
- };
- return WriterToString;
-}(stream_1.Writable));
-exports.WriterToString = WriterToString;
diff --git a/src/index.ts b/src/index.ts
deleted file mode 100644
index 235f033..0000000
--- a/src/index.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * Created by martin on 19.03.2017.
- */
-export {TranslationMessagesFileFactory} from './xliffmerge/translation-messages-file-factory';
-export {ITranslationMessagesFile} from './xliffmerge/i-translation-messages-file';
-export {ITransUnit} from './xliffmerge/i-trans-unit';
diff --git a/src/tsconfig.json b/src/tsconfig.json
index 18196c5..a0fac10 100644
--- a/src/tsconfig.json
+++ b/src/tsconfig.json
@@ -15,7 +15,7 @@
"../node_modules/@types"
]
},
- "include": [
+ "includes": [
"**/*"
]
}
diff --git a/src/xliffmerge/i-trans-unit.ts b/src/xliffmerge/i-trans-unit.ts
deleted file mode 100644
index 634fd03..0000000
--- a/src/xliffmerge/i-trans-unit.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * Created by martin on 19.03.2017.
- */
-
-/**
- * Interface of a translation unit in a translation messages file.
- */
-export interface ITransUnit {
-
- readonly id: string;
-
- sourceContent(): string;
-
- /**
- * the translated value (containing all markup, depends on the concrete format used).
- */
- targetContent(): string;
-
- /**
- * the translated value, but all placeholders are replaced with {{n}} (starting at 0)
- * and all embedded html is replaced by direct html markup.
- */
- targetContentNormalized(): string;
-
- /**
- * State of the translation.
- * (new, final, ...)
- */
- targetState(): string;
-
- /**
- * The description set in the template as value of the i18n-attribute.
- * e.g. i18n="mydescription".
- */
- description(): string;
-
- /**
- * The meaning (intent) set in the template as value of the i18n-attribute.
- * This is the part in front of the | symbol.
- * e.g. i18n="meaning|mydescription".
- */
- meaning(): string;
-
- /**
- * the real xml element used for trans unit.
- * @return {CheerioElement}
- */
- asXmlElement(): CheerioElement;
-
- /**
- * Copy source to target to use it as dummy translation.
- * (better than missing value)
- */
- useSourceAsTarget(isDefaultLang: boolean, copyContent: boolean);
-
- /**
- * Translate trans unit.
- * (very simple, just for tests)
- * @param translation the translated string
- */
- translate(translation: string);
-}
diff --git a/src/xliffmerge/i-translation-messages-file.js b/src/xliffmerge/i-translation-messages-file.js
deleted file mode 100644
index de89c30..0000000
--- a/src/xliffmerge/i-translation-messages-file.js
+++ /dev/null
@@ -1,34 +0,0 @@
-"use strict";
-var xliff_file_1 = require("./xliff-file");
-var xmb_file_1 = require("./xmb-file");
-var util_1 = require("util");
-/**
- * The Common interface of XliffFile and XmbFile.
- * The merge process only uses this interface.
- * Created by martin on 10.03.2017.
- */
-/**
- * Helper class to read file depending on format.
- */
-var TranslationMessagesFileReader = (function () {
- function TranslationMessagesFileReader() {
- }
- /**
- * Read file function, result depends on format, either XliffFile or XmbFile.
- * @param format
- * @param path
- * @param encoding
- * @return {XliffFile}
- */
- TranslationMessagesFileReader.fromFile = function (i18nFormat, path, encoding) {
- if (i18nFormat === 'xlf') {
- return xliff_file_1.XliffFile.fromFile(path, encoding);
- }
- if (i18nFormat === 'xmb') {
- return xmb_file_1.XmbFile.fromFile(path, encoding);
- }
- throw new Error(util_1.format('oops, unsupported format "%s"', i18nFormat));
- };
- return TranslationMessagesFileReader;
-}());
-exports.TranslationMessagesFileReader = TranslationMessagesFileReader;
diff --git a/src/xliffmerge/i-translation-messages-file.ts b/src/xliffmerge/i-translation-messages-file.ts
deleted file mode 100644
index 28d225c..0000000
--- a/src/xliffmerge/i-translation-messages-file.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-import {XliffFile} from './xliff-file';
-import {XmbFile} from './xmb-file';
-import {FileUtil} from '../common/file-util';
-import {format} from 'util';
-import {ITransUnit} from './i-trans-unit';
-
-/**
- * The Common interface of XliffFile and XmbFile.
- * The merge process only uses this interface.
- * Created by martin on 10.03.2017.
- */
-export interface ITranslationMessagesFile {
-
- /**
- * warnings found in the file
- */
- warnings(): string[];
-
- /**
- * Number of translations found in the file.
- */
- numberOfTransUnits(): number;
-
- /**
- * Number of translations without id found in the file.
- */
- numberOfTransUnitsWithMissingId(): number;
-
- /**
- * Get source language.
- * @return {string}
- */
- sourceLanguage(): string;
-
- /**
- * Edit the source language.
- * @param language
- */
- setSourceLanguage(language: string);
-
- /**
- * Get target language.
- * @return {string}
- */
- targetLanguage(): string;
-
- /**
- * Edit the target language.
- * @param language
- */
- setTargetLanguage(language: string);
-
- /**
- * Loop over all Translation Units.
- * @param callback
- */
- forEachTransUnit(callback: ((transunit: ITransUnit) => void));
-
- /**
- * Get trans-unit with given id.
- * @param id
- * @return {Cheerio}
- */
- transUnitWithId(id: string): ITransUnit;
-
- /**
- * Edit functions following her
- */
-
- /**
- * Add a new trans-unit.
- * @param transUnit
- */
- addNewTransUnit(transUnit: ITransUnit);
-
- /**
- * Remove the trans-unit with the given id.
- * @param id
- */
- removeTransUnitWithId(id: string);
-
- /**
- * Copy source to target to use it as dummy translation.
- * (better than missing value)
- */
- useSourceAsTarget(transUnit: ITransUnit, isDefaultLang: boolean, copyContent: boolean);
-
- /**
- * Translate a given trans unit.
- * (very simple, just for tests)
- * @param transUnit
- * @param translation the translated string
- */
- translate(transUnit: ITransUnit, translation: string);
-
- /**
- * The filename where the data is read from.
- */
- filename(): string;
-
- /**
- * The encoding if the xml content (UTF-8, ISO-8859-1, ...)
- */
- encoding(): string;
-
- /**
- * The xml content to be saved after changes are made.
- */
- editedContent(): string;
-
-}
diff --git a/src/xliffmerge/ngx-translate-extractor.ts b/src/xliffmerge/ngx-translate-extractor.ts
index 9863019..a759443 100644
--- a/src/xliffmerge/ngx-translate-extractor.ts
+++ b/src/xliffmerge/ngx-translate-extractor.ts
@@ -1,7 +1,6 @@
-import {ITranslationMessagesFile} from './i-translation-messages-file';
+import {ITranslationMessagesFile, ITransUnit} from 'ngx-i18nsupport-lib';
import {FileUtil} from '../common/file-util';
import {isNullOrUndefined} from 'util';
-import {ITransUnit} from './i-trans-unit';
/**
* Created by roobm on 15.03.2017.
* A tool for extracting messages in ngx-translate format.
@@ -40,7 +39,13 @@ export class NgxTranslateExtractor {
*/
public extractTo(outputFile: string) {
let translations: NgxTranslations = this.toNgxTranslations(this.extract());
- FileUtil.replaceContent(outputFile, JSON.stringify(translations, null, 4), 'UTF-8')
+ if (translations && Object.keys(translations).length > 0) {
+ FileUtil.replaceContent(outputFile, JSON.stringify(translations, null, 4), 'UTF-8')
+ } else {
+ if (FileUtil.exists(outputFile)) {
+ FileUtil.deleteFile(outputFile);
+ }
+ }
}
/**
@@ -50,18 +55,46 @@ export class NgxTranslateExtractor {
private extract(): NgxMessage[] {
let result: NgxMessage[] = [];
this.messagesFile.forEachTransUnit((tu: ITransUnit) => {
- let description = tu.description();
- let id = tu.meaning();
- if (description && description === 'ngx-translate') {
- let messagetext = this.toTranslateString(tu.targetContentNormalized());
- result.push({id: id, message: messagetext});
+ let ngxId = this.ngxTranslateIdFromTU(tu);
+ if (ngxId) {
+ let messagetext = tu.targetContentNormalized();
+ result.push({id: ngxId, message: messagetext});
}
});
return result;
}
- private toTranslateString(contentFromTU: string): string {
- return contentFromTU;
+ /**
+ * Check, wether this tu should be extracted for ngx-translate usage, and return its id for ngx-translate.
+ * There are 2 possibilities:
+ * 1. description is set to "ngx-translate" and meaning contains the id.
+ * 2. id is explicitly set to a string.
+ * @param tu
+ * @return an id or null, if this tu should not be extracted.
+ */
+ private ngxTranslateIdFromTU(tu: ITransUnit): string {
+ if (this.isExplicitlySetId(tu.id)) {
+ return tu.id;
+ }
+ let description = tu.description();
+ if (description && description === 'ngx-translate') {
+ return tu.meaning();
+ }
+ }
+
+ /**
+ * Test, wether ID was explicitly set (via i18n="@myid).
+ * Just heuristic, an ID is explicitly that, if it does not look like a generated one.
+ * @param id
+ * @return {boolean}
+ */
+ private isExplicitlySetId(id: string): boolean {
+ if (isNullOrUndefined(id)) {
+ return false;
+ }
+ // generated IDs are either decimal or sha1 hex
+ let reForGeneratedId = /^[0-9a-f]{11,}$/;
+ return !reForGeneratedId.test(id);
}
/**
diff --git a/src/xliffmerge/translation-messages-file-factory.ts b/src/xliffmerge/translation-messages-file-factory.ts
deleted file mode 100644
index e49e86d..0000000
--- a/src/xliffmerge/translation-messages-file-factory.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * Created by roobm on 21.03.2017.
- */
-import {ITranslationMessagesFile} from './i-translation-messages-file';
-import {XmlReader} from './xml-reader';
-import {XliffFile} from './xliff-file';
-import {XmbFile} from './xmb-file';
-import {format} from 'util';
-
-/**
- * Helper class to read translation files depending on format.
- * This is part of the public api
- */
-export class TranslationMessagesFileFactory {
-
- /**
- * Read file function, result depends on format, either XliffFile or XmbFile.
- * @param format
- * @param xmlContent the file content
- * @param path the path of the file (only used to remember it)
- * @param encoding
- * @return {XliffFile}
- */
- public static fromFileContent(i18nFormat: string, xmlContent: string, path: string, encoding: string): ITranslationMessagesFile {
- if (i18nFormat === 'xlf') {
- return new XliffFile(xmlContent, path, encoding);
- }
- if (i18nFormat === 'xmb') {
- return new XmbFile(xmlContent, path, encoding);
- } else {
- throw new Error(format('oops, unsupported format "%s"', i18nFormat));
- }
- }
-
-}
-
diff --git a/src/xliffmerge/translation-messages-file-reader.ts b/src/xliffmerge/translation-messages-file-reader.ts
index 1ce6d49..672d4a0 100644
--- a/src/xliffmerge/translation-messages-file-reader.ts
+++ b/src/xliffmerge/translation-messages-file-reader.ts
@@ -1,12 +1,9 @@
/**
* Created by roobm on 21.03.2017.
*/
-import {ITranslationMessagesFile} from './i-translation-messages-file';
-import {XmlReader} from './xml-reader';
-import {XliffFile} from './xliff-file';
-import {XmbFile} from './xmb-file';
-import {format} from 'util';
+import {TranslationMessagesFileFactory, ITranslationMessagesFile, ITransUnit} from 'ngx-i18nsupport-lib';
import {FileUtil} from '../common/file-util';
+import {XmlReader} from './xml-reader';
/**
* Helper class to read translation files depending on format.
@@ -20,15 +17,46 @@ export class TranslationMessagesFileReader {
* @param encoding
* @return {XliffFile}
*/
- public static fromFile(i18nFormat: string, path: string, encoding: string): ITranslationMessagesFile {
+ public static fromFile(i18nFormat: string,
+ path: string,
+ encoding: string,
+ optionalMasterFilePath?: string): ITranslationMessagesFile {
let xmlContent = XmlReader.readXmlFileContent(path, encoding);
- if (i18nFormat === 'xlf') {
- return new XliffFile(xmlContent.content, path, xmlContent.encoding);
- }
- if (i18nFormat === 'xmb') {
- return new XmbFile(xmlContent.content, path, xmlContent.encoding);
+ let optionalMaster = TranslationMessagesFileReader.masterFileContent(optionalMasterFilePath, encoding);
+ return TranslationMessagesFileFactory.fromFileContent(i18nFormat, xmlContent.content, path, xmlContent.encoding, optionalMaster);
+ }
+
+ /**
+ * Read file function, result depends on format, either XliffFile or XmbFile.
+ * @param format
+ * @param path
+ * @param encoding
+ * @return {XliffFile}
+ */
+ public static fromUnknownFormatFile(path: string,
+ encoding: string,
+ optionalMasterFilePath?: string): ITranslationMessagesFile {
+ let xmlContent = XmlReader.readXmlFileContent(path, encoding);
+ let optionalMaster = TranslationMessagesFileReader.masterFileContent(optionalMasterFilePath, encoding);
+ return TranslationMessagesFileFactory.fromUnknownFormatFileContent(xmlContent.content, path, xmlContent.encoding, optionalMaster);
+ }
+
+ /**
+ * Read master xmb file
+ * @param optionalMasterFilePath
+ * @param encoding
+ * @return {any} content and encoding of file
+ */
+ private static masterFileContent(optionalMasterFilePath: string, encoding: string): {xmlContent: string, path: string, encoding: string} {
+ if (optionalMasterFilePath) {
+ let masterXmlContent = XmlReader.readXmlFileContent(optionalMasterFilePath, encoding);
+ return {
+ xmlContent: masterXmlContent.content,
+ path: optionalMasterFilePath,
+ encoding: masterXmlContent.encoding
+ };
} else {
- throw new Error(format('oops, unsupported format "%s"', i18nFormat));
+ return null;
}
}
diff --git a/src/xliffmerge/version.js b/src/xliffmerge/version.js
deleted file mode 100644
index fa34032..0000000
--- a/src/xliffmerge/version.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-/**
- * Created by martin on 19.02.2017.
- */
-var path = require("path");
-var pkg = require(path.resolve(__dirname, '..', 'package.json'));
-exports.VERSION = (pkg ? pkg.version : 'unknown');
diff --git a/src/xliffmerge/xliff-file.js b/src/xliffmerge/xliff-file.js
deleted file mode 100644
index 3fc919f..0000000
--- a/src/xliffmerge/xliff-file.js
+++ /dev/null
@@ -1,218 +0,0 @@
-"use strict";
-var cheerio = require("cheerio");
-var file_util_1 = require("../common/file-util");
-var util_1 = require("util");
-var xml_reader_1 = require("./xml-reader");
-/**
- * Created by martin on 23.02.2017.
- * Ab xliff file read from a source file.
- * Defines some relevant get and set method for reading and modifying such a file.
- */
-/**
- * Read-Options for cheerio, enable xml mode.
- * @type {{xmlMode: boolean}}
- */
-var CheerioOptions = {
- xmlMode: true,
- decodeEntities: false,
-};
-var TransUnit = (function () {
- function TransUnit(_transUnit, _id) {
- this._transUnit = _transUnit;
- this._id = _id;
- }
- Object.defineProperty(TransUnit.prototype, "id", {
- get: function () {
- return this._id;
- },
- enumerable: true,
- configurable: true
- });
- TransUnit.prototype.sourceContent = function () {
- return cheerio('source', this._transUnit).html();
- };
- TransUnit.prototype.targetContent = function () {
- return cheerio('target', this._transUnit).html();
- };
- TransUnit.prototype.targetState = function () {
- return cheerio('target', this._transUnit).attr('state');
- };
- /**
- * the real xml element used for trans unit.
- * Here it is a element defined in XLIFF Spec.
- * @return {CheerioElement}
- */
- TransUnit.prototype.asXmlElement = function () {
- return this._transUnit;
- };
- /**
- * Translate trans unit.
- * (very simple, just for tests)
- * @param translation the translated string
- */
- TransUnit.prototype.translate = function (translation) {
- var target = cheerio('target', this._transUnit);
- if (!target) {
- var source = cheerio('source', this._transUnit);
- source.parent().append('');
- target = cheerio('target', source.parent());
- }
- target.html(translation);
- target.attr('state', 'final');
- };
- /**
- * Copy source to target to use it as dummy translation.
- * (better than missing value)
- */
- TransUnit.prototype.useSourceAsTarget = function (isDefaultLang) {
- var source = cheerio('source', this._transUnit);
- var target = cheerio('target', this._transUnit);
- if (!target) {
- source.parent().append('');
- target = cheerio('target', source.parent());
- }
- target.html(source.html());
- if (isDefaultLang) {
- target.attr('state', 'final');
- }
- else {
- target.attr('state', 'new');
- }
- };
- return TransUnit;
-}());
-var XliffFile = (function () {
- function XliffFile() {
- this._warnings = [];
- this._numberOfTransUnitsWithMissingId = 0;
- }
- /**
- * Read an xlf-File.
- * @param path Path to file
- * @param encoding optional encoding of the xml.
- * This is read from the file, but if you know it before, you can avoid reading the file twice.
- * @return {XliffFile}
- */
- XliffFile.fromFile = function (path, encoding) {
- var xlf = new XliffFile();
- var xmlContent = xml_reader_1.XmlReader.readXmlFileContent(path, encoding);
- xlf.initializeFromContent(xmlContent.content, path, xmlContent.encoding);
- return xlf;
- };
- XliffFile.prototype.initializeFromContent = function (xmlString, path, encoding) {
- this.filename = path;
- this.encoding = encoding;
- this.xliffContent = cheerio.load(xmlString, CheerioOptions);
- return this;
- };
- XliffFile.prototype.forEachTransUnit = function (callback) {
- this.initializeTransUnits();
- this.transUnits.forEach(function (tu) { return callback(tu); });
- };
- XliffFile.prototype.warnings = function () {
- this.initializeTransUnits();
- return this._warnings;
- };
- XliffFile.prototype.numberOfTransUnits = function () {
- this.initializeTransUnits();
- return this.transUnits.length;
- };
- XliffFile.prototype.numberOfTransUnitsWithMissingId = function () {
- this.initializeTransUnits();
- return this._numberOfTransUnitsWithMissingId;
- };
- /**
- * Get trans-unit with given id.
- * @param id
- * @return {Cheerio}
- */
- XliffFile.prototype.transUnitWithId = function (id) {
- this.initializeTransUnits();
- return this.transUnits.find(function (tu) { return tu.id == id; });
- };
- XliffFile.prototype.initializeTransUnits = function () {
- var _this = this;
- if (util_1.isNullOrUndefined(this.transUnits)) {
- this.transUnits = [];
- var transUnitsInFile = this.xliffContent('trans-unit');
- transUnitsInFile.each(function (index, transunit) {
- var id = cheerio(transunit).attr('id');
- if (!id) {
- _this._warnings.push(util_1.format('oops, trans-unit without "id" found in master, please check file %s', _this.filename));
- _this._numberOfTransUnitsWithMissingId++;
- }
- _this.transUnits.push(new TransUnit(transunit, id));
- });
- }
- };
- /**
- * Get source language.
- * @return {string}
- */
- XliffFile.prototype.sourceLanguage = function () {
- return this.xliffContent('file').attr('source-language');
- };
- /**
- * Edit the source language.
- * @param language
- */
- XliffFile.prototype.setSourceLanguage = function (language) {
- this.xliffContent('file').attr('source-language', language);
- };
- /**
- * Get target language.
- * @return {string}
- */
- XliffFile.prototype.targetLanguage = function () {
- return this.xliffContent('file').attr('target-language');
- };
- /**
- * Edit the target language.
- * @param language
- */
- XliffFile.prototype.setTargetLanguage = function (language) {
- this.xliffContent('file').attr('target-language', language);
- };
- /**
- * Copy source to target to use it as dummy translation.
- * (better than missing value)
- */
- XliffFile.prototype.useSourceAsTarget = function (transUnit, isDefaultLang) {
- transUnit.useSourceAsTarget(isDefaultLang);
- };
- /**
- * Translate a given trans unit.
- * (very simple, just for tests)
- * @param transUnit
- * @param translation the translated string
- */
- XliffFile.prototype.translate = function (transUnit, translation) {
- transUnit.translate(translation);
- };
- /**
- * Add a new trans-unit.
- * @param transUnit
- */
- XliffFile.prototype.addNewTransUnit = function (transUnit) {
- this.xliffContent('body').append(cheerio(transUnit.asXmlElement()));
- this.initializeTransUnits();
- this.transUnits.push(transUnit);
- };
- /**
- * Remove the trans-unit with the given id.
- * @param id
- */
- XliffFile.prototype.removeTransUnitWithId = function (id) {
- this.xliffContent('#' + id).remove();
- this.initializeTransUnits();
- this.transUnits = this.transUnits.filter(function (tu) { return tu.id != id; });
- };
- /**
- * Save edited content to file.
- */
- XliffFile.prototype.save = function () {
- file_util_1.FileUtil.replaceContent(this.filename, this.xliffContent.xml(), this.encoding);
- };
- return XliffFile;
-}());
-exports.XliffFile = XliffFile;
diff --git a/src/xliffmerge/xliff-file.ts b/src/xliffmerge/xliff-file.ts
deleted file mode 100644
index b38afff..0000000
--- a/src/xliffmerge/xliff-file.ts
+++ /dev/null
@@ -1,326 +0,0 @@
-import * as cheerio from "cheerio";
-import {isNullOrUndefined, format} from 'util';
-import {ITranslationMessagesFile} from './i-translation-messages-file';
-import {ITransUnit} from './i-trans-unit';
-/**
- * Created by martin on 23.02.2017.
- * Ab xliff file read from a source file.
- * Defines some relevant get and set method for reading and modifying such a file.
- */
-
-/**
- * Read-Options for cheerio, enable xml mode.
- * @type {{xmlMode: boolean}}
- */
-const CheerioOptions: CheerioOptionsInterface = {
- xmlMode: true,
- decodeEntities: false,
-
-};
-
-class TransUnit implements ITransUnit {
-
- constructor(private _transUnit: CheerioElement, private _id: string) {
-
- }
-
- public get id(): string {
- return this._id;
- }
-
- public sourceContent(): string {
- return cheerio('source', this._transUnit).html();
- }
-
- /**
- * the translated value (containing all markup, depends on the concrete format used).
- */
- public targetContent(): string {
- return cheerio('target', this._transUnit).html();
- }
-
- /**
- * the translated value, but all placeholders are replaced with {{n}} (starting at 0)
- * and all embedded html is replaced by direct html markup.
- */
- targetContentNormalized(): string {
- let directHtml = this.targetContent();
- if (!directHtml) {
- return directHtml;
- }
- let normalized = directHtml;
- let re0: RegExp = /<\/x>/g;
- normalized = normalized.replace(re0, '{{0}}');
- let reN: RegExp = /<\/x>/g;
- normalized = normalized.replace(reN, '{{$1}}');
-
- let reStartBold: RegExp = /<\/x>/g;
- normalized = normalized.replace(reStartBold, '');
- let reCloseBold: RegExp = /<\/x>/g;
- normalized = normalized.replace(reCloseBold, '');
-
- let reStartAnyTag: RegExp = /<\/x>/g;
- normalized = normalized.replace(reStartAnyTag, '<$2>');
- let reCloseAnyTag: RegExp = /<\/x>/g;
- normalized = normalized.replace(reCloseAnyTag, '$2>');
-
- return normalized;
- }
-
- /**
- * State of the translation.
- * (new, final, ...)
- */
- public targetState(): string {
- return cheerio('target', this._transUnit).attr('state');
- }
-
- /**
- * The description set in the template as value of the i18n-attribute.
- * e.g. i18n="mydescription".
- * In xliff this is stored as a note element with attribute from="description".
- */
- public description(): string {
- let descriptionElem = cheerio('note', this._transUnit).filter((index, elem) => cheerio(elem).attr('from') == 'description');
- return descriptionElem ? descriptionElem.html() : null;
- }
-
- /**
- * The meaning (intent) set in the template as value of the i18n-attribute.
- * This is the part in front of the | symbol.
- * e.g. i18n="meaning|mydescription".
- * In xliff this is stored as a note element with attribute from="meaning".
- */
- public meaning(): string {
- let meaningElem = cheerio('note', this._transUnit).filter((index, elem) => cheerio(elem).attr('from') == 'meaning');
- return meaningElem ? meaningElem.html() : null;
- }
-
- /**
- * the real xml element used for trans unit.
- * Here it is a element defined in XLIFF Spec.
- * @return {CheerioElement}
- */
- public asXmlElement(): CheerioElement {
- return this._transUnit;
- }
-
- /**
- * Translate trans unit.
- * (very simple, just for tests)
- * @param translation the translated string
- */
- public translate(translation: string) {
- let target = cheerio('target', this._transUnit);
- if (!target) {
- let source = cheerio('source', this._transUnit);
- source.parent().append('');
- target = cheerio('target', source.parent());
- }
- let translationContainer: CheerioStatic = cheerio.load('' + translation + '', CheerioOptions);
- let translationParts: Cheerio = translationContainer('dummy');
- target.contents().remove();
- translationParts.contents().each((index, element) => {target.append(cheerio(element));});
- target.attr('state', 'final');
- }
-
- /**
- * Copy source to target to use it as dummy translation.
- * (better than missing value)
- */
- public useSourceAsTarget(isDefaultLang: boolean, copyContent: boolean) {
- let source = cheerio('source', this._transUnit);
- let target = cheerio('target', this._transUnit);
- if (!target) {
- source.parent().append('');
- target = cheerio('target', source.parent());
- }
- if (isDefaultLang || copyContent) {
- target.html(source.html());
- } else {
- target.html('');
- }
- if (isDefaultLang) {
- target.attr('state', 'final');
- } else {
- target.attr('state', 'new');
- }
- }
-
-}
-
-export class XliffFile implements ITranslationMessagesFile {
-
- private _filename: string;
-
- private _encoding: string;
-
- private xliffContent: CheerioStatic;
-
- // trans-unit elements and their id from the file
- private transUnits: ITransUnit[];
-
- private _warnings: string[];
- private _numberOfTransUnitsWithMissingId: number;
-
- /**
- * Create an xlf-File from source.
- * @param xmlString source read from file.
- * @param path Path to file
- * @param encoding optional encoding of the xml.
- * This is read from the file, but if you know it before, you can avoid reading the file twice.
- * @return {XliffFile}
- */
- constructor(xmlString: string, path: string, encoding: string) {
- this._warnings = [];
- this._numberOfTransUnitsWithMissingId = 0;
- this.initializeFromContent(xmlString, path, encoding);
- }
-
- private initializeFromContent(xmlString: string, path: string, encoding: string): XliffFile {
- this._filename = path;
- this._encoding = encoding;
- this.xliffContent = cheerio.load(xmlString, CheerioOptions);
- if (this.xliffContent('xliff').length < 1) {
- throw new Error(format('File "%s" seems to be no xliff file (should contain an xliff element)', path));
- }
- return this;
- }
-
- public forEachTransUnit(callback: ((transunit: ITransUnit) => void)) {
- this.initializeTransUnits();
- this.transUnits.forEach((tu) => callback(tu));
- }
-
- public warnings(): string[] {
- this.initializeTransUnits();
- return this._warnings;
- }
-
- public numberOfTransUnits(): number {
- this.initializeTransUnits();
- return this.transUnits.length;
- }
-
- public numberOfTransUnitsWithMissingId(): number {
- this.initializeTransUnits();
- return this._numberOfTransUnitsWithMissingId;
- }
-
- /**
- * Get trans-unit with given id.
- * @param id
- * @return {Cheerio}
- */
- public transUnitWithId(id: string): ITransUnit {
- this.initializeTransUnits();
- return this.transUnits.find((tu) => tu.id == id);
- }
-
- private initializeTransUnits() {
- if (isNullOrUndefined(this.transUnits)) {
- this.transUnits = [];
- let transUnitsInFile = this.xliffContent('trans-unit');
- transUnitsInFile.each((index, transunit: CheerioElement) => {
- let id = cheerio(transunit).attr('id');
- if (!id) {
- this._warnings.push(format('oops, trans-unit without "id" found in master, please check file %s', this.filename));
- this._numberOfTransUnitsWithMissingId++;
- }
- this.transUnits.push(new TransUnit(transunit, id));
- });
- }
- }
-
- /**
- * Get source language.
- * @return {string}
- */
- public sourceLanguage(): string {
- return this.xliffContent('file').attr('source-language');
- }
-
- /**
- * Edit the source language.
- * @param language
- */
- public setSourceLanguage(language: string) {
- this.xliffContent('file').attr('source-language', language);
- }
-
- /**
- * Get target language.
- * @return {string}
- */
- public targetLanguage(): string {
- return this.xliffContent('file').attr('target-language');
- }
-
- /**
- * Edit the target language.
- * @param language
- */
- public setTargetLanguage(language: string) {
- this.xliffContent('file').attr('target-language', language);
- }
-
- /**
- * Copy source to target to use it as dummy translation.
- * (better than missing value)
- */
- public useSourceAsTarget(transUnit: ITransUnit, isDefaultLang: boolean, copyContent: boolean) {
- transUnit.useSourceAsTarget(isDefaultLang, copyContent);
- }
-
- /**
- * Translate a given trans unit.
- * (very simple, just for tests)
- * @param transUnit
- * @param translation the translated string
- */
- public translate(transUnit: ITransUnit, translation: string) {
- transUnit.translate(translation);
- }
-
- /**
- * Add a new trans-unit.
- * @param transUnit
- */
- public addNewTransUnit(transUnit: ITransUnit) {
- this.xliffContent('body').append(cheerio(transUnit.asXmlElement()));
- this.initializeTransUnits();
- this.transUnits.push(transUnit);
- }
-
- /**
- * Remove the trans-unit with the given id.
- * @param id
- */
- public removeTransUnitWithId(id: string) {
- this.xliffContent('#' + id).remove();
- this.initializeTransUnits();
- this.transUnits = this.transUnits.filter((tu) => tu.id != id);
- }
-
- /**
- * The filename where the data is read from.
- */
- public filename(): string {
- return this._filename;
- }
-
- /**
- * The encoding if the xml content (UTF-8, ISO-8859-1, ...)
- */
- public encoding(): string {
- return this._encoding;
- }
-
- /**
- * The xml to be saved after changes are made.
- */
- public editedContent(): string {
- return this.xliffContent.xml();
- }
-
-}
diff --git a/src/xliffmerge/xliff-merge-error.js b/src/xliffmerge/xliff-merge-error.js
deleted file mode 100644
index ad901be..0000000
--- a/src/xliffmerge/xliff-merge-error.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * Created by martin on 17.02.2017.
- */
-"use strict";
-var __extends = (this && this.__extends) || function (d, b) {
- for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
- function __() { this.constructor = d; }
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
-};
-var XliffMergeError = (function (_super) {
- __extends(XliffMergeError, _super);
- function XliffMergeError(msg) {
- var _this = _super.call(this, msg) || this;
- // Set the prototype explicitly.
- Object.setPrototypeOf(_this, XliffMergeError.prototype);
- return _this;
- }
- return XliffMergeError;
-}(Error));
-exports.XliffMergeError = XliffMergeError;
diff --git a/src/xliffmerge/xliff-merge-parameters.js b/src/xliffmerge/xliff-merge-parameters.js
deleted file mode 100644
index 0827fca..0000000
--- a/src/xliffmerge/xliff-merge-parameters.js
+++ /dev/null
@@ -1,264 +0,0 @@
-/**
- * Created by martin on 17.02.2017.
- * Collection of all parameters used by the tool.
- * The parameters are read form the profile or defaults are used.
- */
-"use strict";
-var fs = require("fs");
-var xliff_merge_error_1 = require("./xliff-merge-error");
-var util_1 = require("util");
-var XliffMergeParameters = (function () {
- function XliffMergeParameters() {
- this.errorsFound = [];
- this.warningsFound = [];
- }
- /**
- * Create Parameters.
- * @param options command options
- * @param profileContent given profile (if not, it is read from the profile path from options).
- * @return {XliffMergeParameters}
- */
- XliffMergeParameters.createFromOptions = function (options, profileContent) {
- var parameters = new XliffMergeParameters();
- parameters.configure(options, profileContent);
- return parameters;
- };
- /**
- * Initialize me from the profile content.
- * (public only for test usage).
- * @param options
- * @param profileContent if null, read it from profile.
- */
- XliffMergeParameters.prototype.configure = function (options, profileContent) {
- this.errorsFound = [];
- this.warningsFound = [];
- if (!profileContent) {
- profileContent = this.readProfile(options);
- }
- var validProfile = (!!profileContent);
- if (options.quiet) {
- this._quiet = options.quiet;
- }
- if (options.verbose) {
- this._verbose = options.verbose;
- }
- if (validProfile) {
- this.initializeFromConfig(profileContent);
- // if languages are given as parameters, they ovveride everything said in profile
- if (!!options.languages && options.languages.length > 0) {
- this._languages = options.languages;
- if (!this._defaultLanguage) {
- this._defaultLanguage = this._languages[0];
- }
- }
- this.checkParameters();
- }
- };
- /**
- * Read profile.
- * @param profilePath
- * @return the read profile (empty, if none, null if errors)
- */
- XliffMergeParameters.prototype.readProfile = function (options) {
- var profilePath = options.profilePath;
- if (!profilePath) {
- return {};
- }
- var content;
- try {
- content = fs.readFileSync(profilePath, 'UTF-8');
- }
- catch (err) {
- this.errorsFound.push(new xliff_merge_error_1.XliffMergeError('could not read profile "' + profilePath + '"'));
- return null;
- }
- var profileContent = JSON.parse(content);
- return profileContent;
- };
- XliffMergeParameters.prototype.initializeFromConfig = function (profileContent) {
- if (!profileContent) {
- return;
- }
- var profile = profileContent.xliffmergeOptions;
- if (profile) {
- if (!util_1.isNullOrUndefined(profile.quiet)) {
- this._quiet = profile.quiet;
- }
- if (!util_1.isNullOrUndefined(profile.verbose)) {
- this._verbose = profile.verbose;
- }
- if (profile.defaultLanguage) {
- this._defaultLanguage = profile.defaultLanguage;
- }
- if (profile.languages) {
- this._languages = profile.languages;
- }
- if (profile.srcDir) {
- this._srcDir = profile.srcDir;
- }
- if (profile.angularCompilerOptions) {
- if (profile.angularCompilerOptions.genDir)
- this._genDir = profile.angularCompilerOptions.genDir;
- }
- if (profile.genDir) {
- // this must be after angularCompilerOptions to be preferred
- this._genDir = profile.genDir;
- }
- if (profile.i18nFile) {
- this._i18nFile = profile.i18nFile;
- }
- if (profile.i18nFormat) {
- this._i18nFormat = profile.i18nFormat;
- }
- if (profile.encoding) {
- this._encoding = profile.encoding;
- }
- if (profile.removeUnusedIds) {
- this._removeUnusedIds = profile.removeUnusedIds;
- }
- }
- else {
- this.warningsFound.push('did not find "xliffmergeOptions" in profile, using defaults');
- }
- };
- /**
- * Check all Parameters, wether they are complete and consistent.
- * if something is wrong with the parameters, it is collected in errorsFound.
- */
- XliffMergeParameters.prototype.checkParameters = function () {
- var _this = this;
- this.checkLanguageSyntax(this.defaultLanguage());
- if (this.languages().length == 0) {
- this.errorsFound.push(new xliff_merge_error_1.XliffMergeError('no languages specified'));
- }
- this.languages().forEach(function (lang) {
- _this.checkLanguageSyntax(lang);
- });
- var stats;
- var err;
- // srcDir should exists
- try {
- stats = fs.statSync(this.srcDir());
- }
- catch (e) {
- err = e;
- }
- if (!!err || !stats.isDirectory()) {
- this.errorsFound.push(new xliff_merge_error_1.XliffMergeError('srcDir "' + this.srcDir() + '" is not a directory'));
- }
- // genDir should exists
- try {
- stats = fs.statSync(this.genDir());
- }
- catch (e) {
- err = e;
- }
- if (!!err || !stats.isDirectory()) {
- this.errorsFound.push(new xliff_merge_error_1.XliffMergeError('genDir "' + this.genDir() + '" is not a directory'));
- }
- // master file MUST exist
- try {
- fs.accessSync(this.i18nFile(), fs.constants.R_OK);
- }
- catch (err) {
- this.errorsFound.push(new xliff_merge_error_1.XliffMergeError('i18nFile "' + this.i18nFile() + '" is not readable'));
- }
- // i18nFormat must be xlf or xmb
- if (!(this.i18nFormat() === 'xlf' || this.i18nFormat() === 'xmb')) {
- this.errorsFound.push(new xliff_merge_error_1.XliffMergeError('i18nFormat "' + this.i18nFormat() + '" invalid, must be "xlf" or "xmb"'));
- }
- };
- /**
- * Check syntax of language.
- * Must be compatible with XML Schema type xsd:language.
- * Pattern: [a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*
- * @param lang
- */
- XliffMergeParameters.prototype.checkLanguageSyntax = function (lang) {
- var pattern = /^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/;
- if (!pattern.test(lang)) {
- this.errorsFound.push(new xliff_merge_error_1.XliffMergeError('language "' + lang + '" is not valid'));
- }
- };
- XliffMergeParameters.prototype.verbose = function () {
- return (util_1.isNullOrUndefined(this._verbose)) ? false : this._verbose;
- };
- XliffMergeParameters.prototype.quiet = function () {
- return (util_1.isNullOrUndefined(this._quiet)) ? false : this._quiet;
- };
- /**
- * Debug output all parameters to commandOutput.
- */
- XliffMergeParameters.prototype.showAllParameters = function (commandOutput) {
- commandOutput.debug('xliffmerge Used Parameters:');
- commandOutput.debug('defaultLanguage:\t"%s"', this.defaultLanguage());
- commandOutput.debug('srcDir:\t"%s"', this.srcDir());
- commandOutput.debug('genDir:\t"%s"', this.genDir());
- commandOutput.debug('i18nFile:\t"%s"', this.i18nFile());
- commandOutput.debug('languages:\t%s', this.languages());
- };
- /**
- * Default-Language, default en.
- * @return {string}
- */
- XliffMergeParameters.prototype.defaultLanguage = function () {
- return this._defaultLanguage ? this._defaultLanguage : 'en';
- };
- /**
- * Liste der zu bearbeitenden Sprachen.
- * @return {string[]}
- */
- XliffMergeParameters.prototype.languages = function () {
- return this._languages ? this._languages : [];
- };
- /**
- * src directory, where the master xlif is located.
- * @return {string}
- */
- XliffMergeParameters.prototype.srcDir = function () {
- return this._srcDir ? this._srcDir : '.';
- };
- /**
- * The master xlif file (the one generated by ng-xi18n).
- * Default is /messages.xlf.
- * @return {string}
- */
- XliffMergeParameters.prototype.i18nFile = function () {
- return this.srcDir() + '/' + (this._i18nFile ? this._i18nFile : 'messages.' + this.i18nFormat());
- };
- /**
- * Format of the master xlif file.
- * Default is "xlf", possible are "xlf" or "xmb".
- * @return {string}
- */
- XliffMergeParameters.prototype.i18nFormat = function () {
- return (this._i18nFormat ? this._i18nFormat : 'xlf');
- };
- /**
- * evtl zu generierendes I18n-File mit den Übersetzungen für eine Sprache.
- * @param lang
- * @return {string}
- */
- XliffMergeParameters.prototype.generatedI18nFile = function (lang) {
- return this.genDir() + '/' + 'messages.' + lang + '.' + this.i18nFormat();
- };
- /**
- * The encoding used to write new XLIFF-files.
- * @return {string}
- */
- XliffMergeParameters.prototype.encoding = function () {
- return this._encoding ? this._encoding : 'UTF-8';
- };
- /**
- * Output-Directory, where the output is written to.
- * Default is .
- */
- XliffMergeParameters.prototype.genDir = function () {
- return this._genDir ? this._genDir : this.srcDir();
- };
- XliffMergeParameters.prototype.removeUnusedIds = function () {
- return (util_1.isNullOrUndefined(this._removeUnusedIds)) ? true : this._removeUnusedIds;
- };
- return XliffMergeParameters;
-}());
-exports.XliffMergeParameters = XliffMergeParameters;
diff --git a/src/xliffmerge/xliff-merge-parameters.ts b/src/xliffmerge/xliff-merge-parameters.ts
index d4c8c95..aa9d511 100644
--- a/src/xliffmerge/xliff-merge-parameters.ts
+++ b/src/xliffmerge/xliff-merge-parameters.ts
@@ -4,7 +4,7 @@
* The parameters are read form the profile or defaults are used.
*/
-import fs = require("fs");
+import * as fs from "fs";
import {XliffMergeError} from './xliff-merge-error';
import {Stats} from 'fs';
import {CommandOutput} from '../common/command-output';
diff --git a/src/xliffmerge/xliff-merge.js b/src/xliffmerge/xliff-merge.js
deleted file mode 100644
index bf0c8ae..0000000
--- a/src/xliffmerge/xliff-merge.js
+++ /dev/null
@@ -1,240 +0,0 @@
-"use strict";
-var program = require("commander");
-var command_output_1 = require("../common/command-output");
-var xliff_merge_parameters_1 = require("./xliff-merge-parameters");
-var xliff_merge_error_1 = require("./xliff-merge-error");
-var file_util_1 = require("../common/file-util");
-var version_1 = require("./version");
-var util_1 = require("util");
-var i_translation_messages_file_1 = require("./i-translation-messages-file");
-var XliffMerge = (function () {
- function XliffMerge(commandOutput, options) {
- this.commandOutput = commandOutput;
- this.options = options;
- this.parameters = null;
- }
- XliffMerge.main = function (argv) {
- var options = XliffMerge.parseArgs(argv);
- var result = new XliffMerge(new command_output_1.CommandOutput(process.stdout), options).run();
- process.exit(result);
- };
- XliffMerge.parseArgs = function (argv) {
- var languages = null;
- delete program.verbose;
- delete program.quiet;
- delete program.profilePath;
- delete program.languages;
- program
- .version(version_1.VERSION)
- .arguments('')
- .option('-p, --profile [configfile]', 'a json configuration file containing all relevant parameters (see details below)')
- .option('-v, --verbose', 'show some output for debugging purposes')
- .option('-q, --quiet', 'only show errors, nothing else')
- .on('--help', function () {
- console.log(' has to be a valid language short string, e,g. "en", "de", "de-ch"');
- console.log('');
- console.log(' configfile can contain the following values:');
- console.log('\tquiet verbose defaultLanguage languages srcDir i18nFile i18nFormat encoding genDir removeUnusedIds');
- console.log('\tfor details please consult the home page https://github.com/martinroob/ngx-i18nsupport');
- })
- .action(function (languageArray) {
- languages = languageArray;
- })
- .parse(argv);
- var options = {
- languages: languages
- };
- if (program.profile) {
- options.profilePath = program.profile;
- }
- if (program.quiet) {
- options.quiet = true;
- }
- if (program.verbose && program.verbose > 0) {
- options.verbose = true;
- }
- return options;
- };
- /**
- * For Tests, create instance with given profile
- * @param commandOutput
- * @param options
- * @param profileContent
- */
- XliffMerge.createFromOptions = function (commandOutput, options, profileContent) {
- var instance = new XliffMerge(commandOutput, options);
- instance.parameters = xliff_merge_parameters_1.XliffMergeParameters.createFromOptions(options, profileContent);
- return instance;
- };
- XliffMerge.prototype.run = function () {
- try {
- this.doRun();
- return 0;
- }
- catch (err) {
- if (err instanceof xliff_merge_error_1.XliffMergeError) {
- this.commandOutput.error(err.message);
- return -1;
- }
- else {
- // unhandled
- this.commandOutput.error('oops ' + err);
- throw err;
- }
- }
- };
- /**
- * Ausführen merge-Process.
- */
- XliffMerge.prototype.doRun = function () {
- var _this = this;
- if (this.options && this.options.quiet) {
- this.commandOutput.setQuiet();
- }
- if (this.options && this.options.verbose) {
- this.commandOutput.setVerbose();
- }
- if (!this.parameters) {
- this.parameters = xliff_merge_parameters_1.XliffMergeParameters.createFromOptions(this.options);
- }
- this.commandOutput.info('xliffmerge version %s', version_1.VERSION);
- if (this.parameters.verbose()) {
- this.parameters.showAllParameters(this.commandOutput);
- }
- if (this.parameters.errorsFound.length > 0) {
- for (var _i = 0, _a = this.parameters.errorsFound; _i < _a.length; _i++) {
- var err = _a[_i];
- this.commandOutput.error(err.message);
- }
- return;
- }
- if (this.parameters.warningsFound.length > 0) {
- for (var _b = 0, _c = this.parameters.warningsFound; _b < _c.length; _b++) {
- var warn = _c[_b];
- this.commandOutput.warn(warn);
- }
- }
- this.readMaster();
- this.parameters.languages().forEach(function (lang) {
- _this.processLanguage(lang);
- });
- };
- /**
- * Return the name of the generated file for given lang.
- * @param lang
- * @return {string}
- */
- XliffMerge.prototype.generatedI18nFile = function (lang) {
- return this.parameters.generatedI18nFile(lang);
- };
- XliffMerge.prototype.readMaster = function () {
- var _this = this;
- this.master = i_translation_messages_file_1.TranslationMessagesFileReader.fromFile(this.parameters.i18nFormat(), this.parameters.i18nFile(), this.parameters.encoding());
- this.master.warnings().forEach(function (warning) {
- _this.commandOutput.warn(warning);
- });
- var count = this.master.numberOfTransUnits();
- var missingIdCount = this.master.numberOfTransUnitsWithMissingId();
- this.commandOutput.info('master contains %s trans-units', count);
- if (missingIdCount > 0) {
- this.commandOutput.warn('master contains %s trans-units, but there are %s without id', count, missingIdCount);
- }
- var sourceLang = this.master.sourceLanguage();
- if (sourceLang && sourceLang !== this.parameters.defaultLanguage()) {
- this.commandOutput.warn('master says to have source-language="%s", should be "%s" (your defaultLanguage)', sourceLang, this.parameters.defaultLanguage());
- this.master.setSourceLanguage(this.parameters.defaultLanguage());
- this.master.save();
- this.commandOutput.warn('changed master source-language="%s" to "%s"', sourceLang, this.parameters.defaultLanguage());
- }
- };
- XliffMerge.prototype.processLanguage = function (lang) {
- this.commandOutput.debug('processing language %s', lang);
- var languageXliffFile = this.parameters.generatedI18nFile(lang);
- if (!file_util_1.FileUtil.exists(languageXliffFile)) {
- this.createUntranslatedXliff(lang, languageXliffFile);
- }
- else {
- this.mergeMasterTo(lang, languageXliffFile);
- }
- };
- /**
- * create a new file for the language, which contains no translations, but all keys.
- * in principle, this is just a copy of the master with target-language set.
- * @param lang
- * @param languageXliffFilePath
- */
- XliffMerge.prototype.createUntranslatedXliff = function (lang, languageXliffFilePath) {
- // copy master ...
- file_util_1.FileUtil.copy(this.parameters.i18nFile(), languageXliffFilePath);
- // read copy and set target-language
- var languageSpecificMessagesFile = i_translation_messages_file_1.TranslationMessagesFileReader.fromFile(this.parameters.i18nFormat(), languageXliffFilePath, this.parameters.encoding());
- languageSpecificMessagesFile.setTargetLanguage(lang);
- // copy source to target
- var isDefaultLang = (lang == this.parameters.defaultLanguage());
- languageSpecificMessagesFile.forEachTransUnit(function (transUnit) {
- languageSpecificMessagesFile.useSourceAsTarget(transUnit, isDefaultLang);
- });
- // write it to file
- languageSpecificMessagesFile.save();
- this.commandOutput.info('created new file "%s" for target-language="%s"', languageXliffFilePath, lang);
- if (!isDefaultLang) {
- this.commandOutput.warn('please translate file "%s" to target-language="%s"', languageXliffFilePath, lang);
- }
- };
- /**
- * Merge all
- * @param lang
- * @param languageXliffFilePath
- */
- XliffMerge.prototype.mergeMasterTo = function (lang, languageXliffFilePath) {
- var _this = this;
- // read lang specific file
- var languageSpecificMessagesFile = i_translation_messages_file_1.TranslationMessagesFileReader.fromFile(this.parameters.i18nFormat(), languageXliffFilePath, this.parameters.encoding());
- var isDefaultLang = (lang == this.parameters.defaultLanguage());
- var newCount = 0;
- this.master.forEachTransUnit(function (masterTransUnit) {
- var transUnit = languageSpecificMessagesFile.transUnitWithId(masterTransUnit.id);
- if (!transUnit) {
- // oops, no translation, must be a new key, so add it
- languageSpecificMessagesFile.useSourceAsTarget(masterTransUnit, isDefaultLang);
- languageSpecificMessagesFile.addNewTransUnit(masterTransUnit);
- newCount++;
- }
- });
- if (newCount > 0) {
- this.commandOutput.warn('merged %s trans-units from master to "%s"', newCount, lang);
- }
- // remove all elements that are no longer used
- var removeCount = 0;
- languageSpecificMessagesFile.forEachTransUnit(function (transUnit) {
- var existsInMaster = !util_1.isNullOrUndefined(_this.master.transUnitWithId(transUnit.id));
- if (!existsInMaster) {
- if (_this.parameters.removeUnusedIds()) {
- languageSpecificMessagesFile.removeTransUnitWithId(transUnit.id);
- }
- removeCount++;
- }
- });
- if (removeCount > 0) {
- if (this.parameters.removeUnusedIds()) {
- this.commandOutput.warn('removed %s unused trans-units in "%s"', removeCount, lang);
- }
- else {
- this.commandOutput.warn('keeping %s unused trans-units in "%s", because removeUnused is disabled', removeCount, lang);
- }
- }
- if (newCount == 0 && removeCount == 0) {
- this.commandOutput.info('file for "%s" was up to date', lang);
- }
- else {
- // write it to file
- languageSpecificMessagesFile.save();
- this.commandOutput.info('updated file "%s" for target-language="%s"', languageXliffFilePath, lang);
- if (newCount > 0 && !isDefaultLang) {
- this.commandOutput.warn('please translate file "%s" to target-language="%s"', languageXliffFilePath, lang);
- }
- }
- };
- return XliffMerge;
-}());
-exports.XliffMerge = XliffMerge;
diff --git a/src/xliffmerge/xliff-merge.spec.js b/src/xliffmerge/xliff-merge.spec.js
deleted file mode 100644
index 22f35bc..0000000
--- a/src/xliffmerge/xliff-merge.spec.js
+++ /dev/null
@@ -1,430 +0,0 @@
-"use strict";
-var fs = require("fs");
-var xliff_merge_1 = require("./xliff-merge");
-var command_output_1 = require("../common/command-output");
-var writer_to_string_1 = require("../common/writer-to-string");
-var file_util_1 = require("../common/file-util");
-var xliff_file_1 = require("./xliff-file");
-var xmb_file_1 = require("./xmb-file");
-/**
- * Created by martin on 18.02.2017.
- * Testcases for XliffMerge.
- */
-describe('XliffMerge test spec', function () {
- var MASTER1FILE = 'ngExtractedMaster1.xlf';
- var MASTER2FILE = 'ngExtractedMaster2.xlf';
- var MASTER1XMBFILE = 'ngExtractedMaster1.xmb';
- var MASTER2XMBFILE = 'ngExtractedMaster2.xmb';
- var SRCDIR = 'test/testdata/i18n/';
- var MASTER1SRC = SRCDIR + MASTER1FILE;
- var MASTER2SRC = SRCDIR + MASTER2FILE;
- var MASTER1XMBSRC = SRCDIR + MASTER1XMBFILE;
- var MASTER2XMBSRC = SRCDIR + MASTER2XMBFILE;
- /**
- * Workdir, not in git.
- * Cleaned up for every test.
- * Tests, that work on files, copy everything they need into this directory.
- * @type {string}
- */
- var WORKDIR = 'test/work/';
- var MASTERFILE = 'messages.xlf';
- var MASTER = WORKDIR + MASTERFILE;
- var MASTERXMBFILE = 'messages.xmb';
- var MASTERXMB = WORKDIR + MASTERXMBFILE;
- describe('test the tooling used in the tests', function () {
- it('should write output to string (Test WriterToString)', function () {
- var ws = new writer_to_string_1.WriterToString();
- ws.write('test test test\n');
- ws.write('line 2');
- expect(ws.writtenData()).toContain('line 2');
- });
- });
- describe('command line and configuration checks', function () {
- it('should parse -v option', function () {
- var options = xliff_merge_1.XliffMerge.parseArgs(['node', 'xliffmerge', '-v']);
- expect(options.verbose).toBeTruthy();
- expect(options.quiet).toBeFalsy();
- });
- it('should parse -q option', function () {
- var options = xliff_merge_1.XliffMerge.parseArgs(['node', 'xliffmerge', '-q']);
- expect(options.quiet).toBeTruthy();
- expect(options.verbose).toBeFalsy();
- });
- it('should output an errror (no languages) when called with defaults', function (done) {
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var xliffMergeCmd = new xliff_merge_1.XliffMerge(commandOut, {});
- xliffMergeCmd.run();
- expect(ws.writtenData()).toContain('ERROR');
- expect(ws.writtenData()).toContain('no languages specified');
- done();
- });
- it('should output an errror (i18nfile) when called with defaults', function (done) {
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var xliffMergeCmd = new xliff_merge_1.XliffMerge(commandOut, { languages: ['de', 'en'] });
- xliffMergeCmd.run();
- expect(ws.writtenData()).toContain('ERROR');
- expect(ws.writtenData()).toContain('i18nFile');
- done();
- });
- it('should output an errror (could not read) when called with a non existing profile', function (done) {
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var xliffMergeCmd = new xliff_merge_1.XliffMerge(commandOut, { verbose: true, profilePath: 'lmaa' });
- xliffMergeCmd.run();
- expect(ws.writtenData()).toContain('ERROR');
- expect(ws.writtenData()).toContain('could not read profile');
- done();
- });
- it('should read test config file', function (done) {
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { profilePath: './test/testdata/xliffmergeconfig.json', verbose: true }, null);
- xliffMergeCmd.run();
- expect(ws.writtenData()).toContain('languages: de,en');
- done();
- });
- it('should output an errror (srcDir not readable) when called with a non existing srcDir', function (done) {
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var profileContent = {
- xliffmergeOptions: {
- srcDir: 'lmaa',
- }
- };
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { verbose: true }, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).toContain('ERROR');
- expect(ws.writtenData()).toContain('srcDir "lmaa" is not a directory');
- done();
- });
- it('should output an errror (genDir not existing) when called with a non existing genDir', function (done) {
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var profileContent = {
- xliffmergeOptions: {
- genDir: 'lmaa',
- }
- };
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { verbose: true }, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).toContain('ERROR');
- expect(ws.writtenData()).toContain('genDir "lmaa" is not a directory');
- done();
- });
- it('should output an errror (i18nFile is not readable) when called with a non existing master file', function (done) {
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var profileContent = {
- xliffmergeOptions: {
- srcDir: 'test/testdata',
- i18nFile: 'nonexistingmaster.xlf'
- }
- };
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, {}, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).toContain('ERROR');
- expect(ws.writtenData()).toContain('i18nFile "test/testdata/nonexistingmaster.xlf" is not readable');
- done();
- });
- it('should output an errror (language not valid) when called with an invalid language code', function (done) {
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var profileContent = {
- xliffmergeOptions: {
- defaultLanguage: 'de/ch',
- }
- };
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, {}, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).toContain('ERROR');
- expect(ws.writtenData()).toContain('language "de/ch" is not valid');
- done();
- });
- it('should output an errror (i18nFormat invalid) when called with an invalid i18n format', function (done) {
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var profileContent = {
- xliffmergeOptions: {
- i18nFormat: 'unknown',
- }
- };
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, {}, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).toContain('ERROR');
- expect(ws.writtenData()).toContain('i18nFormat "unknown" invalid');
- done();
- });
- it('should accept i18n format xlf', function (done) {
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var profileContent = {
- xliffmergeOptions: {
- i18nFormat: 'xlf',
- }
- };
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, {}, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).not.toContain('i18nFormat');
- done();
- });
- it('should accept i18n format xmb', function (done) {
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var profileContent = {
- xliffmergeOptions: {
- i18nFormat: 'xmb',
- }
- };
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, {}, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).not.toContain('i18nFormat');
- done();
- });
- it('should read languages from config file', function (done) {
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var profileContent = {
- xliffmergeOptions: {
- languages: ['de', 'en', 'fr'],
- }
- };
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { verbose: true }, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).toContain('languages: de,en,fr');
- done();
- });
- });
- describe('Merge process checks for format xlf', function () {
- var ID_TRANSLATED_SCHLIESSEN = "1ead0ad1063d0c9e005fe56c9529aef4c1ef9d21"; // an ID from ngExtractedMaster1.xlf
- var ID_REMOVED_STARTSEITE = "c536247d71822c272f8e9155f831e0efb5aa0d31"; // an ID that will be removed in master2
- var ID_REMOVED_SUCHEN = "d17aee1ddf9fe1c0afe8440e02ef5ab906a69699"; // another removed ID
- beforeEach(function () {
- if (!fs.existsSync(WORKDIR)) {
- fs.mkdirSync(WORKDIR);
- }
- // cleanup workdir
- file_util_1.FileUtil.deleteFolderContentRecursive(WORKDIR);
- });
- it('should fix source language, if the masters lang is not the default', function (done) {
- file_util_1.FileUtil.copy(MASTER1SRC, MASTER);
- var master = xliff_file_1.XliffFile.fromFile(MASTER);
- expect(master.sourceLanguage()).toBe('en'); // master is german, but ng-18n extracts it as en
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var profileContent = {
- xliffmergeOptions: {
- defaultLanguage: 'de',
- srcDir: WORKDIR,
- genDir: WORKDIR,
- i18nFile: MASTERFILE,
- }
- };
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de'] }, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).not.toContain('ERROR');
- expect(ws.writtenData()).toContain('master says to have source-language="en"');
- expect(ws.writtenData()).toContain('changed master source-language="en" to "de"');
- var newmaster = xliff_file_1.XliffFile.fromFile(MASTER);
- expect(newmaster.sourceLanguage()).toBe('de'); // master is german
- done();
- });
- it('should generate translated file for default language de from master', function (done) {
- file_util_1.FileUtil.copy(MASTER1SRC, MASTER);
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var profileContent = {
- xliffmergeOptions: {
- defaultLanguage: 'de',
- srcDir: WORKDIR,
- genDir: WORKDIR,
- i18nFile: MASTERFILE
- }
- };
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de'] }, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).not.toContain('ERROR');
- var langFile = xliff_file_1.XliffFile.fromFile(xliffMergeCmd.generatedI18nFile('de'));
- expect(langFile.sourceLanguage()).toBe('de');
- expect(langFile.targetLanguage()).toBe('de');
- langFile.forEachTransUnit(function (tu) {
- expect(tu.targetContent()).toBe(tu.sourceContent());
- expect(tu.targetState()).toBe('final');
- });
- done();
- });
- it('should generate translated file for all languages', function (done) {
- file_util_1.FileUtil.copy(MASTER1SRC, MASTER);
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var profileContent = {
- xliffmergeOptions: {
- defaultLanguage: 'de',
- srcDir: WORKDIR,
- genDir: WORKDIR,
- i18nFile: MASTERFILE
- }
- };
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de', 'en'] }, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).not.toContain('ERROR');
- var langFileGerman = xliff_file_1.XliffFile.fromFile(xliffMergeCmd.generatedI18nFile('de'));
- expect(langFileGerman.sourceLanguage()).toBe('de');
- expect(langFileGerman.targetLanguage()).toBe('de');
- langFileGerman.forEachTransUnit(function (tu) {
- expect(tu.targetContent()).toBe(tu.sourceContent());
- expect(tu.targetState()).toBe('final');
- });
- var langFileEnglish = xliff_file_1.XliffFile.fromFile(xliffMergeCmd.generatedI18nFile('en'));
- expect(langFileEnglish.sourceLanguage()).toBe('de');
- expect(langFileEnglish.targetLanguage()).toBe('en');
- langFileEnglish.forEachTransUnit(function (tu) {
- expect(tu.targetContent()).toBe(tu.sourceContent());
- expect(tu.targetState()).toBe('new');
- });
- done();
- });
- it('should merge translated file for all languages', function (done) {
- file_util_1.FileUtil.copy(MASTER1SRC, MASTER);
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var profileContent = {
- xliffmergeOptions: {
- defaultLanguage: 'de',
- srcDir: WORKDIR,
- genDir: WORKDIR,
- i18nFile: MASTERFILE
- }
- };
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de', 'en'] }, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).not.toContain('ERROR');
- // now translate some texts in the English version
- var langFileEnglish = xliff_file_1.XliffFile.fromFile(xliffMergeCmd.generatedI18nFile('en'));
- var tu = langFileEnglish.transUnitWithId(ID_TRANSLATED_SCHLIESSEN);
- expect(tu).toBeTruthy();
- langFileEnglish.translate(tu, 'Close');
- langFileEnglish.save();
- // next step, use another master
- file_util_1.FileUtil.copy(MASTER2SRC, MASTER);
- ws = new writer_to_string_1.WriterToString();
- commandOut = new command_output_1.CommandOutput(ws);
- xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de', 'en'] }, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).not.toContain('ERROR');
- expect(ws.writtenData()).toContain('merged 12 trans-units from master to "en"');
- expect(ws.writtenData()).toContain('removed 2 unused trans-units in "en"');
- // look, that the new file contains the old translation
- langFileEnglish = xliff_file_1.XliffFile.fromFile(xliffMergeCmd.generatedI18nFile('en'));
- expect(langFileEnglish.transUnitWithId(ID_TRANSLATED_SCHLIESSEN).targetContent()).toBe('Close');
- // look, that the removed IDs are really removed.
- expect(langFileEnglish.transUnitWithId(ID_REMOVED_STARTSEITE)).toBeFalsy();
- expect(langFileEnglish.transUnitWithId(ID_REMOVED_SUCHEN)).toBeFalsy();
- done();
- });
- });
- describe('Merge process checks for format xmb', function () {
- var ID_TRANSLATED_MYFIRST = "2047558209369508311"; // an ID from ngExtractedMaster1.xlf
- var ID_REMOVED_DESCRIPTION = "7499557905529977371"; // an ID that will be removed in master2
- var ID_REMOVED_DESCRIPTION2 = "3274258156935474372"; // another removed ID
- var ID_ADDED = "3274258156935474372"; // an ID that will be added in master2
- beforeEach(function () {
- if (!fs.existsSync(WORKDIR)) {
- fs.mkdirSync(WORKDIR);
- }
- // cleanup workdir
- file_util_1.FileUtil.deleteFolderContentRecursive(WORKDIR);
- });
- it('should generate translated file for default language de from xmb master', function (done) {
- file_util_1.FileUtil.copy(MASTER1XMBSRC, MASTERXMB);
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var profileContent = {
- xliffmergeOptions: {
- defaultLanguage: 'de',
- srcDir: WORKDIR,
- genDir: WORKDIR,
- i18nFile: MASTERXMBFILE,
- i18nFormat: 'xmb'
- }
- };
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de'] }, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).not.toContain('ERROR');
- var langFile = xmb_file_1.XmbFile.fromFile(xliffMergeCmd.generatedI18nFile('de'));
- expect(langFile.sourceLanguage()).toBeFalsy(); // not supported in xmb
- expect(langFile.targetLanguage()).toBeFalsy();
- langFile.forEachTransUnit(function (tu) {
- expect(tu.targetContent()).toBe(tu.sourceContent());
- expect(tu.targetState()).toBeFalsy();
- });
- done();
- });
- it('should generate translated file for all languages using format xmb', function (done) {
- file_util_1.FileUtil.copy(MASTER1XMBSRC, MASTERXMB);
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var profileContent = {
- xliffmergeOptions: {
- defaultLanguage: 'de',
- srcDir: WORKDIR,
- genDir: WORKDIR,
- i18nFile: MASTERXMBFILE,
- i18nFormat: 'xmb'
- }
- };
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de', 'en'] }, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).not.toContain('ERROR');
- var langFileGerman = xmb_file_1.XmbFile.fromFile(xliffMergeCmd.generatedI18nFile('de'));
- langFileGerman.forEachTransUnit(function (tu) {
- expect(tu.targetContent()).toBe(tu.sourceContent());
- });
- var langFileEnglish = xmb_file_1.XmbFile.fromFile(xliffMergeCmd.generatedI18nFile('en'));
- langFileEnglish.forEachTransUnit(function (tu) {
- expect(tu.targetContent()).toBe(tu.sourceContent());
- });
- done();
- });
- it('should merge translated file for all languages using format xmb', function (done) {
- file_util_1.FileUtil.copy(MASTER1XMBSRC, MASTERXMB);
- var ws = new writer_to_string_1.WriterToString();
- var commandOut = new command_output_1.CommandOutput(ws);
- var profileContent = {
- xliffmergeOptions: {
- defaultLanguage: 'de',
- srcDir: WORKDIR,
- genDir: WORKDIR,
- i18nFile: MASTERXMBFILE,
- i18nFormat: 'xmb'
- }
- };
- var xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de', 'en'] }, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).not.toContain('ERROR');
- // now translate some texts in the English version
- var langFileEnglish = xmb_file_1.XmbFile.fromFile(xliffMergeCmd.generatedI18nFile('en'));
- var tu = langFileEnglish.transUnitWithId(ID_TRANSLATED_MYFIRST);
- expect(tu).toBeTruthy();
- langFileEnglish.translate(tu, 'My first app');
- langFileEnglish.save();
- // next step, use another master
- file_util_1.FileUtil.copy(MASTER2XMBSRC, MASTER);
- ws = new writer_to_string_1.WriterToString();
- commandOut = new command_output_1.CommandOutput(ws);
- xliffMergeCmd = xliff_merge_1.XliffMerge.createFromOptions(commandOut, { languages: ['de', 'en'] }, profileContent);
- xliffMergeCmd.run();
- expect(ws.writtenData()).not.toContain('ERROR');
- expect(ws.writtenData()).toContain('merged 100 trans-units from master to "en"');
- expect(ws.writtenData()).toContain('removed 100 unused trans-units in "en"');
- // look, that the new file contains the old translation
- langFileEnglish = xliff_file_1.XliffFile.fromFile(xliffMergeCmd.generatedI18nFile('en'));
- expect(langFileEnglish.transUnitWithId(ID_TRANSLATED_MYFIRST).targetContent()).toBe('My first app');
- // look, that the removed IDs are really removed.
- expect(langFileEnglish.transUnitWithId(ID_REMOVED_DESCRIPTION)).toBeFalsy();
- expect(langFileEnglish.transUnitWithId(ID_REMOVED_DESCRIPTION2)).toBeFalsy();
- done();
- });
- });
-});
diff --git a/src/xliffmerge/xliff-merge.spec.ts b/src/xliffmerge/xliff-merge.spec.ts
index d8165d8..ac6bc87 100644
--- a/src/xliffmerge/xliff-merge.spec.ts
+++ b/src/xliffmerge/xliff-merge.spec.ts
@@ -1,16 +1,14 @@
-import fs = require("fs");
-import child_process = require("child_process");
+import * as fs from "fs";
+import * as child_process from "child_process";
import {XliffMerge} from './xliff-merge';
import {ProgramOptions, IConfigFile} from './i-xliff-merge-options';
import {CommandOutput} from '../common/command-output';
import WritableStream = NodeJS.WritableStream;
import {WriterToString} from '../common/writer-to-string';
import {FileUtil} from '../common/file-util';
-import {ITranslationMessagesFile} from './i-translation-messages-file';
-import {ITransUnit} from './i-trans-unit';
-import {XliffFile} from './xliff-file';
-import {XmbFile} from './xmb-file';
+import {TranslationMessagesFileFactory, ITranslationMessagesFile, ITransUnit} from 'ngx-i18nsupport-lib';
import {TranslationMessagesFileReader} from './translation-messages-file-reader';
+
/**
* Created by martin on 18.02.2017.
* Testcases for XliffMerge.
@@ -33,16 +31,24 @@ describe('XliffMerge test spec', () => {
* Helper function to read Xliff from File
* @type {string}
*/
- function readXliff(path: string): XliffFile {
- return TranslationMessagesFileReader.fromFile('xlf', path, ENCODING);
+ function readXliff(path: string): ITranslationMessagesFile {
+ return TranslationMessagesFileReader.fromFile('xlf', path, ENCODING);
}
/**
* Helper function to read Xmb from File
* @type {string}
*/
- function readXmb(path: string): XmbFile {
- return TranslationMessagesFileReader.fromFile('xmb', path, ENCODING);
+ function readXmb(path: string): ITranslationMessagesFile {
+ return TranslationMessagesFileReader.fromFile('xmb', path, ENCODING);
+ }
+
+ /**
+ * Helper function to read Xmb from 2 Files, the xmb and the master
+ * @type {string}
+ */
+ function readXmbWithMaster(path: string, masterPath: string): ITranslationMessagesFile {
+ return TranslationMessagesFileReader.fromFile('xmb', path, ENCODING, masterPath);
}
describe('test the tooling used in the tests', () => {
@@ -269,7 +275,7 @@ describe('XliffMerge test spec', () => {
it('should fix source language, if the masters lang is not the default', (done) => {
FileUtil.copy(MASTER1SRC, MASTER);
- let master: XliffFile = readXliff(MASTER);
+ let master: ITranslationMessagesFile = readXliff(MASTER);
expect(master.sourceLanguage()).toBe('en'); // master is german, but ng-18n extracts it as en
let ws: WriterToString = new WriterToString();
let commandOut = new CommandOutput(ws);
@@ -286,7 +292,7 @@ describe('XliffMerge test spec', () => {
expect(ws.writtenData()).not.toContain('ERROR');
expect(ws.writtenData()).toContain('master says to have source-language="en"');
expect(ws.writtenData()).toContain('changed master source-language="en" to "de"');
- let newmaster: XliffFile = readXliff(MASTER);
+ let newmaster: ITranslationMessagesFile = readXliff(MASTER);
expect(newmaster.sourceLanguage()).toBe('de'); // master is german
done();
});
@@ -307,7 +313,7 @@ describe('XliffMerge test spec', () => {
let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de']}, profileContent);
xliffMergeCmd.run();
expect(ws.writtenData()).not.toContain('ERROR');
- let langFile: XliffFile = readXliff(xliffMergeCmd.generatedI18nFile('de'));
+ let langFile: ITranslationMessagesFile = readXliff(xliffMergeCmd.generatedI18nFile('de'));
expect(langFile.sourceLanguage()).toBe('de');
expect(langFile.targetLanguage()).toBe('de');
langFile.forEachTransUnit((tu: ITransUnit) => {
@@ -332,14 +338,14 @@ describe('XliffMerge test spec', () => {
let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de', 'en']}, profileContent);
xliffMergeCmd.run();
expect(ws.writtenData()).not.toContain('ERROR');
- let langFileGerman: XliffFile = readXliff(xliffMergeCmd.generatedI18nFile('de'));
+ let langFileGerman: ITranslationMessagesFile = readXliff(xliffMergeCmd.generatedI18nFile('de'));
expect(langFileGerman.sourceLanguage()).toBe('de');
expect(langFileGerman.targetLanguage()).toBe('de');
langFileGerman.forEachTransUnit((tu: ITransUnit) => {
expect(tu.targetContent()).toBe(tu.sourceContent());
expect(tu.targetState()).toBe('final');
});
- let langFileEnglish: XliffFile = readXliff(xliffMergeCmd.generatedI18nFile('en'));
+ let langFileEnglish: ITranslationMessagesFile = readXliff(xliffMergeCmd.generatedI18nFile('en'));
expect(langFileEnglish.sourceLanguage()).toBe('de');
expect(langFileEnglish.targetLanguage()).toBe('en');
langFileEnglish.forEachTransUnit((tu: ITransUnit) => {
@@ -365,14 +371,14 @@ describe('XliffMerge test spec', () => {
let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de', 'en']}, profileContent);
xliffMergeCmd.run();
expect(ws.writtenData()).not.toContain('ERROR');
- let langFileGerman: XliffFile = readXliff(xliffMergeCmd.generatedI18nFile('de'));
+ let langFileGerman: ITranslationMessagesFile = readXliff(xliffMergeCmd.generatedI18nFile('de'));
expect(langFileGerman.sourceLanguage()).toBe('de');
expect(langFileGerman.targetLanguage()).toBe('de');
langFileGerman.forEachTransUnit((tu: ITransUnit) => {
expect(tu.targetContent()).toBe(tu.sourceContent());
expect(tu.targetState()).toBe('final');
});
- let langFileEnglish: XliffFile = readXliff(xliffMergeCmd.generatedI18nFile('en'));
+ let langFileEnglish: ITranslationMessagesFile = readXliff(xliffMergeCmd.generatedI18nFile('en'));
expect(langFileEnglish.sourceLanguage()).toBe('de');
expect(langFileEnglish.targetLanguage()).toBe('en');
langFileEnglish.forEachTransUnit((tu: ITransUnit) => {
@@ -399,7 +405,7 @@ describe('XliffMerge test spec', () => {
expect(ws.writtenData()).not.toContain('ERROR');
// now translate some texts in the English version
- let langFileEnglish: XliffFile = readXliff(xliffMergeCmd.generatedI18nFile('en'));
+ let langFileEnglish: ITranslationMessagesFile = readXliff(xliffMergeCmd.generatedI18nFile('en'));
let tu: ITransUnit = langFileEnglish.transUnitWithId(ID_TRANSLATED_SCHLIESSEN);
expect(tu).toBeTruthy();
langFileEnglish.translate(tu, 'Close');
@@ -450,7 +456,7 @@ describe('XliffMerge test spec', () => {
// look, that the new file contains the translation
langFileEnglish = readXliff(xliffMergeCmd.generatedI18nFile('en'));
- expect(langFileEnglish.transUnitWithId(ID_WITH_PLACEHOLDER).targetContent()).toBe('Item of added.');
+ expect(langFileEnglish.transUnitWithId(ID_WITH_PLACEHOLDER).targetContent()).toBe('Item of added.');
done();
});
@@ -461,6 +467,7 @@ describe('XliffMerge test spec', () => {
let MASTER1FILE = 'ngxtranslate.xlf';
let MASTER1SRC = SRCDIR + MASTER1FILE;
+ let MASTER_WITHOUT_NGX_TRANSLATE_STUFF = SRCDIR + 'ngExtractedMaster1.xlf';
let MASTERFILE = 'messages.xlf';
let MASTER = WORKDIR + MASTERFILE;
@@ -477,7 +484,7 @@ describe('XliffMerge test spec', () => {
it('should return null for unset description and meaning in master xlf file', (done) => {
FileUtil.copy(MASTER1SRC, MASTER);
- let master: XliffFile = readXliff(MASTER);
+ let master: ITranslationMessagesFile = readXliff(MASTER);
expect(master.transUnitWithId(ID_NODESC_NOMEANING).description()).toBeFalsy();
expect(master.transUnitWithId(ID_NODESC_NOMEANING).meaning()).toBeFalsy();
done();
@@ -485,7 +492,7 @@ describe('XliffMerge test spec', () => {
it('should find description and meaning in master xlf file', (done) => {
FileUtil.copy(MASTER1SRC, MASTER);
- let master: XliffFile = readXliff(MASTER);
+ let master: ITranslationMessagesFile = readXliff(MASTER);
expect(master.transUnitWithId(ID_MONDAY).description()).toBe('ngx-translate');
expect(master.transUnitWithId(ID_MONDAY).meaning()).toBe('dateservice.monday');
done();
@@ -506,7 +513,7 @@ describe('XliffMerge test spec', () => {
let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de']}, profileContent);
xliffMergeCmd.run();
expect(ws.writtenData()).not.toContain('ERROR');
- let langFile: XliffFile = readXliff(xliffMergeCmd.generatedI18nFile('de'));
+ let langFile: ITranslationMessagesFile = readXliff(xliffMergeCmd.generatedI18nFile('de'));
expect(langFile.transUnitWithId(ID_MONDAY).description()).toBe('ngx-translate');
expect(langFile.transUnitWithId(ID_MONDAY).meaning()).toBe('dateservice.monday');
done();
@@ -536,6 +543,7 @@ describe('XliffMerge test spec', () => {
expect(translation.myapp).toBeTruthy();
expect(translation.dateservice.monday).toBe("Montag");
expect(translation.dateservice.friday).toBe("Freitag");
+ expect(translation.explicitlysetids.test1).toBe("Explizit gesetzte ID");
done();
});
@@ -595,6 +603,27 @@ describe('XliffMerge test spec', () => {
done();
});
+ it('should not write empty translation json file for ngx-translate, if there are no translation (issue #18)', (done) => {
+ FileUtil.copy(MASTER_WITHOUT_NGX_TRANSLATE_STUFF, MASTER);
+ let ws: WriterToString = new WriterToString();
+ let commandOut = new CommandOutput(ws);
+ let profileContent: IConfigFile = {
+ xliffmergeOptions: {
+ defaultLanguage: 'de',
+ srcDir: WORKDIR,
+ genDir: WORKDIR,
+ i18nFile: MASTERFILE,
+ supportNgxTranslate: true
+ }
+ };
+ let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de']}, profileContent);
+ xliffMergeCmd.run();
+ expect(ws.writtenData()).not.toContain('ERROR');
+ let translationJsonFilename = xliffMergeCmd.generatedNgxTranslateFile('de');
+ expect(FileUtil.exists(translationJsonFilename)).toBeFalsy();
+ done();
+ });
+
});
describe('Merge process checks for format xmb', () => {
@@ -637,8 +666,8 @@ describe('XliffMerge test spec', () => {
xliffMergeCmd.run();
expect(ws.writtenData()).not.toContain('ERROR');
let langFile: ITranslationMessagesFile = readXmb(xliffMergeCmd.generatedI18nFile('de'));
- expect(langFile.sourceLanguage()).toBeFalsy(); // not supported in xmb
- expect(langFile.targetLanguage()).toBeFalsy();
+ expect(langFile.sourceLanguage()).toBeFalsy(); // not supported in xmb when there is no master
+ expect(langFile.targetLanguage()).toBe('de'); // guess from filename
langFile.forEachTransUnit((tu: ITransUnit) => {
expect(tu.targetContent()).toBe(tu.sourceContent());
expect(tu.targetState()).toBeFalsy();
@@ -704,7 +733,7 @@ describe('XliffMerge test spec', () => {
xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de', 'en']}, profileContent);
xliffMergeCmd.run();
expect(ws.writtenData()).not.toContain('ERROR');
- expect(ws.writtenData()).toContain('merged 2 trans-units from master to "en"');
+ expect(ws.writtenData()).toContain('merged 1 trans-units from master to "en"');
expect(ws.writtenData()).toContain('removed 2 unused trans-units in "en"');
// look, that the new file contains the old translation
@@ -751,12 +780,63 @@ describe('XliffMerge test spec', () => {
done();
});
+ it('should return status new for all trans units using format xmb with master file', (done) => {
+ FileUtil.copy(MASTER1SRC, MASTER);
+ let ws: WriterToString = new WriterToString();
+ let commandOut = new CommandOutput(ws);
+ let profileContent: IConfigFile = {
+ xliffmergeOptions: {
+ defaultLanguage: 'de',
+ srcDir: WORKDIR,
+ genDir: WORKDIR,
+ i18nFile: MASTERFILE,
+ i18nFormat: 'xmb'
+ }
+ };
+ let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de', 'en']}, profileContent);
+ xliffMergeCmd.run();
+ expect(ws.writtenData()).not.toContain('ERROR');
+ let langFileEnglish: ITranslationMessagesFile = readXmbWithMaster(xliffMergeCmd.generatedI18nFile('en'), MASTER);
+ langFileEnglish.forEachTransUnit((tu: ITransUnit) => {
+ expect(tu.targetState()).toBe('new');
+ });
+ done();
+ });
+
+ it('should return status final for a translated trans unit using format xmb with master file', (done) => {
+ FileUtil.copy(MASTER1SRC, MASTER);
+ let ws: WriterToString = new WriterToString();
+ let commandOut = new CommandOutput(ws);
+ let profileContent: IConfigFile = {
+ xliffmergeOptions: {
+ defaultLanguage: 'de',
+ srcDir: WORKDIR,
+ genDir: WORKDIR,
+ i18nFile: MASTERFILE,
+ i18nFormat: 'xmb'
+ }
+ };
+ let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de', 'en']}, profileContent);
+ xliffMergeCmd.run();
+ expect(ws.writtenData()).not.toContain('ERROR');
+ let langFileEnglish: ITranslationMessagesFile = readXmbWithMaster(xliffMergeCmd.generatedI18nFile('en'), MASTER);
+ // now translate some texts in the English version
+ let tu: ITransUnit = langFileEnglish.transUnitWithId(ID_TRANSLATED_MYFIRST);
+ expect(tu).toBeTruthy();
+ expect(tu.sourceContent()).toBe('Meine erste I18N-Anwendung');
+ expect(tu.targetState()).toBe('new');
+ langFileEnglish.translate(tu, 'my first i18n application');
+ expect(tu.targetState()).toBe('final');
+ done();
+ });
+
});
describe('ngx-translate processing for format xmb', () => {
let MASTER1FILE = 'ngxtranslate.xmb';
let MASTER1SRC = SRCDIR + MASTER1FILE;
+ let MASTER_WITHOUT_NGX_TRANSLATE_STUFF = SRCDIR + 'ngExtractedMaster1.xmb';
let MASTERFILE = 'messages.xmb';
let MASTER = WORKDIR + MASTERFILE;
@@ -773,7 +853,7 @@ describe('XliffMerge test spec', () => {
it('should return null for unset description and meaning in master xmb file', (done) => {
FileUtil.copy(MASTER1SRC, MASTER);
- let master: XmbFile = readXmb(MASTER);
+ let master: ITranslationMessagesFile = readXmb(MASTER);
expect(master.transUnitWithId(ID_NODESC_NOMEANING).description()).toBeFalsy();
expect(master.transUnitWithId(ID_NODESC_NOMEANING).meaning()).toBeFalsy();
done();
@@ -781,7 +861,7 @@ describe('XliffMerge test spec', () => {
it('should find description and meaning in master xmb file', (done) => {
FileUtil.copy(MASTER1SRC, MASTER);
- let master: XmbFile = readXmb(MASTER);
+ let master: ITranslationMessagesFile = readXmb(MASTER);
expect(master.transUnitWithId(ID_MONDAY).description()).toBe('ngx-translate');
expect(master.transUnitWithId(ID_MONDAY).meaning()).toBe('dateservice.monday');
done();
@@ -803,7 +883,7 @@ describe('XliffMerge test spec', () => {
let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de']}, profileContent);
xliffMergeCmd.run();
expect(ws.writtenData()).not.toContain('ERROR');
- let langFile: XmbFile = readXmb(xliffMergeCmd.generatedI18nFile('de'));
+ let langFile: ITranslationMessagesFile = readXmb(xliffMergeCmd.generatedI18nFile('de'));
expect(langFile.transUnitWithId(ID_MONDAY).description()).toBe('ngx-translate');
expect(langFile.transUnitWithId(ID_MONDAY).meaning()).toBe('dateservice.monday');
done();
@@ -834,6 +914,8 @@ describe('XliffMerge test spec', () => {
expect(translation.myapp).toBeTruthy();
expect(translation.dateservice.monday).toBe("Montag");
expect(translation.dateservice.friday).toBe("Freitag");
+ expect(translation.explicitlysetids.test1).toBe("Explizit gesetzte ID");
+ expect(Object.keys(translation).length).toBe(5);
done();
});
@@ -895,5 +977,27 @@ describe('XliffMerge test spec', () => {
done();
});
+ it('should not write empty translation json file for ngx-translate, if there are no translation (issue #18)', (done) => {
+ FileUtil.copy(MASTER_WITHOUT_NGX_TRANSLATE_STUFF, MASTER);
+ let ws: WriterToString = new WriterToString();
+ let commandOut = new CommandOutput(ws);
+ let profileContent: IConfigFile = {
+ xliffmergeOptions: {
+ defaultLanguage: 'de',
+ srcDir: WORKDIR,
+ genDir: WORKDIR,
+ i18nFile: MASTERFILE,
+ i18nFormat: 'xmb',
+ supportNgxTranslate: true
+ }
+ };
+ let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de']}, profileContent);
+ xliffMergeCmd.run();
+ expect(ws.writtenData()).not.toContain('ERROR');
+ let translationJsonFilename = xliffMergeCmd.generatedNgxTranslateFile('de');
+ expect(FileUtil.exists(translationJsonFilename)).toBeFalsy();
+ done();
+ });
+
});
});
diff --git a/src/xliffmerge/xliff-merge.ts b/src/xliffmerge/xliff-merge.ts
index 2555b1d..834d2ed 100644
--- a/src/xliffmerge/xliff-merge.ts
+++ b/src/xliffmerge/xliff-merge.ts
@@ -6,10 +6,9 @@ import {FileUtil} from '../common/file-util';
import {VERSION} from './version';
import WritableStream = NodeJS.WritableStream;
import {isNullOrUndefined} from 'util';
-import {ITranslationMessagesFile} from './i-translation-messages-file';
+import {ITranslationMessagesFile, ITransUnit} from 'ngx-i18nsupport-lib';
import {ProgramOptions, IConfigFile} from './i-xliff-merge-options';
import {NgxTranslateExtractor} from './ngx-translate-extractor';
-import {ITransUnit} from './i-trans-unit';
import {TranslationMessagesFileReader} from './translation-messages-file-reader';
/**
diff --git a/src/xliffmerge/xmb-file.js b/src/xliffmerge/xmb-file.js
deleted file mode 100644
index 653b58f..0000000
--- a/src/xliffmerge/xmb-file.js
+++ /dev/null
@@ -1,211 +0,0 @@
-"use strict";
-var xml_reader_1 = require("./xml-reader");
-var util_1 = require("util");
-var file_util_1 = require("../common/file-util");
-/**
- * Created by martin on 10.03.2017.
- * xmb-File access.
- */
-/**
- * Read-Options for cheerio, enable xml mode.
- * @type {{xmlMode: boolean}}
- */
-var CheerioOptions = {
- xmlMode: true,
- decodeEntities: false,
-};
-var TransUnit = (function () {
- function TransUnit(_msg, _id) {
- this._msg = _msg;
- this._id = _id;
- }
- Object.defineProperty(TransUnit.prototype, "_transUnitElement", {
- get: function () {
- return this._msg;
- },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(TransUnit.prototype, "id", {
- get: function () {
- return this._id;
- },
- enumerable: true,
- configurable: true
- });
- TransUnit.prototype.sourceContent = function () {
- return cheerio(this._msg).html();
- };
- TransUnit.prototype.targetContent = function () {
- // in fact, target and source are just the same in xmb
- return cheerio(this._msg).html();
- };
- TransUnit.prototype.targetState = function () {
- return null; // not supported in xmb
- };
- /**
- * the real xml element used for trans unit.
- * Here it is a element.
- * @return {CheerioElement}
- */
- TransUnit.prototype.asXmlElement = function () {
- return this._msg;
- };
- /**
- * Copy source to target to use it as dummy translation.
- * (better than missing value)
- * In xmb there is nothing to do, because there is only a target, no source.
- */
- TransUnit.prototype.useSourceAsTarget = function (isDefaultLang) {
- };
- /**
- * Translate trans unit.
- * (very simple, just for tests)
- * @param translation the translated string
- */
- TransUnit.prototype.translate = function (translation) {
- var target = cheerio(this._msg);
- target.html(translation);
- };
- return TransUnit;
-}());
-var XmbFile = (function () {
- function XmbFile() {
- this._warnings = [];
- this._numberOfTransUnitsWithMissingId = 0;
- }
- /**
- * Read an xmb-File.
- * @param path Path to file
- * @param encoding optional encoding of the xml.
- * This is read from the file, but if you know it before, you can avoid reading the file twice.
- * @return {XmbFile}
- */
- XmbFile.fromFile = function (path, encoding) {
- var xmb = new XmbFile();
- var xmlContent = xml_reader_1.XmlReader.readXmlFileContent(path, encoding);
- xmb.initializeFromContent(xmlContent.content, path, xmlContent.encoding);
- return xmb;
- };
- XmbFile.prototype.initializeFromContent = function (xmlString, path, encoding) {
- this.filename = path;
- this.encoding = encoding;
- this.xmbContent = cheerio.load(xmlString, CheerioOptions);
- return this;
- };
- XmbFile.prototype.initializeTransUnits = function () {
- var _this = this;
- if (util_1.isNullOrUndefined(this.transUnits)) {
- this.transUnits = [];
- var transUnitsInFile = this.xmbContent('msg');
- transUnitsInFile.each(function (index, msg) {
- var id = cheerio(msg).attr('id');
- if (!id) {
- _this._warnings.push(util_1.format('oops, msg without "id" found in master, please check file %s', _this.filename));
- _this._numberOfTransUnitsWithMissingId++;
- }
- _this.transUnits.push(new TransUnit(msg, id));
- });
- }
- };
- XmbFile.prototype.forEachTransUnit = function (callback) {
- this.initializeTransUnits();
- this.transUnits.forEach(function (tu) { return callback(tu); });
- };
- /**
- * Get trans-unit with given id.
- * @param id
- * @return {Cheerio}
- */
- XmbFile.prototype.transUnitWithId = function (id) {
- this.initializeTransUnits();
- return this.transUnits.find(function (tu) { return tu.id == id; });
- };
- XmbFile.prototype.warnings = function () {
- this.initializeTransUnits();
- return this._warnings;
- };
- XmbFile.prototype.numberOfTransUnits = function () {
- this.initializeTransUnits();
- return this.transUnits.length;
- };
- XmbFile.prototype.numberOfTransUnitsWithMissingId = function () {
- this.initializeTransUnits();
- return this._numberOfTransUnitsWithMissingId;
- };
- /**
- * Get source language.
- * Unsupported in xmb.
- * @return {string}
- */
- XmbFile.prototype.sourceLanguage = function () {
- return null;
- };
- /**
- * Edit the source language.
- * Unsupported in xmb.
- * @param language
- */
- XmbFile.prototype.setSourceLanguage = function (language) {
- // do nothing, xmb has no notation for this.
- };
- /**
- * Get target language.
- * Unsupported in xmb.
- * @return {string}
- */
- XmbFile.prototype.targetLanguage = function () {
- return null;
- };
- /**
- * Edit the target language.
- * Unsupported in xmb.
- * @param language
- */
- XmbFile.prototype.setTargetLanguage = function (language) {
- // do nothing, xmb has no notation for this.
- };
- /**
- * Copy source to target to use it as dummy translation.
- * (better than missing value)
- * In xmb there is nothing to do, because there is only a target, no source.
- */
- XmbFile.prototype.useSourceAsTarget = function (transUnit, isDefaultLang) {
- transUnit.useSourceAsTarget(isDefaultLang);
- };
- /**
- * Translate a given trans unit.
- * (very simple, just for tests)
- * @param transUnit
- * @param translation the translated string
- */
- XmbFile.prototype.translate = function (transUnit, translation) {
- transUnit.translate(translation);
- };
- /**
- * Add a new trans-unit.
- * @param transUnit
- */
- XmbFile.prototype.addNewTransUnit = function (transUnit) {
- this.xmbContent('messagebundle').append(cheerio(transUnit.asXmlElement()));
- this.initializeTransUnits();
- this.transUnits.push(transUnit);
- };
- /**
- * Remove the trans-unit with the given id.
- * @param id
- */
- XmbFile.prototype.removeTransUnitWithId = function (id) {
- this.xmbContent('#' + id).remove();
- this.initializeTransUnits();
- this.transUnits = this.transUnits.filter(function (tu) { return tu.id != id; });
- };
- /**
- * Save edited content to file.
- */
- XmbFile.prototype.save = function () {
- file_util_1.FileUtil.replaceContent(this.filename, this.xmbContent.xml(), this.encoding);
- };
- return XmbFile;
-}());
-exports.XmbFile = XmbFile;
diff --git a/src/xliffmerge/xmb-file.ts b/src/xliffmerge/xmb-file.ts
deleted file mode 100644
index ec3099f..0000000
--- a/src/xliffmerge/xmb-file.ts
+++ /dev/null
@@ -1,299 +0,0 @@
-import * as cheerio from "cheerio";
-import {ITranslationMessagesFile} from './i-translation-messages-file';
-import {isNullOrUndefined, format} from 'util';
-import {ITransUnit} from './i-trans-unit';
-/**
- * Created by martin on 10.03.2017.
- * xmb-File access.
- */
-
-/**
- * Read-Options for cheerio, enable xml mode.
- * @type {{xmlMode: boolean}}
- */
-const CheerioOptions: CheerioOptionsInterface = {
- xmlMode: true,
- decodeEntities: false,
-};
-
-class TransUnit implements ITransUnit {
-
- constructor(private _msg: CheerioElement, private _id: string) {
-
- }
-
- public get id(): string {
- return this._id;
- }
-
- public sourceContent(): string {
- return cheerio(this._msg).html();
- }
-
- /**
- * the translated value (containing all markup, depends on the concrete format used).
- */
- public targetContent(): string {
- // in fact, target and source are just the same in xmb
- return cheerio(this._msg).html();
- }
-
- /**
- * the translated value, but all placeholders are replaced with {{n}} (starting at 0)
- * and all embedded html is replaced by direct html markup.
- */
- targetContentNormalized(): string {
- let directHtml = this.targetContent();
- if (!directHtml) {
- return directHtml;
- }
- let normalized = directHtml;
- let re0: RegExp = /INTERPOLATION<\/ex><\/ph>/g;
- normalized = normalized.replace(re0, '{{0}}');
- let reN: RegExp = /INTERPOLATION_(\d*)<\/ex><\/ph>/g;
- normalized = normalized.replace(reN, '{{$1}}');
-
- let reStartAnyTag: RegExp = /<(\w*)><\/ex><\/ph>/g;
- normalized = normalized.replace(reStartAnyTag, '<$1>');
- let reCloseAnyTag: RegExp = /<\/(\w*)><\/ex><\/ph>/g;
- normalized = normalized.replace(reCloseAnyTag, '$1>');
-
- return normalized;
- }
-
- /**
- * State of the translation.
- * (not supported in xmb)
- */
- public targetState(): string {
- return null; // not supported in xmb
- }
-
- /**
- * The description set in the template as value of the i18n-attribute.
- * e.g. i18n="mydescription".
- * In xmb this is stored in the attribute "desc".
- */
- public description(): string {
- return cheerio(this._msg).attr('desc');
- }
-
- /**
- * The meaning (intent) set in the template as value of the i18n-attribute.
- * This is the part in front of the | symbol.
- * e.g. i18n="meaning|mydescription".
- * In xmb this is stored in the attribute "meaning".
- */
- public meaning(): string {
- return cheerio(this._msg).attr('meaning');
- }
-
- /**
- * the real xml element used for trans unit.
- * Here it is a element.
- * @return {CheerioElement}
- */
- public asXmlElement(): CheerioElement {
- return this._msg;
- }
-
- /**
- * Copy source to target to use it as dummy translation.
- * (better than missing value)
- * In xmb there is nothing to do, because there is only a target, no source.
- */
- public useSourceAsTarget(isDefaultLang: boolean, copyContent: boolean) {
- }
-
- /**
- * Translate trans unit.
- * (very simple, just for tests)
- * @param translation the translated string
- */
- public translate(translation: string) {
- let target = cheerio(this._msg);
- target.html(translation);
- }
-
-}
-
-export class XmbFile implements ITranslationMessagesFile {
-
- private _filename: string;
-
- private _encoding: string;
-
- private xmbContent: CheerioStatic;
-
- // trans-unit elements and their id from the file
- private transUnits: ITransUnit[];
-
- private _warnings: string[];
- private _numberOfTransUnitsWithMissingId: number;
-
- /**
- * Create an xmb-File from source.
- * @param xmlString file content
- * @param path Path to file
- * @param encoding optional encoding of the xml.
- * This is read from the file, but if you know it before, you can avoid reading the file twice.
- * @return {XmbFile}
- */
- constructor(xmlString: string, path: string, encoding: string) {
- this._warnings = [];
- this._numberOfTransUnitsWithMissingId = 0;
- this.initializeFromContent(xmlString, path, encoding);
- }
-
- private initializeFromContent(xmlString: string, path: string, encoding: string): XmbFile {
- this._filename = path;
- this._encoding = encoding;
- this.xmbContent = cheerio.load(xmlString, CheerioOptions);
- if (this.xmbContent('messagebundle').length != 1) {
- throw new Error(format('File "%s" seems to be no xmb file (should contain a messagebundle element)', path));
- }
- return this;
- }
-
- private initializeTransUnits() {
- if (isNullOrUndefined(this.transUnits)) {
- this.transUnits = [];
- let transUnitsInFile = this.xmbContent('msg');
- transUnitsInFile.each((index, msg: CheerioElement) => {
- let id = cheerio(msg).attr('id');
- if (!id) {
- this._warnings.push(format('oops, msg without "id" found in master, please check file %s', this.filename));
- this._numberOfTransUnitsWithMissingId++;
- }
- this.transUnits.push(new TransUnit(msg, id));
- });
- }
- }
-
- public forEachTransUnit(callback: ((transunit: ITransUnit) => void)) {
- this.initializeTransUnits();
- this.transUnits.forEach((tu) => callback(tu));
- }
-
- /**
- * Get trans-unit with given id.
- * @param id
- * @return {Cheerio}
- */
- public transUnitWithId(id: string): ITransUnit {
- this.initializeTransUnits();
- return this.transUnits.find((tu) => tu.id == id);
- }
-
- public warnings(): string[] {
- this.initializeTransUnits();
- return this._warnings;
- }
-
- public numberOfTransUnits(): number {
- this.initializeTransUnits();
- return this.transUnits.length;
- }
-
- public numberOfTransUnitsWithMissingId(): number {
- this.initializeTransUnits();
- return this._numberOfTransUnitsWithMissingId;
- }
-
- /**
- * Get source language.
- * Unsupported in xmb.
- * @return {string}
- */
- public sourceLanguage(): string {
- return null;
- }
-
- /**
- * Edit the source language.
- * Unsupported in xmb.
- * @param language
- */
- public setSourceLanguage(language: string) {
- // do nothing, xmb has no notation for this.
- }
-
- /**
- * Get target language.
- * Unsupported in xmb.
- * @return {string}
- */
- public targetLanguage(): string {
- return null;
- }
-
- /**
- * Edit the target language.
- * Unsupported in xmb.
- * @param language
- */
- public setTargetLanguage(language: string) {
- // do nothing, xmb has no notation for this.
- }
-
- /**
- * Copy source to target to use it as dummy translation.
- * (better than missing value)
- * In xmb there is nothing to do, because there is only a target, no source.
- */
- public useSourceAsTarget(transUnit: ITransUnit, isDefaultLang: boolean, copyContent: boolean) {
- transUnit.useSourceAsTarget(isDefaultLang, copyContent);
- }
-
- /**
- * Translate a given trans unit.
- * (very simple, just for tests)
- * @param transUnit
- * @param translation the translated string
- */
- public translate(transUnit: ITransUnit, translation: string) {
- transUnit.translate(translation);
- }
-
- /**
- * Add a new trans-unit.
- * @param transUnit
- */
- public addNewTransUnit(transUnit: ITransUnit) {
- this.xmbContent('messagebundle').append(cheerio(transUnit.asXmlElement()));
- this.initializeTransUnits();
- this.transUnits.push(transUnit);
- }
-
- /**
- * Remove the trans-unit with the given id.
- * @param id
- */
- public removeTransUnitWithId(id: string) {
- this.xmbContent('#' + id).remove();
- this.initializeTransUnits();
- this.transUnits = this.transUnits.filter((tu) => tu.id != id);
- }
-
- /**
- * The filename where the data is read from.
- */
- public filename(): string {
- return this._filename;
- }
-
- /**
- * The encoding if the xml content (UTF-8, ISO-8859-1, ...)
- */
- public encoding(): string {
- return this._encoding;
- }
-
- /**
- * The xml to be saved after changes are made.
- */
- public editedContent(): string {
- return this.xmbContent.xml();
- }
-
-}
diff --git a/src/xliffmerge/xml-reader.js b/src/xliffmerge/xml-reader.js
deleted file mode 100644
index ff760c4..0000000
--- a/src/xliffmerge/xml-reader.js
+++ /dev/null
@@ -1,49 +0,0 @@
-"use strict";
-var file_util_1 = require("../common/file-util");
-/**
- * Created by martin on 10.03.2017.
- * Helper class to read XMl with a correct encoding.
- */
-var XmlReader = (function () {
- function XmlReader() {
- }
- /**
- * Read an xml-File.
- * @param path Path to file
- * @param encoding optional encoding of the xml.
- * This is read from the file, but if you know it before, you can avoid reading the file twice.
- * @return file content and encoding found in the file.
- */
- XmlReader.readXmlFileContent = function (path, encoding) {
- if (!encoding) {
- encoding = XmlReader.DEFAULT_ENCODING;
- }
- var content = file_util_1.FileUtil.read(path, encoding);
- var foundEncoding = XmlReader.encodingFromXml(content);
- if (foundEncoding != encoding) {
- // read again with the correct encoding
- content = file_util_1.FileUtil.read(path, foundEncoding);
- }
- return {
- content: content,
- encoding: foundEncoding
- };
- };
- /**
- * Read the encoding from the xml.
- * xml File starts with .. encoding=".."
- * @param xmlString
- * @return {any}
- */
- XmlReader.encodingFromXml = function (xmlString) {
- var index = xmlString.indexOf('encoding="');
- if (index < 0) {
- return this.DEFAULT_ENCODING; // default in xml if not explicitly set
- }
- var endIndex = xmlString.indexOf('"', index + 10); // 10 = length of 'encoding="'
- return xmlString.substring(index + 10, endIndex);
- };
- return XmlReader;
-}());
-XmlReader.DEFAULT_ENCODING = 'UTF-8';
-exports.XmlReader = XmlReader;
diff --git a/test/testdata/i18n/ngExtractedMaster1.xmb b/test/testdata/i18n/ngExtractedMaster1.xmb
index b95add2..67f2a10 100644
--- a/test/testdata/i18n/ngExtractedMaster1.xmb
+++ b/test/testdata/i18n/ngExtractedMaster1.xmb
@@ -21,10 +21,11 @@
]>
- Meine erste I18N-Anwendung
- Diese Anwendung ist eine reine Demonstration und hat keine wirklich nutzbare Funktion.
- Diese Anwendung ist eine reine Demonstration und hat keine wirklich nutzbare Funktion.
- Eintrag INTERPOLATION von INTERPOLATION_1 hinzugefügt.
- Dieser Text
+ S:/experimente/sampleapp41/src/app/app.component.ts:1Meine erste I18N-Anwendung
+ S:/experimente/sampleapp41/src/app/app.component.ts:2S:/experimente/sampleapp41/src/app/app.component.ts:3Anwendung läuft!
+ S:/experimente/sampleapp41/src/app/app.component.ts:4Diese Anwendung ist eine reine Demonstration und hat keine wirklich nutzbare Funktion.
+ S:/experimente/sampleapp41/src/app/app.component.ts:5Diese Anwendung ist eine reine Demonstration und hat keine wirklich nutzbare Funktion.
+ S:/experimente/sampleapp41/src/app/app.component.ts:6Eintrag INTERPOLATION von INTERPOLATION_1 hinzugefügt.
+ S:/experimente/sampleapp41/src/app/app.component.ts:7,8Dieser Text
enthält einen Zeilenumbruch.
diff --git a/test/testdata/i18n/ngExtractedMaster2.xmb b/test/testdata/i18n/ngExtractedMaster2.xmb
index d8c2171..9a94f95 100644
--- a/test/testdata/i18n/ngExtractedMaster2.xmb
+++ b/test/testdata/i18n/ngExtractedMaster2.xmb
@@ -21,11 +21,10 @@
]>
- Meine erste I18N-Anwendung
- Anwendung läuft!
- Eintrag INTERPOLATION von INTERPOLATION_1 hinzugefügt.
- Dieser Text
+ S:/experimente/sampleapp41/src/app/app.component.ts:1Meine erste I18N-Anwendung
+ S:/experimente/sampleapp41/src/app/app.component.ts:2S:/experimente/sampleapp41/src/app/app.component.ts:3Anwendung läuft!
+ S:/experimente/sampleapp41/src/app/app.component.ts:6Eintrag INTERPOLATION von INTERPOLATION_1 hinzugefügt.
+ S:/experimente/sampleapp41/src/app/app.component.ts:7,8Dieser Text
enthält einen Zeilenumbruch.
- Dieser Text enthält <b>eingebettetes html</b>
- Dieser Text enthält <b>eingebettetes html</b>
+ S:/experimente/sampleapp41/src/app/app.component.ts:9Dieser Text enthält <b>eingebettetes html</b>
diff --git a/test/testdata/i18n/ngxtranslate.xlf b/test/testdata/i18n/ngxtranslate.xlf
index 8935f53..1275a80 100644
--- a/test/testdata/i18n/ngxtranslate.xlf
+++ b/test/testdata/i18n/ngxtranslate.xlf
@@ -82,6 +82,14 @@
ngx-translate
embeddedhtml.strange
+
+ Explizit gesetzte ID
+ Explizit gesetzte ID
+
+ S:/experimente/sampleapp41/src/app/ngx-translate-test-data/ngx-translate-test-data.component.ts
+ 18
+
+