Sfoglia il codice sorgente

core: Add translateArray() for i18n with non-string replacements.

Renée Kooi 7 anni fa
parent
commit
5f2528d807
2 ha cambiato i file con 48 aggiunte e 3 eliminazioni
  1. 32 3
      src/core/Translator.js
  2. 16 0
      src/core/Translator.test.js

+ 32 - 3
src/core/Translator.js

@@ -41,9 +41,10 @@ module.exports = class Translator {
    * @return {string} interpolated
    */
   interpolate (phrase, options) {
-    const replace = String.prototype.replace
+    const { split, replace } = String.prototype
     const dollarRegex = /\$/g
     const dollarBillsYall = '$$$$'
+    let interpolated = [phrase]
 
     for (let arg in options) {
       if (arg !== '_' && options.hasOwnProperty(arg)) {
@@ -57,10 +58,28 @@ module.exports = class Translator {
         // We create a new `RegExp` each time instead of using a more-efficient
         // string replace so that the same argument can be replaced multiple times
         // in the same phrase.
-        phrase = replace.call(phrase, new RegExp('%\\{' + arg + '\\}', 'g'), replacement)
+        interpolated = insertReplacement(interpolated, new RegExp('%\\{' + arg + '\\}', 'g'), replacement)
       }
     }
-    return phrase
+
+    return interpolated
+
+    function insertReplacement (source, rx, replacement) {
+      const newParts = []
+      source.forEach((chunk) => {
+        split.call(chunk, rx).forEach((raw, i, list) => {
+          if (raw !== '') {
+            newParts.push(raw)
+          }
+
+          // Interlace with the `replacement` value
+          if (i < list.length - 1) {
+            newParts.push(replacement)
+          }
+        })
+      })
+      return newParts
+    }
   }
 
   /**
@@ -71,6 +90,16 @@ module.exports = class Translator {
    * @return {string} translated (and interpolated)
    */
   translate (key, options) {
+    return this.translateArray(key, options).join('')
+  }
+
+  /**
+   * Get a translation and return the translated and interpolated parts as an array.
+   * @param {string} key
+   * @param {object} options with values that will be used to replace placeholders
+   * @return {Array} The translated and interpolated parts, in order.
+   */
+  translateArray (key, options) {
     if (options && typeof options.smart_count !== 'undefined') {
       var plural = this.locale.pluralize(options.smart_count)
       return this.interpolate(this.opts.locale.strings[key][plural], options)

+ 16 - 0
src/core/Translator.test.js

@@ -8,6 +8,22 @@ describe('core/translator', () => {
       const core = new Core({ locale: russian })
       expect(core.translator.translate('chooseFile')).toEqual('Выберите файл')
     })
+
+    it('should translate a string with non-string elements', () => {
+      const core = new Core({
+        locale: {
+          strings: {
+            test: 'Hello %{who}!',
+            test2: 'Hello %{who}'
+          }
+        }
+      })
+
+      const who = Symbol('who')
+      expect(core.translator.translateArray('test', { who: who })).toEqual(['Hello ', who, '!'])
+      // No empty string at the end.
+      expect(core.translator.translateArray('test2', { who: who })).toEqual(['Hello ', who])
+    })
   })
 
   describe('interpolation', () => {