diff --git a/src/compilers/po.compiler.ts b/src/compilers/po.compiler.ts index 6aa42eb5..e1ab4917 100644 --- a/src/compilers/po.compiler.ts +++ b/src/compilers/po.compiler.ts @@ -24,9 +24,16 @@ export class PoCompiler implements CompilerInterface { }, translations: { [this.domain]: Object.keys(collection.values).reduce((translations, key) => { + const keyParts = key.split('$$context$$'); + const value = collection.get(key); translations[key] = { - msgid: key, - msgstr: collection.get(key) + msgctxt: keyParts.length > 1 ? keyParts[1] : undefined, + msgid: keyParts[0], + msgstr: value.text, + comments: { + translator: value.comment, + reference: value.reference + } }; return translations; }, {}) diff --git a/src/parsers/directive.parser.ts b/src/parsers/directive.parser.ts index d61da53c..b04fa5db 100644 --- a/src/parsers/directive.parser.ts +++ b/src/parsers/directive.parser.ts @@ -13,10 +13,10 @@ export class DirectiveParser extends AbstractTemplateParser implements ParserInt contents = this._extractInlineTemplate(contents); } - return this._parseTemplate(contents); + return this._parseTemplate(contents, path); } - protected _parseTemplate(template: string): TranslationCollection { + protected _parseTemplate(template: string, path?: string): TranslationCollection { let collection: TranslationCollection = new TranslationCollection(); template = this._normalizeTemplateAttributes(template); @@ -28,9 +28,12 @@ export class DirectiveParser extends AbstractTemplateParser implements ParserInt .each((i: number, element: CheerioElement) => { const $element = $(element); const attr = $element.attr('translate') || $element.attr('ng2-translate'); + const context = $element.attr('translate-context'); + const comment = $element.attr('translate-comment'); + const reference = path; if (attr) { - collection = collection.add(attr); + collection = collection.add(attr, null, {context, comment, reference}); } else { $element .contents() @@ -38,10 +41,9 @@ export class DirectiveParser extends AbstractTemplateParser implements ParserInt .filter(node => node.type === 'text') .map(node => node.nodeValue.trim()) .filter(text => text.length > 0) - .forEach(text => collection = collection.add(text)); + .forEach(text => collection = collection.add(text, null, {context, comment, reference})); } }); - return collection; } diff --git a/src/parsers/pipe.parser.ts b/src/parsers/pipe.parser.ts index 604f6fce..910b2e6f 100644 --- a/src/parsers/pipe.parser.ts +++ b/src/parsers/pipe.parser.ts @@ -9,16 +9,16 @@ export class PipeParser extends AbstractTemplateParser implements ParserInterfac contents = this._extractInlineTemplate(contents); } - return this._parseTemplate(contents); + return this._parseTemplate(contents, path); } - protected _parseTemplate(template: string): TranslationCollection { + protected _parseTemplate(template: string, path?: string): TranslationCollection { let collection: TranslationCollection = new TranslationCollection(); const regExp: RegExp = /(['"`])((?:(?!\1).|\\\1)+)\1\s*\|\s*translate/g; let matches: RegExpExecArray; while (matches = regExp.exec(template)) { - collection = collection.add(matches[2].split('\\\'').join('\'')); + collection = collection.add(matches[2].split('\\\'').join('\''), null, {reference: path}); } return collection; diff --git a/src/utils/translation.collection.ts b/src/utils/translation.collection.ts index e650a2cb..a9d17cc9 100644 --- a/src/utils/translation.collection.ts +++ b/src/utils/translation.collection.ts @@ -1,5 +1,11 @@ export interface TranslationType { - [key: string]: string + [key: string]: any +} + +export interface ValueData { + context?: string, + comment?: string, + reference?: string } export class TranslationCollection { @@ -10,8 +16,20 @@ export class TranslationCollection { this.values = values; } - public add(key: string, val: string = ''): TranslationCollection { - return new TranslationCollection(Object.assign({}, this.values, { [key]: val })); + public add(key: string, val: string = '', additionalValueData?: ValueData): TranslationCollection { + if (additionalValueData && additionalValueData.context) { + key = `${key}$$context$$${additionalValueData.context}`; + } + let value: any = { + text: val, + }; + if (additionalValueData && additionalValueData.comment) { + value.comment = additionalValueData.comment; + } + if (additionalValueData && additionalValueData.reference) { + value.reference = additionalValueData.reference; + } + return new TranslationCollection(Object.assign({}, this.values, { [key]: value })); } public addKeys(keys: string[]): TranslationCollection { @@ -59,7 +77,7 @@ export class TranslationCollection { return this.values.hasOwnProperty(key); } - public get(key: string): string { + public get(key: string): any { return this.values[key]; } diff --git a/tests/parsers/directive.parser.spec.ts b/tests/parsers/directive.parser.spec.ts index c1050f41..10463881 100644 --- a/tests/parsers/directive.parser.spec.ts +++ b/tests/parsers/directive.parser.spec.ts @@ -39,6 +39,13 @@ describe('DirectiveParser', () => { expect(keys).to.deep.equal(['KEY']); }); + it('should extract context and comment', () => { + const contents = '
Title
'; + const value = parser.extract(contents, templateFilename).values; + expect(value).to.have.property('Title$$context$$VERB'); + expect(value['Title$$context$$VERB']).to.have.property('comment'); + }); + it('should extract direct text nodes when no translate attribute value is provided', () => { const contents = `
diff --git a/tests/utils/translation.collection.spec.ts b/tests/utils/translation.collection.spec.ts index 1d983122..04a1e77c 100644 --- a/tests/utils/translation.collection.spec.ts +++ b/tests/utils/translation.collection.spec.ts @@ -17,12 +17,29 @@ describe('StringCollection', () => { it('should add key with value', () => { const newCollection = collection.add('theKey', 'theVal'); - expect(newCollection.get('theKey')).to.equal('theVal'); + expect(newCollection.get('theKey').text).to.equal('theVal'); }); it('should add key with default value', () => { collection = collection.add('theKey'); - expect(collection.get('theKey')).to.equal(''); + expect(collection.get('theKey').text).to.equal(''); + }); + + it('should add key with context', () => { + const newCollection = collection.add('theKey', null, {context: 'VERB'}); + expect(newCollection.keys()[0]).to.equal('theKey$$context$$VERB'); + }); + + it('should add key with comment', () => { + const newCollection = collection.add('theKey', null, {comment: 'This is a new key'}); + expect(newCollection.get('theKey')).to.have.property('comment'); + expect(newCollection.get('theKey').comment).to.equal('This is a new key'); + }); + + it('should add key with reference', () => { + const newCollection = collection.add('theKey', null, {reference: '/path/file/name'}); + expect(newCollection.get('theKey')).to.have.property('reference'); + expect(newCollection.get('theKey').reference).to.equal('/path/file/name'); }); it('should not mutate collection when adding key', () => { @@ -63,8 +80,8 @@ describe('StringCollection', () => { it('should merge with other collection', () => { collection = collection.add('oldKey', 'oldVal'); - const newCollection = new TranslationCollection({ newKey: 'newVal' }); - expect(collection.union(newCollection).values).to.deep.equal({ oldKey: 'oldVal', newKey: 'newVal' }); + const newCollection = new TranslationCollection({ newKey: {text: 'newVal'} }); + expect(collection.union(newCollection).values).to.deep.equal({ oldKey: {text: 'oldVal'}, newKey: {text: 'newVal'} }); }); it('should intersect with passed collection', () => {