import * as fs from 'fs' ; import { XliffMerge } from './xliff-merge' ; import { IConfigFile } from './i-xliff-merge-options' ; import { CommandOutput } from '../common/command-output' ; import { WriterToString } from '../common/writer-to-string' ; import { FileUtil } from '../common/file-util' ; import { ITranslationMessagesFile , ITransUnit , STATE_FINAL , STATE_NEW , STATE_TRANSLATED } from '@ngx-i18nsupport/ngx-i18nsupport-lib' ; import { TranslationMessagesFileReader } from './translation-messages-file-reader' ; import { format } from 'util' ; import { getApiKey } from '../autotranslate/auto-translate-service.spec' ; import { XmlReader } from './xml-reader' ; /**
 * Created by martin on 18.02.2017.
 * Testcases for XliffMerge Format XLIFF 1.2.
 */ describe ( 'XliffMerge XLIFF 1.2 format tests' , ( ) => { /**
     * Workdir, not in git.
     * Cleaned up for every test.
     * Tests, that work on files, copy everything they need into this directory.
     */ const WORKDIR = 'test/work/' ; const SRCDIR = 'test/testdata/i18n/' ; const ENCODING = 'UTF-8' ; /**
     * Helper function to read Xliff from File
     */ function readXliff ( path ) { if ( ! path ) { throw new Error ( 'oops, no file' ) ; } try { return TranslationMessagesFileReader . fromFile ( 'xlf' , path , ENCODING ) ; } catch ( err ) { console . log ( format ( 'error reading %s: "%s"' , path , err . message ) ) ; return null ; } } describe ( 'Merge process checks for format xlf' , ( ) => { const MASTER1FILE = 'ngExtractedMaster1.xlf' ; const MASTER2FILE = 'ngExtractedMaster2.xlf' ; const MASTER1SRC = SRCDIR + MASTER1FILE ; const MASTER2SRC = SRCDIR + MASTER2FILE ; const MASTERFILE = 'messages.xlf' ; const MASTER = WORKDIR + MASTERFILE ; const ID_TRANSLATED_SCHLIESSEN = '1ead0ad1063d0c9e005fe56c9529aef4c1ef9d21' ; const ID_REMOVED_STARTSEITE = 'c536247d71822c272f8e9155f831e0efb5aa0d31' ; const ID_REMOVED_SUCHEN = 'd17aee1ddf9fe1c0afe8440e02ef5ab906a69699' ; const ID_WITH_PLACEHOLDER = 'af0819ea4a5db68737ebcabde2f5e432b66352e8' ; const ID_MISSING_SOURCEREF = '57e605bfa130afb4de4ee40e496e854a9e8a28a7' ; const ID_DESCRIPTION_CHANGE = 'DescriptionAndMeaning1' ; const ID_DESCRIPTION_ADD = 'AddDescriptionAndMeaning' ; const ID_DESCRIPTION_REMOVE = 'RemoveDescriptionAndMeaning' ; beforeEach ( ( ) => { if ( ! fs . existsSync ( WORKDIR ) ) { fs . mkdirSync ( WORKDIR ) ; } FileUtil . deleteFolderContentRecursive ( WORKDIR ) ; } ) ; it ( 'should fix source language, if the masters lang is not the default' , ( done ) => { FileUtil . copy ( MASTER1SRC , MASTER ) ; const master = readXliff ( MASTER ) ; expect ( master . sourceLanguage ( ) ) . toBe ( 'en' ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , } } ; const 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"' ) ; const newmaster = readXliff ( MASTER ) ; expect ( newmaster . sourceLanguage ( ) ) . toBe ( 'de' ) ; done ( ) ; } ) ; it ( 'should generate translated file for default language de from master' , ( done ) => { FileUtil . copy ( MASTER1SRC , MASTER ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , useSourceAsTarget : false } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const langFile = readXliff ( xliffMergeCmd . generatedI18nFile ( 'de' ) ) ; expect ( langFile . sourceLanguage ( ) ) . toBe ( 'de' ) ; expect ( langFile . targetLanguage ( ) ) . toBe ( 'de' ) ; langFile . forEachTransUnit ( ( tu ) => { 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 ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const langFileGerman = readXliff ( xliffMergeCmd . generatedI18nFile ( 'de' ) ) ; expect ( langFileGerman . sourceLanguage ( ) ) . toBe ( 'de' ) ; expect ( langFileGerman . targetLanguage ( ) ) . toBe ( 'de' ) ; langFileGerman . forEachTransUnit ( ( tu ) => { expect ( tu . targetContent ( ) ) . toBe ( tu . sourceContent ( ) ) ; expect ( tu . targetState ( ) ) . toBe ( 'final' ) ; } ) ; const langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; expect ( langFileEnglish . sourceLanguage ( ) ) . toBe ( 'de' ) ; expect ( langFileEnglish . targetLanguage ( ) ) . toBe ( 'en' ) ; langFileEnglish . forEachTransUnit ( ( tu ) => { 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 ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , useSourceAsTarget : false } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const langFileGerman = readXliff ( xliffMergeCmd . generatedI18nFile ( 'de' ) ) ; expect ( langFileGerman . sourceLanguage ( ) ) . toBe ( 'de' ) ; expect ( langFileGerman . targetLanguage ( ) ) . toBe ( 'de' ) ; langFileGerman . forEachTransUnit ( ( tu ) => { expect ( tu . targetContent ( ) ) . toBe ( tu . sourceContent ( ) ) ; expect ( tu . targetState ( ) ) . toBe ( 'final' ) ; } ) ; const langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; expect ( langFileEnglish . sourceLanguage ( ) ) . toBe ( 'de' ) ; expect ( langFileEnglish . targetLanguage ( ) ) . toBe ( 'en' ) ; langFileEnglish . forEachTransUnit ( ( tu ) => { expect ( tu . targetContent ( ) ) . toBe ( '' ) ; expect ( tu . targetState ( ) ) . toBe ( 'new' ) ; } ) ; done ( ) ; } ) ; it ( 'should generate translated file for all languages with set praefix and suffix (#70)' , ( done ) => { FileUtil . copy ( MASTER1SRC , MASTER ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , targetPraefix : '%%' , targetSuffix : '!!' , } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const langFileGerman = readXliff ( xliffMergeCmd . generatedI18nFile ( 'de' ) ) ; expect ( langFileGerman . sourceLanguage ( ) ) . toBe ( 'de' ) ; expect ( langFileGerman . targetLanguage ( ) ) . toBe ( 'de' ) ; langFileGerman . forEachTransUnit ( ( tu ) => { if ( ! tu . targetContent ( ) . startsWith ( '{VAR' ) ) { expect ( tu . targetContent ( ) ) . toBe ( '%%' + tu . sourceContent ( ) + '!!' ) ; } else { expect ( tu . targetContent ( ) ) . toBe ( tu . sourceContent ( ) ) ; } expect ( tu . targetState ( ) ) . toBe ( 'final' ) ; } ) ; const langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; expect ( langFileEnglish . sourceLanguage ( ) ) . toBe ( 'de' ) ; expect ( langFileEnglish . targetLanguage ( ) ) . toBe ( 'en' ) ; langFileEnglish . forEachTransUnit ( ( tu ) => { if ( ! tu . targetContent ( ) . startsWith ( '{VAR' ) ) { expect ( tu . targetContent ( ) ) . toBe ( '%%' + tu . sourceContent ( ) + '!!' ) ; } else { expect ( tu . targetContent ( ) ) . toBe ( tu . sourceContent ( ) ) ; } expect ( tu . targetState ( ) ) . toBe ( 'new' ) ; } ) ; done ( ) ; } ) ; it ( 'should merge translated file for all languages' , ( done ) => { FileUtil . copy ( MASTER1SRC , MASTER ) ; let ws = new WriterToString ( ) ; let commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE } } ; let xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; let langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; const tu = langFileEnglish . transUnitWithId ( ID_TRANSLATED_SCHLIESSEN ) ; expect ( tu ) . toBeTruthy ( ) ; tu . translate ( 'Close' ) ; TranslationMessagesFileReader . save ( langFileEnglish ) ; 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 12 trans-units from master to "en"' ) ; expect ( ws . writtenData ( ) ) . toContain ( 'removed 5 unused trans-units in "en"' ) ; langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; expect ( langFileEnglish . transUnitWithId ( ID_TRANSLATED_SCHLIESSEN ) . targetContent ( ) ) . toBe ( 'Close' ) ; expect ( langFileEnglish . transUnitWithId ( ID_REMOVED_STARTSEITE ) ) . toBeFalsy ( ) ; expect ( langFileEnglish . transUnitWithId ( ID_REMOVED_SUCHEN ) ) . toBeFalsy ( ) ; done ( ) ; } ) ; it ( 'should merge changed source content with explicit ID to default language file (#81)' , ( done ) => { const ID_SOURCE_CHANGE = 'sourcechanged' ; const ID_SOURCE_CHANGE_STATE_FINAL = 'sourcechanged_state_final' ; const TRANSLATED_FILE = 'WithSourceContentChange.de.xlf' ; FileUtil . copy ( SRCDIR + 'ngExtractedMasterWithSourceContentChange.xlf' , MASTER ) ; FileUtil . copy ( SRCDIR + TRANSLATED_FILE , WORKDIR + 'messages.de.xlf' ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] , verbose : true } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; expect ( ws . writtenData ( ) ) . toContain ( 'WARNING: transferred 2 changed source content from master to "de"' ) ; const langFileGerman = readXliff ( xliffMergeCmd . generatedI18nFile ( 'de' ) ) ; const tu = langFileGerman . transUnitWithId ( ID_SOURCE_CHANGE ) ; expect ( tu ) . toBeTruthy ( ) ; expect ( tu . sourceContent ( ) ) . toBe ( 'Test Änderung Source (geändert!)' ) ; expect ( tu . targetContent ( ) ) . toBe ( 'Test Änderung Source (geändert!)' ) ; expect ( tu . targetState ( ) ) . toBe ( STATE_FINAL ) ; done ( ) ; } ) ; it ( 'should merge changed source content to already translated files' , ( done ) => { const ID_SOURCE_CHANGE = 'sourcechanged' ; const ID_SOURCE_CHANGE_STATE_FINAL = 'sourcechanged_state_final' ; const TRANSLATED_FILE = 'WithSourceContentChange.en.xlf' ; FileUtil . copy ( SRCDIR + 'ngExtractedMasterWithSourceContentChange.xlf' , MASTER ) ; FileUtil . copy ( SRCDIR + TRANSLATED_FILE , WORKDIR + 'messages.en.xlf' ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] , verbose : true } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; expect ( ws . writtenData ( ) ) . toContain ( 'WARNING: transferred 2 changed source content from master to "en"' ) ; const langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; const tu = langFileEnglish . transUnitWithId ( ID_SOURCE_CHANGE ) ; expect ( tu ) . toBeTruthy ( ) ; expect ( tu . sourceContent ( ) ) . toBe ( 'Test Änderung Source (geändert!)' ) ; expect ( tu . targetState ( ) ) . toBe ( STATE_NEW ) ; const tuFinal = langFileEnglish . transUnitWithId ( ID_SOURCE_CHANGE_STATE_FINAL ) ; expect ( tuFinal ) . toBeTruthy ( ) ; expect ( tuFinal . sourceContent ( ) ) . toBe ( 'Test Änderung Source (state final, geändert!)' ) ; expect ( tuFinal . targetState ( ) ) . toBe ( STATE_TRANSLATED ) ; done ( ) ; } ) ; it ( 'should merge missing source refs to already translated files' , ( done ) => { const MISSING_SOURCEREF_FILE = 'missingSourcerefs.en.xlf' ; FileUtil . copy ( MASTER1SRC , MASTER ) ; FileUtil . copy ( SRCDIR + MISSING_SOURCEREF_FILE , WORKDIR + 'messages.en.xlf' ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; expect ( ws . writtenData ( ) ) . toContain ( 'WARNING: transferred 2 source references' ) ; const langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; const tu = langFileEnglish . transUnitWithId ( ID_MISSING_SOURCEREF ) ; expect ( tu ) . toBeTruthy ( ) ; expect ( tu . targetContent ( ) ) . toBe ( 'News' ) ; expect ( tu . sourceReferences ( ) . length ) . toBe ( 2 ) ; done ( ) ; } ) ; it ( 'should merge changed descriptions and meanings to already translated files' , ( done ) => { const TRANSLATED_FILE = 'WithDescriptions.en.xlf' ; FileUtil . copy ( SRCDIR + 'ngExtractedMasterWithDescriptions.xlf' , MASTER ) ; FileUtil . copy ( SRCDIR + TRANSLATED_FILE , WORKDIR + 'messages.en.xlf' ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] , verbose : true } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; expect ( ws . writtenData ( ) ) . toContain ( 'WARNING: transferred 3 changed descriptions/meanings from master to "en"' ) ; const langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; const tu = langFileEnglish . transUnitWithId ( ID_DESCRIPTION_CHANGE ) ; expect ( tu ) . toBeTruthy ( ) ; expect ( tu . description ( ) ) . toBe ( 'changed description' ) ; expect ( tu . meaning ( ) ) . toBe ( 'changed meaning' ) ; const tuAdded = langFileEnglish . transUnitWithId ( ID_DESCRIPTION_ADD ) ; expect ( tuAdded ) . toBeTruthy ( ) ; expect ( tuAdded . description ( ) ) . toBe ( 'added description' ) ; expect ( tuAdded . meaning ( ) ) . toBe ( 'added meaning' ) ; const tuRemoved = langFileEnglish . transUnitWithId ( ID_DESCRIPTION_REMOVE ) ; expect ( tuRemoved ) . toBeTruthy ( ) ; expect ( tuRemoved . description ( ) ) . toBeNull ( ) ; expect ( tuRemoved . meaning ( ) ) . toBeNull ( ) ; done ( ) ; } ) ; it ( 'should preserve order when merging new units (#96)' , ( done ) => { FileUtil . copy ( SRCDIR + 'preserveOrderMaster1.xlf' , MASTER ) ; let ws = new WriterToString ( ) ; let commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'en' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE } } ; let xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'en' , 'de' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; FileUtil . copy ( SRCDIR + 'preserveOrderMaster2.xlf' , MASTER ) ; ws = new WriterToString ( ) ; commandOut = new CommandOutput ( ws ) ; xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'en' , 'de' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; expect ( ws . writtenData ( ) ) . toContain ( 'merged 3 trans-units from master to "de"' ) ; const langFileGerman = readXliff ( xliffMergeCmd . generatedI18nFile ( 'de' ) ) ; const addedTu = langFileGerman . transUnitWithId ( 'addedunit1' ) ; expect ( addedTu ) . toBeTruthy ( ) ; expect ( addedTu . sourceContent ( ) ) . toBe ( 'added unit 1' ) ; expect ( langFileGerman . editedContent ( ) . replace ( /(\r\n|\n|\r)/gm , '' ) ) . toMatch ( /addedunit1.*firstunit.*addedunit2.*lastunit.*addedunit3/ ) ; done ( ) ; } ) ; it ( 'should not preserve order when merging new units when disabled via config (#108)' , ( done ) => { FileUtil . copy ( SRCDIR + 'preserveOrderMaster1.xlf' , MASTER ) ; let ws = new WriterToString ( ) ; let commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'en' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , preserveOrder : false } } ; let xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'en' , 'de' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; FileUtil . copy ( SRCDIR + 'preserveOrderMaster2.xlf' , MASTER ) ; ws = new WriterToString ( ) ; commandOut = new CommandOutput ( ws ) ; xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'en' , 'de' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; expect ( ws . writtenData ( ) ) . toContain ( 'merged 3 trans-units from master to "de"' ) ; const langFileGerman = readXliff ( xliffMergeCmd . generatedI18nFile ( 'de' ) ) ; const addedTu = langFileGerman . transUnitWithId ( 'addedunit1' ) ; expect ( addedTu ) . toBeTruthy ( ) ; expect ( addedTu . sourceContent ( ) ) . toBe ( 'added unit 1' ) ; expect ( langFileGerman . editedContent ( ) . replace ( /(\r\n|\n|\r)/gm , '' ) ) . toMatch ( /firstunit.*lastunit.*addedunit1.*addedunit2.*addedunit3/ ) ; done ( ) ; } ) ; it ( 'should not remove trailing line break when merging' , ( done ) => { FileUtil . copy ( MASTER1SRC , MASTER ) ; const masterContent = FileUtil . read ( MASTER , XmlReader . DEFAULT_ENCODING ) ; expect ( masterContent . endsWith ( '\n' ) ) . toBeTruthy ( 'master file should end with EOL' ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const newContent = FileUtil . read ( xliffMergeCmd . generatedI18nFile ( 'de' ) , XmlReader . DEFAULT_ENCODING ) ; expect ( newContent . endsWith ( '\n' ) ) . toBeTruthy ( 'file should end with EOL' ) ; done ( ) ; } ) ; it ( 'should translate messages with placeholder' , ( done ) => { FileUtil . copy ( MASTER2SRC , MASTER ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; let langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; const tu = langFileEnglish . transUnitWithId ( ID_WITH_PLACEHOLDER ) ; expect ( tu ) . toBeTruthy ( ) ; tu . translate ( 'Item <x id="INTERPOLATION"/> of <x id="INTERPOLATION_1"/> added.' ) ; TranslationMessagesFileReader . save ( langFileEnglish ) ; langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; expect ( langFileEnglish . transUnitWithId ( ID_WITH_PLACEHOLDER ) . targetContent ( ) ) . toBe ( 'Item <x id="INTERPOLATION"/> of <x id="INTERPOLATION_1"/> added.' ) ; expect ( langFileEnglish . transUnitWithId ( ID_WITH_PLACEHOLDER ) . targetContentNormalized ( ) . asDisplayString ( ) ) . toBe ( 'Item {{0}} of {{1}} added.' ) ; done ( ) ; } ) ; it ( 'should translate messages with 2 custom tags with different ids (#84)' , ( done ) => { const ID_2_CUSTOM_TAGS = '8856d298b6fa89a339475c5d5cd20f2d2afcfbf7' ; FileUtil . copy ( MASTER1SRC , MASTER ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; let langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; const tu = langFileEnglish . transUnitWithId ( ID_2_CUSTOM_TAGS ) ; expect ( tu ) . toBeTruthy ( ) ; expect ( tu . sourceContentNormalized ( ) . asDisplayString ( ) ) . toBe ( 'Neues <bs-activity-stream-element></bs-activity-stream-element> wurde gemeldet durch <bs-activity-stream-element id="1"></bs-activity-stream-element>' ) ; const translation = tu . sourceContentNormalized ( ) . translate ( 'New <bs-activity-stream-element></bs-activity-stream-element> was reported by <bs-activity-stream-element id="1"></bs-activity-stream-element>' ) ; tu . translate ( translation ) ; TranslationMessagesFileReader . save ( langFileEnglish ) ; langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; expect ( langFileEnglish . transUnitWithId ( ID_2_CUSTOM_TAGS ) . targetContent ( ) ) . toBe ( 'New <x id="START_TAG_BS-ACTIVITY-STREAM-ELEMENT" ctype="x-bs-activity-stream-element" equiv-text="&lt;bs-activity-stream-element>"/><x id="CLOSE_TAG_BS-ACTIVITY-STREAM-ELEMENT" ctype="x-bs-activity-stream-element"/> was reported by <x id="START_TAG_BS-ACTIVITY-STREAM-ELEMENT_1" ctype="x-bs-activity-stream-element" equiv-text="&lt;bs-activity-stream-element>"/><x id="CLOSE_TAG_BS-ACTIVITY-STREAM-ELEMENT" ctype="x-bs-activity-stream-element"/>' ) ; expect ( langFileEnglish . transUnitWithId ( ID_2_CUSTOM_TAGS ) . targetContentNormalized ( ) . asDisplayString ( ) ) . toBe ( 'New <bs-activity-stream-element></bs-activity-stream-element> was reported by <bs-activity-stream-element id="1"></bs-activity-stream-element>' ) ; done ( ) ; } ) ; it ( 'should translate ICU message with placeholder (#83)' , ( done ) => { const ID_ICU_WITH_PLACEHOLDER = '8856d298b6fa89a339475c5d5cd20f2d2afcfbf8' ; FileUtil . copy ( MASTER1SRC , MASTER ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; let langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; const tu = langFileEnglish . transUnitWithId ( ID_ICU_WITH_PLACEHOLDER ) ; expect ( tu ) . toBeTruthy ( ) ; expect ( tu . sourceContentNormalized ( ) . asDisplayString ( ) ) . toBe ( '<ICU-Message/>' ) ; const translation = tu . sourceContentNormalized ( ) . translateICUMessage ( { '=1' : 'Crash <x id="INTERPOLATION" equiv-text="{{ a }}"/> was' } ) ; tu . translate ( translation ) ; TranslationMessagesFileReader . save ( langFileEnglish ) ; langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; expect ( langFileEnglish . transUnitWithId ( ID_ICU_WITH_PLACEHOLDER ) . targetContentNormalized ( ) . asDisplayString ( ) ) . toBe ( '<ICU-Message/>' ) ; expect ( langFileEnglish . transUnitWithId ( ID_ICU_WITH_PLACEHOLDER ) . targetContentNormalized ( ) . getICUMessage ( ) . asNativeString ( ) ) . toContain ( 'Crash' ) ; done ( ) ; } ) ; it ( 'allowIdChange feature should merge only white space changed content with changed ID' + ' to already translated files (#65)' , ( done ) => { const ID_ORIGINAL = 'originalId' ; const ID_CHANGED = 'changedId' ; const TRANSLATED_FILE = 'WithIdChange.en.xlf' ; FileUtil . copy ( SRCDIR + 'ngExtractedMasterWithIdChange.xlf' , MASTER ) ; FileUtil . copy ( SRCDIR + TRANSLATED_FILE , WORKDIR + 'messages.en.xlf' ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , allowIdChange : true } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] , verbose : true } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; expect ( ws . writtenData ( ) ) . toContain ( 'WARNING: found 2 changed id\'s in "en"' ) ; const langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; const tuChanged = langFileEnglish . transUnitWithId ( ID_CHANGED ) ; expect ( tuChanged ) . toBeTruthy ( ) ; expect ( tuChanged . sourceContent ( ) . trim ( ) ) . toBe ( 'Test kleine Änderung, nur white spaces!' ) ; expect ( tuChanged . targetState ( ) ) . toBe ( STATE_TRANSLATED ) ; expect ( tuChanged . targetContent ( ) ) . toBe ( 'Test for a small white space change' ) ; const tuOriginal = langFileEnglish . transUnitWithId ( ID_ORIGINAL ) ; expect ( tuOriginal ) . toBeFalsy ( ) ; done ( ) ; } ) ; it ( 'allowIdChange feature, should merge untranslated only white space changed content with changed ID, ' + 'but should set preserve state "new" (#68)' , ( done ) => { const ID_ORIGINAL = 'originalIdUntranslated' ; const ID_CHANGED = 'changedIdUntranslated' ; const TRANSLATED_FILE = 'WithIdChange.en.xlf' ; FileUtil . copy ( SRCDIR + 'ngExtractedMasterWithIdChange.xlf' , MASTER ) ; FileUtil . copy ( SRCDIR + TRANSLATED_FILE , WORKDIR + 'messages.en.xlf' ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , allowIdChange : true } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] , verbose : true } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; expect ( ws . writtenData ( ) ) . toContain ( 'WARNING: found 2 changed id\'s in "en"' ) ; const langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; const tuChanged = langFileEnglish . transUnitWithId ( ID_CHANGED ) ; expect ( tuChanged ) . toBeTruthy ( ) ; expect ( tuChanged . sourceContent ( ) . trim ( ) ) . toBe ( 'Unübersetzt' ) ; expect ( tuChanged . targetState ( ) ) . toBe ( STATE_NEW ) ; expect ( tuChanged . targetContent ( ) ) . toBe ( '' ) ; const tuOriginal = langFileEnglish . transUnitWithId ( ID_ORIGINAL ) ; expect ( tuOriginal ) . toBeFalsy ( ) ; done ( ) ; } ) ; it ( 'allowIdChange feature with added ICU message (#138)' , ( done ) => { const ID_OLD_ICU = 'oldicu' ; const ID_OLD_ICUREF = 'oldicuref' ; const ID_CHANGED_ICU = 'changedicu' ; const ID_CHANGED_ICUREF = 'changedicuref' ; const ID_ADDDED_ICU = 'newicu' ; const ID_ADDDED_ICUREF = 'newicuref' ; const TRANSLATED_FILE = 'issue138IdChangeICU.de.xlf' ; FileUtil . copy ( SRCDIR + 'issue138IdChangeICUMaster.xlf' , MASTER ) ; FileUtil . copy ( SRCDIR + TRANSLATED_FILE , WORKDIR + 'messages.de.xlf' ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'en' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , allowIdChange : true } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'en' , 'de' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; expect ( ws . writtenData ( ) ) . toContain ( 'WARNING: merged 2 trans-units from master to "de"' ) ; expect ( ws . writtenData ( ) ) . toContain ( 'WARNING: found 2 changed id\'s in "de"' ) ; expect ( ws . writtenData ( ) ) . toContain ( 'WARNING: removed 2 unused trans-units in "de"' ) ; const langFileGerman = readXliff ( xliffMergeCmd . generatedI18nFile ( 'de' ) ) ; FileUtil . copy ( xliffMergeCmd . generatedI18nFile ( 'de' ) , 'test/' + 'issue138.de.xlf' ) ; expect ( langFileGerman . numberOfTransUnits ( ) ) . toBe ( 6 ) ; const tuOldIcuRef = langFileGerman . transUnitWithId ( ID_OLD_ICUREF ) ; expect ( tuOldIcuRef ) . toBeTruthy ( ) ; const tuOldIcu = langFileGerman . transUnitWithId ( ID_OLD_ICU ) ; expect ( tuOldIcu ) . toBeTruthy ( ) ; expect ( tuOldIcuRef . targetContent ( ) ) . toContain ( '<x id="ICU" equiv-text="{ fruit, select, Windstorm {...}' ) ; expect ( tuOldIcuRef . targetState ( ) ) . toBe ( STATE_TRANSLATED ) ; expect ( tuOldIcu . sourceContent ( ) ) . toContain ( 'Windstorm {Windstorm}' ) ; expect ( tuOldIcu . targetContent ( ) ) . toContain ( 'Windstorm {Stürmer}' ) ; expect ( tuOldIcu . targetState ( ) ) . toBe ( STATE_TRANSLATED ) ; const tuChangedIcuRef = langFileGerman . transUnitWithId ( ID_CHANGED_ICUREF ) ; expect ( tuChangedIcuRef ) . toBeTruthy ( ) ; const tuChangedIcu = langFileGerman . transUnitWithId ( ID_CHANGED_ICU ) ; expect ( tuChangedIcu ) . toBeTruthy ( ) ; expect ( tuChangedIcuRef . targetContent ( ) ) . toContain ( '<x id="ICU" equiv-text="{ choice, select, A {...}' ) ; expect ( tuChangedIcuRef . targetState ( ) ) . toBe ( STATE_TRANSLATED ) ; expect ( tuChangedIcu . sourceContent ( ) ) . toContain ( 'A {A}' ) ; expect ( tuChangedIcu . targetContent ( ) ) . toContain ( 'A {A1}' ) ; expect ( tuChangedIcu . targetState ( ) ) . toBe ( STATE_TRANSLATED ) ; const tuAddedIcuRef = langFileGerman . transUnitWithId ( ID_ADDDED_ICUREF ) ; expect ( tuAddedIcuRef ) . toBeTruthy ( ) ; const tuAddedIcu = langFileGerman . transUnitWithId ( ID_ADDDED_ICU ) ; expect ( tuAddedIcu ) . toBeTruthy ( ) ; expect ( tuAddedIcuRef . targetContent ( ) ) . toContain ( '<x id="ICU" equiv-text="{ fruit, select, Apple {...}' ) ; expect ( tuAddedIcuRef . targetState ( ) ) . toBe ( STATE_NEW ) ; expect ( tuAddedIcu . sourceContent ( ) ) . toContain ( 'Apple {Apple}' ) ; expect ( tuAddedIcu . targetContent ( ) ) . toBe ( tuAddedIcu . sourceContent ( ) ) ; expect ( tuAddedIcu . targetState ( ) ) . toBe ( STATE_NEW ) ; done ( ) ; } ) ; it ( 'should report an error with filename when there is something wrong' , ( done ) => { FileUtil . copy ( SRCDIR + 'schrott.xlf' , MASTER ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , supportNgxTranslate : true } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; try { xliffMergeCmd . run ( ) ; } catch ( e ) { } expect ( ws . writtenData ( ) ) . toContain ( 'ERROR' ) ; expect ( ws . writtenData ( ) ) . toContain ( 'messages.de.xlf' ) ; done ( ) ; } ) ; it ( 'should use beautify when requested (#64, #88)' , ( done ) => { FileUtil . copy ( MASTER1SRC , MASTER ) ; let ws = new WriterToString ( ) ; let commandOut = new CommandOutput ( ws ) ; let profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE } } ; let xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const unformattedContent = XmlReader . readXmlFileContent ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; expect ( unformattedContent . content ) . toContain ( '<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">' ) ; FileUtil . deleteFile ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; ws = new WriterToString ( ) ; commandOut = new CommandOutput ( ws ) ; profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , beautifyOutput : true } } ; xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const formattedContent = XmlReader . readXmlFileContent ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; expect ( formattedContent . content ) . toContain ( '\n        <source>Nachrichten</source>' ) ; done ( ) ; } ) ; it ( 'should not add empty lines when using beautify whith complex content (#97)' , ( done ) => { FileUtil . copy ( SRCDIR + 'issue97emptylines.xlf' , MASTER ) ; let ws = new WriterToString ( ) ; let commandOut = new CommandOutput ( ws ) ; let profileContent = { xliffmergeOptions : { defaultLanguage : 'en' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , beautifyOutput : true } } ; let xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'en' , 'ru' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const formattedContent1 = XmlReader . readXmlFileContent ( xliffMergeCmd . generatedI18nFile ( 'ru' ) ) ; ws = new WriterToString ( ) ; commandOut = new CommandOutput ( ws ) ; profileContent = { xliffmergeOptions : { defaultLanguage : 'en' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , beautifyOutput : true } } ; xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'en' , 'ru' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const formattedContent2 = XmlReader . readXmlFileContent ( xliffMergeCmd . generatedI18nFile ( 'ru' ) ) ; expect ( formattedContent2 . content ) . toMatch ( /I accept the\r?\n[ \t]*<x/ ) ; expect ( formattedContent2 . content ) . not . toMatch ( /I accept the\r?\n[ \t]*\r?\n[ \t]*<x/ ) ; done ( ) ; } ) ; it ( 'should not change translation state when source is unchanged but has different line ending (#128)' , ( done ) => { FileUtil . copy ( SRCDIR + 'issue128master.xlf' , MASTER ) ; const langfileName = WORKDIR + 'messages.en.xlf' ; FileUtil . copy ( SRCDIR + 'issue128translated.xlf' , langfileName ) ; const originalContent = FileUtil . read ( langfileName , 'UTF-8' ) ; const contentWithoutCRLF = originalContent . replace ( /[\n\r]/g , '' ) ; expect ( originalContent ) . not . toBe ( contentWithoutCRLF ) ; FileUtil . replaceContent ( langfileName , contentWithoutCRLF , 'UTF-8' ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , beautifyOutput : false } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; const tu = langFileEnglish . transUnitWithId ( 'issue128' ) ; expect ( tu . targetState ( ) ) . toBe ( STATE_FINAL ) ; done ( ) ; } ) ; describe ( 'autotranslate via google translate' , ( ) => { let apikey ; const ID_NACHRICHTEN = '57e605bfa130afb4de4ee40e496e854a9e8a28a7' ; const ID_BESCHREIBUNG_WITH_PLACEHOLDER = 'a52ba049c16778bdb2e5a19a41acaadf87b104dc' ; const ID_ICUMESSAGE = 'efec69fdcf74bd6d640b2a771558b7b09e271c28' ; beforeEach ( ( ) => { apikey = getApiKey ( ) ; } ) ; it ( 'should detect invalid key' , ( done ) => { if ( ! apikey ) { done ( ) ; return ; } FileUtil . copy ( MASTER1SRC , MASTER ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , autotranslate : true , apikey : 'lmaa' } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; xliffMergeCmd . run ( ( retcode ) => { expect ( ws . writtenData ( ) ) . toContain ( 'API key not valid' ) ; done ( ) ; } ) ; } ) ; it ( 'should auto translate file' , ( done ) => { if ( ! apikey ) { done ( ) ; return ; } FileUtil . copy ( MASTER1SRC , MASTER ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , autotranslate : true , apikey : apikey } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; xliffMergeCmd . run ( ( ) => { expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; expect ( langFileEnglish . targetLanguage ( ) ) . toBe ( 'en' ) ; const tu = langFileEnglish . transUnitWithId ( ID_NACHRICHTEN ) ; expect ( tu . sourceContent ( ) ) . toBe ( 'Nachrichten' ) ; expect ( tu . targetContent ( ) ) . toBe ( 'news' ) ; expect ( tu . targetState ( ) ) . toBe ( 'translated' ) ; const tuICU = langFileEnglish . transUnitWithId ( ID_ICUMESSAGE ) ; expect ( tuICU . sourceContent ( ) ) . toContain ( 'VAR_PLURAL' ) ; expect ( tuICU . targetContent ( ) ) . toBe ( '{VAR_PLURAL, plural, =0 {no sheep} =1 {1 sheep} other {x sheep}}' ) ; expect ( tuICU . targetState ( ) ) . toBe ( 'translated' ) ; done ( ) ; } ) ; } ) ; it ( 'should auto translate file with region code (which will be ignored)' , ( done ) => { if ( ! apikey ) { done ( ) ; return ; } FileUtil . copy ( MASTER1SRC , MASTER ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de-de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , autotranslate : true , apikey : apikey } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de-de' , 'en-us' ] } , profileContent ) ; xliffMergeCmd . run ( ( retcode ) => { expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en-us' ) ) ; expect ( langFileEnglish ) . toBeTruthy ( ) ; if ( langFileEnglish ) { expect ( langFileEnglish . targetLanguage ( ) ) . toBe ( 'en-us' ) ; const tu = langFileEnglish . transUnitWithId ( ID_BESCHREIBUNG_WITH_PLACEHOLDER ) ; expect ( tu . sourceContentNormalized ( ) . asDisplayString ( ) ) . toBe ( 'Beschreibung zu {{0}} ({{1}})' ) ; expect ( tu . targetContentNormalized ( ) . asDisplayString ( ) ) . toBe ( 'Description of {{0}} ({{1}})' ) ; expect ( tu . targetState ( ) ) . toBe ( 'translated' ) ; } done ( ) ; } ) ; } ) ; it ( 'should detect unsupported language when using auto translate' , ( done ) => { if ( ! apikey ) { done ( ) ; return ; } FileUtil . copy ( MASTER1SRC , MASTER ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , languages : [ 'de' , 'xy' , 'en' ] , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , autotranslate : true , apikey : apikey } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { verbose : true } , profileContent ) ; xliffMergeCmd . run ( ( retcode ) => { expect ( ws . writtenData ( ) ) . toContain ( 'ERROR' ) ; expect ( ws . writtenData ( ) ) . toContain ( '"xy" not supported' ) ; const langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; expect ( langFileEnglish ) . toBeTruthy ( ) ; if ( langFileEnglish ) { expect ( langFileEnglish . targetLanguage ( ) ) . toBe ( 'en' ) ; const tu = langFileEnglish . transUnitWithId ( ID_BESCHREIBUNG_WITH_PLACEHOLDER ) ; expect ( tu . sourceContentNormalized ( ) . asDisplayString ( ) ) . toBe ( 'Beschreibung zu {{0}} ({{1}})' ) ; expect ( tu . targetContentNormalized ( ) . asDisplayString ( ) ) . toBe ( 'Description of {{0}} ({{1}})' ) ; expect ( tu . targetState ( ) ) . toBe ( 'translated' ) ; } const langFileXy = readXliff ( xliffMergeCmd . generatedI18nFile ( 'xy' ) ) ; expect ( langFileXy ) . toBeTruthy ( ) ; if ( langFileXy ) { expect ( langFileXy . targetLanguage ( ) ) . toBe ( 'xy' ) ; const tu = langFileXy . transUnitWithId ( ID_BESCHREIBUNG_WITH_PLACEHOLDER ) ; expect ( tu . sourceContentNormalized ( ) . asDisplayString ( ) ) . toBe ( 'Beschreibung zu {{0}} ({{1}})' ) ; expect ( tu . targetContentNormalized ( ) . asDisplayString ( ) ) . toBe ( 'Beschreibung zu {{0}} ({{1}})' ) ; expect ( tu . targetState ( ) ) . toBe ( 'new' ) ; } done ( ) ; } ) ; } ) ; it ( 'should auto translate text containing linefeeds (originated by #78)' , ( done ) => { if ( ! apikey ) { done ( ) ; return ; } FileUtil . copy ( SRCDIR + 'autotranslateMaster1.xlf' , MASTER ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , autotranslate : true , apikey : apikey } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' , 'en' ] } , profileContent ) ; xliffMergeCmd . run ( ( ) => { expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const langFileEnglish = readXliff ( xliffMergeCmd . generatedI18nFile ( 'en' ) ) ; const tu1 = langFileEnglish . transUnitWithId ( 'totallyEmptyline1' ) ; expect ( tu1 . sourceContent ( ) . trim ( ) ) . toBe ( '' ) ; expect ( tu1 . targetContent ( ) ) . toBe ( '' ) ; expect ( tu1 . targetState ( ) ) . toBe ( 'translated' ) ; const tu2 = langFileEnglish . transUnitWithId ( 'nearlytotallyEmptyline' ) ; expect ( tu2 . sourceContent ( ) ) . toContain ( 'START_BOLD_TEXT' ) ; expect ( tu2 . targetContent ( ) . trim ( ) ) . toEqual ( tu2 . sourceContent ( ) . trim ( ) ) ; expect ( tu2 . targetState ( ) ) . toBe ( 'translated' ) ; const tu3 = langFileEnglish . transUnitWithId ( 'emptylineText' ) ; expect ( tu3 . sourceContent ( ) ) . toContain ( 'Text mit Zeilenumbruch' ) ; expect ( tu3 . targetContent ( ) ) . toBe ( 'Text with line break' ) ; expect ( tu3 . targetState ( ) ) . toBe ( 'translated' ) ; done ( ) ; } ) ; } ) ; it ( 'should auto translate english text to french containing apostrophes (originated by #94)' , ( done ) => { if ( ! apikey ) { done ( ) ; return ; } FileUtil . copy ( SRCDIR + 'englishToFrench.xlf' , MASTER ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'en' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , autotranslate : true , apikey : apikey } } ; const ID_OPERATOR_LOG = '50614ab096d22b3796a4891f21ab7e38b527b72b' ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'en' , 'fr' ] } , profileContent ) ; xliffMergeCmd . run ( ( retcode ) => { expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const langFileFrench = readXliff ( xliffMergeCmd . generatedI18nFile ( 'fr' ) ) ; const tu1 = langFileFrench . transUnitWithId ( ID_OPERATOR_LOG ) ; expect ( tu1 ) . toBeTruthy ( ) ; expect ( tu1 . sourceContent ( ) . trim ( ) ) . toBe ( 'Operator Logs' ) ; expect ( tu1 . targetContent ( ) ) . toBe ( 'Journaux d\'opérateur' ) ; expect ( tu1 . targetState ( ) ) . toBe ( 'translated' ) ; done ( ) ; } ) ; } ) ; } ) ; } ) ; describe ( 'ngx-translate processing for format xlf' , ( ) => { const MASTER1FILE = 'ngxtranslate.xlf' ; const MASTER1SRC = SRCDIR + MASTER1FILE ; const MASTER_WITHOUT_NGX_TRANSLATE_STUFF = SRCDIR + 'ngExtractedMaster1.xlf' ; const MASTERFILE = 'messages.xlf' ; const MASTER = WORKDIR + MASTERFILE ; const ID_NODESC_NOMEANING = 'a8f10794864e49b16224b22faaf4a86229b6c53d' ; const ID_MONDAY = '84e8cd8ba480129d90f512cc3462bb43efcf389f' ; beforeEach ( ( ) => { if ( ! fs . existsSync ( WORKDIR ) ) { fs . mkdirSync ( WORKDIR ) ; } FileUtil . deleteFolderContentRecursive ( WORKDIR ) ; } ) ; it ( 'should return null for unset description and meaning in master  xlf file' , ( done ) => { FileUtil . copy ( MASTER1SRC , MASTER ) ; const master = readXliff ( 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  xlf file' , ( done ) => { FileUtil . copy ( MASTER1SRC , MASTER ) ; const master = readXliff ( 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 xlf file' , ( done ) => { FileUtil . copy ( MASTER1SRC , MASTER ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const langFile = readXliff ( 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 ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , supportNgxTranslate : true } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const translationJsonFilename = xliffMergeCmd . generatedNgxTranslateFile ( 'de' ) ; expect ( FileUtil . exists ( translationJsonFilename ) ) . toBeTruthy ( ) ; const fileContent = FileUtil . read ( translationJsonFilename , 'UTF-8' ) ; const translation = 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 ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , supportNgxTranslate : true } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const translationJsonFilename = xliffMergeCmd . generatedNgxTranslateFile ( 'de' ) ; expect ( FileUtil . exists ( translationJsonFilename ) ) . toBeTruthy ( ) ; const fileContent = FileUtil . read ( translationJsonFilename , 'UTF-8' ) ; const translation = 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 ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , supportNgxTranslate : true } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const translationJsonFilename = xliffMergeCmd . generatedNgxTranslateFile ( 'de' ) ; expect ( FileUtil . exists ( translationJsonFilename ) ) . toBeTruthy ( ) ; const fileContent = FileUtil . read ( translationJsonFilename , 'UTF-8' ) ; const translation = JSON . parse ( fileContent ) ; expect ( translation ) . toBeTruthy ( ) ; expect ( translation . embeddedhtml ) . toBeTruthy ( ) ; expect ( translation . embeddedhtml . bold ) . toBe ( 'Diese Nachricht ist <b>WICHTIG</b>' ) ; expect ( translation . embeddedhtml . boldstrong ) . toBe ( 'Diese Nachricht ist <b><strong>SEHR WICHTIG</strong></b>' ) ; expect ( translation . embeddedhtml . strange ) . toBe ( 'Diese Nachricht ist <strange>{{0}}</strange>' ) ; 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 ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , supportNgxTranslate : true } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const translationJsonFilename = xliffMergeCmd . generatedNgxTranslateFile ( 'de' ) ; expect ( FileUtil . exists ( translationJsonFilename ) ) . toBeFalsy ( ) ; done ( ) ; } ) ; it ( 'should not export @@ids to translation json file, when this is supressed in pattern (issue #62)' , ( done ) => { FileUtil . copy ( MASTER1SRC , MASTER ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , supportNgxTranslate : true , ngxTranslateExtractionPattern : 'ngx-translate' } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const translationJsonFilename = xliffMergeCmd . generatedNgxTranslateFile ( 'de' ) ; expect ( FileUtil . exists ( translationJsonFilename ) ) . toBeTruthy ( ) ; const fileContent = FileUtil . read ( translationJsonFilename , 'UTF-8' ) ; const translation = JSON . parse ( fileContent ) ; expect ( translation ) . toBeTruthy ( ) ; expect ( translation . dateservice . monday ) . toBe ( 'Montag' ) ; expect ( translation . explicitlysetids ) . toBeFalsy ( ) ; expect ( translation [ 'alt-ngx-translate' ] ) . toBeFalsy ( ) ; done ( ) ; } ) ; it ( 'should export other then ngx-translate description marked entries to translation json file,' + 'when this is specified in pattern (issue #62)' , ( done ) => { FileUtil . copy ( MASTER1SRC , MASTER ) ; const ws = new WriterToString ( ) ; const commandOut = new CommandOutput ( ws ) ; const profileContent = { xliffmergeOptions : { defaultLanguage : 'de' , srcDir : WORKDIR , genDir : WORKDIR , i18nFile : MASTERFILE , supportNgxTranslate : true , ngxTranslateExtractionPattern : 'ngx-translate|alt-ngx-translate' } } ; const xliffMergeCmd = XliffMerge . createFromOptions ( commandOut , { languages : [ 'de' ] } , profileContent ) ; xliffMergeCmd . run ( ) ; expect ( ws . writtenData ( ) ) . not . toContain ( 'ERROR' ) ; const translationJsonFilename = xliffMergeCmd . generatedNgxTranslateFile ( 'de' ) ; expect ( FileUtil . exists ( translationJsonFilename ) ) . toBeTruthy ( ) ; const fileContent = FileUtil . read ( translationJsonFilename , 'UTF-8' ) ; const translation = JSON . parse ( fileContent ) ; expect ( translation ) . toBeTruthy ( ) ; expect ( translation . dateservice . monday ) . toBe ( 'Montag' ) ; expect ( translation . explicitlysetids ) . toBeFalsy ( ) ; expect ( translation [ 'alt-ngx-translate' ] . example1 ) . toBe ( 'Alternate description for ngx-translate export' ) ; done ( ) ; } ) ; } ) ; } ) ;