diff --git a/.gitignore b/.gitignore index 8e89ed52c..b257f71cf 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.pyo *.o *.psp +_build build-* .DS_Store runtime/.qmake.cache diff --git a/docs/en_US/index.rst b/docs/en_US/index.rst index 9bc65fc3a..52674d590 100644 --- a/docs/en_US/index.rst +++ b/docs/en_US/index.rst @@ -75,6 +75,7 @@ learn how pgAdmin works, and how to develop improvements and new features. coding-standards code-overview submitting-patches + translations ******* Website diff --git a/docs/en_US/translations.rst b/docs/en_US/translations.rst new file mode 100644 index 000000000..f3f4faede --- /dev/null +++ b/docs/en_US/translations.rst @@ -0,0 +1,134 @@ +Translations +============ + +pgAdmin supports multiple languages using the `Flask-Babel +`_ Python module. A list of supported +languages is included in the **web/config.py** configuration file and must be +updated whenever langauges are added or removed. + +Translation Marking +------------------- + +Strings can be marked for translation in either Python code (using **gettext()**) +or Jinja templates (using **_()**). Here are some examples that show how this +is achieved. + +Python:: + + errormsg = gettext('No server group name was specified') + +Jinja: + +.. code-block:: html + + + +.. code-block:: html + + {{ _('%(appname)s Password Change', appname=config.APP_NAME) }} + +.. code-block:: javascript + + var alert = alertify.prompt( + '{{ _('Add a server group') }}', + '{{ _('Enter a name for the new server group') }}', + '' + ... + ) + +Updating and Merging +-------------------- + +Whenever new strings are added to the application, the template catalogues +(**web/pgadmin/messages.pot**) must be updated and the existing catalogues +merged with the updated template and compiled. This can be achieved using the +following command from the **web** directory, in the Python virtual environment +used for pgAdmin: + +.. code-block:: bash + + (pgadmin4)piranha:web dpage$ pybabel extract -F babel.cfg -o pgadmin/messages.pot pgadmin + +For example: + +.. code-block:: bash + + (pgadmin4)piranha:web dpage$ pybabel extract -F babel.cfg -o pgadmin/messages.pot pgadmin + extracting messages from pgadmin/__init__.py + extracting messages from pgadmin/about/__init__.py + extracting messages from pgadmin/about/hooks.py + extracting messages from pgadmin/about/views.py + extracting messages from pgadmin/about/templates/about/index.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_") + extracting messages from pgadmin/browser/__init__.py + extracting messages from pgadmin/browser/hooks.py + extracting messages from pgadmin/browser/views.py + extracting messages from pgadmin/browser/nodes/CollectionNode.py + extracting messages from pgadmin/browser/nodes/ObjectNode.py + extracting messages from pgadmin/browser/nodes/__init__.py + extracting messages from pgadmin/browser/nodes/server_groups/__init__.py + extracting messages from pgadmin/browser/nodes/server_groups/hooks.py + extracting messages from pgadmin/browser/nodes/server_groups/views.py + extracting messages from pgadmin/browser/templates/browser/body.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_") + extracting messages from pgadmin/browser/templates/browser/index.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_") + extracting messages from pgadmin/browser/templates/browser/messages.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_") + extracting messages from pgadmin/help/__init__.py + extracting messages from pgadmin/help/hooks.py + extracting messages from pgadmin/help/views.py + extracting messages from pgadmin/redirects/__init__.py + extracting messages from pgadmin/redirects/views.py + extracting messages from pgadmin/settings/__init__.py + extracting messages from pgadmin/settings/hooks.py + extracting messages from pgadmin/settings/settings_model.py + extracting messages from pgadmin/settings/views.py + extracting messages from pgadmin/templates/base.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_") + extracting messages from pgadmin/templates/security/change_password.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_") + extracting messages from pgadmin/templates/security/fields.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_") + extracting messages from pgadmin/templates/security/forgot_password.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_") + extracting messages from pgadmin/templates/security/login_user.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_") + extracting messages from pgadmin/templates/security/messages.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_") + extracting messages from pgadmin/templates/security/panel.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_") + extracting messages from pgadmin/templates/security/reset_password.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_") + extracting messages from pgadmin/templates/security/watermark.html (extensions="jinja2.ext.autoescape,jinja2.ext.with_") + extracting messages from pgadmin/test/__init__.py + extracting messages from pgadmin/test/hooks.py + extracting messages from pgadmin/test/views.py + extracting messages from pgadmin/utils/__init__.py + extracting messages from pgadmin/utils/views.py + writing PO template file to pgadmin/messages.pot + +Once the template has been updated, it needs to be merged into the existing +message catalogues, for example: + +.. code-block:: bash + + (pgadmin4)piranha:web dpage$ pybabel update -i pgadmin/messages.pot -d pgadmin/translations + updating catalog 'pgadmin/translations/fr/LC_MESSAGES/messages.po' based on 'pgadmin/messages.pot' + +Finally, the message catalogues can be compiled for use: + +.. code-block:: bash + + (pgadmin4)piranha:web dpage$ pybabel compile -d pgadmin/translations + compiling catalog 'pgadmin/translations/fr/LC_MESSAGES/messages.po' to 'pgadmin/translations/fr/LC_MESSAGES/messages.mo' + +Adding a new Language +--------------------- + +Adding a new language is simple. First, add the language name and identifier to +**web/config.py**:: + + # Languages we support in the UI + LANGUAGES = { + 'en': 'English', + 'fr': 'Français' + } + +Then, create the new message catalogue from the **web** directory in the source +tree, in the Python virtual environment used for pgAdmin: + +.. code-block:: bash + + (pgadmin4)piranha:web dpage$ pybabel init -i pgadmin/messages.pot -d pgadmin/translations -l fr + +This will initialise a new catalogue for a French translation. + diff --git a/requirements.txt b/requirements.txt index d573d6b85..f1eb3dae8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,6 @@ +Babel==1.3 Flask==0.10.1 +Flask-Babel==0.9 Flask-Gravatar==0.4.1 Flask-Login==0.2.11 Flask-Mail==0.9.1 @@ -19,5 +21,7 @@ html5lib==1.0b3 itsdangerous==0.24 passlib==1.6.2 psycopg2==2.5.2 +pytz==2014.10 six==1.9.0 +speaklater==1.3 wsgiref==0.1.2 diff --git a/web/babel.cfg b/web/babel.cfg new file mode 100644 index 000000000..f0234b326 --- /dev/null +++ b/web/babel.cfg @@ -0,0 +1,3 @@ +[python: **.py] +[jinja2: **/templates/**.html] +extensions=jinja2.ext.autoescape,jinja2.ext.with_ diff --git a/web/config.py b/web/config.py index 445f49c09..f2f3a980d 100644 --- a/web/config.py +++ b/web/config.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + ########################################################################## # # pgAdmin 4 - PostgreSQL Tools @@ -34,6 +36,12 @@ APP_COPYRIGHT = 'Copyright 2014 - 2015, The pgAdmin Development Team' # Path to the online help. HELP_PATH = '../../../docs/en_US/_build/html/' +# Languages we support in the UI +LANGUAGES = { + 'en': 'English', + 'fr': 'Français' +} + # DO NOT CHANGE! # The application version string, constructed from the components APP_VERSION = '%s.%s.%s-%s' % (APP_MAJOR, APP_MINOR, APP_REVISION, APP_SUFFIX) diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py index 74620e62d..c440e6651 100644 --- a/web/pgadmin/__init__.py +++ b/web/pgadmin/__init__.py @@ -10,7 +10,8 @@ """The main pgAdmin module. This handles the application initialisation tasks, such as setup of logging, dynamic loading of modules etc.""" -from flask import Flask, abort +from flask import Flask, abort, request +from flask.ext.babel import Babel from flask.ext.sqlalchemy import SQLAlchemy from flask.ext.security import Security, SQLAlchemyUserDatastore, login_required from flask_security.utils import login_user @@ -66,6 +67,23 @@ def create_app(app_name=config.APP_NAME): app.logger.info('Starting %s v%s...', config.APP_NAME, config.APP_VERSION) app.logger.info('################################################################################') + ########################################################################## + # Setup i18n + ########################################################################## + + # Initialise i18n + babel = Babel(app) + + app.logger.debug('Available translations: %s' % babel.list_translations()) + + @babel.localeselector + def get_locale(): + """Get the best language for the user.""" + language = request.accept_languages.best_match(config.LANGUAGES.keys()) + app.logger.info('Using language: %s', language) + + return language + ########################################################################## # Setup authentication ########################################################################## diff --git a/web/pgadmin/about/templates/about/index.html b/web/pgadmin/about/templates/about/index.html index 09a846e5f..80c299a34 100644 --- a/web/pgadmin/about/templates/about/index.html +++ b/web/pgadmin/about/templates/about/index.html @@ -1,25 +1,25 @@
-
Version
+
{{ _('Version') }}
{{ config.APP_VERSION }}
-
Copyright
+
{{ _('Copyright') }}
{{ config.APP_COPYRIGHT }}
-
Python Version
+
{{ _('Python Version') }}
{{ info.python_version }}
-
Flask Version
+
{{ _('Flask Version') }}
{{ info.flask_version }}
-
Application Mode
+
{{ _('Application Mode') }}
{{ info.app_mode }}
-
Current User
+
{{ _('Current User') }}
{{ info.current_user }}
diff --git a/web/pgadmin/about/views.py b/web/pgadmin/about/views.py index 44732df26..0feed10cd 100644 --- a/web/pgadmin/about/views.py +++ b/web/pgadmin/about/views.py @@ -11,6 +11,7 @@ MODULE_NAME = 'about' from flask import Blueprint, Response, current_app, render_template, __version__ +from flask.ext.babel import gettext from flask.ext.security import current_user, login_required import sys @@ -31,9 +32,9 @@ def index(): info['python_version'] = sys.version info['flask_version'] = __version__ if config.SERVER_MODE == True: - info['app_mode'] = 'Server' + info['app_mode'] = gettext('Server') else: - info['app_mode'] = 'Desktop' + info['app_mode'] = gettext('Desktop') info['current_user'] = current_user.email return render_template(MODULE_NAME + '/index.html', info=info) diff --git a/web/pgadmin/browser/nodes/server_groups/hooks.py b/web/pgadmin/browser/nodes/server_groups/hooks.py index a1095c46e..183623d0e 100644 --- a/web/pgadmin/browser/nodes/server_groups/hooks.py +++ b/web/pgadmin/browser/nodes/server_groups/hooks.py @@ -10,6 +10,7 @@ """Integration hooks for server groups.""" from flask import render_template, url_for +from flask.ext.babel import gettext from flask.ext.security import current_user from pgadmin.settings.settings_model import db, ServerGroup @@ -30,17 +31,17 @@ def get_file_menu_items(): """Return a (set) of dicts of file menu items, with name, priority, URL, target and onclick code.""" return [ - {'name': 'mnu_add_server_group', 'label': 'Add a server group...', 'priority': 10, 'url': '#', 'onclick': 'add_server_group()'}, - {'name': 'mnu_delete_server_group', 'label': 'Delete server group', 'priority': 20, 'url': '#', 'onclick': 'delete_server_group()'}, - {'name': 'mnu_rename_server_group', 'label': 'Rename server group...', 'priority': 30, 'url': '#', 'onclick': 'rename_server_group()'} + {'name': 'mnu_add_server_group', 'label': gettext('Add a server group...'), 'priority': 10, 'url': '#', 'onclick': 'add_server_group()'}, + {'name': 'mnu_delete_server_group', 'label': gettext('Delete server group'), 'priority': 20, 'url': '#', 'onclick': 'delete_server_group()'}, + {'name': 'mnu_rename_server_group', 'label': gettext('Rename server group...'), 'priority': 30, 'url': '#', 'onclick': 'rename_server_group()'} ] def get_context_menu_items(): """Return a (set) of dicts of content menu items with name, label, priority and JS""" return [ - {'name': 'delete', 'label': 'Delete server group', 'priority': 100, 'onclick': 'delete_server_group(item);'}, - {'name': 'rename', 'label': 'Rename server group...', 'priority': 200, 'onclick': 'rename_server_group(item);'} + {'name': 'delete', 'label': gettext('Delete server group'), 'priority': 100, 'onclick': 'delete_server_group(item);'}, + {'name': 'rename', 'label': gettext('Rename server group...'), 'priority': 200, 'onclick': 'rename_server_group(item);'} ] diff --git a/web/pgadmin/browser/nodes/server_groups/templates/server_groups/server_groups.js b/web/pgadmin/browser/nodes/server_groups/templates/server_groups/server_groups.js index de40ee3c2..ee107c84d 100644 --- a/web/pgadmin/browser/nodes/server_groups/templates/server_groups/server_groups.js +++ b/web/pgadmin/browser/nodes/server_groups/templates/server_groups/server_groups.js @@ -1,8 +1,8 @@ // Add a server group function add_server_group() { var alert = alertify.prompt( - 'Add a server group', - 'Enter a name for the new server group', + '{{ _('Add a server group') }}', + '{{ _('Enter a name for the new server group') }}', '', function(evt, value) { $.post("{{ url_for('NODE-server-group.add') }}", { name: value }) @@ -34,8 +34,8 @@ function add_server_group() { // Delete a server group function delete_server_group(item) { alertify.confirm( - 'Delete server group?', - 'Are you sure you wish to delete the server group "{0}"?'.replace('{0}', tree.getLabel(item)), + '{{ _('Delete server group?') }}', + '{{ _('Are you sure you wish to delete the server group "{0}"?') }}'.replace('{0}', tree.getLabel(item)), function() { var id = tree.getId(item) $.post("{{ url_for('NODE-server-group.delete') }}", { id: id }) @@ -62,8 +62,8 @@ function delete_server_group(item) { // Rename a server group function rename_server_group(item) { alertify.prompt( - 'Rename server group', - 'Enter a new name for the server group', + '{{ _('Rename server group') }}', + '{{ _('Enter a new name for the server group') }}', tree.getLabel(item), function(evt, value) { var id = tree.getId(item) diff --git a/web/pgadmin/browser/nodes/server_groups/views.py b/web/pgadmin/browser/nodes/server_groups/views.py index 9fbda176b..531700118 100644 --- a/web/pgadmin/browser/nodes/server_groups/views.py +++ b/web/pgadmin/browser/nodes/server_groups/views.py @@ -15,6 +15,7 @@ NODE_PATH = '/browser/' + NODE_NAME import traceback from flask import Blueprint, Response, current_app, request +from flask.ext.babel import gettext from flask.ext.security import current_user, login_required from utils.ajax import make_json_response @@ -44,7 +45,7 @@ def add(): else: success = 0 - errormsg = "No server group name was specified" + errormsg = gettext('No server group name was specified') if success == 1: data['id'] = servergroup.id @@ -69,7 +70,7 @@ def delete(): if servergroup is None: success = 0 - errormsg = 'The specified server group could not be found.' + errormsg = gettext('The specified server group could not be found.') else: try: db.session.delete(servergroup) @@ -80,7 +81,7 @@ def delete(): else: success = 0 - errormsg = "No server group was specified." + errormsg = gettext('No server group was specified.') return make_json_response(success=success, errormsg=errormsg, @@ -100,7 +101,7 @@ def rename(): if servergroup is None: success = 0 - errormsg = 'The specified server group could not be found.' + errormsg = gettext('The specified server group could not be found.') else: try: servergroup.name = request.form['name'] @@ -111,9 +112,10 @@ def rename(): else: success = 0 - errormsg = "No server group was specified." + errormsg = gettext('No server group was specified.') return make_json_response(success=success, errormsg=errormsg, info=traceback.format_exc(), - result=request.form) \ No newline at end of file + result=request.form) + \ No newline at end of file diff --git a/web/pgadmin/browser/static/js/utils.js b/web/pgadmin/browser/static/js/utils.js deleted file mode 100644 index 7550fa62c..000000000 --- a/web/pgadmin/browser/static/js/utils.js +++ /dev/null @@ -1,39 +0,0 @@ -function report_error(message, info) { - - text = '
\ -
\ - \ -
\ -
' + message + '
\ -
\ -
' - - if (info != '') { - text += '
\ - \ -
\ -
' + info + '
\ -
\ -
\ -
' - } - - text += '' - - alertify.alert( - 'An error has occurred', - text - ) -} \ No newline at end of file diff --git a/web/pgadmin/browser/templates/browser/body.html b/web/pgadmin/browser/templates/browser/body.html index 0e521e34e..47579a0eb 100644 --- a/web/pgadmin/browser/templates/browser/body.html +++ b/web/pgadmin/browser/templates/browser/body.html @@ -8,11 +8,11 @@
diff --git a/web/pgadmin/browser/templates/browser/index.html b/web/pgadmin/browser/templates/browser/index.html index b93a736f8..595f44bd3 100644 --- a/web/pgadmin/browser/templates/browser/index.html +++ b/web/pgadmin/browser/templates/browser/index.html @@ -5,7 +5,7 @@
' + + alertify.alert( + '{{ _('An error has occurred') }}', + text + ) +} \ No newline at end of file diff --git a/web/pgadmin/browser/views.py b/web/pgadmin/browser/views.py index 4eac5dcde..d3ac3cfad 100644 --- a/web/pgadmin/browser/views.py +++ b/web/pgadmin/browser/views.py @@ -59,7 +59,6 @@ def index(): # Add browser scripts scripts.append(url_for('static', filename='js/codemirror/codemirror.js')) scripts.append(url_for('static', filename='js/codemirror/mode/sql.js')) - scripts.append(url_for('browser.static', filename='js/utils.js')) scripts.append(url_for('browser.static', filename='js/aciTree/jquery.aciPlugin.min.js')) scripts.append(url_for('browser.static', filename='js/aciTree/jquery.aciTree.dom.js')) scripts.append(url_for('browser.static', filename='js/aciTree/jquery.aciTree.min.js')) diff --git a/web/pgadmin/help/hooks.py b/web/pgadmin/help/hooks.py index 3d73561d3..a943d40d4 100644 --- a/web/pgadmin/help/hooks.py +++ b/web/pgadmin/help/hooks.py @@ -10,6 +10,7 @@ """Browser integration functions for the Help module.""" from flask import url_for +from flask.ext.babel import gettext import config @@ -17,7 +18,7 @@ def get_help_menu_items(): """Return a (set) of dicts of help menu items, with name, priority, URL, target and onclick code.""" return [{'name': 'mnu_contents', - 'label': 'Contents', + 'label': gettext('Contents'), 'priority': 1, 'target': '_new', 'url': url_for('help.static', filename='index.html') }] \ No newline at end of file diff --git a/web/pgadmin/messages.pot b/web/pgadmin/messages.pot new file mode 100644 index 000000000..5a5e4660b --- /dev/null +++ b/web/pgadmin/messages.pot @@ -0,0 +1,210 @@ +# Translations template for PROJECT. +# Copyright (C) 2015 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2015. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2015-02-25 16:30+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" + +#: pgadmin/about/views.py:35 +msgid "Server" +msgstr "" + +#: pgadmin/about/views.py:37 +msgid "Desktop" +msgstr "" + +#: pgadmin/about/templates/about/index.html:2 +msgid "Version" +msgstr "" + +#: pgadmin/about/templates/about/index.html:6 +msgid "Copyright" +msgstr "" + +#: pgadmin/about/templates/about/index.html:10 +msgid "Python Version" +msgstr "" + +#: pgadmin/about/templates/about/index.html:14 +msgid "Flask Version" +msgstr "" + +#: pgadmin/about/templates/about/index.html:18 +msgid "Application Mode" +msgstr "" + +#: pgadmin/about/templates/about/index.html:22 +msgid "Current User" +msgstr "" + +#: pgadmin/browser/nodes/server_groups/hooks.py:34 +msgid "Add a server group..." +msgstr "" + +#: pgadmin/browser/nodes/server_groups/hooks.py:35 +#: pgadmin/browser/nodes/server_groups/hooks.py:43 +msgid "Delete server group" +msgstr "" + +#: pgadmin/browser/nodes/server_groups/hooks.py:36 +#: pgadmin/browser/nodes/server_groups/hooks.py:44 +msgid "Rename server group..." +msgstr "" + +#: pgadmin/browser/nodes/server_groups/views.py:48 +msgid "No server group name was specified" +msgstr "" + +#: pgadmin/browser/nodes/server_groups/views.py:73 +#: pgadmin/browser/nodes/server_groups/views.py:104 +msgid "The specified server group could not be found." +msgstr "" + +#: pgadmin/browser/nodes/server_groups/views.py:84 +msgid "No server group was specified." +msgstr "" + +#: pgadmin/browser/nodes/server_groups/views.py:115 +msgid "No server group was specified." +msgstr "" + +#: pgadmin/browser/templates/browser/body.html:11 +msgid "Dashboard" +msgstr "" + +#: pgadmin/browser/templates/browser/body.html:12 +msgid "Properties" +msgstr "" + +#: pgadmin/browser/templates/browser/body.html:13 +msgid "Statistics" +msgstr "" + +#: pgadmin/browser/templates/browser/body.html:14 +msgid "Dependencies" +msgstr "" + +#: pgadmin/browser/templates/browser/body.html:15 +msgid "Dependents" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:8 +msgid "Toggle navigation" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:21 +msgid "File" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:28 +msgid "Edit" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:35 +msgid "Tools" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:42 +msgid "Management" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:49 +msgid "Help" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:61 +#: pgadmin/templates/security/change_password.html:10 +msgid "Change Password" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:63 +msgid "Logout" +msgstr "" + +#: pgadmin/help/hooks.py:21 +msgid "Contents" +msgstr "" + +#: pgadmin/templates/security/change_password.html:2 +#, python-format +msgid "%(appname)s Password Change" +msgstr "" + +#: pgadmin/templates/security/forgot_password.html:2 +#, python-format +msgid "Recover %(appname)s Password" +msgstr "" + +#: pgadmin/templates/security/forgot_password.html:4 +msgid "" +"Enter the email address for the user account you wish to recover the " +"password for:" +msgstr "" + +#: pgadmin/templates/security/forgot_password.html:9 +msgid "Recover Password" +msgstr "" + +#: pgadmin/templates/security/login_user.html:2 +#, python-format +msgid "%(appname)s Login" +msgstr "" + +#: pgadmin/templates/security/login_user.html:9 +msgid "Login" +msgstr "" + +#: pgadmin/templates/security/login_user.html:12 +#, python-format +msgid "Forgotten your password?" +msgstr "" + +#: pgadmin/templates/security/messages.html:6 +msgid "Close" +msgstr "" + +#: pgadmin/templates/security/reset_password.html:2 +#, python-format +msgid "%(appname)s Password Reset" +msgstr "" + +#: pgadmin/templates/security/reset_password.html:9 +msgid "Reset Password" +msgstr "" + +#: pgadmin/test/hooks.py:19 +msgid "Generated Test HTML" +msgstr "" + +#: pgadmin/test/hooks.py:20 +msgid "Test Alert" +msgstr "" + +#: pgadmin/test/hooks.py:21 +msgid "Test Confirm" +msgstr "" + +#: pgadmin/test/hooks.py:22 +msgid "Test Dialog" +msgstr "" + +#: pgadmin/test/hooks.py:23 +msgid "Test Prompt" +msgstr "" + +#: pgadmin/test/hooks.py:24 +msgid "Test Notifier" +msgstr "" + diff --git a/web/pgadmin/templates/security/change_password.html b/web/pgadmin/templates/security/change_password.html index 60440c38c..4e91c9696 100644 --- a/web/pgadmin/templates/security/change_password.html +++ b/web/pgadmin/templates/security/change_password.html @@ -1,5 +1,5 @@ {% extends "security/panel.html" %} -{% block panel_title %}pgAdmin Password Change{% endblock %} +{% block panel_title %}{{ _('%(appname)s Password Change', appname=config.APP_NAME) }}{% endblock %} {% block panel_body %}
{{ change_password_form.hidden_tag() }} @@ -7,7 +7,7 @@ {{ render_field_with_errors(change_password_form.password, "password") }} {{ render_field_with_errors(change_password_form.new_password, "password") }} {{ render_field_with_errors(change_password_form.new_password_confirm, "password") }} - +
{% endblock %} diff --git a/web/pgadmin/templates/security/forgot_password.html b/web/pgadmin/templates/security/forgot_password.html index 20ef2079f..a0393c37f 100644 --- a/web/pgadmin/templates/security/forgot_password.html +++ b/web/pgadmin/templates/security/forgot_password.html @@ -1,12 +1,12 @@ {% extends "security/panel.html" %} -{% block panel_title %}Recover pgAdmin Password{% endblock %} +{% block panel_title %}{{ _('Recover %(appname)s Password', appname=config.APP_NAME) }}{% endblock %} {% block panel_body %} -

Enter the email address for the user account you wish to recover the password for:

+

{{ _('Enter the email address for the user account you wish to recover the password for:') }}

{{ forgot_password_form.hidden_tag() }}
{{ render_field_with_errors(forgot_password_form.email, "text") }} - +
{% endblock %} diff --git a/web/pgadmin/templates/security/login_user.html b/web/pgadmin/templates/security/login_user.html index cebefa360..b09216cf3 100644 --- a/web/pgadmin/templates/security/login_user.html +++ b/web/pgadmin/templates/security/login_user.html @@ -1,13 +1,13 @@ {% extends "security/panel.html" %} -{% block panel_title %}pgAdmin Login{% endblock %} +{% block panel_title %}{{ _('%(appname)s Login', appname=config.APP_NAME) }}{% endblock %} {% block panel_body %}
{{ login_user_form.hidden_tag() }}
{{ render_field_with_errors(login_user_form.email, "text") }} {{ render_field_with_errors(login_user_form.password, "password") }} - +
-Forgotten your password? +{{ _('Forgotten your password?', url=url_for('security.forgot_password')) }} {% endblock %} diff --git a/web/pgadmin/templates/security/messages.html b/web/pgadmin/templates/security/messages.html index d6b758da0..bc919094e 100644 --- a/web/pgadmin/templates/security/messages.html +++ b/web/pgadmin/templates/security/messages.html @@ -3,7 +3,7 @@
{% for category, message in messages %} {% endfor %} diff --git a/web/pgadmin/templates/security/reset_password.html b/web/pgadmin/templates/security/reset_password.html index e04085e36..5c1be5048 100644 --- a/web/pgadmin/templates/security/reset_password.html +++ b/web/pgadmin/templates/security/reset_password.html @@ -1,12 +1,12 @@ {% extends "security/panel.html" %} -{% block panel_title %}pgAdmin Password Reset{% endblock %} +{% block panel_title %}{{ _('%(appname)s Password Reset', appname=config.APP_NAME) }}{% endblock %} {% block panel_body %}
{{ reset_password_form.hidden_tag() }}
{{ render_field_with_errors(reset_password_form.password, "password") }} {{ render_field_with_errors(reset_password_form.password_confirm, "password") }} - +
{% endblock %} diff --git a/web/pgadmin/templates/security/watermark.html b/web/pgadmin/templates/security/watermark.html index 67f66c4b2..3e7a4cc01 100644 --- a/web/pgadmin/templates/security/watermark.html +++ b/web/pgadmin/templates/security/watermark.html @@ -1,5 +1,5 @@ {% block watermark %}
- pgAdmin 4 + {{ config.APP_NAME }}
{% endblock %} diff --git a/web/pgadmin/test/hooks.py b/web/pgadmin/test/hooks.py index 12a501858..5bb319d72 100644 --- a/web/pgadmin/test/hooks.py +++ b/web/pgadmin/test/hooks.py @@ -10,17 +10,18 @@ """Browser integration functions for the Test module.""" from flask import render_template, url_for +from flask.ext.babel import gettext def get_file_menu_items(): """Return a (set) of dicts of file menu items, with name, priority, URL, target and onclick code.""" return [ - {'name': 'mnu_generate_test_html', 'label': 'Generated Test HTML', 'priority': 100, 'url': url_for('test.generated')}, - {'name': 'mnu_test_alert', 'label': 'Test Alert', 'priority': 200, 'url': '#', 'onclick': 'test_alert()'}, - {'name': 'mnu_test_confirm', 'label': 'Test Confirm', 'priority': 300, 'url': '#', 'onclick': 'test_confirm()'}, - {'name': 'mnu_test_dialog', 'label': 'Test Dialog', 'priority': 400, 'url': '#', 'onclick': 'test_dialog()'}, - {'name': 'mnu_test_prompt', 'label': 'Test Prompt', 'priority': 500, 'url': '#', 'onclick': 'test_prompt()'}, - {'name': 'mnu_test_notifier', 'label': 'Test Notifier', 'priority': 600, 'url': '#', 'onclick': 'test_notifier()'}, + {'name': 'mnu_generate_test_html', 'label': gettext('Generated Test HTML'), 'priority': 100, 'url': url_for('test.generated')}, + {'name': 'mnu_test_alert', 'label': gettext('Test Alert'), 'priority': 200, 'url': '#', 'onclick': 'test_alert()'}, + {'name': 'mnu_test_confirm', 'label': gettext('Test Confirm'), 'priority': 300, 'url': '#', 'onclick': 'test_confirm()'}, + {'name': 'mnu_test_dialog', 'label': gettext('Test Dialog'), 'priority': 400, 'url': '#', 'onclick': 'test_dialog()'}, + {'name': 'mnu_test_prompt', 'label': gettext('Test Prompt'), 'priority': 500, 'url': '#', 'onclick': 'test_prompt()'}, + {'name': 'mnu_test_notifier', 'label': gettext('Test Notifier'), 'priority': 600, 'url': '#', 'onclick': 'test_notifier()'}, ] def get_scripts(): diff --git a/web/pgadmin/translations/fr/LC_MESSAGES/messages.mo b/web/pgadmin/translations/fr/LC_MESSAGES/messages.mo new file mode 100644 index 000000000..eaa998f6a Binary files /dev/null and b/web/pgadmin/translations/fr/LC_MESSAGES/messages.mo differ diff --git a/web/pgadmin/translations/fr/LC_MESSAGES/messages.po b/web/pgadmin/translations/fr/LC_MESSAGES/messages.po new file mode 100644 index 000000000..7eec5ddcc --- /dev/null +++ b/web/pgadmin/translations/fr/LC_MESSAGES/messages.po @@ -0,0 +1,211 @@ +# French translations for PROJECT. +# Copyright (C) 2015 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2015. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2015-02-25 16:30+0000\n" +"PO-Revision-Date: 2015-02-25 17:04+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: fr \n" +"Plural-Forms: nplurals=2; plural=(n > 1)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" + +#: pgadmin/about/views.py:35 +msgid "Server" +msgstr "" + +#: pgadmin/about/views.py:37 +msgid "Desktop" +msgstr "" + +#: pgadmin/about/templates/about/index.html:2 +msgid "Version" +msgstr "" + +#: pgadmin/about/templates/about/index.html:6 +msgid "Copyright" +msgstr "" + +#: pgadmin/about/templates/about/index.html:10 +msgid "Python Version" +msgstr "" + +#: pgadmin/about/templates/about/index.html:14 +msgid "Flask Version" +msgstr "" + +#: pgadmin/about/templates/about/index.html:18 +msgid "Application Mode" +msgstr "" + +#: pgadmin/about/templates/about/index.html:22 +msgid "Current User" +msgstr "" + +#: pgadmin/browser/nodes/server_groups/hooks.py:34 +msgid "Add a server group..." +msgstr "" + +#: pgadmin/browser/nodes/server_groups/hooks.py:35 +#: pgadmin/browser/nodes/server_groups/hooks.py:43 +msgid "Delete server group" +msgstr "" + +#: pgadmin/browser/nodes/server_groups/hooks.py:36 +#: pgadmin/browser/nodes/server_groups/hooks.py:44 +msgid "Rename server group..." +msgstr "" + +#: pgadmin/browser/nodes/server_groups/views.py:48 +msgid "No server group name was specified" +msgstr "" + +#: pgadmin/browser/nodes/server_groups/views.py:73 +#: pgadmin/browser/nodes/server_groups/views.py:104 +msgid "The specified server group could not be found." +msgstr "" + +#: pgadmin/browser/nodes/server_groups/views.py:84 +msgid "No server group was specified." +msgstr "" + +#: pgadmin/browser/nodes/server_groups/views.py:115 +msgid "No server group was specified." +msgstr "" + +#: pgadmin/browser/templates/browser/body.html:11 +msgid "Dashboard" +msgstr "" + +#: pgadmin/browser/templates/browser/body.html:12 +msgid "Properties" +msgstr "" + +#: pgadmin/browser/templates/browser/body.html:13 +msgid "Statistics" +msgstr "" + +#: pgadmin/browser/templates/browser/body.html:14 +msgid "Dependencies" +msgstr "" + +#: pgadmin/browser/templates/browser/body.html:15 +msgid "Dependents" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:8 +msgid "Toggle navigation" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:21 +msgid "File" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:28 +msgid "Edit" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:35 +msgid "Tools" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:42 +msgid "Management" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:49 +msgid "Help" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:61 +#: pgadmin/templates/security/change_password.html:10 +msgid "Change Password" +msgstr "" + +#: pgadmin/browser/templates/browser/index.html:63 +msgid "Logout" +msgstr "" + +#: pgadmin/help/hooks.py:21 +msgid "Contents" +msgstr "" + +#: pgadmin/templates/security/change_password.html:2 +#, python-format +msgid "%(appname)s Password Change" +msgstr "" + +#: pgadmin/templates/security/forgot_password.html:2 +#, python-format +msgid "Recover %(appname)s Password" +msgstr "" + +#: pgadmin/templates/security/forgot_password.html:4 +msgid "" +"Enter the email address for the user account you wish to recover the " +"password for:" +msgstr "" + +#: pgadmin/templates/security/forgot_password.html:9 +msgid "Recover Password" +msgstr "" + +#: pgadmin/templates/security/login_user.html:2 +#, python-format +msgid "%(appname)s Login" +msgstr "" + +#: pgadmin/templates/security/login_user.html:9 +msgid "Login" +msgstr "" + +#: pgadmin/templates/security/login_user.html:12 +#, python-format +msgid "Forgotten your password?" +msgstr "" + +#: pgadmin/templates/security/messages.html:6 +msgid "Close" +msgstr "" + +#: pgadmin/templates/security/reset_password.html:2 +#, python-format +msgid "%(appname)s Password Reset" +msgstr "" + +#: pgadmin/templates/security/reset_password.html:9 +msgid "Reset Password" +msgstr "" + +#: pgadmin/test/hooks.py:19 +msgid "Generated Test HTML" +msgstr "" + +#: pgadmin/test/hooks.py:20 +msgid "Test Alert" +msgstr "" + +#: pgadmin/test/hooks.py:21 +msgid "Test Confirm" +msgstr "" + +#: pgadmin/test/hooks.py:22 +msgid "Test Dialog" +msgstr "" + +#: pgadmin/test/hooks.py:23 +msgid "Test Prompt" +msgstr "" + +#: pgadmin/test/hooks.py:24 +msgid "Test Notifier" +msgstr "" +