diff options
| author | Olivier Dony <odo@openerp.com> | 2012-09-13 16:29:20 +0200 |
|---|---|---|
| committer | Olivier Dony <odo@openerp.com> | 2012-09-13 16:29:20 +0200 |
| commit | 550751b35825d60af0ed5985cd46b4ff4e2d3d01 (patch) | |
| tree | 851595921d697b234715ca05b2cb703afdb4c59e | |
| parent | 09ba29883c06d1f1de06c40e89c864c85f53d5c7 (diff) | |
[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
| -rw-r--r-- | openerp/addons/base/__openerp__.py | 1 | ||||
| -rw-r--r-- | openerp/addons/base/ir/ir.xml | 69 | ||||
| -rw-r--r-- | openerp/addons/base/ir/ir_translation.py | 125 | ||||
| -rw-r--r-- | openerp/addons/base/ir/ir_ui_view.py | 5 | ||||
| -rw-r--r-- | openerp/addons/base/module/module.py | 16 | ||||
| -rw-r--r-- | openerp/service/web_services.py | 24 | ||||
| -rw-r--r-- | openerp/tests/common.py | 1 | ||||
| -rw-r--r-- | openerp/tests/test_xmlrpc.py | 5 | ||||
| -rw-r--r-- | openerp/tools/translate.py | 61 |
9 files changed, 99 insertions, 208 deletions
diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index 937c9cbd20b..082cf260373 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -44,6 +44,7 @@ The kernel of OpenERP, needed for all installation. 'data/res.country.state.csv', 'ir/wizard/wizard_menu_view.xml', 'ir/ir.xml', + 'ir/ir_translation_view.xml', 'ir/ir_filters.xml', 'ir/ir_config_parameter_view.xml', 'ir/workflow/workflow_view.xml', diff --git a/openerp/addons/base/ir/ir.xml b/openerp/addons/base/ir/ir.xml index 29bb681981a..515d9641001 100644 --- a/openerp/addons/base/ir/ir.xml +++ b/openerp/addons/base/ir/ir.xml @@ -1147,75 +1147,6 @@ <menuitem action="action_model_relation" id="ir_model_relation_menu" parent="base.next_id_9" 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 diff --git a/openerp/addons/base/ir/ir_translation.py b/openerp/addons/base/ir/ir_translation.py index c8f9cf8e6fe..3ed61a7ddb3 100644 --- a/openerp/addons/base/ir/ir_translation.py +++ b/openerp/addons/base/ir/ir_translation.py @@ -19,10 +19,11 @@ # ############################################################################## -from osv import fields, osv import tools import logging + import openerp.modules +from openerp.osv import fields, osv _logger = logging.getLogger(__name__) @@ -58,7 +59,6 @@ class ir_translation_import_cursor(object): the data. @param parent an instance of ir.translation ORM model """ - self._cr = cr self._uid = uid self._context = context @@ -77,8 +77,9 @@ class ir_translation_import_cursor(object): """Feed a translation, as a dictionary, into the cursor """ 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) - 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, + 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, %%(comments)s)""" % self._table_name, params) def finish(self): @@ -106,11 +107,10 @@ class ir_translation_import_cursor(object): for row in cr.fetchall(): _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 # 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 " \ " AND irt.name = ti.name AND irt.src = ti.src " \ @@ -120,14 +120,14 @@ class ir_translation_import_cursor(object): if self._overwrite: cr.execute("""UPDATE ONLY %s AS irt SET value = ti.value, - state = 'translated' + state = 'translated' FROM %s AS ti WHERE %s AND ti.value IS NOT NULL AND ti.value != '' """ % (self._parent_table, self._table_name, find_expr)) # Step 3: insert new translations - cr.execute("""INSERT INTO %s(name, lang, res_id, src, type, value, module, state) - SELECT 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, comments FROM %s AS ti WHERE NOT EXISTS(SELECT 1 FROM ONLY %s AS irt WHERE %s); """ % (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] _columns = { - 'name': fields.char('Field Name', size=128, required=True), - 'res_id': fields.integer('Resource ID', select=True), - 'lang': fields.selection(_get_language, string='Language', size=16), - 'type': fields.selection(TRANSLATION_TYPE, string='Type', size=16, select=True), + 'name': fields.char('Translated field', required=True), + 'res_id': fields.integer('Record ID', select=True), + 'lang': fields.selection(_get_language, string='Language'), + 'type': fields.selection(TRANSLATION_TYPE, string='Type', select=True), 'src': fields.text('Source'), 'value': fields.text('Translation Value'), - 'module': fields.char('Module Name', size=128), - 'state': fields.selection([('to_translate','To Translate'), - ('inprogress','Translation in Progress'), - ('translated','Translated')]) + 'module': fields.char('Module', help="Module this term belongs to", select=True), + + 'state': fields.selection( + [('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 = { - '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' ), ] def _auto_init(self, cr, context=None): 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',)) if cr.fetchone(): #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': return return super(ir_translation, self)._check_selection_field_value(cr, uid, field, value, context=context) - + @tools.ormcache_multi(skiparg=3, multi=6) def _get_ids(self, cr, uid, name, tt, lang, ids): 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 # so we can remove the string encoding/decoding. if not lang: - return u'' + return tools.ustr(source or '') if isinstance(types, basestring): types = (types,) if source: - query = """SELECT value - FROM ir_translation - WHERE lang=%s - AND type in %s + query = """SELECT value + FROM ir_translation + WHERE lang=%s + AND type in %s AND src=%s""" params = (lang or '', types, tools.ustr(source)) if name: @@ -304,9 +312,9 @@ class ir_translation(osv.osv): if isinstance(ids, (int, long)): ids = [ids] 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'): - result = vals.update({'state':'translated'}) + vals.update({'state':'translated'}) 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): 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 ir_translation_import_cursor(cr, uid, self, context=context) - - def load(self, cr, modules, langs, flag=None, context=None): - translated_data = {} + + def load(self, cr, modules, langs, context=None): + context = dict(context or {}) # local copy for module_name in modules: - translated_data[module_name] = {'messages':[]} modpath = openerp.modules.get_module_path(module_name) if not modpath: - # unable to find the module. we skip continue for lang in langs: - iso_lang = tools.get_iso_codes(lang) - f = openerp.modules.get_module_resource(module_name, 'i18n', iso_lang + '.po') - context2 = context and context.copy() or {} - if f and '_' in iso_lang: - iso_lang2 = iso_lang.split('_')[0] - f2 = openerp.modules.get_module_resource(module_name, 'i18n', iso_lang2 + '.po') - if f2: - _logger.info('module %s: loading base translation file %s for language %s', module_name, iso_lang2, lang) - translated_data[module_name]['messages'].extend(tools.trans_load(cr, f2, lang, verbose=False, flag=flag, module_name=module_name, context=context)) - context2['overwrite'] = True - # Implementation notice: we must first search for the full name of - # the language derivative, like "en_UK", and then the generic, - # like "en". - if (not f) and '_' in iso_lang: - iso_lang = iso_lang.split('_')[0] - f = openerp.modules.get_module_resource(module_name, 'i18n', iso_lang + '.po') - if f: - _logger.info('module %s: loading translation file (%s) for language %s', module_name, iso_lang, lang) - translated_data[module_name]['messages'].extend(tools.trans_load(cr, f, lang, verbose=False, flag=flag, module_name=module_name, context=context2)) - elif iso_lang != 'en': - _logger.warning('module %s: no translation for language %s', module_name, iso_lang) - return translated_data - -ir_translation() + lang_code = tools.get_iso_codes(lang) + base_lang_code = None + if '_' in lang_code: + base_lang_code = lang_code.split('_')[0] + + # Step 1: for sub-languages, load base language first (e.g. es_CL.po is loaded over es.po) + if base_lang_code: + base_trans_file = openerp.modules.get_module_resource(module_name, 'i18n', base_lang_code + '.po') + if base_trans_file: + _logger.info('module %s: loading base translation file %s for language %s', module_name, base_lang_code, lang) + tools.trans_load(cr, base_trans_file, lang, verbose=False, module_name=module_name, context=context) + context['overwrite'] = True # make sure the requested translation will override the base terms later + + # Step 2: then load the main translation file, possibly overriding the terms coming from the base language + trans_file = openerp.modules.get_module_resource(module_name, 'i18n', lang_code + '.po') + if trans_file: + _logger.info('module %s: loading translation file (%s) for language %s', module_name, lang_code, lang) + tools.trans_load(cr, trans_file, lang, verbose=False, module_name=module_name, context=context) + elif lang_code != 'en': + _logger.warning('module %s: no translation for language %s', module_name, lang_code) + return True -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py index bad2c3d85af..db1e134e046 100644 --- a/openerp/addons/base/ir/ir_ui_view.py +++ b/openerp/addons/base/ir/ir_ui_view.py @@ -192,15 +192,12 @@ class view(osv.osv): def write(self, cr, uid, ids, vals, context=None): if not isinstance(ids, (list, tuple)): ids = [ids] - result = super(view, self).write(cr, uid, ids, vals, context) - # drop the corresponding view customizations (used for dashboards for example), otherwise # 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)]) if custom_view_ids: self.pool.get('ir.ui.view.custom').unlink(cr, uid, custom_view_ids) - - return result + return super(view, self).write(cr, uid, ids, vals, context) def graph_get(self, cr, uid, id, model, node_obj, conn_obj, src_node, des_node, label, scale, context=None): nodes=[] diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py index 04b1fed9b2b..541bf86190d 100644 --- a/openerp/addons/base/module/module.py +++ b/openerp/addons/base/module/module.py @@ -632,20 +632,14 @@ class module(osv.osv): self.write(cr, uid, [mod_browse.id], {'category_id': p_id}) 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: - lang_obj = pool.get('res.lang') - lang_ids = lang_obj.search(cr, uid, [('translatable', '=', True)]) - filter_lang = [lang.code for lang in lang_obj.browse(cr, uid, lang_ids)] + res_lang = self.pool.get('res.lang') + lang_ids = res_lang.search(cr, uid, [('translatable', '=', True)]) + filter_lang = [lang.code for lang in res_lang.browse(cr, uid, lang_ids)] elif not isinstance(filter_lang, (list, tuple)): filter_lang = [filter_lang] - - for mod in self.browse(cr, uid, ids): - if mod.state != 'installed': - continue - pool.get('ir.translation').load(cr, [mod.name], filter_lang, context=context) + modules = [m.name for m in self.browse(cr, uid, ids) if m.state == 'installed'] + self.pool.get('ir.translation').load(cr, modules, filter_lang, context=context) def check(self, cr, uid, ids, context=None): for mod in self.browse(cr, uid, ids, context=context): diff --git a/openerp/service/web_services.py b/openerp/service/web_services.py index 6e1f463c1cb..0a2e270d758 100644 --- a/openerp/service/web_services.py +++ b/openerp/service/web_services.py @@ -777,36 +777,12 @@ class report_spool(netsvc.ExportService): else: 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(): db() common() objects_proxy() wizard() report_spool() - translation() - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/tests/common.py b/openerp/tests/common.py index 80e1971e277..53c67c68844 100644 --- a/openerp/tests/common.py +++ b/openerp/tests/common.py @@ -83,7 +83,6 @@ class RpcCase(unittest2.TestCase): self.proxy.common_61 = xmlrpclib.ServerProxy(url_61 + 'common') self.proxy.db_61 = xmlrpclib.ServerProxy(url_61 + 'db') self.proxy.model_61 = xmlrpclib.ServerProxy(url_61 + 'model/' + DB) - self.proxy.translation_61 = xmlrpclib.ServerProxy(url_61 + 'translation') @classmethod def generate_database_name(cls): diff --git a/openerp/tests/test_xmlrpc.py b/openerp/tests/test_xmlrpc.py index 70ac6b1f75f..37655e72718 100644 --- a/openerp/tests/test_xmlrpc.py +++ b/openerp/tests/test_xmlrpc.py @@ -71,11 +71,6 @@ class test_xmlrpc(common.RpcCase): """ 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__': unittest2.main() diff --git a/openerp/tools/translate.py b/openerp/tools/translate.py index 93034b92f67..0ead12970cb 100644 --- a/openerp/tools/translate.py +++ b/openerp/tools/translate.py @@ -262,7 +262,7 @@ class TinyPoFile(object): self.lines_count = len(self.lines); self.first = True - self.tnrs= [] + self.extra_lines= [] return self def _get_lines(self): @@ -278,14 +278,14 @@ class TinyPoFile(object): return (self.lines_count - len(self.lines)) def next(self): - type = name = res_id = source = trad = None - - if self.tnrs: - type, name, res_id, source, trad = self.tnrs.pop(0) + trans_type = name = res_id = source = trad = None + if self.extra_lines: + trans_type, name, res_id, source, trad, comments = self.extra_lines.pop(0) if not res_id: res_id = '0' else: - tmp_tnrs = [] + comments = [] + targets = [] line = None fuzzy = False while (not line): @@ -295,15 +295,20 @@ class TinyPoFile(object): while line.startswith('#'): if line.startswith('#~ '): 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(' '): trans_info = lpart.strip().split(':',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' trans_info[:0] = ['code'] 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'): fuzzy = True 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 # msgstr with the informations about the traduction and the # traductor; we skip it - self.tnrs = [] + self.extra_lines = [] while line: line = self.lines.pop(0).strip() return self.next() @@ -343,10 +348,10 @@ class TinyPoFile(object): trad += unquote(line) line = self.lines.pop(0).strip() - if tmp_tnrs and not fuzzy: - type, name, res_id = tmp_tnrs.pop(0) - for t, n, r in tmp_tnrs: - self.tnrs.append((t, n, r, source, trad)) + if targets and not fuzzy: + trans_type, name, res_id = targets.pop(0) + for t, n, r in targets: + self.extra_lines.append((t, n, r, source, trad, comments)) 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.cur_line(), source[:30]) 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): import openerp.release as release @@ -843,21 +848,14 @@ def trans_generate(lang, modules, cr): 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: fileobj = misc.file_open(filename) - traslation_obj = pooler.get_pool(cr.dbname).get('ir.translation') _logger.info("loading %s", filename) - transl = [] - if flag == 'web': - 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) + fileformat = os.path.splitext(filename)[-1][1:].lower() + result = trans_load_data(cr, fileobj, fileformat, lang, verbose=verbose, module_name=module_name, context=context) fileobj.close() - return transl + return result except IOError: if verbose: _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') iso_lang = misc.get_iso_codes(lang) try: - uid = 1 - ids = lang_obj.search(cr, uid, [('code','=', lang)]) + ids = lang_obj.search(cr, SUPERUSER_ID, [('code','=', lang)]) if not ids: # 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 elif fileformat == 'po': reader = TinyPoFile(fileobj) - f = ['type', 'name', 'res_id', 'src', 'value', 'module'] + f = ['type', 'name', 'res_id', 'src', 'value', 'comments'] else: _logger.error('Bad file format: %s', fileformat) raise Exception(_('Bad file format')) # read the rest of the file 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: 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 # {'lang': ..., 'type': ..., 'name': ..., 'res_id': ..., # '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 for i, field in enumerate(f): - if field == 'module': - continue dic[field] = row[i] # This would skip terms that fail to specify a res_id |
