From 67aa9fa31a7c64bf59a1b942ecbe6dc83c878241 Mon Sep 17 00:00:00 2001 From: "Turkesh Patel (Open ERP)" Date: Wed, 11 Jul 2012 12:44:05 +0530 Subject: [PATCH 01/14] [IMP] load translation using 'translation' http service bzr revid: tpa@tinyerp.com-20120711071405-g0biuqlctedlbcs9 --- addons/web/controllers/main.py | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 412ea9abda2..5d7aa93f3a5 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -353,25 +353,15 @@ class WebClient(openerpweb.Controller): langs = lang.split(separator) langs = [separator.join(langs[:x]) for x in range(1, len(langs) + 1)] - transs = {} - for addon_name in mods: - transl = {"messages":[]} - transs[addon_name] = transl - addons_path = openerpweb.addons_manifest[addon_name]['addons_path'] - for l in langs: - f_name = os.path.join(addons_path, addon_name, "i18n", l + ".po") - if not os.path.exists(f_name): - continue - try: - with open(f_name) as t_file: - po = babel.messages.pofile.read_po(t_file) - except Exception: - continue - for x in po: - if x.id and x.string and "openerp-web" in x.auto_comments: - transl["messages"].append({'id': x.id, 'string': x.string}) - return {"modules": transs, - "lang_parameters": lang_obj} + messages = {} + for mod in mods: + messages[mod] = {"messages":[]} + proxy = req.session.proxy("translation") + trans = proxy.load(req.session._db, [mod], langs, "web") + if trans: + messages[mod] = trans + return {"modules": {'messages': messages}, + "lang_parameters": lang_obj} @openerpweb.jsonrequest def version_info(self, req): From f0f4ba6d413ce89e016b26895f1e3fb62450d2ae Mon Sep 17 00:00:00 2001 From: "Turkesh Patel (Open ERP)" Date: Thu, 12 Jul 2012 16:11:10 +0530 Subject: [PATCH 02/14] [IMP] improved code. bzr revid: tpa@tinyerp.com-20120712104110-wot1evq0affpx2tp --- addons/web/controllers/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 5d7aa93f3a5..eb60b178ad2 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -360,7 +360,7 @@ class WebClient(openerpweb.Controller): trans = proxy.load(req.session._db, [mod], langs, "web") if trans: messages[mod] = trans - return {"modules": {'messages': messages}, + return {"modules": messages, "lang_parameters": lang_obj} @openerpweb.jsonrequest From 4bbbef1929fc41b9928690ac77112ec5aa3db452 Mon Sep 17 00:00:00 2001 From: "Turkesh Patel (Open ERP)" Date: Thu, 12 Jul 2012 16:29:55 +0530 Subject: [PATCH 03/14] [IMP] improved code for load translation when run web without embedded mode. bzr revid: tpa@tinyerp.com-20120712105955-szwm5vb49va6o4dp --- addons/web/controllers/main.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index eb60b178ad2..75feed44c69 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -360,6 +360,24 @@ class WebClient(openerpweb.Controller): trans = proxy.load(req.session._db, [mod], langs, "web") if trans: messages[mod] = trans + # keep loading from .po (Reason to run web without embedded mode) + if not messages['web']['messages']: + for addon_name in mods: + transl = {'messages':[]} + messages[addon_name] = transl + addons_path = openerpweb.addons_manifest[addon_name]['addons_path'] + for l in langs: + f_name = os.path.join(addons_path, addon_name, "i18n", l + ".po") + if not os.path.exists(f_name): + continue + try: + with open(f_name) as t_file: + po = babel.messages.pofile.read_po(t_file) + except Exception: + continue + for x in po: + if x.id and x.string and "openerp-web" in x.auto_comments: + transl["messages"].append({'id': x.id, 'string': x.string}) return {"modules": messages, "lang_parameters": lang_obj} From e9c78767dd87c003c6e93f679e531e34b90d04c7 Mon Sep 17 00:00:00 2001 From: "Turkesh Patel (Open ERP)" Date: Thu, 12 Jul 2012 18:55:42 +0530 Subject: [PATCH 04/14] [IMP] improved code bzr revid: tpa@tinyerp.com-20120712132542-c19ysod7jm5jmukc --- addons/web/controllers/main.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 75feed44c69..6c0e2e4dc9b 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -357,9 +357,7 @@ class WebClient(openerpweb.Controller): for mod in mods: messages[mod] = {"messages":[]} proxy = req.session.proxy("translation") - trans = proxy.load(req.session._db, [mod], langs, "web") - if trans: - messages[mod] = trans + messages[mod] = proxy.load(req.session._db, [mod], langs, "web") # keep loading from .po (Reason to run web without embedded mode) if not messages['web']['messages']: for addon_name in mods: From 0d4bd736e1bd8c8acb78f63e190111b1c72b05af Mon Sep 17 00:00:00 2001 From: "Turkesh Patel (Open ERP)" Date: Fri, 13 Jul 2012 12:30:48 +0530 Subject: [PATCH 05/14] [IMP] improved code to get formeted traslation from server. bzr revid: tpa@tinyerp.com-20120713070048-7yxm3fcajemiingc --- addons/web/controllers/main.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 6c0e2e4dc9b..7cde4040e4f 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -353,11 +353,8 @@ class WebClient(openerpweb.Controller): langs = lang.split(separator) langs = [separator.join(langs[:x]) for x in range(1, len(langs) + 1)] - messages = {} - for mod in mods: - messages[mod] = {"messages":[]} - proxy = req.session.proxy("translation") - messages[mod] = proxy.load(req.session._db, [mod], langs, "web") + proxy = req.session.proxy("translation") + messages = proxy.load(req.session._db, mods, langs, "web") # keep loading from .po (Reason to run web without embedded mode) if not messages['web']['messages']: for addon_name in mods: From 58e20e9c8f0f40b93a0d4dd1ff68666d49311949 Mon Sep 17 00:00:00 2001 From: "Turkesh Patel (Open ERP)" Date: Mon, 16 Jul 2012 11:30:56 +0530 Subject: [PATCH 06/14] [IMP] improved code to load data from po. bzr revid: tpa@tinyerp.com-20120716060056-3az6awpd6gw39hii --- addons/web/controllers/main.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 7cde4040e4f..024360ce5e6 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -355,14 +355,11 @@ class WebClient(openerpweb.Controller): proxy = req.session.proxy("translation") messages = proxy.load(req.session._db, mods, langs, "web") - # keep loading from .po (Reason to run web without embedded mode) - if not messages['web']['messages']: - for addon_name in mods: - transl = {'messages':[]} - messages[addon_name] = transl - addons_path = openerpweb.addons_manifest[addon_name]['addons_path'] + for mod in messages: + if not messages[mod]['messages']: + addons_path = openerpweb.addons_manifest[mod]['addons_path'] for l in langs: - f_name = os.path.join(addons_path, addon_name, "i18n", l + ".po") + f_name = os.path.join(addons_path, mod, "i18n", l + ".po") if not os.path.exists(f_name): continue try: @@ -372,7 +369,7 @@ class WebClient(openerpweb.Controller): continue for x in po: if x.id and x.string and "openerp-web" in x.auto_comments: - transl["messages"].append({'id': x.id, 'string': x.string}) + messages[mod]["messages"].append({'id': x.id, 'string': x.string}) return {"modules": messages, "lang_parameters": lang_obj} From a3a2ec416b3fb4be2dbf6ed0333b3d1417ddc206 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 18 Sep 2012 09:28:02 +0200 Subject: [PATCH 07/14] [IMP] translation: load translations from ir.translation after authenticating, use local POs for bootstrap only (login page) bzr revid: odo@openerp.com-20120918072802-568n19bg1ecm1m2t --- addons/web/controllers/main.py | 161 ++++++++++++++------------ addons/web/static/src/js/coresetup.js | 7 +- addons/web/static/src/xml/base.xml | 2 +- 3 files changed, 93 insertions(+), 77 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index d420ba9175d..35698d1085d 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -19,7 +19,6 @@ import zlib from xml.etree import ElementTree from cStringIO import StringIO -import babel.messages.pofile import werkzeug.utils import werkzeug.wrappers try: @@ -203,47 +202,8 @@ def module_installed(req): sorted_modules = module_topological_sort(modules) return sorted_modules -def module_installed_bypass_session(dbname): - loadable = openerpweb.addons_manifest.keys() - modules = {} - try: - import openerp.modules.registry - registry = openerp.modules.registry.RegistryManager.get(dbname) - with registry.cursor() as cr: - m = registry.get('ir.module.module') - # TODO The following code should move to ir.module.module.list_installed_modules() - domain = [('state','=','installed'), ('name','in', loadable)] - ids = m.search(cr, 1, [('state','=','installed'), ('name','in', loadable)]) - for module in m.read(cr, 1, ids, ['name', 'dependencies_id']): - modules[module['name']] = [] - deps = module.get('dependencies_id') - if deps: - deps_read = registry.get('ir.module.module.dependency').read(cr, 1, deps, ['name']) - dependencies = [i['name'] for i in deps_read] - modules[module['name']] = dependencies - except Exception,e: - pass - sorted_modules = module_topological_sort(modules) - return sorted_modules - def module_boot(req): - serverside = [] - dbside = [] - for i in req.config.server_wide_modules: - if i in openerpweb.addons_manifest: - serverside.append(i) - # if only one db load every module at boot - dbs = [] - try: - dbs = db_list(req) - except xmlrpclib.Fault: - # ignore access denied - pass - if len(dbs) == 1: - dbside = module_installed_bypass_session(dbs[0]) - dbside = [i for i in dbside if i not in serverside] - addons = serverside + dbside - return addons + return [m for m in req.config.server_wide_modules if m in openerpweb.addons_manifest] def concat_xml(file_list): """Concatenate xml files @@ -531,6 +491,38 @@ def parse_context(context, session): except ValueError: return common.nonliterals.Context(session, context) + +# PO file parsing - only used to boostrap translations on the login page +try: + # Use the faster PO parser from OpenERP server when available + from openerp.tools.translate import TinyPoFile + def _local_web_translations(trans_file): + messages = [] + try: + with open(trans_file) as t_file: + po = TinyPoFile(t_file) + for _, _, _, source, value, comments in po: + if "openerp-web" in comments: + messages.append({'id': source, 'string': value}) + except Exception: + pass + return messages +except ImportError: + # Otherwise fallback to Babel's slightly slower PO parser + import babel.messages.pofile + def _local_web_translations(trans_file): + messages = [] + try: + with open(trans_file) as t_file: + po = babel.messages.pofile.read_po(t_file) + except Exception: + return + for x in po: + if x.id and x.string and "openerp-web" in x.auto_comments: + messages.append({'id': x.id, 'string': x.string}) + return messages + + #---------------------------------------------------------- # OpenERP Web web Controllers #---------------------------------------------------------- @@ -576,6 +568,7 @@ class Home(openerpweb.Controller): def login(self, req, db, login, key): return login_and_redirect(req, db, login, key) + class WebClient(openerpweb.Controller): _cp_path = "/web/webclient" @@ -658,41 +651,59 @@ class WebClient(openerpweb.Controller): last_modified, checksum) @openerpweb.jsonrequest - def translations(self, req, mods, lang): - lang_model = req.session.model('res.lang') - ids = lang_model.search([("code", "=", lang)]) - if ids: - lang_obj = lang_model.read(ids[0], ["direction", "date_format", "time_format", - "grouping", "decimal_point", "thousands_sep"]) - else: - lang_obj = None + def bootstrap_translations(self, req, mods): + """ Load local translations from *.po files, as a temporary solution + until we have established a valid session. This is meant only + for translating the login page and db management chrome, using + the browser's language. """ + lang = req.httprequest.accept_languages.best or 'en' + # For performance reasons we only load a single translation, so for + # sub-languages (that should only be partially translated) we load the + # main language PO instead - that should be enough for the login screen. + if '-' in lang: # RFC2616 uses '-' separators for sublanguages + lang = [lang.split('-',1)[0], lang] - if "_" in lang: - separator = "_" - else: - separator = "@" - langs = lang.split(separator) - langs = [separator.join(langs[:x]) for x in range(1, len(langs) + 1)] - - proxy = req.session.proxy("translation") - messages = proxy.load(req.session._db, mods, langs, "web") + translations_per_module = {} for addon_name in mods: - if not messages[addon_name]['messages']: - addons_path = openerpweb.addons_manifest[addon_name]['addons_path'] - for l in langs: - f_name = os.path.join(addons_path, addon_name, "i18n", l + ".po") - if not os.path.exists(f_name): - continue - try: - with open(f_name) as t_file: - po = babel.messages.pofile.read_po(t_file) - except Exception: - continue - for x in po: - if x.id and x.string and "openerp-web" in x.auto_comments: - messages[addon_name]["messages"].append({'id': x.id, 'string': x.string}) - return {"modules": messages, - "lang_parameters": lang_obj} + addons_path = openerpweb.addons_manifest[addon_name]['addons_path'] + f_name = os.path.join(addons_path, addon_name, "i18n", lang + ".po") + if not os.path.exists(f_name): + continue + translations_per_module[addon_name] = {'messages': _local_web_translations(f_name)} + + return {"modules": translations_per_module, + "lang_parameters": None} + + @openerpweb.jsonrequest + def translations(self, req, mods, lang): + res_lang = req.session.model('res.lang') + ids = res_lang.search([("code", "=", lang)]) + lang_params = None + if ids: + lang_params = res_lang.read(ids[0], ["direction", "date_format", "time_format", + "grouping", "decimal_point", "thousands_sep"]) + + # Regional languages (ll_CC) must inherit/override their parent lang (ll), but this is + # done server-side when the language is loaded, so we only need to load the user's lang. + start = datetime.datetime.now() + ir_translation = req.session.model('ir.translation') + translations_per_module = {} + messages = ir_translation.search_read([('module','in',mods),('lang','=',lang), + ('comments','like','openerp-web'),('value','!=',False), + ('value','!=','')], + ['module','src','value','lang'], order='module') + for mod, msg_group in itertools.groupby(messages, key=operator.itemgetter('module')): + translations_per_module.setdefault(mod,{'messages':[]}) + translations_per_module[mod]['messages'].extend({'id': m['src'], + 'string': m['value']} \ + for m in msg_group) + + print "Loaded translations in ", datetime.datetime.now()-start + import pprint + pprint.pprint(translations_per_module) + + return {"modules": translations_per_module, + "lang_parameters": lang_params} @openerpweb.jsonrequest def version_info(self, req): @@ -769,7 +780,7 @@ class Database(openerpweb.Controller): {'fileToken': int(token)} ) except xmlrpclib.Fault, e: - return simplejson.dumps([[],[{'error': e.faultCode, 'title': 'backup Database'}]]) + return simplejson.dumps([[],[{'error': e.faultCode, 'title': 'backup Database'}]]) @openerpweb.httprequest def restore(self, req, db_file, restore_pwd, new_db): diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js index ea160d6faee..826275bfa0f 100644 --- a/addons/web/static/src/js/coresetup.js +++ b/addons/web/static/src/js/coresetup.js @@ -57,7 +57,12 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess if(self.session_is_valid()) { return deferred.pipe(function() { return self.load_modules(); }); } - return deferred; + return $.when( + deferred, + self.rpc('/web/webclient/bootstrap_translations', {mods: instance._modules}).pipe(function(trans) { + instance.web._t.database.set_bundle(trans); + }) + ); }); }, /** diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index b6b89a4f1ec..d1d028aa3f5 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -407,7 +407,7 @@
From 13dfee0de0fdca7edfc0eae157ebcb8904a6a8df Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 18 Sep 2012 15:51:11 +0200 Subject: [PATCH 08/14] [IMP] translations: keep only one method for loading translations bzr revid: odo@openerp.com-20120918135111-o6ylzs1n36kqkh4c --- addons/web/controllers/main.py | 41 ++++++++++------------------------ 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 35698d1085d..234d765d5c7 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -19,6 +19,7 @@ import zlib from xml.etree import ElementTree from cStringIO import StringIO +import babel.messages.pofile import werkzeug.utils import werkzeug.wrappers try: @@ -492,35 +493,17 @@ def parse_context(context, session): return common.nonliterals.Context(session, context) -# PO file parsing - only used to boostrap translations on the login page -try: - # Use the faster PO parser from OpenERP server when available - from openerp.tools.translate import TinyPoFile - def _local_web_translations(trans_file): - messages = [] - try: - with open(trans_file) as t_file: - po = TinyPoFile(t_file) - for _, _, _, source, value, comments in po: - if "openerp-web" in comments: - messages.append({'id': source, 'string': value}) - except Exception: - pass - return messages -except ImportError: - # Otherwise fallback to Babel's slightly slower PO parser - import babel.messages.pofile - def _local_web_translations(trans_file): - messages = [] - try: - with open(trans_file) as t_file: - po = babel.messages.pofile.read_po(t_file) - except Exception: - return - for x in po: - if x.id and x.string and "openerp-web" in x.auto_comments: - messages.append({'id': x.id, 'string': x.string}) - return messages +def _local_web_translations(trans_file): + messages = [] + try: + with open(trans_file) as t_file: + po = babel.messages.pofile.read_po(t_file) + except Exception: + return + for x in po: + if x.id and x.string and "openerp-web" in x.auto_comments: + messages.append({'id': x.id, 'string': x.string}) + return messages #---------------------------------------------------------- From f742d3b213e36df0e6b826fb3d0de610251db4fc Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 28 Sep 2012 23:00:07 +0200 Subject: [PATCH 09/14] [FIX] web: minor improvements to some translateable terms bzr revid: odo@openerp.com-20120928210007-ukf4u20rpwmugfwt --- addons/web/static/src/js/coresetup.js | 3 +-- addons/web/static/src/js/search.js | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js index 826275bfa0f..4a30a312b7a 100644 --- a/addons/web/static/src/js/coresetup.js +++ b/addons/web/static/src/js/coresetup.js @@ -605,8 +605,7 @@ var messages_by_seconds = function() { [120, _t("Don't leave yet,
it's still loading...")], [300, _t("You may not believe it,
but the application is actually loading...")], [420, _t("Take a minute to get a coffee,
because it's loading...")], - [600, _t("It's loading...
By the way, did you tried the kitten mode?")], - [3600, _t("Maybe you should consider pressing F5...")], + [3600, _t("Maybe you should consider reloading the application by pressing F5...")], ]; }; diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 8e9a31922b8..cd3611366e4 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -1496,7 +1496,7 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({ if (value.length > 1) { // more than one search_default m2o id? Should we OR them? throw new Error( - _("M2O search fields do not currently handle multiple default values")); + _t("M2O search fields do not currently handle multiple default values")); } // there are many cases of {search_default_$m2ofield: [id]}, need // to handle this as if it were a single value. @@ -1581,7 +1581,7 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({ $filter.unbind('click').click(function () { self.view.query.reset([{ - category: _("Custom Filter"), + category: _t("Custom Filter"), icon: 'M', field: { get_context: function () { return filter.context; }, From 42ae23d0323ff1377d5e6a3dad490c871af5b810 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 2 Oct 2012 11:33:59 +0200 Subject: [PATCH 10/14] [FIX] base.xml: disable translation on CSS style element bzr revid: odo@openerp.com-20121002093359-dxdd60auidfra3rj --- addons/web/static/src/xml/base.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 58bc224918c..b035c2c8c14 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -1119,7 +1119,7 @@ - width: 83px; + width: 83px;