diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 36db03d6bba..d4d420590ab 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -18,6 +18,7 @@ import openerpweb import openerpweb.ast import openerpweb.nonliterals +from babel.messages.pofile import read_po # Should move to openerpweb.Xml2Json class Xml2Json: @@ -156,6 +157,26 @@ class WebClient(openerpweb.Controller): 'css': css } return r + + @openerpweb.jsonrequest + def translations(self, req, mods, lang): + transs = {} + for addon_name in mods: + transl = {"messages":[]} + transs[addon_name] = transl + f_name = os.path.join(openerpweb.path_addons, addon_name, "po", lang + ".po") + if not os.path.exists(f_name): + continue + try: + with open(f_name) as t_file: + po = read_po(t_file) + except: + continue + for x in po: + if x.id: + transl["messages"].append({'id': x.id, 'string': x.string}) + return {"modules": transs} + class Database(openerpweb.Controller): _cp_path = "/base/database" @@ -251,10 +272,12 @@ class Session(openerpweb.Controller): @openerpweb.jsonrequest def login(self, req, db, login, password): req.session.login(db, login, password) + ctx = req.session.get_context() return { "session_id": req.session_id, "uid": req.session._uid, + "context": ctx } @openerpweb.jsonrequest diff --git a/addons/base/po/base.pot b/addons/base/po/base.pot new file mode 100644 index 00000000000..84f7ebfe6db --- /dev/null +++ b/addons/base/po/base.pot @@ -0,0 +1,32 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2011. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2011-08-16 09:44+0200\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 0.9.4\n" + +#: addons/base/static/src/js/form.js:1459 +msgid "   Search More..." +msgstr "" + +#: addons/base/static/src/js/form.js:1472 +#, python-format +msgid "   Create \"%s\"" +msgstr "" + +#: addons/base/static/src/js/form.js:1478 +msgid "   Create and Edit..." +msgstr "" + diff --git a/addons/base/po/fr_FR.po b/addons/base/po/fr_FR.po new file mode 100644 index 00000000000..08905cac036 --- /dev/null +++ b/addons/base/po/fr_FR.po @@ -0,0 +1,33 @@ +# Translations template for PROJECT. +# Copyright (C) 2011 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# niv , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2011-08-09 17:30+0200\n" +"PO-Revision-Date: 2011-08-09 17:31+0200\n" +"Last-Translator: niv \n" +"Language-Team: French\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 0.9.4\n" +"Language: fr\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: addons/base/static/src/js/form.js:1459 +msgid "   Search More..." +msgstr "   Chercher plus..." + +#: addons/base/static/src/js/form.js:1472 +#, python-format +msgid "   Create \"%s\"" +msgstr "   Créer \"%s\"" + +#: addons/base/static/src/js/form.js:1478 +msgid "   Create and Edit..." +msgstr "   Créer et éditer..." + diff --git a/addons/base/static/src/js/chrome.js b/addons/base/static/src/js/chrome.js index 7e7f5ae6ab6..49d2099c948 100644 --- a/addons/base/static/src/js/chrome.js +++ b/addons/base/static/src/js/chrome.js @@ -681,7 +681,7 @@ openerp.base.WebClient = openerp.base.Widget.extend({ } this.$element.html(QWeb.render("Interface", params)); - this.session = new openerp.base.Session(this,"oe_errors"); + this.session = new openerp.base.Session(); this.loading = new openerp.base.Loading(this,"oe_loading"); this.crashmanager = new openerp.base.CrashManager(this); this.crashmanager.start(); diff --git a/addons/base/static/src/js/core.js b/addons/base/static/src/js/core.js index da9b5abf3e8..8efae36863a 100644 --- a/addons/base/static/src/js/core.js +++ b/addons/base/static/src/js/core.js @@ -305,16 +305,8 @@ openerp.base.Registry = openerp.base.Class.extend( /** @lends openerp.base.Regis } }); -/** - * Utility class that any class is allowed to extend to easy common manipulations. - * - * It provides rpc calls, callback on all methods preceded by "on_" or "do_" and a - * logging facility. - */ -openerp.base.SessionAware = openerp.base.Class.extend({ - init: function(session) { - this.session = session; - +openerp.base.CallbackEnabled = openerp.base.Class.extend({ + init: function() { // Transform on_* method into openerp.base.callbacks for (var name in this) { if(typeof(this[name]) == "function") { @@ -325,6 +317,19 @@ openerp.base.SessionAware = openerp.base.Class.extend({ } } } + } +}); + +/** + * Utility class that any class is allowed to extend to easy common manipulations. + * + * It provides rpc calls, callback on all methods preceded by "on_" or "do_" and a + * logging facility. + */ +openerp.base.SessionAware = openerp.base.CallbackEnabled.extend({ + init: function(session) { + this._super(); + this.session = session; }, /** * Performs a JSON-RPC call @@ -558,15 +563,56 @@ openerp.base.OldWidget = openerp.base.Widget.extend({ } }); -openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Session# */{ +openerp.base.TranslationDataBase = openerp.base.Class.extend({ + init: function() { + this.db = {}; + }, + set_bundle: function(translation_bundle) { + var self = this; + this.db = {}; + var modules = _.keys(translation_bundle.modules).sort(); + if (_.include(modules, "base")) { + modules = ["base"].concat(_.without(modules, "base")); + } + _.each(modules, function(name) { + self.add_module_translation(translation_bundle.modules[name]); + }); + }, + add_module_translation: function(mod) { + var self = this; + _.each(mod.messages, function(message) { + if (self.db[message.id] === undefined) { + self.db[message.id] = message.string; + } + }); + }, + build_translation_function: function() { + var self = this; + var fcnt = function(str) { + var tmp = self.get(str); + return tmp === undefined ? str : tmp; + } + fcnt.database = this; + return fcnt; + }, + get: function(key) { + if (this.db[key]) + return this.db[key]; + return undefined; + } +}); + +openerp.base._t = new openerp.base.TranslationDataBase().build_translation_function(); + +openerp.base.Session = openerp.base.CallbackEnabled.extend( /** @lends openerp.base.Session# */{ /** * @constructs * @param element_id to use for exception reporting * @param server * @param port */ - init: function(parent, element_id, server, port) { - this._super(parent, element_id); + init: function(server, port) { + this._super(); this.server = (server == undefined) ? location.hostname : server; this.port = (port == undefined) ? location.port : port; this.rpc_mode = (server == location.hostname) ? "ajax" : "jsonp"; @@ -574,6 +620,7 @@ openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Sessi this.db = ""; this.login = ""; this.password = ""; + this.user_context= {}; this.uid = false; this.session_id = false; this.module_list = []; @@ -700,6 +747,7 @@ openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Sessi this.rpc("/base/session/login", params, function(result) { self.session_id = result.session_id; self.uid = result.uid; + self.user_context = result.context; self.session_save(); self.on_session_valid(); if (success_callback) @@ -717,6 +765,7 @@ openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Sessi this.session_id = this.get_cookie('session_id'); this.db = this.get_cookie('db'); this.login = this.get_cookie('login'); + this.user_context = this.get_cookie("user_context"); // we should do an rpc to confirm that this session_id is valid and if it is retrieve the information about db and login // then call on_session_valid this.on_session_valid(); @@ -729,6 +778,7 @@ openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Sessi this.set_cookie('session_id', this.session_id); this.set_cookie('db', this.db); this.set_cookie('login', this.login); + this.set_cookie('user_context', this.user_context); }, logout: function() { delete this.uid; @@ -781,15 +831,22 @@ openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Sessi var self = this; this.rpc('/base/session/modules', {}, function(result) { self.module_list = result; - var modules = self.module_list.join(','); - if(self.debug || true) { - self.rpc('/base/webclient/csslist', {"mods": modules}, self.do_load_css); - self.rpc('/base/webclient/jslist', {"mods": modules}, self.do_load_js); - } else { - self.do_load_css(["/base/webclient/css?mods="+modules]); - self.do_load_js(["/base/webclient/js?mods="+modules]); - } - openerp._modules_loaded = true; + var lang = self.user_context.lang; + self.rpc('/base/webclient/translations',{ + mods: ["base"].concat(result), + lang: lang}) + .then(function(transs) { + openerp.base._t.database.set_bundle(transs); + var modules = self.module_list.join(','); + if(self.debug || true) { + self.rpc('/base/webclient/csslist', {"mods": modules}, self.do_load_css); + self.rpc('/base/webclient/jslist', {"mods": modules}, self.do_load_js); + } else { + self.do_load_css(["/base/webclient/css?mods="+modules]); + self.do_load_js(["/base/webclient/js?mods="+modules]); + } + openerp._modules_loaded = true; + }); }); }, do_load_css: function (files) { @@ -827,6 +884,7 @@ openerp.base.Session = openerp.base.Widget.extend( /** @lends openerp.base.Sessi openerp[mod] = {}; // init module mod if(openerp._openerp[mod] != undefined) { + openerp._openerp[mod]._T = openerp.base._t.database.build_translation_function(); openerp._openerp[mod](openerp); this.module_loaded[mod] = true; } diff --git a/addons/base/static/src/js/form.js b/addons/base/static/src/js/form.js index 4e7876b1768..6eeff025e1f 100644 --- a/addons/base/static/src/js/form.js +++ b/addons/base/static/src/js/form.js @@ -1,4 +1,6 @@ openerp.base.form = function (openerp) { + +var _t = openerp.base._t; openerp.base.views.add('form', 'openerp.base.FormView'); openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormView# */{ @@ -1454,7 +1456,7 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({ // search more... if more results that max if (values.length > self.limit) { values = values.slice(0, self.limit); - values.push({label: "   Search More...", action: function() { + values.push({label: _t("   Search More..."), action: function() { dataset.name_search(search_val, self.build_domain(), 'ilike' , false, function(data) { self._change_int_value(null); @@ -1467,13 +1469,13 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({ if (search_val.length > 0 && !_.include(raw_result, search_val) && (!self.value || search_val !== self.value[1])) { - values.push({label: '   Create "' + - $('').text(search_val).html() + '"', action: function() { + values.push({label: _.sprintf(_t('   Create "%s"'), + $('').text(search_val).html()), action: function() { self._quick_create(search_val); }}); } // create... - values.push({label: "   Create and Edit...", action: function() { + values.push({label: _t("   Create and Edit..."), action: function() { self._change_int_value(null); self._search_create_popup("form", undefined, {"default_name": search_val}); }}); diff --git a/babel.cfg b/babel.cfg new file mode 100644 index 00000000000..bcfd3572f3e --- /dev/null +++ b/babel.cfg @@ -0,0 +1,13 @@ +## Extraction from Python source files +#[python: **.py] +## Extraction from Genshi HTML and text templates +#[genshi: **/templates/**.html] +#ignore_tags = script,style +#include_attrs = alt title summary +#[genshi: **/templates/**.txt] +#template_class = genshi.template:TextTemplate +#encoding = ISO-8819-15 +## Extraction from JavaScript files +[javascript: **.js] +[javascript: **.xml] + diff --git a/gen_translations.sh b/gen_translations.sh new file mode 100755 index 00000000000..9c3a14e2dcc --- /dev/null +++ b/gen_translations.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +usage() +{ +cat << EOF +usage: $0 -a +usage: $0 DIR OUTPUT_FILE + +OPTIONS: + -a recreate the .pot file for all addons + -h print this message +EOF +exit 0 +} + +do_all= + +while getopts "a" opt +do + case "$opt" in + a) + do_all=true;; + h) + usage;; + \?) + usage;; + esac +done + +shift $((OPTIND-1)) + +if [ -n "$do_all" ] +then + echo "Extracting all the translations" + $0 addons/base/static/src/ addons/base/po/base.pot +elif [ -n "$2" ] +then + pybabel extract -F babel.cfg -o $2 -k _t --no-default-keywords $1 +else + usage +fi