Add language configuration wizard
issue9172 review267031002
This commit is contained in:
1 parent
0081dc431d
commit
3378e283fd
9 files changed
+149
-22
No files matched your search
@@ -1,3 +1,4 @@
|
||||
* Add language configuration wizard
|
||||
* Allow copying attachments and notes to created records
|
||||
* Add link button on form
|
||||
* Support explicit delete and remove for saving and on_change xxx2Many
|
||||
|
||||
@@ -71,6 +71,7 @@ def register():
|
||||
note.NoteRead,
|
||||
cron.Cron,
|
||||
lang.Lang,
|
||||
lang.LangConfigStart,
|
||||
export.Export,
|
||||
export.ExportLine,
|
||||
rule.RuleGroup,
|
||||
@@ -105,6 +106,7 @@ def register():
|
||||
module.ModuleConfigWizard,
|
||||
module.ModuleActivateUpgrade,
|
||||
module.ModuleConfig,
|
||||
lang.LangConfig,
|
||||
module='ir', type_='wizard')
|
||||
Pool.register(
|
||||
model.ModelGraph,
|
||||
|
||||
+77
-5
@@ -8,18 +8,17 @@ from ast import literal_eval
|
||||
from sql import Table
|
||||
|
||||
from ..model import ModelView, ModelSQL, DeactivableMixin, fields, Check
|
||||
from ..modules import create_graph, load_translations
|
||||
from ..cache import Cache
|
||||
from ..transaction import Transaction
|
||||
from ..pool import Pool
|
||||
from ..pyson import Eval
|
||||
from ..exceptions import UserError
|
||||
from ..i18n import gettext
|
||||
from ..wizard import Wizard, StateView, Button, StateTransition
|
||||
|
||||
Transaction.cache_keys.add('translate_name')
|
||||
|
||||
__all__ = [
|
||||
'Lang',
|
||||
]
|
||||
|
||||
|
||||
class GroupingError(UserError):
|
||||
pass
|
||||
@@ -43,7 +42,7 @@ class Lang(DeactivableMixin, ModelSQL, ModelView):
|
||||
name = fields.Char('Name', required=True, translate=True)
|
||||
code = fields.Char('Code', required=True,
|
||||
help="RFC 4646 tag: http://tools.ietf.org/html/rfc4646")
|
||||
translatable = fields.Boolean('Translatable')
|
||||
translatable = fields.Boolean('Translatable', readonly=True)
|
||||
parent = fields.Char("Parent Code", help="Code of the exceptional parent")
|
||||
direction = fields.Selection([
|
||||
('ltr', 'Left-to-right'),
|
||||
@@ -87,6 +86,12 @@ class Lang(DeactivableMixin, ModelSQL, ModelView):
|
||||
Check(table, table.decimal_point != table.thousands_sep),
|
||||
'decimal_point and thousands_sep must be different!'),
|
||||
]
|
||||
cls._buttons.update({
|
||||
'load_translations': {},
|
||||
'unload_translations': {
|
||||
'invisible': ~Eval('translatable', False),
|
||||
},
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def search_rec_name(cls, name, clause):
|
||||
@@ -186,6 +191,37 @@ class Lang(DeactivableMixin, ModelSQL, ModelView):
|
||||
def default_n_sep_by_space(cls):
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
def load_translations(cls, languages):
|
||||
pool = Pool()
|
||||
Module = pool.get('ir.module')
|
||||
codes = set()
|
||||
cls.write(languages, {'translatable': True})
|
||||
for language in languages:
|
||||
code = language.code
|
||||
while code:
|
||||
codes.add(code)
|
||||
code = get_parent_language(code)
|
||||
modules = Module.search([
|
||||
('state', '=', 'activated'),
|
||||
])
|
||||
modules = [m.name for m in modules]
|
||||
for node in create_graph(modules):
|
||||
load_translations(pool, node, codes)
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
def unload_translations(cls, languages):
|
||||
pool = Pool()
|
||||
Translation = pool.get('ir.translation')
|
||||
cls.write(languages, {'translatable': False})
|
||||
languages = [l.code for l in languages]
|
||||
Translation.delete(Translation.search([
|
||||
('lang', 'in', languages),
|
||||
('module', '!=', None),
|
||||
]))
|
||||
|
||||
@classmethod
|
||||
def validate(cls, languages):
|
||||
super(Lang, cls).validate(languages)
|
||||
@@ -503,6 +539,42 @@ class Lang(DeactivableMixin, ModelSQL, ModelView):
|
||||
return value.strftime(format)
|
||||
|
||||
|
||||
class LangConfigStart(ModelView):
|
||||
'Language Configuration Start'
|
||||
__name__ = 'ir.lang.config.start'
|
||||
|
||||
languages = fields.Many2Many('ir.lang', None, None, "Languages")
|
||||
|
||||
@classmethod
|
||||
def default_languages(cls):
|
||||
pool = Pool()
|
||||
Lang = pool.get('ir.lang')
|
||||
return [x.id for x in Lang.search([('translatable', '=', True)])]
|
||||
|
||||
|
||||
class LangConfig(Wizard):
|
||||
'Configure languages'
|
||||
__name__ = 'ir.lang.config'
|
||||
|
||||
start = StateView('ir.lang.config.start',
|
||||
'ir.lang_config_start_view_form', [
|
||||
Button('Cancel', 'end', 'tryton-cancel'),
|
||||
Button('Load', 'load', 'tryton-ok', default=True),
|
||||
])
|
||||
load = StateTransition()
|
||||
|
||||
def transition_load(self):
|
||||
pool = Pool()
|
||||
Lang = pool.get('ir.lang')
|
||||
Lang.load_translations(list(self.start.languages))
|
||||
untranslated_languages = Lang.search([
|
||||
('id', 'not in', [l.id for l in self.start.languages]),
|
||||
('translatable', '=', True),
|
||||
])
|
||||
Lang.unload_translations(untranslated_languages)
|
||||
return 'end'
|
||||
|
||||
|
||||
def get_parent_language(code):
|
||||
if code not in _parents:
|
||||
# Use SQL because it is used by load_module_graph
|
||||
|
||||
@@ -495,5 +495,34 @@ this repository contains the full copyright notices and license terms. -->
|
||||
</record>
|
||||
<menuitem name="Languages" parent="ir.menu_localization"
|
||||
action="act_lang_form" id="menu_lang_form"/>
|
||||
|
||||
<record model="ir.model.button" id="lang_load_translations_button">
|
||||
<field name="name">load_translations</field>
|
||||
<field name="string">Load translations</field>
|
||||
<field name="model" search="[('model', '=', 'ir.lang')]"/>
|
||||
<field name="confirm">Are you sure you want to load languages' translations?</field>
|
||||
</record>
|
||||
<record model="ir.model.button" id="lang_unload_translations_button">
|
||||
<field name="name">unload_translations</field>
|
||||
<field name="string">Unload translations</field>
|
||||
<field name="confirm">Are you sure you want to remove languages' translations?</field>
|
||||
<field name="model" search="[('model', '=', 'ir.lang')]"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="lang_config_start_view_form">
|
||||
<field name="model">ir.lang.config.start</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">lang_config_start_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.wizard" id="act_lang_config">
|
||||
<field name="name">Configure Languages</field>
|
||||
<field name="wiz_name">ir.lang.config</field>
|
||||
<field name="window" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.module.config_wizard.item" id="config_wizard_item_lang">
|
||||
<field name="action" ref="act_lang_config"/>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<form col="2">
|
||||
<image name="tryton-info" xexpand="0" xfill="0"/>
|
||||
<label string="You can now load aditional translations to the system."
|
||||
id="load" yalign="0.0" xalign="0.0" xexpand="1"/>
|
||||
<field name="languages" colspan="2" widget="multiselection"/>
|
||||
</form>
|
||||
@@ -55,4 +55,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="p_sep_by_space"/>
|
||||
<label name="n_sep_by_space"/>
|
||||
<field name="n_sep_by_space"/>
|
||||
<group id="buttons" colspan="6" col="-1">
|
||||
<button name="load_translations" icon="tryton-launch"/>
|
||||
<button name="unload_translations" icon="tryton-launch"/>
|
||||
</group>
|
||||
</form>
|
||||
@@ -1,9 +1,10 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tree editable="1">
|
||||
<tree>
|
||||
<field name="name" expand="1"/>
|
||||
<field name="code"/>
|
||||
<field name="direction"/>
|
||||
<field name="translatable"/>
|
||||
<button name="load_translations"/>
|
||||
</tree>
|
||||
+21
-16
@@ -166,6 +166,26 @@ def is_module_to_install(module, update):
|
||||
return False
|
||||
|
||||
|
||||
def load_translations(pool, node, languages):
|
||||
module = node.name
|
||||
localedir = '%s/%s' % (node.info['directory'], 'locale')
|
||||
lang2filenames = defaultdict(list)
|
||||
for filename in itertools.chain(
|
||||
iglob('%s/*.po' % localedir),
|
||||
iglob('%s/override/*.po' % localedir)):
|
||||
filename = filename.replace('/', os.sep)
|
||||
lang = os.path.splitext(os.path.basename(filename))[0]
|
||||
if lang not in languages:
|
||||
continue
|
||||
lang2filenames[lang].append(filename)
|
||||
base_path_position = len(node.info['directory']) + 1
|
||||
for language, files in lang2filenames.items():
|
||||
filenames = [f[base_path_position:] for f in files]
|
||||
logger.info('%s:loading %s', module, ','.join(filenames))
|
||||
Translation = pool.get('ir.translation')
|
||||
Translation.translation_import(language, module, files)
|
||||
|
||||
|
||||
def load_module_graph(graph, pool, update=None, lang=None):
|
||||
from trytond.ir.lang import get_parent_language
|
||||
|
||||
@@ -233,22 +253,7 @@ def load_module_graph(graph, pool, update=None, lang=None):
|
||||
|
||||
modules_todo.append((module, list(tryton_parser.to_delete)))
|
||||
|
||||
localedir = '%s/%s' % (node.info['directory'], 'locale')
|
||||
lang2filenames = defaultdict(list)
|
||||
for filename in itertools.chain(
|
||||
iglob('%s/*.po' % localedir),
|
||||
iglob('%s/override/*.po' % localedir)):
|
||||
filename = filename.replace('/', os.sep)
|
||||
lang2 = os.path.splitext(os.path.basename(filename))[0]
|
||||
if lang2 not in lang:
|
||||
continue
|
||||
lang2filenames[lang2].append(filename)
|
||||
base_path_position = len(node.info['directory']) + 1
|
||||
for language, files in lang2filenames.items():
|
||||
filenames = [f[base_path_position:] for f in files]
|
||||
logger.info('%s:loading %s', module, ','.join(filenames))
|
||||
Translation = pool.get('ir.translation')
|
||||
Translation.translation_import(language, module, files)
|
||||
load_translations(pool, node, lang)
|
||||
|
||||
if package_state == 'to remove':
|
||||
continue
|
||||
|
||||
@@ -560,6 +560,10 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="action" ref="ir.act_translation_export"/>
|
||||
<field name="group" ref="group_admin"/>
|
||||
</record>
|
||||
<record model="ir.action-res.group" id="act_lang_config">
|
||||
<field name="action" ref="ir.act_lang_config"/>
|
||||
<field name="group" ref="group_admin"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.menu-res.group" id="menu_administration_group_admin">
|
||||
<field name="menu" ref="ir.menu_administration"/>
|
||||
|
||||
Reference in new issue
Block a user