@@ -1,3 +1,4 @@
|
||||
* Support language suffix in CSV export
|
||||
* Close tab with mouse middle click
|
||||
* Support language suffix in CSV import
|
||||
|
||||
|
||||
+28
-10
@@ -1196,6 +1196,15 @@
|
||||
|
||||
Sao.Window.CSV = Sao.class_(Object, {
|
||||
init: function(title) {
|
||||
this.languages = Sao.rpc({
|
||||
'method': 'model.ir.lang.search_read',
|
||||
'params': [
|
||||
[['translatable', '=', true]],
|
||||
0, null, null, ['code', 'name'],
|
||||
{},
|
||||
],
|
||||
}, this.session, false);
|
||||
|
||||
this.dialog = new Sao.Dialog(title, 'csv', 'lg');
|
||||
this.el = this.dialog.modal;
|
||||
|
||||
@@ -1398,14 +1407,6 @@
|
||||
this.session = Sao.Session.current_session;
|
||||
this.fields_data = {}; // Ask before Removing this.
|
||||
this.fields_invert = {};
|
||||
this.languages = Sao.rpc({
|
||||
'method': 'model.ir.lang.search_read',
|
||||
'params': [
|
||||
[['translatable', '=', true]],
|
||||
0, null, null, ['code', 'name'],
|
||||
{},
|
||||
],
|
||||
}, this.session, false);
|
||||
Sao.Window.Import._super.init.call(this,
|
||||
Sao.i18n.gettext('CSV Import: %1', name));
|
||||
|
||||
@@ -1983,8 +1984,25 @@
|
||||
this.fields[path] = node;
|
||||
|
||||
// Insert relation only to real field
|
||||
if (item.name.indexOf('.') == -1 && item.field.relation) {
|
||||
node.children = {};
|
||||
if (item.name.indexOf('.') == -1) {
|
||||
if (item.field.relation) {
|
||||
node.children = {};
|
||||
} else if (item.field.translate) {
|
||||
node.children = {};
|
||||
for (const language of this.languages) {
|
||||
const l_path = `${path}:lang=${language.code}`;
|
||||
const l_string = (
|
||||
`${long_string} (${language.name})`);
|
||||
const l_node = {
|
||||
path: l_path,
|
||||
string: language.name,
|
||||
long_string: l_string,
|
||||
relation: null,
|
||||
};
|
||||
node.children[language.code] = l_node;
|
||||
this.fields[l_path] = l_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
* Support language suffix in CSV export
|
||||
* Close tab with mouse middle click
|
||||
* Support language suffix in CSV import
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import sys
|
||||
|
||||
from gi.repository import Gdk, GObject, Gtk
|
||||
|
||||
from tryton.common import IconFactory
|
||||
from tryton.common import IconFactory, RPCExecute
|
||||
from tryton.common.underline import set_underline
|
||||
from tryton.config import TRYTON_ICON
|
||||
from tryton.gui import Main
|
||||
@@ -36,6 +36,11 @@ class WinCSV(NoModal):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(WinCSV, self).__init__(*args, **kwargs)
|
||||
|
||||
self.languages = RPCExecute(
|
||||
'model', 'ir.lang', 'search_read', [
|
||||
('translatable', '=', True),
|
||||
], 0, None, [('name', 'DESC')], ['code', 'name'])
|
||||
|
||||
self.dialog = Gtk.Dialog(
|
||||
transient_for=self.parent, destroy_with_parent=True)
|
||||
Main().add_window(self.dialog)
|
||||
|
||||
@@ -176,6 +176,13 @@ class WinExport(WinCSV):
|
||||
if '.' not in name:
|
||||
if field.get('relation'):
|
||||
self.model1.insert(node, 0, [None, ''])
|
||||
elif field.get('translate', False):
|
||||
for language in self.languages:
|
||||
l_path = f"{path}:lang={language['code']}"
|
||||
l_string = f"{string_} ({language['name']})"
|
||||
self.model1.insert(
|
||||
node, 0, [language['name'], l_path])
|
||||
self.fields[l_path] = (l_string, None)
|
||||
|
||||
def _get_fields(self, model):
|
||||
try:
|
||||
|
||||
@@ -26,10 +26,6 @@ class WinImport(WinCSV):
|
||||
self.fields_data = {}
|
||||
self.fields = {}
|
||||
self.fields_invert = {}
|
||||
self.languages = RPCExecute(
|
||||
'model', 'ir.lang', 'search_read', [
|
||||
('translatable', '=', True),
|
||||
], 0, None, None, ['code', 'name'])
|
||||
super(WinImport, self).__init__()
|
||||
self.dialog.set_title(_('CSV Import: %s') % name)
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
* Add language support per field in export data
|
||||
* Add translated descriptor for Char and Text fields
|
||||
* Include row and column in error message when importing data
|
||||
* Remove support for ``:id`` suffix in import data
|
||||
|
||||
@@ -742,8 +742,11 @@ class ModelStorage(Model):
|
||||
break
|
||||
field_name = fields_tree[i]
|
||||
descriptor = None
|
||||
language = None
|
||||
if '.' in field_name:
|
||||
field_name, descriptor = field_name.split('.')
|
||||
elif ':lang=' in field_name:
|
||||
field_name, language = field_name.split(':lang=')
|
||||
eModel = pool.get(value.__name__)
|
||||
field = eModel._fields[field_name]
|
||||
if field.states and 'invisible' in field.states:
|
||||
@@ -754,6 +757,8 @@ class ModelStorage(Model):
|
||||
break
|
||||
if descriptor:
|
||||
value = getattr(field, descriptor)().__get__(value, eModel)
|
||||
elif language:
|
||||
value = field.translated().__get__(value, eModel)(language)
|
||||
else:
|
||||
value = getattr(value, field_name)
|
||||
if isinstance(value, (list, tuple)):
|
||||
@@ -790,6 +795,7 @@ class ModelStorage(Model):
|
||||
def _convert_field_names(cls, fields_names):
|
||||
pool = Pool()
|
||||
ModelField = pool.get('ir.model.field')
|
||||
Lang = pool.get('ir.lang')
|
||||
result = []
|
||||
for names in fields_names:
|
||||
descriptions = []
|
||||
@@ -798,6 +804,9 @@ class ModelStorage(Model):
|
||||
translated = name.endswith('.translated')
|
||||
if translated:
|
||||
name = name[:-len('.translated')]
|
||||
language = None
|
||||
if ':lang=' in name:
|
||||
name, language = name.split(':lang=')
|
||||
field = class_._fields[name]
|
||||
field_name = ModelField.get_name(class_.__name__, name)
|
||||
if translated:
|
||||
@@ -807,6 +816,9 @@ class ModelStorage(Model):
|
||||
elif isinstance(field, fields.Reference):
|
||||
field_name = gettext(
|
||||
'ir.msg_field_model_name', field=field_name)
|
||||
if language:
|
||||
lang = Lang.get(language)
|
||||
field_name += f' ({lang.name})'
|
||||
descriptions.append(field_name)
|
||||
if hasattr(field, 'get_target'):
|
||||
class_ = field.get_target()
|
||||
|
||||
@@ -20,6 +20,7 @@ class ExportData(ModelSQL):
|
||||
float = fields.Float('Float')
|
||||
numeric = fields.Numeric('Numeric')
|
||||
char = fields.Char('Char')
|
||||
char_translated = fields.Char("Char", translate=True)
|
||||
text = fields.Text('Text')
|
||||
date = fields.Date('Date')
|
||||
datetime = fields.DateTime('DateTime')
|
||||
|
||||
@@ -7,6 +7,7 @@ from decimal import Decimal
|
||||
|
||||
from trytond.pool import Pool
|
||||
from trytond.tests.test_tryton import activate_module, with_transaction
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
|
||||
class ExportDataTestCase(unittest.TestCase):
|
||||
@@ -130,6 +131,32 @@ class ExportDataTestCase(unittest.TestCase):
|
||||
ExportData.export_data([export1, export2], ['char']),
|
||||
[['test'], ['']])
|
||||
|
||||
@with_transaction()
|
||||
def test_char_translated(self):
|
||||
"Test export_data char translated"
|
||||
pool = Pool()
|
||||
ExportData = pool.get('test.export_data')
|
||||
Language = pool.get('ir.lang')
|
||||
|
||||
english, = Language.search([('code', '=', 'en')])
|
||||
english.translatable = True
|
||||
english.save()
|
||||
|
||||
french, = Language.search([('code', '=', 'fr')])
|
||||
french.translatable = True
|
||||
french.save()
|
||||
|
||||
with Transaction().set_context(language='en'):
|
||||
record, = ExportData.create([{'char_translated': 'foo'}])
|
||||
with Transaction().set_context(language='fr'):
|
||||
ExportData.write([record], {'char_translated': 'bar'})
|
||||
|
||||
self.assertEqual(
|
||||
ExportData.export_data(
|
||||
[record],
|
||||
['char_translated:lang=en', 'char_translated:lang=fr']),
|
||||
[['foo', 'bar']])
|
||||
|
||||
@with_transaction()
|
||||
def test_text(self):
|
||||
'Test export_data text'
|
||||
@@ -433,11 +460,14 @@ class ExportDataTestCase(unittest.TestCase):
|
||||
|
||||
export1, = ExportData.create([{
|
||||
'char': "Test",
|
||||
"char_translated": "Test 2",
|
||||
'integer': 2,
|
||||
}])
|
||||
self.assertEqual(
|
||||
ExportData.export_data([export1], ['char', 'integer'], True),
|
||||
[["Char", "Integer"], ["Test", 2]])
|
||||
ExportData.export_data(
|
||||
[export1],
|
||||
['char', 'char_translated:lang=en', 'integer'], True),
|
||||
[["Char", "Char (English)", "Integer"], ["Test", "Test 2", 2]])
|
||||
|
||||
@with_transaction()
|
||||
def test_nested_header(self):
|
||||
|
||||
Reference in New Issue
Block a user