From 92cebd5802d3a98871070bb6fab925290e79fa0f Mon Sep 17 00:00:00 2001
From: Christoph Reiter <reiter.christoph@gmail.com>
Date: Thu, 8 Aug 2019 14:11:41 +0200
Subject: [PATCH] Add a i18next wrapper

---
 packages/common/i18next.js      | 59 +++++++++++++++++++++++++++++++++
 packages/common/package.json    |  3 ++
 packages/common/test/i18next.js | 49 +++++++++++++++++++++++++++
 packages/common/test/unit.js    |  2 +-
 4 files changed, 112 insertions(+), 1 deletion(-)
 create mode 100644 packages/common/i18next.js
 create mode 100644 packages/common/test/i18next.js

diff --git a/packages/common/i18next.js b/packages/common/i18next.js
new file mode 100644
index 00000000..7dc135f0
--- /dev/null
+++ b/packages/common/i18next.js
@@ -0,0 +1,59 @@
+import i18next from 'i18next';
+
+/**
+ * Like Intl.DateTimeFormat().format() but uses the current language as locale.
+ *
+ * A i18next instance can be created with createInstance()
+ *
+ * @param {i18next.i18n} i18n - The i18next instance
+ * @param {Date} date - The date to format
+ * @param options - Options passed to Intl.DateTimeFormat
+ * @returns {string}
+ */
+export function dateTimeFormat(i18n, date, options) {
+    return new Intl.DateTimeFormat(i18n.languages, options).format(date);
+}
+
+/**
+ * Like Intl.NumberFormat().format() but uses the current language as locale.
+ *
+ * A i18next instance can be created with createInstance()
+ *
+ * @param {i18next.i18n} i18n - The i18next instance
+ * @param {Number} number - The number to format
+ * @param {Object} options - Options passed to Intl.NumberFormat
+ * @returns {string}
+ */
+export function numberFormat(i18n, number, options) {
+    return new Intl.NumberFormat(i18n.languages, options).format(number);
+}
+
+/**
+ * Creates a new i18next instance that is fully initialized.
+ *
+ * Call changeLanguage() on the returned object to change the language.
+ *
+ * @param {Object} languages - Mapping from languages to translation objects
+ * @param {string} lng - The default language
+ * @param {string} fallback - The fallback language to use for unknown languages or untranslated keys
+ * @returns {i18next.i18n}
+ */
+export function createInstance(languages, lng, fallback) {
+    var options = {
+        lng: lng,
+        fallbackLng: fallback,
+        debug: false,
+        initImmediate: false, // Don't init async
+        resources: {},
+    };
+
+    Object.keys(languages).forEach(function(key) {
+        options['resources'][key] = {translation: languages[key]};
+    });
+
+    var i18n = i18next.createInstance();
+    i18n.init(options);
+    console.assert(i18n.isInitialized);
+
+    return i18n;
+}
\ No newline at end of file
diff --git a/packages/common/package.json b/packages/common/package.json
index 6f014fd5..125be379 100644
--- a/packages/common/package.json
+++ b/packages/common/package.json
@@ -21,5 +21,8 @@
     "build": "npm run build-local",
     "build-test": "rollup -c --environment BUILD:test",
     "test": "npm run build-test && karma start --singleRun"
+  },
+  "dependencies": {
+    "i18next": "^17.0.9"
   }
 }
diff --git a/packages/common/test/i18next.js b/packages/common/test/i18next.js
new file mode 100644
index 00000000..d5b6512b
--- /dev/null
+++ b/packages/common/test/i18next.js
@@ -0,0 +1,49 @@
+import * as i18next from '../i18next.js';
+
+describe('i18next', () => {
+    it('createInstance', () => {
+        var inst = i18next.createInstance({de:  {}}, 'de', 'en');
+        assert.exists(inst);
+        assert.deepEqual(inst.languages, ['de', 'en']);
+    });
+
+    it('translations', () => {
+        var inst = i18next.createInstance({de:  {foo: 'bar'}, en: {foo: 'baz', extra: 'quux'}}, 'de', 'en');
+        assert.deepEqual(inst.languages, ['de', 'en']);
+        assert.equal( inst.t('foo'), 'bar');
+        assert.equal( inst.t('nope'), 'nope');
+        assert.equal( inst.t('extra'), 'quux');
+        inst.changeLanguage('en');
+        assert.deepEqual(inst.languages, ['en']);
+        assert.equal( inst.t('foo'), 'baz');
+        assert.equal( inst.t('nope'), 'nope');
+        inst.changeLanguage('nope');
+        assert.deepEqual(inst.languages, ['nope', 'en']);
+        assert.equal( inst.t('foo'), 'baz');
+        assert.equal( inst.t('nope'), 'nope');
+    });
+
+    it('date format', () => {
+        var inst = i18next.createInstance({de:  {}}, 'de', 'en');
+        assert.deepEqual(inst.languages, ['de', 'en']);
+
+        var date = new Date('1995-12-17T03:24:00');
+        assert.equal(i18next.dateTimeFormat(inst, date), '17.12.1995');
+        inst.changeLanguage('en');
+        // TODO: not sure it's a good idea to use the english format even if english is selected because it's just confusing
+        assert.equal(i18next.dateTimeFormat(inst, date), '12/17/1995');
+    });
+
+    it('number format', () => {
+        var inst = i18next.createInstance({de:  {}}, 'de', 'en');
+        assert.deepEqual(inst.languages, ['de', 'en']);
+
+        assert.equal(i18next.numberFormat(inst, 42), '42');
+        assert.equal(i18next.numberFormat(inst, 1.25), '1,25');
+        assert.equal(i18next.numberFormat(inst, 1234), '1.234');
+        inst.changeLanguage('en');
+        assert.equal(i18next.numberFormat(inst, 42), '42');
+        assert.equal(i18next.numberFormat(inst, 1.25), '1.25');
+        assert.equal(i18next.numberFormat(inst, 1234), '1,234');
+    });
+});
diff --git a/packages/common/test/unit.js b/packages/common/test/unit.js
index a7849e10..e800730c 100644
--- a/packages/common/test/unit.js
+++ b/packages/common/test/unit.js
@@ -18,7 +18,7 @@ describe('utils', () => {
         var res = utils.defineCustomElement("test-some-element", SomeElement);
         expect(res).to.equal(true);
 
-        node = document.createElement('test-some-element');
+        var node = document.createElement('test-some-element');
         expect(node.foo).to.equal(42);
     });
 });
-- 
GitLab