[merge] added i18n capabilities

bzr revid: nicolas.vanhoren@openerp.com-20110816075635-db2i5kfiog9di8vq
This commit is contained in:
niv-openerp 2011-08-16 09:56:35 +02:00
commit da7a365ebf
8 changed files with 229 additions and 27 deletions

View File

@ -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

32
addons/base/po/base.pot Normal file
View File

@ -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 <EMAIL@ADDRESS>, 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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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 "<em>   Search More...</em>"
msgstr ""
#: addons/base/static/src/js/form.js:1472
#, python-format
msgid "<em>   Create \"<strong>%s</strong>\"</em>"
msgstr ""
#: addons/base/static/src/js/form.js:1478
msgid "<em>   Create and Edit...</em>"
msgstr ""

33
addons/base/po/fr_FR.po Normal file
View File

@ -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 <nicolas.vanhoren@openerp.com>, 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 <nicolas.vanhoren@openerp.com>\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 "<em>   Search More...</em>"
msgstr "<em>   Chercher plus...</em>"
#: addons/base/static/src/js/form.js:1472
#, python-format
msgid "<em>   Create \"<strong>%s</strong>\"</em>"
msgstr "<em>   Créer \"<strong>%s</strong>\"</em>"
#: addons/base/static/src/js/form.js:1478
msgid "<em>   Create and Edit...</em>"
msgstr "<em>   Créer et éditer...</em>"

View File

@ -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();

View File

@ -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;
}

View File

@ -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: "<em>   Search More...</em>", action: function() {
values.push({label: _t("<em>   Search More...</em>"), 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: '<em>   Create "<strong>' +
$('<span />').text(search_val).html() + '</strong>"</em>', action: function() {
values.push({label: _.sprintf(_t('<em>   Create "<strong>%s</strong>"</em>'),
$('<span />').text(search_val).html()), action: function() {
self._quick_create(search_val);
}});
}
// create...
values.push({label: "<em>   Create and Edit...</em>", action: function() {
values.push({label: _t("<em>   Create and Edit...</em>"), action: function() {
self._change_int_value(null);
self._search_create_popup("form", undefined, {"default_name": search_val});
}});

13
babel.cfg Normal file
View File

@ -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]

41
gen_translations.sh Executable file
View File

@ -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