From 9a3d1554f2755a33e6330970e36a428b79fc76f4 Mon Sep 17 00:00:00 2001
From: George Gelashvili and Tira Odhner <pair+ggelashvili+aodhner@pivotal.io>
Date: Tue, 7 Mar 2017 15:23:46 -0500
Subject: [PATCH 2/7] Enable refactoring javascript with translations:

- Create a translations.js and translate.js which uses flask to pull in translations, but
      lets us have the flask template rendering confined to that one file,
      enabling us to test javascript files that rely on translations
---
 test/javascript/fake_translations.js           |  3 ++
 test/javascript/translate_spec.js              | 43 ++++++++++++++++++++++++++
 web/pgadmin/static/js/translate.js             | 32 +++++++++++++++++++
 web/pgadmin/tools/__init__.py                  | 19 +++++++++++-
 web/pgadmin/tools/templates/js/translations.js |  4 +++
 5 files changed, 100 insertions(+), 1 deletion(-)
 create mode 100644 test/javascript/fake_translations.js
 create mode 100644 test/javascript/translate_spec.js
 create mode 100644 web/pgadmin/static/js/translate.js
 create mode 100644 web/pgadmin/tools/templates/js/translations.js

diff --git a/test/javascript/fake_translations.js b/test/javascript/fake_translations.js
new file mode 100644
index 00000000..e0ab7098
--- /dev/null
+++ b/test/javascript/fake_translations.js
@@ -0,0 +1,3 @@
+define(function () {
+  return {}
+});
\ No newline at end of file
diff --git a/test/javascript/translate_spec.js b/test/javascript/translate_spec.js
new file mode 100644
index 00000000..825cc337
--- /dev/null
+++ b/test/javascript/translate_spec.js
@@ -0,0 +1,43 @@
+define(["sources/translate", "translations"], function (translate, translations) {
+  describe("translate", function () {
+    describe("when there is no translation", function () {
+      it("returns the original string", function () {
+        expect(translate("something to be translated")).toEqual("something to be translated");
+      });
+
+      describe("when there are substitutions", function () {
+        it("interpolates a substitution", function () {
+          expect(translate("translate text for %(person)s", {"person": "Sarah"})).toEqual("translate text for Sarah")
+        });
+
+        it("interpolates multiple substitutions", function () {
+          expect(translate("translate '%(text)s' for %(person)s",
+            {
+              "text": "constitution",
+              "person": "Sarah"
+            }
+          )).toEqual("translate 'constitution' for Sarah")
+        });
+      });
+
+    });
+
+    describe("when there is a translation", function () {
+      beforeEach(function () {
+        translations['something to be translated'] = 'etwas zum uebersetzen';
+        translations['another translation for %(person)s'] = 'eine weitere Uebersetzung fuer %(person)s';
+      });
+
+      it("returns the translation", function () {
+        expect(translate("something to be translated")).toEqual("etwas zum uebersetzen");
+      });
+
+      describe("when there is a substitution", function () {
+        it("interpolates the substitution", function () {
+          expect(translate("another translation for %(person)s", {"person": "Sarah"}))
+            .toEqual("eine weitere Uebersetzung fuer Sarah");
+        });
+      });
+    });
+  });
+});
diff --git a/web/pgadmin/static/js/translate.js b/web/pgadmin/static/js/translate.js
new file mode 100644
index 00000000..ac1164ee
--- /dev/null
+++ b/web/pgadmin/static/js/translate.js
@@ -0,0 +1,32 @@
+define(["translations"], function (translations) {
+
+  /***
+   * This method behaves as a drop-in replacement for flask translation rendering.
+   * It uses the same translation file under the hood and uses flask to determine the language.
+   *
+   * ex. translate("some %(adjective)s text", {adjective: "cool"})
+   *
+   * @param {String} text
+   * @param {Object} substitutions
+   */
+  return function translate(text, substitutions) {
+
+    var rawTranslation = translations[text] ? translations[text] : text;
+
+    // captures things of the form %(substitutionName)s
+    var substitutionGroupsRegExp = /([^%]*)%\(([^\)]+)\)s(.*)/;
+    var matchFound;
+
+    var interpolated = rawTranslation;
+    do {
+      matchFound = false;
+      interpolated = interpolated.replace(substitutionGroupsRegExp, function (_, textBeginning, substitutionName, textEnd) {
+        matchFound = true;
+        return textBeginning + substitutions[substitutionName] + textEnd;
+      });
+    } while (matchFound);
+
+    return interpolated;
+  };
+
+});
\ No newline at end of file
diff --git a/web/pgadmin/tools/__init__.py b/web/pgadmin/tools/__init__.py
index a81519cf..59b8c2e6 100644
--- a/web/pgadmin/tools/__init__.py
+++ b/web/pgadmin/tools/__init__.py
@@ -9,7 +9,11 @@
 
 """A blueprint module container for keeping all submodule of type tool."""
 
+from flask import render_template, Response
+from flask import url_for
+from flask.ext.babel import get_translations
 from flask_babel import gettext
+
 from pgadmin.utils import PgAdminModule
 from pgadmin.utils.ajax import bad_request
 
@@ -17,8 +21,11 @@ MODULE_NAME = 'tools'
 
 class ToolsModule(PgAdminModule):
     def get_own_javascripts(self):
-        from flask import url_for
         return [{
+            'name': 'translations',
+            'path': url_for('tools.index') + "translations",
+            'when': None
+        },{
             'name': 'pgadmin-sqlfoldcode',
             'path': url_for(
                 'static',
@@ -49,3 +56,13 @@ blueprint = ToolsModule(MODULE_NAME, __name__)
 def index():
     """Calling tools index URL directly is not allowed."""
     return bad_request(gettext('This URL cannot be requested directly.'))
+
+@blueprint.route("/translations.js")
+def translations():
+    """Return a js file that will handle translations so Flask interpolation can be isolated"""
+    template = render_template("js/translations.js", translations=get_translations()._catalog)
+    return Response(
+        response=template,
+        status=200,
+        mimetype="application/javascript"
+    )
\ No newline at end of file
diff --git a/web/pgadmin/tools/templates/js/translations.js b/web/pgadmin/tools/templates/js/translations.js
new file mode 100644
index 00000000..2847224c
--- /dev/null
+++ b/web/pgadmin/tools/templates/js/translations.js
@@ -0,0 +1,4 @@
+define(function () {
+  var translations = {{ translations|tojson }};
+  return translations;
+});
\ No newline at end of file
-- 
2.12.0

