diff --git a/README.md b/README.md index f0ef401..5fe104f 100644 --- a/README.md +++ b/README.md @@ -219,6 +219,8 @@ static-i18n --attr-selector my-attr-t ... } } ``` +* `interpolationPrefix` (default: `{{`): Override the default interpolation prefix +* `interpolationSuffix` (default: `}}`): Override the default interpolation suffix * `i18n`: Object passed directly to [`i18next.init`](http://i18next.com/pages/doc_init.html). This allows you to override pretty much anything. Read [i18next](http://i18next.com/) doc for more info. When using the CLI, `outputOverride` and `i18n` options are parsed as JSON. diff --git a/lib/index.js b/lib/index.js index 118b420..2962e23 100644 --- a/lib/index.js +++ b/lib/index.js @@ -38,6 +38,8 @@ const defaults = { nsSeparator: ":", encoding: 'utf8', translateConditionalComments: false, + interpolationPrefix: '{{', + interpolationSuffix: '}}', i18n: { resGetPath: 'locales/__lng__.json', setJqueryExt: false @@ -105,6 +107,13 @@ function getOptions(baseOptions) { if (_.isUndefined(baseOptions.outputDir)) { options.outputDir = path.join(process.cwd(), 'i18n'); } + + if (_.isUndefined(options.i18n.interpolation)){ + options.i18n.interpolation = {} + options.i18n.interpolation.prefix = options.interpolationPrefix = _.escapeRegExp(options.interpolationPrefix); + options.i18n.interpolation.suffix = options.interpolationSuffix = _.escapeRegExp(options.interpolationSuffix); + } + return options; } @@ -155,7 +164,8 @@ function translateAttributes($elem, options, t) { const attr = isData ? k : k.substring(0, k.length - options.attrSuffix.length); let trans = t(v); if (interpolate) { - trans = v.replace(/{{([^{}]*)}}/g, function(aa, bb) { + const replaceRegex = new RegExp(`${options.interpolationPrefix}([^{}]*)${options.interpolationSuffix}`, 'g') + trans = v.replace(replaceRegex, function(aa, bb) { return t(bb); }); } @@ -175,6 +185,8 @@ function translateAttributes($elem, options, t) { function translateElem($, elem, options, t) { let key, attr; + const replaceRegex = new RegExp(`${options.interpolationPrefix}([^{}]*)${options.interpolationSuffix}`, 'g') + const $elem = $(elem); if (options.useAttr && (attr = /^\[(.*?)\]$/.exec(options.selector))) { key = $elem.attr(attr[1]); @@ -192,7 +204,7 @@ function translateElem($, elem, options, t) { const interpolateAttr = getAttrFromSelector(options.interpolateSelector); const interpolate = $elem.filter(options.interpolateSelector).length; if (interpolate) { - trans = trans.replace(/{{([^{}]*)}}/g, function(aa, bb) { + trans = trans.replace(replaceRegex, function(aa, bb) { return t(bb); }); } @@ -201,7 +213,7 @@ function translateElem($, elem, options, t) { } if (options.allowHtml) { if (interpolate) { - $elem.html($elem.html().replace(/{{([^{}]*)}}/g, function(aa, bb) { + $elem.html($elem.html().replace(replaceRegex, function(aa, bb) { return t(bb); })); } else { diff --git a/package.json b/package.json index 9b9a377..5d1a14a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "static-i18n", - "version": "0.2.10", + "version": "0.2.11", "description": "Utility to translate static HTML files.", "main": "lib/index.js", "bin": { diff --git a/test/index-test.js b/test/index-test.js index 3923ffb..88bb262 100644 --- a/test/index-test.js +++ b/test/index-test.js @@ -75,6 +75,40 @@ describe('processor', function () { expect($('input').attr('data-attr-t-interpolate')).to.be(undefined); }); + it('should support custom prefix and suffix when translating attributes with interpolation', async function () { + options = _.merge({}, options, { locales: ['en', 'ja'], interpolationPrefix: '_{', interpolationSuffix: '}' }); + const input = + ''; + const results = await staticI18n.process(input, options); + let $ = cheerio.load(results.en); + expect($('input').attr('href')).to.be( + 'http://www.example.com/filename.html' + ); + expect($('input').attr('data-attr-t-interpolate')).to.be(undefined); + $ = cheerio.load(results.ja); + expect($('input').attr('href')).to.be( + 'http://www.example.com/ja/filename.htm' + ); + expect($('input').attr('data-attr-t-interpolate')).to.be(undefined); + }); + + it('should escape regex characters in prefix and suffix', async function () { + options = _.merge({}, options, { locales: ['en', 'ja'], interpolationPrefix: '${', interpolationSuffix: '}$' }); + const input = + ''; + const results = await staticI18n.process(input, options); + let $ = cheerio.load(results.en); + expect($('input').attr('href')).to.be( + 'http://www.example.com/filename.html' + ); + expect($('input').attr('data-attr-t-interpolate')).to.be(undefined); + $ = cheerio.load(results.ja); + expect($('input').attr('href')).to.be( + 'http://www.example.com/ja/filename.htm' + ); + expect($('input').attr('data-attr-t-interpolate')).to.be(undefined); + }); + it('should remove interpolation related attributes', async function () { options = _.merge({}, options, { locales: ['en'] }); @@ -145,12 +179,12 @@ describe('processor', function () { describe('#processDir', function () { it('should process all files', async function () { - _.merge(options, { locales: ['en', 'ja'], exclude: ['ignored/'] }); + _.merge(options, { locales: ['en', 'ja'], exclude: [`ignored${path.sep}`] }); const results = await staticI18n.processDir(basepath, options); expect(results).to.only.have.keys([ 'index.html', 'other.html', - 'sub/index.html', + path.join('sub', 'index.html'), ]); expect(results['index.html']).to.only.have.keys(['en', 'ja']); expect(results['other.html']).to.only.have.keys(['en', 'ja']);