message-accumulator
Advanced tools
Comparing version 2.0.2 to 2.1.0
@@ -21,7 +21,8 @@ 'use strict';Object.defineProperty(exports,'__esModule',{value:true});var _createClass=function(){function defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if('value'in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor)}}return function(Constructor,protoProps,staticProps){if(protoProps)defineProperties(Constructor.prototype,protoProps);if(staticProps)defineProperties(Constructor,staticProps);return Constructor}}();/** | ||
var whiteSpaceStart=/^[\t-\r \xA0\u1680\u2000-\u200D\u2028\u2029\u202F\u205F\u2060\u3000\uFEFF]+/;var whiteSpaceEnd=/[\t-\r \xA0\u1680\u2000-\u200D\u2028\u2029\u202F\u205F\u2060\u3000\uFEFF]+$/;var whiteSpace=/[\t-\r \xA0\u1680\u2000-\u200D\u2028\u2029\u202F\u205F\u2060\u3000\uFEFF]+/g;// use [\s\S]*? instead of .* with the "s" flag because node 6 and earlier throw errors about the unknown "s" flag | ||
var re=/(<(c\d+)>[\s\S]*?<\/\2>)/g;var first=/^<c(\d+)>/;var selfclosing=/(<c(\d+)\/>)/g;/** | ||
var re=/(<(c\d+)>[\s\S]*?<\/\2>)/g;var first=/^<c(\d+)>/;var selfclosing=/(<([cp](\d+))\/>)/g;// "c" for component, "p" for parameter | ||
/** | ||
* MessageAccumulator.js - accumulate a translatable message as a string | ||
*/var MessageAccumulator=function(){/** | ||
* Create a new accumulator instance. | ||
*/function MessageAccumulator(){_classCallCheck(this,MessageAccumulator);this.root=new _ilibTreeNode2.default({type:'root',parent:null,index:-1});this.currentLevel=this.root;this.componentIndex=0;this.text='';this.mapping={}}/** | ||
*/function MessageAccumulator(){_classCallCheck(this,MessageAccumulator);this.root=new _ilibTreeNode2.default({type:'root',parent:null,index:-1});this.currentLevel=this.root;this.componentIndex=0;this.paramIndex=0;this.text='';this.mapping={}}/** | ||
* Factory method to create a new MessageAccumulator instance from | ||
@@ -31,3 +32,4 @@ * the given string and a source message accumulator. This will | ||
* then attach the "extra" information from the source accumulator | ||
* to the equivalent nodes in the new accumulator. | ||
* to the equivalent nodes in the new accumulator. This includes | ||
* the source information for components and replacement parameters. | ||
* | ||
@@ -43,3 +45,3 @@ * @param {String} translated the translated string to parse | ||
var substr=parts[i].substring(len,parts[i].length-len-1);var component=new _ilibTreeNode2.default({type:'component',parent:parent,index:index,extra:mapping&&mapping['c'+index]});this._parse(substr,mapping,component);parent.add(component);i++;// skip the number in the next iteration | ||
}else if(parts[i]&&parts[i].length){var subparts=parts[i].split(selfclosing);for(var j=0;j<subparts.length;j++){selfclosing.lastIndex=0;if((match=selfclosing.exec(subparts[j]))!==null){var _index=match[2];parent.add(new _ilibTreeNode2.default({type:'component',parent:parent,index:_index,extra:mapping&&mapping['c'+_index]}));j++;// skip the number in the next iteration | ||
}else if(parts[i]&&parts[i].length){var subparts=parts[i].split(selfclosing);for(var j=0;j<subparts.length;j++){selfclosing.lastIndex=0;if((match=selfclosing.exec(subparts[j]))!==null){var _index=match[3];parent.add(new _ilibTreeNode2.default({type:match[2][0]==='p'?'param':'component',parent:parent,index:_index,extra:mapping&&mapping[match[2]]}));j+=2;// skip the other parts of the match in the next iteration | ||
}else if(subparts[j]&&subparts[j].length){// don't store empty strings | ||
@@ -50,4 +52,46 @@ parent.add(new _ilibTreeNode2.default({type:'text',value:subparts[j]}))}}}}}/** | ||
*/},{key:'addText',value:function addText(text){if(typeof text==='string'){this.currentLevel.add(new _ilibTreeNode2.default({type:'text',value:text}))}this.text+=text}/** | ||
* Add a replacement parameter to the string. This is a coding | ||
* for a replacement parameter in the programming language | ||
* or i18n library that does substitutions. By coding the replacement | ||
* parameters instead of leaving them in as-is, the strings are | ||
* normalized.<p> | ||
* | ||
* This has two advantages. First, translations for strings | ||
* with the same text but different replacement parameter styles | ||
* can be shared across i18n libraries. For | ||
* example, some libraries use "C" style parameters like "%1s" | ||
* and others use named parameters like "{name}". That means | ||
* the translation of "User %1s logged in." and of "User {name} | ||
* logged in." should have the exact same translation.<p> | ||
* | ||
* Second, the parameters can be numbered automatically so that | ||
* the translator has the freedom to re-arrange the parameters | ||
* in a string with multiple parameters as required by the | ||
* grammar of the target language. For some parameter styles | ||
* that use numbered parameters instead of named ones, the | ||
* caller may need to amend original parameter to insert the | ||
* number if the original code did not have it already. That | ||
* is bad style anyways and you should strongly discourage your | ||
* engineers from writing strings with multiple replacement | ||
* parameters that are unnumbered.<p> | ||
* | ||
* Parameters appear in the composed string as XML tags that | ||
* are distinct from the component tags. When creating a | ||
* translated string, the parameters are substituted back | ||
* into the string. | ||
* | ||
* @param {Object} extra extra information that the caller can | ||
* use to identify the original replacement parameter | ||
*/},{key:'addParam',value:function addParam(extra){var index=this.paramIndex++;this.currentLevel.add(new _ilibTreeNode2.default({type:'param',index:index,extra:extra,closed:true}));var contents='p'+index;this.text+='<'+contents+'/>';this.mapping[contents]=extra}/** | ||
* Create a new subcontext for a component such that all text | ||
* added to the accumulator goes into the new context. | ||
* added to the accumulator goes into the new context.<p> | ||
* | ||
* A component is represented in the composed string as an | ||
* XML tag that is numbered according to the order of the | ||
* components in the string. This class maintains a mapping | ||
* between the component number and the given "extra" | ||
* information so that this can be used to create a translated | ||
* accumulator with the same extra info. (See the | ||
* MessageAccumulator.create static function.) | ||
* | ||
* @param {Object} extra extra information that the caller would | ||
@@ -68,7 +112,8 @@ * like to associate with the component. For example, this may | ||
*/},{key:'_getString',value:function _getString(rootnode){if(rootnode.children.length===0){return rootnode.value||''}return rootnode.children.map(function(child){return child.toArray().map(function(node){if(node.type==='component'){if(node.index>-1){if(node.use==='start'){return'<c'+node.index+'>'}else if(node.use==='end'){return'</c'+node.index+'>'}else{// self-closing | ||
return'<c'+node.index+'/>'}}}else{return node.value}}).join('')}).join('')}/** | ||
return'<c'+node.index+'/>'}}}else if(node.type==='param'){// self-closing | ||
return'<p'+node.index+'/>'}else{return node.value}}).join('')}).join('')}/** | ||
* @private | ||
*/},{key:'_isEmpty',value:function _isEmpty(node){var _this=this;whiteSpace.lastIndex=0;if(node.type==='text'&&node.value.replace(whiteSpace,'')!=='')return false;if(node.type==='component'&&node.children&&node.children.length){return node.children.every(function(child){return _this._isEmpty(child)})}return true}/** | ||
*/},{key:'_isEmpty',value:function _isEmpty(node){var _this=this;whiteSpace.lastIndex=0;if(node.type==='param')return false;if(node.type==='text'&&node.value.replace(whiteSpace,'')!=='')return false;if(node.type==='component'&&node.children&&node.children.length){return node.children.every(function(child){return _this._isEmpty(child)})}return true}/** | ||
* @private | ||
*/},{key:'_renumber',value:function _renumber(node){var _this2=this;if(node.type==='component'){node.index=this.componentIndex++;this.mapping['c'+node.index]=node.extra}if(node.children){node.children.forEach(function(child){_this2._renumber(child)})}}/** | ||
*/},{key:'_renumber',value:function _renumber(node){var _this2=this;if(node.type==='component'){node.index=this.componentIndex++;this.mapping['c'+node.index]=node.extra}else if(node.type==='param'){this.mapping['p'+node.index]=node.extra}if(node.children){node.children.forEach(function(child){_this2._renumber(child)})}}/** | ||
* @private | ||
@@ -158,2 +203,12 @@ */},{key:'_minimize',value:function _minimize(){if(this.minimized)return;var value,changed=true;if(!this.prefixes)this.prefixes=[];if(!this.suffixes)this.suffixes=[];// keep stripping off parts until we haven't changed anything, or we have stripped off everything | ||
*/},{key:'getExtra',value:function getExtra(componentNumber){return this.mapping['c'+componentNumber]}/** | ||
* Return the mapping between a replacement parameter | ||
* and the "extra" information used when creating those | ||
* components. | ||
* | ||
* @param {number} paramNumber the number of the | ||
* parameter for which the "extra" information is | ||
* being sought | ||
* @returns {Object} the "extra" information that was | ||
* given when the parameter was created | ||
*/},{key:'getParam',value:function getParam(paramNumber){return this.mapping['p'+paramNumber]}/** | ||
* Return the mappings between component names and | ||
@@ -160,0 +215,0 @@ * their "extra" information they represent. |
@@ -31,3 +31,3 @@ /** | ||
let first = /^<c(\d+)>/; | ||
let selfclosing = /(<c(\d+)\/>)/g; | ||
let selfclosing = /(<([cp](\d+))\/>)/g; // "c" for component, "p" for parameter | ||
@@ -49,2 +49,3 @@ /** | ||
this.componentIndex = 0; | ||
this.paramIndex = 0; | ||
this.text = ''; | ||
@@ -59,3 +60,4 @@ this.mapping = {}; | ||
* then attach the "extra" information from the source accumulator | ||
* to the equivalent nodes in the new accumulator. | ||
* to the equivalent nodes in the new accumulator. This includes | ||
* the source information for components and replacement parameters. | ||
* | ||
@@ -108,10 +110,10 @@ * @param {String} translated the translated string to parse | ||
if ((match = selfclosing.exec(subparts[j])) !== null) { | ||
const index = match[2]; | ||
const index = match[3]; | ||
parent.add(new Node({ | ||
type: 'component', | ||
type: match[2][0] === "p" ? 'param' : 'component', | ||
parent, | ||
index, | ||
extra: mapping && mapping[`c${index}`] | ||
extra: mapping && mapping[match[2]] | ||
})); | ||
j++; // skip the number in the next iteration | ||
j += 2; // skip the other parts of the match in the next iteration | ||
} else if (subparts[j] && subparts[j].length) { | ||
@@ -144,4 +146,60 @@ // don't store empty strings | ||
/** | ||
* Add a replacement parameter to the string. This is a coding | ||
* for a replacement parameter in the programming language | ||
* or i18n library that does substitutions. By coding the replacement | ||
* parameters instead of leaving them in as-is, the strings are | ||
* normalized.<p> | ||
* | ||
* This has two advantages. First, translations for strings | ||
* with the same text but different replacement parameter styles | ||
* can be shared across i18n libraries. For | ||
* example, some libraries use "C" style parameters like "%1s" | ||
* and others use named parameters like "{name}". That means | ||
* the translation of "User %1s logged in." and of "User {name} | ||
* logged in." should have the exact same translation.<p> | ||
* | ||
* Second, the parameters can be numbered automatically so that | ||
* the translator has the freedom to re-arrange the parameters | ||
* in a string with multiple parameters as required by the | ||
* grammar of the target language. For some parameter styles | ||
* that use numbered parameters instead of named ones, the | ||
* caller may need to amend original parameter to insert the | ||
* number if the original code did not have it already. That | ||
* is bad style anyways and you should strongly discourage your | ||
* engineers from writing strings with multiple replacement | ||
* parameters that are unnumbered.<p> | ||
* | ||
* Parameters appear in the composed string as XML tags that | ||
* are distinct from the component tags. When creating a | ||
* translated string, the parameters are substituted back | ||
* into the string. | ||
* | ||
* @param {Object} extra extra information that the caller can | ||
* use to identify the original replacement parameter | ||
*/ | ||
addParam(extra) { | ||
let index = this.paramIndex++; | ||
this.currentLevel.add(new Node({ | ||
type: 'param', | ||
index, | ||
extra, | ||
closed: true | ||
})); | ||
let contents = `p${index}`; | ||
this.text += `<${contents}/>`; | ||
this.mapping[contents] = extra; | ||
} | ||
/** | ||
* Create a new subcontext for a component such that all text | ||
* added to the accumulator goes into the new context. | ||
* added to the accumulator goes into the new context.<p> | ||
* | ||
* A component is represented in the composed string as an | ||
* XML tag that is numbered according to the order of the | ||
* components in the string. This class maintains a mapping | ||
* between the component number and the given "extra" | ||
* information so that this can be used to create a translated | ||
* accumulator with the same extra info. (See the | ||
* MessageAccumulator.create static function.) | ||
* | ||
* @param {Object} extra extra information that the caller would | ||
@@ -158,3 +216,2 @@ * like to associate with the component. For example, this may | ||
closed: false | ||
}); | ||
@@ -206,2 +263,5 @@ this.currentLevel.add(newNode); | ||
} | ||
} else if (node.type === "param") { | ||
// self-closing | ||
return `<p${node.index}/>`; | ||
} else { | ||
@@ -219,2 +279,3 @@ return node.value; | ||
whiteSpace.lastIndex = 0; | ||
if (node.type === "param") return false; | ||
if (node.type === "text" && node.value.replace(whiteSpace, '') !== "") return false; | ||
@@ -236,2 +297,4 @@ if (node.type === "component" && node.children && node.children.length) { | ||
this.mapping[`c${node.index}`] = node.extra; | ||
} else if (node.type === "param") { | ||
this.mapping[`p${node.index}`] = node.extra; | ||
} | ||
@@ -457,2 +520,17 @@ if (node.children) { | ||
/** | ||
* Return the mapping between a replacement parameter | ||
* and the "extra" information used when creating those | ||
* components. | ||
* | ||
* @param {number} paramNumber the number of the | ||
* parameter for which the "extra" information is | ||
* being sought | ||
* @returns {Object} the "extra" information that was | ||
* given when the parameter was created | ||
*/ | ||
getParam(paramNumber) { | ||
return this.mapping[`p${paramNumber}`]; | ||
} | ||
/** | ||
* Return the mappings between component names and | ||
@@ -459,0 +537,0 @@ * their "extra" information they represent. |
{ | ||
"name": "message-accumulator", | ||
"version": "2.0.2", | ||
"version": "2.1.0", | ||
"main": "./message-accumulator-es5.js", | ||
@@ -5,0 +5,0 @@ "main-es6": "./message-accumulator.js", |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
88124
723