From f022acea09f658a0322c45de9b1dbc654663925b 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/6] 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

