[IMP] translations: wip, remove unnecessary code, support loading PO comments and storing them, split ir.translation view data in separate XML file
bzr revid: odo@openerp.com-20120913142920-ggpeqth4s2wwqwd2
This commit is contained in:
parent
09ba29883c
commit
550751b358
|
@ -44,6 +44,7 @@ The kernel of OpenERP, needed for all installation.
|
||||||
'data/res.country.state.csv',
|
'data/res.country.state.csv',
|
||||||
'ir/wizard/wizard_menu_view.xml',
|
'ir/wizard/wizard_menu_view.xml',
|
||||||
'ir/ir.xml',
|
'ir/ir.xml',
|
||||||
|
'ir/ir_translation_view.xml',
|
||||||
'ir/ir_filters.xml',
|
'ir/ir_filters.xml',
|
||||||
'ir/ir_config_parameter_view.xml',
|
'ir/ir_config_parameter_view.xml',
|
||||||
'ir/workflow/workflow_view.xml',
|
'ir/workflow/workflow_view.xml',
|
||||||
|
|
|
@ -1147,75 +1147,6 @@
|
||||||
<menuitem action="action_model_relation" id="ir_model_relation_menu" parent="base.next_id_9"
|
<menuitem action="action_model_relation" id="ir_model_relation_menu" parent="base.next_id_9"
|
||||||
groups="base.group_no_one"/>
|
groups="base.group_no_one"/>
|
||||||
|
|
||||||
<!-- Translations -->
|
|
||||||
|
|
||||||
<record id="view_translation_search" model="ir.ui.view">
|
|
||||||
<field name="name">Translations</field>
|
|
||||||
<field name="model">ir.translation</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<search string="Translations">
|
|
||||||
<filter icon="terp-gdu-smart-failing"
|
|
||||||
string="Untranslated"
|
|
||||||
domain="['|',('value', '=', False),('value','=','')]"/>
|
|
||||||
<field name="name" operator="="/>
|
|
||||||
<field name="lang"/>
|
|
||||||
<field name="src"/>
|
|
||||||
<field name="value"/>
|
|
||||||
</search>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="view_translation_form" model="ir.ui.view">
|
|
||||||
<field name="name">Translations</field>
|
|
||||||
<field name="model">ir.translation</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="Translations" version="7.0">
|
|
||||||
<header>
|
|
||||||
<field name="state" widget="statusbar" nolabel="1"/>
|
|
||||||
</header>
|
|
||||||
<sheet>
|
|
||||||
<group>
|
|
||||||
<group>
|
|
||||||
<field name="name"/>
|
|
||||||
<field name="lang"/>
|
|
||||||
</group>
|
|
||||||
<group>
|
|
||||||
<field name="type"/>
|
|
||||||
<field name="res_id"/>
|
|
||||||
</group>
|
|
||||||
<group string="Source Term">
|
|
||||||
<field name="src" nolabel="1" height="400"/>
|
|
||||||
</group>
|
|
||||||
<group string="Translation">
|
|
||||||
<field name="value" nolabel="1" height="400"/>
|
|
||||||
</group>
|
|
||||||
</group>
|
|
||||||
</sheet>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<record id="view_translation_tree" model="ir.ui.view">
|
|
||||||
<field name="name">Translations</field>
|
|
||||||
<field name="model">ir.translation</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<tree string="Translations" editable="bottom">
|
|
||||||
<field name="src" readonly="True"/>
|
|
||||||
<field name="value"/>
|
|
||||||
<field name="name" readonly="True"/>
|
|
||||||
<field name="lang" readonly="True"/>
|
|
||||||
<field name="type" readonly="True"/>
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="action_translation" model="ir.actions.act_window">
|
|
||||||
<field name="name">Translated Terms</field>
|
|
||||||
<field name="res_model">ir.translation</field>
|
|
||||||
<field name="view_type">form</field>
|
|
||||||
<field name="view_id" ref="view_translation_tree"/>
|
|
||||||
</record>
|
|
||||||
<menuitem action="action_translation" id="menu_action_translation" parent="base.menu_translation_app" />
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
=============================================================
|
=============================================================
|
||||||
Menu Edition
|
Menu Edition
|
||||||
|
|
|
@ -19,10 +19,11 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from osv import fields, osv
|
|
||||||
import tools
|
import tools
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import openerp.modules
|
import openerp.modules
|
||||||
|
from openerp.osv import fields, osv
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -58,7 +59,6 @@ class ir_translation_import_cursor(object):
|
||||||
the data.
|
the data.
|
||||||
@param parent an instance of ir.translation ORM model
|
@param parent an instance of ir.translation ORM model
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._cr = cr
|
self._cr = cr
|
||||||
self._uid = uid
|
self._uid = uid
|
||||||
self._context = context
|
self._context = context
|
||||||
|
@ -77,8 +77,9 @@ class ir_translation_import_cursor(object):
|
||||||
"""Feed a translation, as a dictionary, into the cursor
|
"""Feed a translation, as a dictionary, into the cursor
|
||||||
"""
|
"""
|
||||||
params = dict(trans_dict, state="translated" if trans_dict['value'] else "to_translate")
|
params = dict(trans_dict, state="translated" if trans_dict['value'] else "to_translate")
|
||||||
self._cr.execute("""INSERT INTO %s (name, lang, res_id, src, type, imd_model, module, imd_name, value, state)
|
self._cr.execute("""INSERT INTO %s (name, lang, res_id, src, type, imd_model, module, imd_name, value, state, comments)
|
||||||
VALUES (%%(name)s, %%(lang)s, %%(res_id)s, %%(src)s, %%(type)s, %%(imd_model)s, %%(module)s, %%(imd_name)s, %%(value)s, %%(state)s)""" % self._table_name,
|
VALUES (%%(name)s, %%(lang)s, %%(res_id)s, %%(src)s, %%(type)s, %%(imd_model)s, %%(module)s,
|
||||||
|
%%(imd_name)s, %%(value)s, %%(state)s, %%(comments)s)""" % self._table_name,
|
||||||
params)
|
params)
|
||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
|
@ -106,11 +107,10 @@ class ir_translation_import_cursor(object):
|
||||||
for row in cr.fetchall():
|
for row in cr.fetchall():
|
||||||
_logger.debug("ir.translation.cursor: missing res_id for %s. %s/%s ", *row)
|
_logger.debug("ir.translation.cursor: missing res_id for %s. %s/%s ", *row)
|
||||||
|
|
||||||
cr.execute("DELETE FROM %s WHERE res_id IS NULL AND module IS NOT NULL" % \
|
|
||||||
self._table_name)
|
|
||||||
|
|
||||||
# Records w/o res_id must _not_ be inserted into our db, because they are
|
# Records w/o res_id must _not_ be inserted into our db, because they are
|
||||||
# referencing non-existent data.
|
# referencing non-existent data.
|
||||||
|
cr.execute("DELETE FROM %s WHERE res_id IS NULL AND module IS NOT NULL" % \
|
||||||
|
self._table_name)
|
||||||
|
|
||||||
find_expr = "irt.lang = ti.lang AND irt.type = ti.type " \
|
find_expr = "irt.lang = ti.lang AND irt.type = ti.type " \
|
||||||
" AND irt.name = ti.name AND irt.src = ti.src " \
|
" AND irt.name = ti.name AND irt.src = ti.src " \
|
||||||
|
@ -120,14 +120,14 @@ class ir_translation_import_cursor(object):
|
||||||
if self._overwrite:
|
if self._overwrite:
|
||||||
cr.execute("""UPDATE ONLY %s AS irt
|
cr.execute("""UPDATE ONLY %s AS irt
|
||||||
SET value = ti.value,
|
SET value = ti.value,
|
||||||
state = 'translated'
|
state = 'translated'
|
||||||
FROM %s AS ti
|
FROM %s AS ti
|
||||||
WHERE %s AND ti.value IS NOT NULL AND ti.value != ''
|
WHERE %s AND ti.value IS NOT NULL AND ti.value != ''
|
||||||
""" % (self._parent_table, self._table_name, find_expr))
|
""" % (self._parent_table, self._table_name, find_expr))
|
||||||
|
|
||||||
# Step 3: insert new translations
|
# Step 3: insert new translations
|
||||||
cr.execute("""INSERT INTO %s(name, lang, res_id, src, type, value, module, state)
|
cr.execute("""INSERT INTO %s(name, lang, res_id, src, type, value, module, state, comments)
|
||||||
SELECT name, lang, res_id, src, type, value, module, state
|
SELECT name, lang, res_id, src, type, value, module, state, comments
|
||||||
FROM %s AS ti
|
FROM %s AS ti
|
||||||
WHERE NOT EXISTS(SELECT 1 FROM ONLY %s AS irt WHERE %s);
|
WHERE NOT EXISTS(SELECT 1 FROM ONLY %s AS irt WHERE %s);
|
||||||
""" % (self._parent_table, self._table_name, self._parent_table, find_expr))
|
""" % (self._parent_table, self._table_name, self._parent_table, find_expr))
|
||||||
|
@ -155,29 +155,37 @@ class ir_translation(osv.osv):
|
||||||
return [(d['code'], d['name']) for d in lang_data]
|
return [(d['code'], d['name']) for d in lang_data]
|
||||||
|
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Field Name', size=128, required=True),
|
'name': fields.char('Translated field', required=True),
|
||||||
'res_id': fields.integer('Resource ID', select=True),
|
'res_id': fields.integer('Record ID', select=True),
|
||||||
'lang': fields.selection(_get_language, string='Language', size=16),
|
'lang': fields.selection(_get_language, string='Language'),
|
||||||
'type': fields.selection(TRANSLATION_TYPE, string='Type', size=16, select=True),
|
'type': fields.selection(TRANSLATION_TYPE, string='Type', select=True),
|
||||||
'src': fields.text('Source'),
|
'src': fields.text('Source'),
|
||||||
'value': fields.text('Translation Value'),
|
'value': fields.text('Translation Value'),
|
||||||
'module': fields.char('Module Name', size=128),
|
'module': fields.char('Module', help="Module this term belongs to", select=True),
|
||||||
'state': fields.selection([('to_translate','To Translate'),
|
|
||||||
('inprogress','Translation in Progress'),
|
'state': fields.selection(
|
||||||
('translated','Translated')])
|
[('to_translate','To Translate'),
|
||||||
|
('inprogress','Translation in Progress'),
|
||||||
|
('translated','Translated')],
|
||||||
|
string="State",
|
||||||
|
help="Automatically set to let administators find new terms that might need to be translated"),
|
||||||
|
|
||||||
|
# aka gettext extracted-comments - we use them to flag openerp-web translation
|
||||||
|
# cfr: http://www.gnu.org/savannah-checkouts/gnu/gettext/manual/html_node/PO-Files.html
|
||||||
|
'comments': fields.text('Translation comments', select=True),
|
||||||
}
|
}
|
||||||
|
|
||||||
_defaults = {
|
_defaults = {
|
||||||
'state':'to_translate',
|
'state': 'to_translate',
|
||||||
}
|
}
|
||||||
|
|
||||||
_sql_constraints = [ ('lang_fkey_res_lang', 'FOREIGN KEY(lang) REFERENCES res_lang(code)',
|
_sql_constraints = [ ('lang_fkey_res_lang', 'FOREIGN KEY(lang) REFERENCES res_lang(code)',
|
||||||
'Language code of translation item must be among known languages' ), ]
|
'Language code of translation item must be among known languages' ), ]
|
||||||
|
|
||||||
def _auto_init(self, cr, context=None):
|
def _auto_init(self, cr, context=None):
|
||||||
super(ir_translation, self)._auto_init(cr, context)
|
super(ir_translation, self)._auto_init(cr, context)
|
||||||
|
|
||||||
# FIXME: there is a size limit on btree indexed values so we can't index src column with normal btree.
|
# FIXME: there is a size limit on btree indexed values so we can't index src column with normal btree.
|
||||||
cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('ir_translation_ltns',))
|
cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('ir_translation_ltns',))
|
||||||
if cr.fetchone():
|
if cr.fetchone():
|
||||||
#temporarily removed: cr.execute('CREATE INDEX ir_translation_ltns ON ir_translation (name, lang, type, src)')
|
#temporarily removed: cr.execute('CREATE INDEX ir_translation_ltns ON ir_translation (name, lang, type, src)')
|
||||||
|
@ -203,7 +211,7 @@ class ir_translation(osv.osv):
|
||||||
if field == 'lang':
|
if field == 'lang':
|
||||||
return
|
return
|
||||||
return super(ir_translation, self)._check_selection_field_value(cr, uid, field, value, context=context)
|
return super(ir_translation, self)._check_selection_field_value(cr, uid, field, value, context=context)
|
||||||
|
|
||||||
@tools.ormcache_multi(skiparg=3, multi=6)
|
@tools.ormcache_multi(skiparg=3, multi=6)
|
||||||
def _get_ids(self, cr, uid, name, tt, lang, ids):
|
def _get_ids(self, cr, uid, name, tt, lang, ids):
|
||||||
translations = dict.fromkeys(ids, False)
|
translations = dict.fromkeys(ids, False)
|
||||||
|
@ -263,14 +271,14 @@ class ir_translation(osv.osv):
|
||||||
# FIXME: should assert that `source` is unicode and fix all callers to always pass unicode
|
# FIXME: should assert that `source` is unicode and fix all callers to always pass unicode
|
||||||
# so we can remove the string encoding/decoding.
|
# so we can remove the string encoding/decoding.
|
||||||
if not lang:
|
if not lang:
|
||||||
return u''
|
return tools.ustr(source or '')
|
||||||
if isinstance(types, basestring):
|
if isinstance(types, basestring):
|
||||||
types = (types,)
|
types = (types,)
|
||||||
if source:
|
if source:
|
||||||
query = """SELECT value
|
query = """SELECT value
|
||||||
FROM ir_translation
|
FROM ir_translation
|
||||||
WHERE lang=%s
|
WHERE lang=%s
|
||||||
AND type in %s
|
AND type in %s
|
||||||
AND src=%s"""
|
AND src=%s"""
|
||||||
params = (lang or '', types, tools.ustr(source))
|
params = (lang or '', types, tools.ustr(source))
|
||||||
if name:
|
if name:
|
||||||
|
@ -304,9 +312,9 @@ class ir_translation(osv.osv):
|
||||||
if isinstance(ids, (int, long)):
|
if isinstance(ids, (int, long)):
|
||||||
ids = [ids]
|
ids = [ids]
|
||||||
if vals.get('src') or ('value' in vals and not(vals.get('value'))):
|
if vals.get('src') or ('value' in vals and not(vals.get('value'))):
|
||||||
result = vals.update({'state':'to_translate'})
|
vals.update({'state':'to_translate'})
|
||||||
if vals.get('value'):
|
if vals.get('value'):
|
||||||
result = vals.update({'state':'translated'})
|
vals.update({'state':'translated'})
|
||||||
result = super(ir_translation, self).write(cursor, user, ids, vals, context=context)
|
result = super(ir_translation, self).write(cursor, user, ids, vals, context=context)
|
||||||
for trans_obj in self.read(cursor, user, ids, ['name','type','res_id','src','lang'], context=context):
|
for trans_obj in self.read(cursor, user, ids, ['name','type','res_id','src','lang'], context=context):
|
||||||
self._get_source.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], trans_obj['src'])
|
self._get_source.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], trans_obj['src'])
|
||||||
|
@ -374,40 +382,35 @@ class ir_translation(osv.osv):
|
||||||
""" Return a cursor-like object for fast inserting translations
|
""" Return a cursor-like object for fast inserting translations
|
||||||
"""
|
"""
|
||||||
return ir_translation_import_cursor(cr, uid, self, context=context)
|
return ir_translation_import_cursor(cr, uid, self, context=context)
|
||||||
|
|
||||||
def load(self, cr, modules, langs, flag=None, context=None):
|
def load(self, cr, modules, langs, context=None):
|
||||||
translated_data = {}
|
context = dict(context or {}) # local copy
|
||||||
for module_name in modules:
|
for module_name in modules:
|
||||||
translated_data[module_name] = {'messages':[]}
|
|
||||||
modpath = openerp.modules.get_module_path(module_name)
|
modpath = openerp.modules.get_module_path(module_name)
|
||||||
if not modpath:
|
if not modpath:
|
||||||
# unable to find the module. we skip
|
|
||||||
continue
|
continue
|
||||||
for lang in langs:
|
for lang in langs:
|
||||||
iso_lang = tools.get_iso_codes(lang)
|
lang_code = tools.get_iso_codes(lang)
|
||||||
f = openerp.modules.get_module_resource(module_name, 'i18n', iso_lang + '.po')
|
base_lang_code = None
|
||||||
context2 = context and context.copy() or {}
|
if '_' in lang_code:
|
||||||
if f and '_' in iso_lang:
|
base_lang_code = lang_code.split('_')[0]
|
||||||
iso_lang2 = iso_lang.split('_')[0]
|
|
||||||
f2 = openerp.modules.get_module_resource(module_name, 'i18n', iso_lang2 + '.po')
|
# Step 1: for sub-languages, load base language first (e.g. es_CL.po is loaded over es.po)
|
||||||
if f2:
|
if base_lang_code:
|
||||||
_logger.info('module %s: loading base translation file %s for language %s', module_name, iso_lang2, lang)
|
base_trans_file = openerp.modules.get_module_resource(module_name, 'i18n', base_lang_code + '.po')
|
||||||
translated_data[module_name]['messages'].extend(tools.trans_load(cr, f2, lang, verbose=False, flag=flag, module_name=module_name, context=context))
|
if base_trans_file:
|
||||||
context2['overwrite'] = True
|
_logger.info('module %s: loading base translation file %s for language %s', module_name, base_lang_code, lang)
|
||||||
# Implementation notice: we must first search for the full name of
|
tools.trans_load(cr, base_trans_file, lang, verbose=False, module_name=module_name, context=context)
|
||||||
# the language derivative, like "en_UK", and then the generic,
|
context['overwrite'] = True # make sure the requested translation will override the base terms later
|
||||||
# like "en".
|
|
||||||
if (not f) and '_' in iso_lang:
|
# Step 2: then load the main translation file, possibly overriding the terms coming from the base language
|
||||||
iso_lang = iso_lang.split('_')[0]
|
trans_file = openerp.modules.get_module_resource(module_name, 'i18n', lang_code + '.po')
|
||||||
f = openerp.modules.get_module_resource(module_name, 'i18n', iso_lang + '.po')
|
if trans_file:
|
||||||
if f:
|
_logger.info('module %s: loading translation file (%s) for language %s', module_name, lang_code, lang)
|
||||||
_logger.info('module %s: loading translation file (%s) for language %s', module_name, iso_lang, lang)
|
tools.trans_load(cr, trans_file, lang, verbose=False, module_name=module_name, context=context)
|
||||||
translated_data[module_name]['messages'].extend(tools.trans_load(cr, f, lang, verbose=False, flag=flag, module_name=module_name, context=context2))
|
elif lang_code != 'en':
|
||||||
elif iso_lang != 'en':
|
_logger.warning('module %s: no translation for language %s', module_name, lang_code)
|
||||||
_logger.warning('module %s: no translation for language %s', module_name, iso_lang)
|
return True
|
||||||
return translated_data
|
|
||||||
|
|
||||||
ir_translation()
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
||||||
|
|
|
@ -192,15 +192,12 @@ class view(osv.osv):
|
||||||
def write(self, cr, uid, ids, vals, context=None):
|
def write(self, cr, uid, ids, vals, context=None):
|
||||||
if not isinstance(ids, (list, tuple)):
|
if not isinstance(ids, (list, tuple)):
|
||||||
ids = [ids]
|
ids = [ids]
|
||||||
result = super(view, self).write(cr, uid, ids, vals, context)
|
|
||||||
|
|
||||||
# drop the corresponding view customizations (used for dashboards for example), otherwise
|
# drop the corresponding view customizations (used for dashboards for example), otherwise
|
||||||
# not all users would see the updated views
|
# not all users would see the updated views
|
||||||
custom_view_ids = self.pool.get('ir.ui.view.custom').search(cr, uid, [('ref_id','in',ids)])
|
custom_view_ids = self.pool.get('ir.ui.view.custom').search(cr, uid, [('ref_id','in',ids)])
|
||||||
if custom_view_ids:
|
if custom_view_ids:
|
||||||
self.pool.get('ir.ui.view.custom').unlink(cr, uid, custom_view_ids)
|
self.pool.get('ir.ui.view.custom').unlink(cr, uid, custom_view_ids)
|
||||||
|
return super(view, self).write(cr, uid, ids, vals, context)
|
||||||
return result
|
|
||||||
|
|
||||||
def graph_get(self, cr, uid, id, model, node_obj, conn_obj, src_node, des_node, label, scale, context=None):
|
def graph_get(self, cr, uid, id, model, node_obj, conn_obj, src_node, des_node, label, scale, context=None):
|
||||||
nodes=[]
|
nodes=[]
|
||||||
|
|
|
@ -632,20 +632,14 @@ class module(osv.osv):
|
||||||
self.write(cr, uid, [mod_browse.id], {'category_id': p_id})
|
self.write(cr, uid, [mod_browse.id], {'category_id': p_id})
|
||||||
|
|
||||||
def update_translations(self, cr, uid, ids, filter_lang=None, context=None):
|
def update_translations(self, cr, uid, ids, filter_lang=None, context=None):
|
||||||
pool = pooler.get_pool(cr.dbname)
|
|
||||||
if context is None:
|
|
||||||
context = {}
|
|
||||||
if not filter_lang:
|
if not filter_lang:
|
||||||
lang_obj = pool.get('res.lang')
|
res_lang = self.pool.get('res.lang')
|
||||||
lang_ids = lang_obj.search(cr, uid, [('translatable', '=', True)])
|
lang_ids = res_lang.search(cr, uid, [('translatable', '=', True)])
|
||||||
filter_lang = [lang.code for lang in lang_obj.browse(cr, uid, lang_ids)]
|
filter_lang = [lang.code for lang in res_lang.browse(cr, uid, lang_ids)]
|
||||||
elif not isinstance(filter_lang, (list, tuple)):
|
elif not isinstance(filter_lang, (list, tuple)):
|
||||||
filter_lang = [filter_lang]
|
filter_lang = [filter_lang]
|
||||||
|
modules = [m.name for m in self.browse(cr, uid, ids) if m.state == 'installed']
|
||||||
for mod in self.browse(cr, uid, ids):
|
self.pool.get('ir.translation').load(cr, modules, filter_lang, context=context)
|
||||||
if mod.state != 'installed':
|
|
||||||
continue
|
|
||||||
pool.get('ir.translation').load(cr, [mod.name], filter_lang, context=context)
|
|
||||||
|
|
||||||
def check(self, cr, uid, ids, context=None):
|
def check(self, cr, uid, ids, context=None):
|
||||||
for mod in self.browse(cr, uid, ids, context=context):
|
for mod in self.browse(cr, uid, ids, context=context):
|
||||||
|
|
|
@ -777,36 +777,12 @@ class report_spool(netsvc.ExportService):
|
||||||
else:
|
else:
|
||||||
raise Exception, 'ReportNotFound'
|
raise Exception, 'ReportNotFound'
|
||||||
|
|
||||||
class translation(netsvc.ExportService):
|
|
||||||
|
|
||||||
def __init__(self, name="translation"):
|
|
||||||
netsvc.ExportService.__init__(self, name)
|
|
||||||
|
|
||||||
def exp_load(self, db, modules, langs, flag=None, context=None):
|
|
||||||
cr = pooler.get_db(db).cursor()
|
|
||||||
translated_data = pooler.get_pool(db).get('ir.translation').load(cr, modules, langs, flag, context=context)
|
|
||||||
cr.commit()
|
|
||||||
cr.close()
|
|
||||||
return translated_data
|
|
||||||
|
|
||||||
def dispatch(self, method, params):
|
|
||||||
if method in ['load']:
|
|
||||||
# No security check for these methods
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise KeyError("Method not found: %s" % method)
|
|
||||||
fn = getattr(self, 'exp_'+method)
|
|
||||||
return fn(*params)
|
|
||||||
|
|
||||||
|
|
||||||
def start_web_services():
|
def start_web_services():
|
||||||
db()
|
db()
|
||||||
common()
|
common()
|
||||||
objects_proxy()
|
objects_proxy()
|
||||||
wizard()
|
wizard()
|
||||||
report_spool()
|
report_spool()
|
||||||
translation()
|
|
||||||
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,6 @@ class RpcCase(unittest2.TestCase):
|
||||||
self.proxy.common_61 = xmlrpclib.ServerProxy(url_61 + 'common')
|
self.proxy.common_61 = xmlrpclib.ServerProxy(url_61 + 'common')
|
||||||
self.proxy.db_61 = xmlrpclib.ServerProxy(url_61 + 'db')
|
self.proxy.db_61 = xmlrpclib.ServerProxy(url_61 + 'db')
|
||||||
self.proxy.model_61 = xmlrpclib.ServerProxy(url_61 + 'model/' + DB)
|
self.proxy.model_61 = xmlrpclib.ServerProxy(url_61 + 'model/' + DB)
|
||||||
self.proxy.translation_61 = xmlrpclib.ServerProxy(url_61 + 'translation')
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_database_name(cls):
|
def generate_database_name(cls):
|
||||||
|
|
|
@ -71,11 +71,6 @@ class test_xmlrpc(common.RpcCase):
|
||||||
"""
|
"""
|
||||||
assert self.proxy.db_60.drop(ADMIN_PASSWORD, DB) is True
|
assert self.proxy.db_60.drop(ADMIN_PASSWORD, DB) is True
|
||||||
|
|
||||||
def test_xmlrpc_61_translation_load(self):
|
|
||||||
""" Try a load translation service like web. """
|
|
||||||
messages = self.proxy.translation_61.load(DB, ['base', 'web'], ['en_US'], 'web')
|
|
||||||
assert messages
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest2.main()
|
unittest2.main()
|
||||||
|
|
||||||
|
|
|
@ -262,7 +262,7 @@ class TinyPoFile(object):
|
||||||
self.lines_count = len(self.lines);
|
self.lines_count = len(self.lines);
|
||||||
|
|
||||||
self.first = True
|
self.first = True
|
||||||
self.tnrs= []
|
self.extra_lines= []
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def _get_lines(self):
|
def _get_lines(self):
|
||||||
|
@ -278,14 +278,14 @@ class TinyPoFile(object):
|
||||||
return (self.lines_count - len(self.lines))
|
return (self.lines_count - len(self.lines))
|
||||||
|
|
||||||
def next(self):
|
def next(self):
|
||||||
type = name = res_id = source = trad = None
|
trans_type = name = res_id = source = trad = None
|
||||||
|
if self.extra_lines:
|
||||||
if self.tnrs:
|
trans_type, name, res_id, source, trad, comments = self.extra_lines.pop(0)
|
||||||
type, name, res_id, source, trad = self.tnrs.pop(0)
|
|
||||||
if not res_id:
|
if not res_id:
|
||||||
res_id = '0'
|
res_id = '0'
|
||||||
else:
|
else:
|
||||||
tmp_tnrs = []
|
comments = []
|
||||||
|
targets = []
|
||||||
line = None
|
line = None
|
||||||
fuzzy = False
|
fuzzy = False
|
||||||
while (not line):
|
while (not line):
|
||||||
|
@ -295,15 +295,20 @@ class TinyPoFile(object):
|
||||||
while line.startswith('#'):
|
while line.startswith('#'):
|
||||||
if line.startswith('#~ '):
|
if line.startswith('#~ '):
|
||||||
break
|
break
|
||||||
if line.startswith('#:'):
|
if line.startswith('#.'):
|
||||||
|
line = line[2:].strip()
|
||||||
|
if not line.startswith('module:'):
|
||||||
|
comments.append(line)
|
||||||
|
elif line.startswith('#:'):
|
||||||
for lpart in line[2:].strip().split(' '):
|
for lpart in line[2:].strip().split(' '):
|
||||||
trans_info = lpart.strip().split(':',2)
|
trans_info = lpart.strip().split(':',2)
|
||||||
if trans_info and len(trans_info) == 2:
|
if trans_info and len(trans_info) == 2:
|
||||||
# looks like the translation type is missing, which is not
|
# looks like the translation trans_type is missing, which is not
|
||||||
# unexpected because it is not a GetText standard. Default: 'code'
|
# unexpected because it is not a GetText standard. Default: 'code'
|
||||||
trans_info[:0] = ['code']
|
trans_info[:0] = ['code']
|
||||||
if trans_info and len(trans_info) == 3:
|
if trans_info and len(trans_info) == 3:
|
||||||
tmp_tnrs.append(trans_info)
|
# this is a ref line holding the destination info (model, field, record)
|
||||||
|
targets.append(trans_info)
|
||||||
elif line.startswith('#,') and (line[2:].strip() == 'fuzzy'):
|
elif line.startswith('#,') and (line[2:].strip() == 'fuzzy'):
|
||||||
fuzzy = True
|
fuzzy = True
|
||||||
line = self.lines.pop(0).strip()
|
line = self.lines.pop(0).strip()
|
||||||
|
@ -326,7 +331,7 @@ class TinyPoFile(object):
|
||||||
# if the source is "" and it's the first msgid, it's the special
|
# if the source is "" and it's the first msgid, it's the special
|
||||||
# msgstr with the informations about the traduction and the
|
# msgstr with the informations about the traduction and the
|
||||||
# traductor; we skip it
|
# traductor; we skip it
|
||||||
self.tnrs = []
|
self.extra_lines = []
|
||||||
while line:
|
while line:
|
||||||
line = self.lines.pop(0).strip()
|
line = self.lines.pop(0).strip()
|
||||||
return self.next()
|
return self.next()
|
||||||
|
@ -343,10 +348,10 @@ class TinyPoFile(object):
|
||||||
trad += unquote(line)
|
trad += unquote(line)
|
||||||
line = self.lines.pop(0).strip()
|
line = self.lines.pop(0).strip()
|
||||||
|
|
||||||
if tmp_tnrs and not fuzzy:
|
if targets and not fuzzy:
|
||||||
type, name, res_id = tmp_tnrs.pop(0)
|
trans_type, name, res_id = targets.pop(0)
|
||||||
for t, n, r in tmp_tnrs:
|
for t, n, r in targets:
|
||||||
self.tnrs.append((t, n, r, source, trad))
|
self.extra_lines.append((t, n, r, source, trad, comments))
|
||||||
|
|
||||||
self.first = False
|
self.first = False
|
||||||
|
|
||||||
|
@ -355,7 +360,7 @@ class TinyPoFile(object):
|
||||||
self.warn('Missing "#:" formated comment at line %d for the following source:\n\t%s',
|
self.warn('Missing "#:" formated comment at line %d for the following source:\n\t%s',
|
||||||
self.cur_line(), source[:30])
|
self.cur_line(), source[:30])
|
||||||
return self.next()
|
return self.next()
|
||||||
return type, name, res_id, source, trad
|
return trans_type, name, res_id, source, trad, '\n'.join(comments)
|
||||||
|
|
||||||
def write_infos(self, modules):
|
def write_infos(self, modules):
|
||||||
import openerp.release as release
|
import openerp.release as release
|
||||||
|
@ -843,21 +848,14 @@ def trans_generate(lang, modules, cr):
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def trans_load(cr, filename, lang, verbose=True, flag=None, module_name=None, context=None):
|
def trans_load(cr, filename, lang, verbose=True, module_name=None, context=None):
|
||||||
try:
|
try:
|
||||||
fileobj = misc.file_open(filename)
|
fileobj = misc.file_open(filename)
|
||||||
traslation_obj = pooler.get_pool(cr.dbname).get('ir.translation')
|
|
||||||
_logger.info("loading %s", filename)
|
_logger.info("loading %s", filename)
|
||||||
transl = []
|
fileformat = os.path.splitext(filename)[-1][1:].lower()
|
||||||
if flag == 'web':
|
result = trans_load_data(cr, fileobj, fileformat, lang, verbose=verbose, module_name=module_name, context=context)
|
||||||
cr.execute("select DISTINCT src,value from ir_translation where module='%s' AND lang='%s' AND value != ''"% (module_name,lang))
|
|
||||||
for src, value in cr.fetchall():
|
|
||||||
transl.append({'id': src, 'string': value})
|
|
||||||
else:
|
|
||||||
fileformat = os.path.splitext(filename)[-1][1:].lower()
|
|
||||||
trans_load_data(cr, fileobj, fileformat, lang, verbose=verbose, module_name=module_name, context=context)
|
|
||||||
fileobj.close()
|
fileobj.close()
|
||||||
return transl
|
return result
|
||||||
except IOError:
|
except IOError:
|
||||||
if verbose:
|
if verbose:
|
||||||
_logger.error("couldn't read translation file %s", filename)
|
_logger.error("couldn't read translation file %s", filename)
|
||||||
|
@ -875,8 +873,7 @@ def trans_load_data(cr, fileobj, fileformat, lang, lang_name=None, verbose=True,
|
||||||
trans_obj = pool.get('ir.translation')
|
trans_obj = pool.get('ir.translation')
|
||||||
iso_lang = misc.get_iso_codes(lang)
|
iso_lang = misc.get_iso_codes(lang)
|
||||||
try:
|
try:
|
||||||
uid = 1
|
ids = lang_obj.search(cr, SUPERUSER_ID, [('code','=', lang)])
|
||||||
ids = lang_obj.search(cr, uid, [('code','=', lang)])
|
|
||||||
|
|
||||||
if not ids:
|
if not ids:
|
||||||
# lets create the language with locale information
|
# lets create the language with locale information
|
||||||
|
@ -893,14 +890,14 @@ def trans_load_data(cr, fileobj, fileformat, lang, lang_name=None, verbose=True,
|
||||||
break
|
break
|
||||||
elif fileformat == 'po':
|
elif fileformat == 'po':
|
||||||
reader = TinyPoFile(fileobj)
|
reader = TinyPoFile(fileobj)
|
||||||
f = ['type', 'name', 'res_id', 'src', 'value', 'module']
|
f = ['type', 'name', 'res_id', 'src', 'value', 'comments']
|
||||||
else:
|
else:
|
||||||
_logger.error('Bad file format: %s', fileformat)
|
_logger.error('Bad file format: %s', fileformat)
|
||||||
raise Exception(_('Bad file format'))
|
raise Exception(_('Bad file format'))
|
||||||
|
|
||||||
# read the rest of the file
|
# read the rest of the file
|
||||||
line = 1
|
line = 1
|
||||||
irt_cursor = trans_obj._get_import_cursor(cr, uid, context=context)
|
irt_cursor = trans_obj._get_import_cursor(cr, SUPERUSER_ID, context=context)
|
||||||
|
|
||||||
for row in reader:
|
for row in reader:
|
||||||
line += 1
|
line += 1
|
||||||
|
@ -911,11 +908,9 @@ def trans_load_data(cr, fileobj, fileformat, lang, lang_name=None, verbose=True,
|
||||||
# dictionary which holds values for this line of the csv file
|
# dictionary which holds values for this line of the csv file
|
||||||
# {'lang': ..., 'type': ..., 'name': ..., 'res_id': ...,
|
# {'lang': ..., 'type': ..., 'name': ..., 'res_id': ...,
|
||||||
# 'src': ..., 'value': ..., 'module':...}
|
# 'src': ..., 'value': ..., 'module':...}
|
||||||
dic = dict.fromkeys(('name', 'res_id', 'src', 'type', 'imd_model', 'imd_name', 'module', 'value'))
|
dic = dict.fromkeys(('name', 'res_id', 'src', 'type', 'imd_model', 'imd_name', 'module', 'value', 'comments'))
|
||||||
dic['lang'] = lang
|
dic['lang'] = lang
|
||||||
for i, field in enumerate(f):
|
for i, field in enumerate(f):
|
||||||
if field == 'module':
|
|
||||||
continue
|
|
||||||
dic[field] = row[i]
|
dic[field] = row[i]
|
||||||
|
|
||||||
# This would skip terms that fail to specify a res_id
|
# This would skip terms that fail to specify a res_id
|
||||||
|
|
Loading…
Reference in New Issue