UNPKG

ngx-i18nsupport-lib

Version:

A Typescript library to work with Angular generated i18n files (xliff, xmb)

392 lines 17.6 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); Object.defineProperty(exports, "__esModule", { value: true }); var api_1 = require("../api"); var dom_utilities_1 = require("./dom-utilities"); var abstract_trans_unit_1 = require("./abstract-trans-unit"); var xliff2_message_parser_1 = require("./xliff2-message-parser"); var util_1 = require("util"); /** * Created by martin on 04.05.2017. * A Translation Unit in an XLIFF 2.0 file. */ var Xliff2TransUnit = /** @class */ (function (_super) { __extends(Xliff2TransUnit, _super); function Xliff2TransUnit(_element, _id, _translationMessagesFile) { return _super.call(this, _element, _id, _translationMessagesFile) || this; } Xliff2TransUnit.prototype.sourceContent = function () { var sourceElement = dom_utilities_1.DOMUtilities.getFirstElementByTagName(this._element, 'source'); return dom_utilities_1.DOMUtilities.getXMLContent(sourceElement); }; /** * Set new source content in the transunit. * Normally, this is done by ng-extract. * Method only exists to allow xliffmerge to merge missing changed source content. * @param newContent the new content. */ Xliff2TransUnit.prototype.setSourceContent = function (newContent) { var source = dom_utilities_1.DOMUtilities.getFirstElementByTagName(this._element, 'source'); if (!source) { // should not happen, there always has to be a source, but who knows.. var segment = dom_utilities_1.DOMUtilities.getFirstElementByTagName(this._element, 'segment'); source = segment.parentNode.appendChild(this._element.ownerDocument.createElement('source')); } dom_utilities_1.DOMUtilities.replaceContentWithXMLContent(source, newContent); }; /** * Return a parser used for normalized messages. */ Xliff2TransUnit.prototype.messageParser = function () { return new xliff2_message_parser_1.Xliff2MessageParser(); }; /** * The original text value, that is to be translated, as normalized message. */ Xliff2TransUnit.prototype.createSourceContentNormalized = function () { var sourceElement = dom_utilities_1.DOMUtilities.getFirstElementByTagName(this._element, 'source'); if (sourceElement) { return this.messageParser().createNormalizedMessageFromXML(sourceElement, null); } else { return null; } }; /** * the translated value (containing all markup, depends on the concrete format used). */ Xliff2TransUnit.prototype.targetContent = function () { var targetElement = dom_utilities_1.DOMUtilities.getFirstElementByTagName(this._element, 'target'); return dom_utilities_1.DOMUtilities.getXMLContent(targetElement); }; /** * the translated value, but all placeholders are replaced with {{n}} (starting at 0) * and all embedded html is replaced by direct html markup. */ Xliff2TransUnit.prototype.targetContentNormalized = function () { var targetElement = dom_utilities_1.DOMUtilities.getFirstElementByTagName(this._element, 'target'); return new xliff2_message_parser_1.Xliff2MessageParser().createNormalizedMessageFromXML(targetElement, this.sourceContentNormalized()); }; /** * State of the translation as stored in the xml. */ Xliff2TransUnit.prototype.nativeTargetState = function () { var segmentElement = dom_utilities_1.DOMUtilities.getFirstElementByTagName(this._element, 'segment'); if (segmentElement) { return segmentElement.getAttribute('state'); } else { return null; } }; /** * set state in xml. * @param nativeState */ Xliff2TransUnit.prototype.setNativeTargetState = function (nativeState) { var segmentElement = dom_utilities_1.DOMUtilities.getFirstElementByTagName(this._element, 'segment'); if (segmentElement) { segmentElement.setAttribute('state', nativeState); } }; /** * Map an abstract state (new, translated, final) to a concrete state used in the xml. * Returns the state to be used in the xml. * @param state one of Constants.STATE... * @returns a native state (depends on concrete format) * @throws error, if state is invalid. */ Xliff2TransUnit.prototype.mapStateToNativeState = function (state) { switch (state) { case api_1.STATE_NEW: return 'initial'; case api_1.STATE_TRANSLATED: return 'translated'; case api_1.STATE_FINAL: return 'final'; default: throw new Error('unknown state ' + state); } }; /** * Map a native state (found in the document) to an abstract state (new, translated, final). * Returns the abstract state. * @param nativeState */ Xliff2TransUnit.prototype.mapNativeStateToState = function (nativeState) { switch (nativeState) { case 'initial': return api_1.STATE_NEW; case 'translated': return api_1.STATE_TRANSLATED; case 'reviewed': // same as translated return api_1.STATE_TRANSLATED; case 'final': return api_1.STATE_FINAL; default: return api_1.STATE_NEW; } }; /** * All the source elements in the trans unit. * The source element is a reference to the original template. * It contains the name of the template file and a line number with the position inside the template. * It is just a help for translators to find the context for the translation. * This is set when using Angular 4.0 or greater. * Otherwise it just returns an empty array. */ Xliff2TransUnit.prototype.sourceReferences = function () { // Source is found as <file>:<line> in <note category="location">... var noteElements = this._element.getElementsByTagName('note'); var sourceRefs = []; for (var i = 0; i < noteElements.length; i++) { var noteElem = noteElements.item(i); if (noteElem.getAttribute('category') === 'location') { var sourceAndPos = dom_utilities_1.DOMUtilities.getPCDATA(noteElem); sourceRefs.push(this.parseSourceAndPos(sourceAndPos)); } } return sourceRefs; }; /** * Parses something like 'c:\xxx:7' and returns source and linenumber. * @param sourceAndPos something like 'c:\xxx:7', last colon is the separator * @return {{sourcefile: string, linenumber: number}} */ Xliff2TransUnit.prototype.parseSourceAndPos = function (sourceAndPos) { var index = sourceAndPos.lastIndexOf(':'); if (index < 0) { return { sourcefile: sourceAndPos, linenumber: 0 }; } else { return { sourcefile: sourceAndPos.substring(0, index), linenumber: this.parseLineNumber(sourceAndPos.substring(index + 1)) }; } }; Xliff2TransUnit.prototype.parseLineNumber = function (lineNumberString) { return Number.parseInt(lineNumberString); }; /** * Set source ref elements in the transunit. * Normally, this is done by ng-extract. * Method only exists to allow xliffmerge to merge missing source refs. * @param sourceRefs the sourcerefs to set. Old ones are removed. */ Xliff2TransUnit.prototype.setSourceReferences = function (sourceRefs) { var _this = this; this.removeAllSourceReferences(); var notesElement = dom_utilities_1.DOMUtilities.getFirstElementByTagName(this._element, 'notes'); if (sourceRefs.length === 0 && !util_1.isNullOrUndefined(notesElement) && notesElement.childNodes.length === 0) { // remove empty notes element notesElement.parentNode.removeChild(notesElement); return; } if (util_1.isNullOrUndefined(notesElement)) { notesElement = this._element.ownerDocument.createElement('notes'); this._element.insertBefore(notesElement, this._element.childNodes.item(0)); } sourceRefs.forEach(function (ref) { var note = _this._element.ownerDocument.createElement('note'); note.setAttribute('category', 'location'); note.appendChild(_this._element.ownerDocument.createTextNode(ref.sourcefile + ':' + ref.linenumber.toString(10))); notesElement.appendChild(note); }); }; Xliff2TransUnit.prototype.removeAllSourceReferences = function () { var noteElements = this._element.getElementsByTagName('note'); var toBeRemoved = []; for (var i = 0; i < noteElements.length; i++) { var elem = noteElements.item(i); if (elem.getAttribute('category') === 'location') { toBeRemoved.push(elem); } } toBeRemoved.forEach(function (elem) { elem.parentNode.removeChild(elem); }); }; /** * The description set in the template as value of the i18n-attribute. * e.g. i18n="mydescription". * In xliff 2.0 this is stored as a note element with attribute category="description". */ Xliff2TransUnit.prototype.description = function () { var noteElem = this.findNoteElementWithCategoryAttribute('description'); if (noteElem) { return dom_utilities_1.DOMUtilities.getPCDATA(noteElem); } else { return null; } }; /** * Change description property of trans-unit. * @param {string} description */ Xliff2TransUnit.prototype.setDescription = function (description) { var noteElem = this.findNoteElementWithCategoryAttribute('description'); if (description) { if (util_1.isNullOrUndefined(noteElem)) { // create it noteElem = this.createNoteElementWithCategoryAttribute('description'); } dom_utilities_1.DOMUtilities.replaceContentWithXMLContent(noteElem, description); } else { if (!util_1.isNullOrUndefined(noteElem)) { // remove node this.removeNoteElementWithCategoryAttribute('description'); } } }; /** * Find a note element with attribute from='<attrValue>' * @param {string} attrValue * @return {Element} element or null is absent */ Xliff2TransUnit.prototype.findNoteElementWithCategoryAttribute = function (attrValue) { var noteElements = this._element.getElementsByTagName('note'); for (var i = 0; i < noteElements.length; i++) { var noteElem = noteElements.item(i); if (noteElem.getAttribute('category') === attrValue) { return noteElem; } } return null; }; /** * Create a new note element with attribute from='<attrValue>' * @param {string} attrValue * @return the new created element */ Xliff2TransUnit.prototype.createNoteElementWithCategoryAttribute = function (attrValue) { var notesElement = dom_utilities_1.DOMUtilities.getFirstElementByTagName(this._element, 'notes'); if (util_1.isNullOrUndefined(notesElement)) { // create it notesElement = this._element.ownerDocument.createElement('notes'); this._element.appendChild(notesElement); } var noteElement = this._element.ownerDocument.createElement('note'); noteElement.setAttribute('category', attrValue); notesElement.appendChild(noteElement); return noteElement; }; /** * Remove note element with attribute from='<attrValue>' * @param {string} attrValue */ Xliff2TransUnit.prototype.removeNoteElementWithCategoryAttribute = function (attrValue) { var noteElement = this.findNoteElementWithCategoryAttribute(attrValue); if (noteElement) { this._element.removeChild(noteElement); } }; /** * 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 2.0 this is stored as a note element with attribute category="meaning". */ Xliff2TransUnit.prototype.meaning = function () { var noteElem = this.findNoteElementWithCategoryAttribute('meaning'); if (noteElem) { return dom_utilities_1.DOMUtilities.getPCDATA(noteElem); } else { return null; } }; /** * Change meaning property of trans-unit. * @param {string} meaning */ Xliff2TransUnit.prototype.setMeaning = function (meaning) { var noteElem = this.findNoteElementWithCategoryAttribute('meaning'); if (meaning) { if (util_1.isNullOrUndefined(noteElem)) { // create it noteElem = this.createNoteElementWithCategoryAttribute('meaning'); } dom_utilities_1.DOMUtilities.replaceContentWithXMLContent(noteElem, meaning); } else { if (!util_1.isNullOrUndefined(noteElem)) { // remove node this.removeNoteElementWithCategoryAttribute('meaning'); } } }; /** * Set the translation to a given string (including markup). * @param translation */ Xliff2TransUnit.prototype.translateNative = function (translation) { var target = dom_utilities_1.DOMUtilities.getFirstElementByTagName(this._element, 'target'); if (!target) { var source = dom_utilities_1.DOMUtilities.getFirstElementByTagName(this._element, 'source'); target = source.parentNode.appendChild(this._element.ownerDocument.createElement('target')); } dom_utilities_1.DOMUtilities.replaceContentWithXMLContent(target, translation); this.setTargetState(api_1.STATE_TRANSLATED); }; /** * Copy source to target to use it as dummy translation. * Returns a changed copy of this trans unit. * receiver is not changed. * (internal usage only, a client should call importNewTransUnit on ITranslationMessageFile) */ Xliff2TransUnit.prototype.cloneWithSourceAsTarget = function (isDefaultLang, copyContent, targetFile) { var element = this._element.cloneNode(true); var clone = new Xliff2TransUnit(element, this._id, targetFile); clone.useSourceAsTarget(isDefaultLang, copyContent); return clone; }; /** * Copy source to target to use it as dummy translation. * (internal usage only, a client should call createTranslationFileForLang on ITranslationMessageFile) */ Xliff2TransUnit.prototype.useSourceAsTarget = function (isDefaultLang, copyContent) { var source = dom_utilities_1.DOMUtilities.getFirstElementByTagName(this._element, 'source'); var target = dom_utilities_1.DOMUtilities.getFirstElementByTagName(this._element, 'target'); if (!target) { target = source.parentNode.appendChild(this._element.ownerDocument.createElement('target')); } if (isDefaultLang || copyContent) { var sourceString = dom_utilities_1.DOMUtilities.getXMLContent(source); var newTargetString = sourceString; if (!this.isICUMessage(sourceString)) { newTargetString = this.translationMessagesFile().getNewTransUnitTargetPraefix() + sourceString + this.translationMessagesFile().getNewTransUnitTargetSuffix(); } dom_utilities_1.DOMUtilities.replaceContentWithXMLContent(target, newTargetString); } else { dom_utilities_1.DOMUtilities.replaceContentWithXMLContent(target, ''); } var segment = dom_utilities_1.DOMUtilities.getFirstElementByTagName(this._element, 'segment'); if (segment) { if (isDefaultLang) { segment.setAttribute('state', this.mapStateToNativeState(api_1.STATE_FINAL)); } else { segment.setAttribute('state', this.mapStateToNativeState(api_1.STATE_NEW)); } } }; return Xliff2TransUnit; }(abstract_trans_unit_1.AbstractTransUnit)); exports.Xliff2TransUnit = Xliff2TransUnit; //# sourceMappingURL=S:/experimente/ngx-i18nsupport-lib/src/impl/xliff2-trans-unit.js.map