diff --git a/Changelog.md b/Changelog.md index a0408bc..0590cf2 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,4 +1,11 @@ - + +# [0.5.0](https://github.com/martinroob/ngx-i18nsupport/compare/v0.4.0...v0.5.0) (2017-05-05) + +### Features + +* **xliffmerge:** added XLIFF 2.0 support. ([#20](https://github.com/martinroob/ngx-i18nsupport/issues/20)) + + # [0.4.0](https://github.com/martinroob/ngx-i18nsupport/compare/v0.3.1...v0.4.0) (2017-05-03) ### Bug Fixes diff --git a/README.md b/README.md index fd3d01a..aa53e6f 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ It is described in the official documentation Angular Cookbook [Internationaliza Said in one sentence, * markup your strings to translate in your templates with an attribute `i18n` -* run the Amgular extraction tool (`ng-xi18n`) to extract the strings in an XML Format called [[XLIFF]]((http://docs.oasis-open.org/xliff/xliff-core/xliff-core.html)) +* run the Amgular extraction tool (`ng-xi18n`) to extract the strings in an XML Format called [[XLIFF-1.2]](http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html) * copy and then translate the extracted file for every language you plan to support * run the ng compiler to generate a special version of your app for the different languages @@ -104,8 +104,8 @@ The options are: - `srcDir` (string, default "."): directory, where the master file is expected - `genDir` (string, default "."): directory, where files are written to (normally identical with srcDir) - `i18nFile` (string, default "messages.xlf"): master file (relativ to srcDir) -- `i18nFormat` (string, default "xlf"): "xlf" for XLIFF or "xmb" for XML Message Bundles -- `encoding` (string, default "UTF-8"): expected encoding of xlf or xmb files +- `i18nFormat` (string, default "xlf"): `xlf` for XLIFF 1.2 or `xlf2` for XLIFF 2.0 or `xmb` for XML Message Bundles +- `encoding` (string, default "UTF-8"): expected encoding of xlf, xlf2 or xmb files - `defaultLanguage` (string, default "en"): the native language used in your templates - `languages` (array of strings): list of languages (if not spefified at command line) - `removeUnusedIds` (boolean, default `true`): flag, if unused IDs should be removed during merge @@ -201,7 +201,8 @@ But if you are interesting, send me an email, so that we can discuss it. * Phillippe Martin [Deploying an i18n Angular app with angular-cli](https://medium.com/@feloy/deploying-an-i18n-angular-app-with-angular-cli-fc788f17e358) * Roland Oldengarm: [Angular 2: Automated i18n workflow using gulp](http://rolandoldengarm.com/index.php/2016/10/17/angular-2-automated-i18n-workflow-using-gulp/) -* XLIFF Specification: [XLIFF Spec](http://docs.oasis-open.org/xliff/xliff-core/xliff-core.html) +* XLIFF 1.2 Specification: [XLIFF-1.2](http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html) +* XLIFF 2.0 Specification: [XLIFF-2.0](http://docs.oasis-open.org/xliff/xliff-core/v2.0/os/xliff-core-v2.0-os.html) * My Tiny Translator Tool: [TinyTranslator](https://github.com/martinroob/tiny-translator) [travis-badge]: https://travis-ci.org/martinroob/ngx-i18nsupport.svg?branch=master diff --git a/package.json b/package.json index 034c78c..b3d7c48 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ngx-i18nsupport", - "version": "0.4.0", + "version": "0.5.0", "description": "Some tooling to be used with the Angular 2 i18n workflow", "main": "index.js", "module": "./src", @@ -49,6 +49,6 @@ "dependencies": { "chalk": "^1.1.3", "commander": "^2.9.0", - "ngx-i18nsupport-lib": "^0.0.8" + "ngx-i18nsupport-lib": "^0.1.3" } } diff --git a/src/xliffmerge/xliff-merge-parameters.ts b/src/xliffmerge/xliff-merge-parameters.ts index aa9d511..ec5d9b7 100644 --- a/src/xliffmerge/xliff-merge-parameters.ts +++ b/src/xliffmerge/xliff-merge-parameters.ts @@ -189,9 +189,9 @@ export class XliffMergeParameters { } catch (err) { this.errorsFound.push(new XliffMergeError('i18nFile "' + this.i18nFile() + '" is not readable')); } - // i18nFormat must be xlf or xmb - if (!(this.i18nFormat() === 'xlf' || this.i18nFormat() === 'xmb')) { - this.errorsFound.push(new XliffMergeError('i18nFormat "' + this.i18nFormat() + '" invalid, must be "xlf" or "xmb"')); + // i18nFormat must be xlf xlf2 or xmb + if (!(this.i18nFormat() === 'xlf' || this.i18nFormat() === 'xlf2' || this.i18nFormat() === 'xmb')) { + this.errorsFound.push(new XliffMergeError('i18nFormat "' + this.i18nFormat() + '" invalid, must be "xlf" or "xlf2" or "xmb"')); } } @@ -267,7 +267,7 @@ export class XliffMergeParameters { /** * Format of the master xlif file. - * Default is "xlf", possible are "xlf" or "xmb". + * Default is "xlf", possible are "xlf" or "xlf2" or "xmb". * @return {string} */ public i18nFormat(): string { diff --git a/src/xliffmerge/xliff-merge.spec.ts b/src/xliffmerge/xliff-merge.spec.ts index ac6bc87..3b45679 100644 --- a/src/xliffmerge/xliff-merge.spec.ts +++ b/src/xliffmerge/xliff-merge.spec.ts @@ -35,6 +35,14 @@ describe('XliffMerge test spec', () => { return TranslationMessagesFileReader.fromFile('xlf', path, ENCODING); } + /** + * Helper function to read XLIFF 2.0 from File + * @type {string} + */ + function readXliff2(path: string): ITranslationMessagesFile { + return TranslationMessagesFileReader.fromFile('xlf2', path, ENCODING); + } + /** * Helper function to read Xmb from File * @type {string} @@ -222,6 +230,20 @@ describe('XliffMerge test spec', () => { done(); }); + it('should accept i18n format xlf2', (done) => { + let ws: WriterToString = new WriterToString(); + let commandOut = new CommandOutput(ws); + let profileContent: IConfigFile = { + xliffmergeOptions: { + i18nFormat: 'xlf2', + } + }; + let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {}, profileContent); + xliffMergeCmd.run(); + expect(ws.writtenData()).not.toContain('i18nFormat'); + done(); + }); + it('should accept i18n format xmb', (done) => { let ws: WriterToString = new WriterToString(); let commandOut = new CommandOutput(ws); @@ -457,6 +479,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).targetContentNormalized()).toBe('Item {{0}} of {{1}} added.'); done(); }); @@ -626,6 +649,370 @@ describe('XliffMerge test spec', () => { }); + describe('Merge process checks for format XLIFF 2.0', () => { + let MASTER1FILE = 'ngExtractedMaster1.xlf2'; + let MASTER2FILE = 'ngExtractedMaster2.xlf2'; + let MASTER1SRC = SRCDIR + MASTER1FILE; + let MASTER2SRC = SRCDIR + MASTER2FILE; + let MASTERFILE = 'messages.xlf2'; + let MASTER = WORKDIR + MASTERFILE; + + let ID_APP_RUNS = "4371668001355139802"; // an ID from ngExtractedMaster1.xlf + let ID_REMOVED_MYFIRST = "2047558209369508311"; // an ID that will be removed in master2 + let ID_REMOVED_APPDESCRIPTION = "7499557905529977371"; // another removed ID + let ID_WITH_PLACEHOLDER = "9030312858648510700"; + + beforeEach(() => { + if (!fs.existsSync(WORKDIR)){ + fs.mkdirSync(WORKDIR); + } + // cleanup workdir + FileUtil.deleteFolderContentRecursive(WORKDIR); + }); + + it('should fix source language, if the masters lang is not the default', (done) => { + FileUtil.copy(MASTER1SRC, MASTER); + let master: ITranslationMessagesFile = readXliff2(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); + let profileContent: IConfigFile = { + xliffmergeOptions: { + defaultLanguage: 'de', + srcDir: WORKDIR, + genDir: WORKDIR, + i18nFormat: 'xlf2', + i18nFile: MASTERFILE, + } + }; + let xliffMergeCmd = 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"'); + let newmaster: ITranslationMessagesFile = readXliff2(MASTER); + expect(newmaster.sourceLanguage()).toBe('de'); // master is german + done(); + }); + + it('should generate translated file for default language de from master', (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, + i18nFormat: 'xlf2', + i18nFile: MASTERFILE, + useSourceAsTarget: false + } + }; + let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de']}, profileContent); + xliffMergeCmd.run(); + expect(ws.writtenData()).not.toContain('ERROR'); + let langFile: ITranslationMessagesFile = readXliff2(xliffMergeCmd.generatedI18nFile('de')); + expect(langFile.sourceLanguage()).toBe('de'); + expect(langFile.targetLanguage()).toBe('de'); + langFile.forEachTransUnit((tu: ITransUnit) => { + expect(tu.targetContent()).toBe(tu.sourceContent()); + expect(tu.targetState()).toBe('final'); + }); + done(); + }); + + it('should generate translated file for all languages', (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, + i18nFormat: 'xlf2', + i18nFile: MASTERFILE + } + }; + let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de', 'en']}, profileContent); + xliffMergeCmd.run(); + expect(ws.writtenData()).not.toContain('ERROR'); + let langFileGerman: ITranslationMessagesFile = readXliff2(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: ITranslationMessagesFile = readXliff2(xliffMergeCmd.generatedI18nFile('en')); + expect(langFileEnglish.sourceLanguage()).toBe('de'); + expect(langFileEnglish.targetLanguage()).toBe('en'); + langFileEnglish.forEachTransUnit((tu: ITransUnit) => { + expect(tu.targetContent()).toBe(tu.sourceContent()); + expect(tu.targetState()).toBe('new'); + }); + done(); + }); + + it('should generate translated file for all languages with empty targets for non default languages', (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, + i18nFormat: 'xlf2', + i18nFile: MASTERFILE, + useSourceAsTarget: false + } + }; + let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de', 'en']}, profileContent); + xliffMergeCmd.run(); + expect(ws.writtenData()).not.toContain('ERROR'); + let langFileGerman: ITranslationMessagesFile = readXliff2(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: ITranslationMessagesFile = readXliff2(xliffMergeCmd.generatedI18nFile('en')); + expect(langFileEnglish.sourceLanguage()).toBe('de'); + expect(langFileEnglish.targetLanguage()).toBe('en'); + langFileEnglish.forEachTransUnit((tu: ITransUnit) => { + expect(tu.targetContent()).toBe(''); + expect(tu.targetState()).toBe('new'); + }); + done(); + }); + + it('should merge translated file for all languages', (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, + i18nFormat: 'xlf2', + i18nFile: MASTERFILE + } + }; + let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de', 'en']}, profileContent); + xliffMergeCmd.run(); + expect(ws.writtenData()).not.toContain('ERROR'); + + // now translate some texts in the English version + let langFileEnglish: ITranslationMessagesFile = readXliff2(xliffMergeCmd.generatedI18nFile('en')); + let tu: ITransUnit = langFileEnglish.transUnitWithId(ID_APP_RUNS); + expect(tu).toBeTruthy(); + langFileEnglish.translate(tu, 'App runs'); + TranslationMessagesFileReader.save(langFileEnglish); + + // next step, use another master + FileUtil.copy(MASTER2SRC, MASTER); + ws = new WriterToString(); + commandOut = new CommandOutput(ws); + xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de', 'en']}, profileContent); + xliffMergeCmd.run(); + expect(ws.writtenData()).not.toContain('ERROR'); + 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 + langFileEnglish = readXliff2(xliffMergeCmd.generatedI18nFile('en')); + expect(langFileEnglish.transUnitWithId(ID_APP_RUNS).targetContent()).toBe('App runs'); + + // look, that the removed IDs are really removed. + expect(langFileEnglish.transUnitWithId(ID_REMOVED_MYFIRST)).toBeFalsy(); + expect(langFileEnglish.transUnitWithId(ID_REMOVED_APPDESCRIPTION)).toBeFalsy(); + done(); + }); + + it('should translate messages with placeholder', (done) => { + FileUtil.copy(MASTER2SRC, MASTER); + let ws: WriterToString = new WriterToString(); + let commandOut = new CommandOutput(ws); + let profileContent: IConfigFile = { + xliffmergeOptions: { + defaultLanguage: 'de', + srcDir: WORKDIR, + genDir: WORKDIR, + i18nFormat: 'xlf2', + i18nFile: MASTERFILE + } + }; + let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de', 'en']}, profileContent); + xliffMergeCmd.run(); + expect(ws.writtenData()).not.toContain('ERROR'); + + // now translate some texts in the English version + let langFileEnglish: ITranslationMessagesFile = readXliff2(xliffMergeCmd.generatedI18nFile('en')); + let tu: ITransUnit = langFileEnglish.transUnitWithId(ID_WITH_PLACEHOLDER); + expect(tu).toBeTruthy(); + langFileEnglish.translate(tu, 'Item of added.'); + TranslationMessagesFileReader.save(langFileEnglish); + + // look, that the new file contains the translation + langFileEnglish = readXliff2(xliffMergeCmd.generatedI18nFile('en')); + expect(langFileEnglish.transUnitWithId(ID_WITH_PLACEHOLDER).targetContent()).toBe('Item of added.'); + expect(langFileEnglish.transUnitWithId(ID_WITH_PLACEHOLDER).targetContentNormalized()).toBe('Item {{0}} of {{1}} added.'); + + done(); + }); + + }); + + describe('ngx-translate processing for format XLIFF 2.0', () => { + + let MASTER1FILE = 'ngxtranslate.xlf2'; + let MASTER1SRC = SRCDIR + MASTER1FILE; + let MASTER_WITHOUT_NGX_TRANSLATE_STUFF = SRCDIR + 'ngExtractedMaster1.xlf2'; + let MASTERFILE = 'messages.xlf2'; + let MASTER = WORKDIR + MASTERFILE; + + let ID_NODESC_NOMEANING = "2047558209369508311"; // an ID without set meaning and description + let ID_MONDAY = "6830980354990918030"; // an ID from ngxtranslate.xlf with meaning "x.y" and description "ngx-translate" + + beforeEach(() => { + if (!fs.existsSync(WORKDIR)){ + fs.mkdirSync(WORKDIR); + } + // cleanup workdir + FileUtil.deleteFolderContentRecursive(WORKDIR); + }); + + it('should return null for unset description and meaning in master xlf2 file', (done) => { + FileUtil.copy(MASTER1SRC, MASTER); + let master: ITranslationMessagesFile = readXliff2(MASTER); + expect(master.transUnitWithId(ID_NODESC_NOMEANING).description()).toBeFalsy(); + expect(master.transUnitWithId(ID_NODESC_NOMEANING).meaning()).toBeFalsy(); + done(); + }); + + it('should find description and meaning in master xlf2 file', (done) => { + FileUtil.copy(MASTER1SRC, MASTER); + let master: ITranslationMessagesFile = readXliff2(MASTER); + expect(master.transUnitWithId(ID_MONDAY).description()).toBe('ngx-translate'); + expect(master.transUnitWithId(ID_MONDAY).meaning()).toBe('dateservice.monday'); + done(); + }); + + it('should find description and meaning in translated xlf2 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, + i18nFormat: 'xlf2', + i18nFile: MASTERFILE + } + }; + let xliffMergeCmd = XliffMerge.createFromOptions(commandOut, {languages: ['de']}, profileContent); + xliffMergeCmd.run(); + expect(ws.writtenData()).not.toContain('ERROR'); + let langFile: ITranslationMessagesFile = readXliff2(xliffMergeCmd.generatedI18nFile('de')); + expect(langFile.transUnitWithId(ID_MONDAY).description()).toBe('ngx-translate'); + expect(langFile.transUnitWithId(ID_MONDAY).meaning()).toBe('dateservice.monday'); + done(); + }); + + it('should write translation json file for ngx-translate', (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, + i18nFormat: 'xlf2', + 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)).toBeTruthy(); + let fileContent = FileUtil.read(translationJsonFilename, 'UTF-8'); + let translation: any = JSON.parse(fileContent); + expect(translation).toBeTruthy(); + 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(); + }); + + it('should handle placeholders in json file for ngx-translate', (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, + i18nFormat: 'xlf2', + 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)).toBeTruthy(); + let fileContent = FileUtil.read(translationJsonFilename, 'UTF-8'); + let translation: any = JSON.parse(fileContent); + expect(translation).toBeTruthy(); + expect(translation.placeholders).toBeTruthy(); + expect(translation.placeholders.test1placeholder).toBe('{{0}}: Eine Nachricht mit einem Platzhalter'); + expect(translation.placeholders.test2placeholder).toBe('{{0}}: Eine Nachricht mit 2 Platzhaltern: {{1}}'); + expect(translation.placeholders.test2placeholderRepeated).toBe('{{0}}: Eine Nachricht mit 2 Platzhaltern: {{0}} {{1}}'); + done(); + }); + + it('should handle embedded html markup in json file for ngx-translate', (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, + i18nFormat: 'xlf2', + 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)).toBeTruthy(); + let fileContent = FileUtil.read(translationJsonFilename, 'UTF-8'); + let translation: any = JSON.parse(fileContent); + expect(translation).toBeTruthy(); + expect(translation.embeddedhtml).toBeTruthy(); + expect(translation.embeddedhtml.bold).toBe('Diese Nachricht ist WICHTIG'); + expect(translation.embeddedhtml.boldstrong).toBe('Diese Nachricht ist SEHR WICHTIG'); + expect(translation.embeddedhtml.strange).toBe('Diese Nachricht ist {{0}}'); + done(); + }); + + }); + describe('Merge process checks for format xmb', () => { let MASTER1FILE = 'ngExtractedMaster1.xmb'; diff --git a/src/xliffmerge/xliff-merge.ts b/src/xliffmerge/xliff-merge.ts index 834d2ed..1b29de2 100644 --- a/src/xliffmerge/xliff-merge.ts +++ b/src/xliffmerge/xliff-merge.ts @@ -73,7 +73,7 @@ export class XliffMerge { /** * The read master xlf file. */ - private master: ITranslationMessagesFile; // XliffFile or XmbFile + private master: ITranslationMessagesFile; // XliffFile or Xliff2File or XmbFile /** * For Tests, create instance with given profile diff --git a/test/testdata/i18n/ngExtractedMaster1.xlf2 b/test/testdata/i18n/ngExtractedMaster1.xlf2 new file mode 100644 index 0000000..ac6ad34 --- /dev/null +++ b/test/testdata/i18n/ngExtractedMaster1.xlf2 @@ -0,0 +1,216 @@ + + + + + + Meine erste I18N-Anwendung + + + + + Anwendung läuft! + + + + + Beschreibung der Anwendung + + + Diese Anwendung ist eine reine Demonstration und hat keine wirklich nutzbare Funktion. + + + + + sampleapp.appdescription + ngx-translate + + + Diese Anwendung ist eine reine Demonstration und hat keine wirklich nutzbare Funktion. + + + + + placeholder sample + + + Eintrag von hinzugefügt. + + + + + linebreak sample + + + Dieser Text + enthält einen Zeilenumbruch. + + + + + embedded html sample + + + Dieser Text enthält eingebettetes html + + + + + Eine Nachricht per ngx-translate + + + + + ngx-translate + appTitle + + + Sample App Title + + + + + ngx-translate + messages.example + + + : A message from a service + + + + + ngx-translate + myapp + + + Meine Anwendung + + + + + ngx-translate + dateservice.monday + + + Montag + + + + + ngx-translate + dateservice.tuesday + + + Dienstag + + + + + ngx-translate + dateservice.wednesday + + + Mittwoch + + + + + ngx-translate + dateservice.thursday + + + Donnerstag + + + + + ngx-translate + dateservice.friday + + + Freitag + + + + + ngx-translate + dateservice.saturday + + + Samstag + + + + + ngx-translate + dateservice.sunday + + + Sonntag + + + + + ngx-translate + placeholders.test1placeholder + + + : Eine Nachricht mit einem Platzhalter + + + + + ngx-translate + placeholders.test2placeholder + + + : Eine Nachricht mit 2 Platzhaltern: + + + + + ngx-translate + placeholders.test2placeholderRepeated + + + : Eine Nachricht mit 2 Platzhaltern: + + + + + ngx-translate + embeddedhtml.bold + + + Diese Nachricht ist WICHTIG + + + + + ngx-translate + embeddedhtml.boldstrong + + + Diese Nachricht ist SEHR WICHTIG + + + + + ngx-translate + embeddedhtml.strange + + + Diese Nachricht ist + + + + + Explizit gesetzte ID + + + + + unit without id + + + + diff --git a/test/testdata/i18n/ngExtractedMaster2.xlf2 b/test/testdata/i18n/ngExtractedMaster2.xlf2 new file mode 100644 index 0000000..c3cad31 --- /dev/null +++ b/test/testdata/i18n/ngExtractedMaster2.xlf2 @@ -0,0 +1,211 @@ + + + + + + Anwendung läuft! + + + + + Added unit + + + this message is a new one. + + + + + sampleapp.appdescription + ngx-translate + + + Diese Anwendung ist eine reine Demonstration und hat keine wirklich nutzbare Funktion. + + + + + placeholder sample + + + Eintrag von hinzugefügt. + + + + + linebreak sample + + + Dieser Text + enthält einen Zeilenumbruch. + + + + + embedded html sample + + + Dieser Text enthält eingebettetes html + + + + + Eine Nachricht per ngx-translate + + + + + ngx-translate + appTitle + + + Sample App Title + + + + + ngx-translate + messages.example + + + : A message from a service + + + + + ngx-translate + myapp + + + Meine Anwendung + + + + + ngx-translate + dateservice.monday + + + Montag + + + + + ngx-translate + dateservice.tuesday + + + Dienstag + + + + + ngx-translate + dateservice.wednesday + + + Mittwoch + + + + + ngx-translate + dateservice.thursday + + + Donnerstag + + + + + ngx-translate + dateservice.friday + + + Freitag + + + + + ngx-translate + dateservice.saturday + + + Samstag + + + + + ngx-translate + dateservice.sunday + + + Sonntag + + + + + ngx-translate + placeholders.test1placeholder + + + : Eine Nachricht mit einem Platzhalter + + + + + ngx-translate + placeholders.test2placeholder + + + : Eine Nachricht mit 2 Platzhaltern: + + + + + ngx-translate + placeholders.test2placeholderRepeated + + + : Eine Nachricht mit 2 Platzhaltern: + + + + + ngx-translate + embeddedhtml.bold + + + Diese Nachricht ist WICHTIG + + + + + ngx-translate + embeddedhtml.boldstrong + + + Diese Nachricht ist SEHR WICHTIG + + + + + ngx-translate + embeddedhtml.strange + + + Diese Nachricht ist + + + + + Explizit gesetzte ID + + + + + unit without id + + + + diff --git a/test/testdata/i18n/ngxtranslate.xlf2 b/test/testdata/i18n/ngxtranslate.xlf2 new file mode 100644 index 0000000..260c71d --- /dev/null +++ b/test/testdata/i18n/ngxtranslate.xlf2 @@ -0,0 +1,237 @@ + + + + + + Meine erste I18N-Anwendung + My first i18n application + + + + + Anwendung läuft! + app workst! + + + + + Beschreibung der Anwendung + + + Diese Anwendung ist eine reine Demonstration und hat keine wirklich nutzbare Funktion. + This app is for demonstration purposes only. + + + + + sampleapp.appdescription + ngx-translate + + + Diese Anwendung ist eine reine Demonstration und hat keine wirklich nutzbare Funktion. + This app is for demonstration purposes only. + + + + + placeholder sample + + + Eintrag von hinzugefügt. + Entry of total added. + + + + + linebreak sample + + + Dieser Text + enthält einen Zeilenumbruch. + This text + contains a line break. + + + + + embedded html sample + + + Dieser Text enthält eingebettetes html + This text contains embedded html + + + + + Eine Nachricht per ngx-translate + A message via ngx-translate + + + + + ngx-translate + appTitle + + + Sample App Title + Sample App Title + + + + + ngx-translate + messages.example + + + : A message from a service + : A message from a service + + + + + ngx-translate + myapp + + + Meine Anwendung + My app + + + + + ngx-translate + dateservice.monday + + + Montag + Monday + + + + + ngx-translate + dateservice.tuesday + + + Dienstag + Tuesday + + + + + ngx-translate + dateservice.wednesday + + + Mittwoch + Wednesday + + + + + ngx-translate + dateservice.thursday + + + Donnerstag + Thursday + + + + + ngx-translate + dateservice.friday + + + Freitag + Fryday + + + + + ngx-translate + dateservice.saturday + + + Samstag + Saturday + + + + + ngx-translate + dateservice.sunday + + + Sonntag + Sunday + + + + + ngx-translate + placeholders.test1placeholder + + + : Eine Nachricht mit einem Platzhalter + : A message with a placeholder + + + + + ngx-translate + placeholders.test2placeholder + + + : Eine Nachricht mit 2 Platzhaltern: + : A message with 2 placeholders: + + + + + ngx-translate + placeholders.test2placeholderRepeated + + + : Eine Nachricht mit 2 Platzhaltern: + : A message with 2 placeholders: + + + + + ngx-translate + embeddedhtml.bold + + + Diese Nachricht ist WICHTIG + This message is IMPORTANT + + + + + ngx-translate + embeddedhtml.boldstrong + + + Diese Nachricht ist SEHR WICHTIG + This message is VERY IMPORTANT + + + + + ngx-translate + embeddedhtml.strange + + + Diese Nachricht ist + This message is + + + + + Explizit gesetzte ID + Explicitly set ID + + + + diff --git a/test/testdata/i18n/readme.txt b/test/testdata/i18n/readme.txt index d63138f..a3f5eff 100644 --- a/test/testdata/i18n/readme.txt +++ b/test/testdata/i18n/readme.txt @@ -9,4 +9,5 @@ It contains the same IDs as Master1, but some additional ones. ngttranslate.xlf is an extracted master with some messages with description and meaning to be used with ngx-translate. -The xmb files are the same in principle, but for format xmb. \ No newline at end of file +The xmb files are the same in principle, but for format xmb. +And the xlf2 files are for XLIFF 2.0 \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 38a7eed..64ae12a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -944,9 +944,9 @@ nan@^2.3.0: version "2.6.1" resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.1.tgz#8c84f7b14c96b89f57fbc838012180ec8ca39a01" -ngx-i18nsupport-lib@^0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/ngx-i18nsupport-lib/-/ngx-i18nsupport-lib-0.0.8.tgz#ce8d527ea166f4e76ad0c2e90cdede78125e8979" +ngx-i18nsupport-lib@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/ngx-i18nsupport-lib/-/ngx-i18nsupport-lib-0.1.3.tgz#c1b00e5e43c0a2310679c27621e0e76a6b971ee5" dependencies: "@types/xmldom" "^0.1.29" xmldom "^0.1.27"