diff --git a/test/javascript/fake_translations.js b/test/javascript/fake_translations.js new file mode 100644 index 000000000..e0ab7098c --- /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 000000000..825cc337e --- /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 000000000..ac1164ee5 --- /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 a81519cff..59b8c2e65 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 000000000..2847224c7 --- /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