[IMP] core: store translated fields as JSONB columns
[IMP] core: store translated fields as JSONB columns
Translated fields no longer use the model ir.translation. Instead they store
all their values as JSON, and store them into JSONB columns in the model's
table. The field's column value is either NULL or a JSON dict mapping language
codes to text (the field's value in the corresponding language), and must
contain an entry for key 'en_US' (as it is used as a fallback for all other
languages). Empty text is allowed in translation values, but not NULL.
Here are examples for a field with translate=True:
`NULL`
`{"en_US": "Foo"}`
`{"en_US": "Foo", "fr_FR": "Bar", "nl_NL": "Baz"}`
`{"en_US": "Foo", "fr_FR": "", "nl_NL": "Baz"}`
Like before, writing False to the field makes it NULL, i.e., False in all
languages. However, writing "" to the field makes its value empty in the
current language, but does not discard the values in the other languages.
Here are examples for a field with translate=xml_translate:
` NULL`
`{"en_US": "<div>Foo<p>Bar</p></div>", "fr_FR": "<div>Fou<p>Barre</p></div>"}`
Change for callable(translate) fields: one can now write any value in any
language on such a field. The new value will be adapted in all languages, based
on the mapping of terms between languages in the old values. Basically the
structure of the value must remain the same in all languages, like before.
Reading a translated field is now both simpler and faster than the former
implementation. We fetch the value of the field in the current language by
coalescing its value with the 'en_US' value of the field:
`SELECT id, COALESCE(name->>'fr_FR', name->>'en_US') AS name ...`
The raw cache of the field contains either None or a dict which is conceptually
a subset of the JSON value in database (except for missing languages). For the
sake of simplicity, most cache operations deal with the dict and return the text
value in the current language.
Trigram indexes have been adapted to the new storing strategy, and should enable
to search in any language. Before this change, only the source value of the
field ('en_US') could be indexed.
Computed stored translated fields are not supported by the framework, because of
the complexity of the computation itself: the field would need to be computed in
all active languages. We chose to not provide any hook to compute a field in
all languages at once, and the framework always invokes a compute method once to
recompute it.
Code translations are no longer stored into the database. They become static,
and are extracted from the PO files when needed. The worker simply uses a cache
with extracted code translations for performance. This is reasonable, since
fr_FR code translations for all modules takes around 2MB of memory, and the
cache can be shared among all registries in the worker. Changing code
translations requires to update the corresponding PO file and reloading the
worker(s).
Performance summary:
(+) reading 'model' translated fields is faster
(+) reading 'model_terms' translated fields is much faster (no need to inject
translations into the source value)
(+) searching translated fields with operator 'ilike' is much faster when the
field is indexed with 'trigram'
(+) updating translated fields requires less ORM flushing
(-) importing translations from PO files is 2x slower
Some extra fixes:
- make field 'name' of ir.actions.actions translated; because of the PG
inheritance, this is necessary to make the column definition consistent in
all models that inherit from ir.actions.actions.
- add some backend API for the web/website client for editing translations
- move methods get_field_string() to model ir.model.fields
- move _load_module_terms to model ir.module.module
- adapt tests in test_impex, test_new_api
- because env.lang is injected into SQL queries, its returned value is
now guaranteed to correspond to a valid active language or None
- remove wizard to insert missing translations (no longer makes sense)
closes odoo/odoo#97692
Task-id: 2081307
Signed-off-by: Raphael Collet <rco@odoo.com>
This commit is contained in:
@@ -727,8 +727,15 @@ class Import(models.TransientModel):
|
||||
|
||||
if '/' not in header:
|
||||
# Then, try exact match
|
||||
IrTranslation = self.env['ir.translation']
|
||||
translated_header = IrTranslation._get_source('ir.model.fields,field_description', 'model', self.env.lang, header).lower()
|
||||
if header:
|
||||
field_rec = (
|
||||
self.env['ir.model.fields'].sudo().with_context(lang='en_US')
|
||||
.search([('field_description', '=', header)], limit=1)
|
||||
.with_env(self.env)
|
||||
)
|
||||
translated_header = (field_rec.sudo().field_description or header).lower()
|
||||
else:
|
||||
translated_header = ""
|
||||
for field in fields_tree:
|
||||
# exact match found based on the field technical name
|
||||
if header.casefold() == field['name'].casefold():
|
||||
|
||||
@@ -193,7 +193,9 @@ class HrEmployeePrivate(models.Model):
|
||||
public.read(fields)
|
||||
for fname in fields:
|
||||
values = self.env.cache.get_values(public, public._fields[fname])
|
||||
self.env.cache.update(self, self._fields[fname], values)
|
||||
if self._fields[fname].translate:
|
||||
values = [(value.copy() if value else None) for value in values]
|
||||
self.env.cache.update_raw(self, self._fields[fname], values)
|
||||
|
||||
@api.model
|
||||
def _cron_check_work_permit_validity(self):
|
||||
|
||||
@@ -297,7 +297,7 @@ class IrHttp(models.AbstractModel):
|
||||
modules = IrHttpModel.get_translation_frontend_modules()
|
||||
user_context = request.session.context if request.session.uid else {}
|
||||
lang = user_context.get('lang')
|
||||
translation_hash = request.env['ir.translation'].get_web_translations_hash(modules, lang)
|
||||
translation_hash = request.env['ir.http'].get_web_translations_hash(modules, lang)
|
||||
|
||||
session_info.update({
|
||||
'translationURL': '/website/translations',
|
||||
|
||||
@@ -153,14 +153,19 @@ class AccountFrFec(models.TransientModel):
|
||||
unaffected_earnings_results = self._do_query_unaffected_earnings()
|
||||
unaffected_earnings_line = False
|
||||
|
||||
sql_query = '''
|
||||
if self.pool['account.account'].name.translate:
|
||||
lang = self.env.user.lang or get_lang(self.env).code
|
||||
aa_name = f"COALESCE(aa.name->>'{lang}', aa.name->>'en_US')"
|
||||
else:
|
||||
aa_name = "aa.name"
|
||||
sql_query = f'''
|
||||
SELECT
|
||||
'OUV' AS JournalCode,
|
||||
'Balance initiale' AS JournalLib,
|
||||
'OUVERTURE/' || %s AS EcritureNum,
|
||||
%s AS EcritureDate,
|
||||
MIN(aa.code) AS CompteNum,
|
||||
replace(replace(MIN(aa.name), '|', '/'), '\t', '') AS CompteLib,
|
||||
replace(replace(MIN({aa_name}), '|', '/'), '\t', '') AS CompteLib,
|
||||
'' AS CompAuxNum,
|
||||
'' AS CompAuxLib,
|
||||
'-' AS PieceRef,
|
||||
@@ -236,14 +241,14 @@ class AccountFrFec(models.TransientModel):
|
||||
rows_to_write.append(unaffected_earnings_results)
|
||||
|
||||
# INITIAL BALANCE - receivable/payable
|
||||
sql_query = '''
|
||||
sql_query = f'''
|
||||
SELECT
|
||||
'OUV' AS JournalCode,
|
||||
'Balance initiale' AS JournalLib,
|
||||
'OUVERTURE/' || %s AS EcritureNum,
|
||||
%s AS EcritureDate,
|
||||
MIN(aa.code) AS CompteNum,
|
||||
replace(MIN(aa.name), '|', '/') AS CompteLib,
|
||||
replace(MIN({aa_name}), '|', '/') AS CompteLib,
|
||||
CASE WHEN MIN(aa.account_type) IN ('asset_receivable', 'liability_payable')
|
||||
THEN
|
||||
CASE WHEN rp.ref IS null OR rp.ref = ''
|
||||
@@ -298,14 +303,19 @@ class AccountFrFec(models.TransientModel):
|
||||
rows_to_write.append(listrow)
|
||||
|
||||
# LINES
|
||||
sql_query = '''
|
||||
if self.pool['account.journal'].name.translate:
|
||||
lang = self.env.user.lang or get_lang(self.env).code
|
||||
aj_name = f"COALESCE(aj.name->>'{lang}', aj.name->>'en_US')"
|
||||
else:
|
||||
aj_name = "aj.name"
|
||||
sql_query = f'''
|
||||
SELECT
|
||||
REGEXP_REPLACE(replace(aj.code, '|', '/'), '[\\t\\r\\n]', ' ', 'g') AS JournalCode,
|
||||
REGEXP_REPLACE(replace(COALESCE(aj__name.value, aj.name), '|', '/'), '[\\t\\r\\n]', ' ', 'g') AS JournalLib,
|
||||
REGEXP_REPLACE(replace({aj_name}, '|', '/'), '[\\t\\r\\n]', ' ', 'g') AS JournalLib,
|
||||
REGEXP_REPLACE(replace(am.name, '|', '/'), '[\\t\\r\\n]', ' ', 'g') AS EcritureNum,
|
||||
TO_CHAR(am.date, 'YYYYMMDD') AS EcritureDate,
|
||||
aa.code AS CompteNum,
|
||||
REGEXP_REPLACE(replace(aa.name, '|', '/'), '[\\t\\r\\n]', ' ', 'g') AS CompteLib,
|
||||
REGEXP_REPLACE(replace({aa_name}, '|', '/'), '[\\t\\r\\n]', ' ', 'g') AS CompteLib,
|
||||
CASE WHEN aa.account_type IN ('asset_receivable', 'liability_payable')
|
||||
THEN
|
||||
CASE WHEN rp.ref IS null OR rp.ref = ''
|
||||
@@ -343,11 +353,6 @@ class AccountFrFec(models.TransientModel):
|
||||
LEFT JOIN account_move am ON am.id=aml.move_id
|
||||
LEFT JOIN res_partner rp ON rp.id=aml.partner_id
|
||||
JOIN account_journal aj ON aj.id = am.journal_id
|
||||
LEFT JOIN ir_translation aj__name ON aj__name.res_id = aj.id
|
||||
AND aj__name.type = 'model'
|
||||
AND aj__name.name = 'account.journal,name'
|
||||
AND aj__name.lang = %s
|
||||
AND aj__name.value != ''
|
||||
JOIN account_account aa ON aa.id = aml.account_id
|
||||
LEFT JOIN res_currency rc ON rc.id = aml.currency_id
|
||||
LEFT JOIN account_full_reconcile rec ON rec.id = aml.full_reconcile_id
|
||||
@@ -369,9 +374,8 @@ class AccountFrFec(models.TransientModel):
|
||||
am.name,
|
||||
aml.id
|
||||
'''
|
||||
lang = self.env.user.lang or get_lang(self.env).code
|
||||
self._cr.execute(
|
||||
sql_query, (lang, self.date_from, self.date_to, company.id))
|
||||
sql_query, (self.date_from, self.date_to, company.id))
|
||||
|
||||
for row in self._cr.fetchall():
|
||||
rows_to_write.append(list(row))
|
||||
|
||||
@@ -82,9 +82,3 @@ class AccountAnalyticAccount(models.Model):
|
||||
_inherit = 'account.analytic.account'
|
||||
|
||||
name = fields.Char(translate=True)
|
||||
|
||||
|
||||
class ResCountryState(models.Model):
|
||||
_inherit = 'res.country.state'
|
||||
|
||||
name = fields.Char(translate=True)
|
||||
|
||||
@@ -38,26 +38,9 @@ class AccountChartTemplate(models.Model):
|
||||
|
||||
:return: True
|
||||
"""
|
||||
xlat_obj = self.env['ir.translation']
|
||||
#find the source from Account Template
|
||||
for lang in langs:
|
||||
#find the value from Translation
|
||||
value = xlat_obj._get_ids(in_ids._name + ',' + in_field, 'model', lang, in_ids.ids)
|
||||
counter = 0
|
||||
for element in in_ids.with_context(lang=None):
|
||||
if value[element.id]:
|
||||
#copy Translation from Source to Destination object
|
||||
xlat_obj._set_ids(
|
||||
out_ids._name + ',' + in_field,
|
||||
'model',
|
||||
lang,
|
||||
out_ids[counter].ids,
|
||||
value[element.id],
|
||||
element[in_field]
|
||||
)
|
||||
else:
|
||||
_logger.info('Language: %s. Translation from template: there is no translation available for %s!' % (lang, element[in_field]))
|
||||
counter += 1
|
||||
for in_id, out_id in zip(in_ids.with_context(lang=lang), out_ids.with_context(lang=lang)):
|
||||
out_id[in_field] = in_id[in_field]
|
||||
return True
|
||||
|
||||
def process_coa_translations(self):
|
||||
|
||||
@@ -52,7 +52,6 @@ from . import ir_http
|
||||
from . import ir_mail_server
|
||||
from . import ir_model
|
||||
from . import ir_model_fields
|
||||
from . import ir_translation
|
||||
from . import ir_ui_view
|
||||
from . import ir_qweb
|
||||
from . import ir_websocket
|
||||
|
||||
@@ -18,7 +18,7 @@ class IrHttp(models.AbstractModel):
|
||||
user_context = {'lang': guest.lang}
|
||||
mods = odoo.conf.server_wide_modules or []
|
||||
lang = user_context.get("lang")
|
||||
translation_hash = request.env['ir.translation'].sudo().get_web_translations_hash(mods, lang)
|
||||
translation_hash = request.env['ir.http'].sudo().get_web_translations_hash(mods, lang)
|
||||
result['cache_hashes']['translations'] = translation_hash
|
||||
result.update({
|
||||
'name': guest.name,
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import models, _
|
||||
from odoo.exceptions import AccessError
|
||||
|
||||
|
||||
class IrTranslation(models.Model):
|
||||
_inherit = 'ir.translation'
|
||||
|
||||
def create(self, vals_list):
|
||||
translations = super().create(vals_list)
|
||||
translations._check_is_dynamic()
|
||||
return translations
|
||||
|
||||
def write(self, vals):
|
||||
res = super().write(vals)
|
||||
self._check_is_dynamic()
|
||||
return res
|
||||
|
||||
def _check_is_dynamic(self):
|
||||
# if we don't modify translation of at least a model that inherits from mail.render.mixin, we ignore it
|
||||
# translation.name can be a path, and so not in the pool, so type(None) will exclude these translations.
|
||||
translations_for_mail_render_mixin = self.filtered(
|
||||
lambda translation: issubclass(type(self.env.get(translation.name.split(',')[0])), self.pool['mail.render.mixin'])
|
||||
)
|
||||
if not translations_for_mail_render_mixin:
|
||||
return
|
||||
|
||||
# if we are admin, or that we can update mail.template we ignore
|
||||
if self.env.is_admin() or self.env.user.has_group('mail.group_mail_template_editor'):
|
||||
return
|
||||
|
||||
# Check that we don't add qweb code in translation when you don't have the rights
|
||||
|
||||
# prefill cache
|
||||
ids_by_model_by_lang = {}
|
||||
tuple_lang_model_id = translations_for_mail_render_mixin.mapped(
|
||||
lambda translation: (translation.lang, translation.name.split(',')[0], translation.res_id)
|
||||
)
|
||||
for lang, model, _id in tuple_lang_model_id:
|
||||
ids_by_model_by_lang.setdefault(lang, {}).setdefault(model, set()).add(_id)
|
||||
for lang in ids_by_model_by_lang:
|
||||
for res_model, res_ids in ids_by_model_by_lang[lang].items():
|
||||
self.env[res_model].with_context(lang=lang).browse(res_ids)
|
||||
|
||||
for trans in translations_for_mail_render_mixin:
|
||||
res_model, res_id = trans.name.split(',')[0], trans.res_id
|
||||
rec = self.env[res_model].with_context(lang=trans.lang).browse(res_id)
|
||||
|
||||
if rec._is_dynamic():
|
||||
group = self.env.ref('mail.group_mail_template_editor')
|
||||
more_info = len(self) > 1 and ' [%s]' % rec or ''
|
||||
raise AccessError(
|
||||
_('Only users belonging to the "%(group)s" group can modify translation related to dynamic templates.%(xtra)s',
|
||||
group=group.name,
|
||||
xtra=more_info
|
||||
)
|
||||
)
|
||||
@@ -104,6 +104,16 @@ class MailRenderMixin(models.AbstractModel):
|
||||
self._check_access_right_dynamic_template()
|
||||
return True
|
||||
|
||||
def _update_field_translations(self, fname, translations, digest=None):
|
||||
res = super()._update_field_translations(fname, translations, digest)
|
||||
# TBD the below check is only for model_term translations.
|
||||
# Because for model translations, super().update_field_translations will call write to check
|
||||
if self._unrestricted_rendering:
|
||||
# If the rendering is unrestricted (e.g. mail.template),
|
||||
# check the user is part of the mail editor group to modify a template if the template is dynamic
|
||||
self._check_access_right_dynamic_template()
|
||||
return res
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# TOOLS
|
||||
# ------------------------------------------------------------
|
||||
|
||||
@@ -11,7 +11,7 @@ from odoo.modules import get_module_resource
|
||||
from odoo.modules.module import get_resource_from_path, get_resource_path
|
||||
from odoo.tools.convert import xml_import
|
||||
from odoo.tools.misc import file_open
|
||||
from odoo.tools.translate import TranslationFileReader
|
||||
from odoo.tools.translate import TranslationFileReader, _trans_load_data
|
||||
|
||||
|
||||
class TemplateResetMixin(models.AbstractModel):
|
||||
@@ -62,10 +62,8 @@ class TemplateResetMixin(models.AbstractModel):
|
||||
|
||||
def _override_translation_term(self, module_name, xml_ids):
|
||||
processed_base_langs = []
|
||||
trans_to_remove = []
|
||||
for code, _ in self.env['res.lang'].get_installed():
|
||||
lang_code = tools.get_iso_codes(code)
|
||||
translation_processed = False
|
||||
# In case of sub languages (e.g fr_BE), load the base language first, (e.g fr.po) and
|
||||
# then load the main translation file (e.g fr_BE.po)
|
||||
|
||||
@@ -76,28 +74,17 @@ class TemplateResetMixin(models.AbstractModel):
|
||||
if base_trans_file:
|
||||
if base_lang_code not in processed_base_langs:
|
||||
processed_base_langs.append(base_lang_code)
|
||||
translation_processed = self._process_translation_data(base_trans_file, code, xml_ids)
|
||||
self._process_translation_data(base_trans_file, code, xml_ids)
|
||||
|
||||
# Step 2: reset translation file with main language file (can possibly override the
|
||||
# terms coming from the base language)
|
||||
trans_file = get_module_resource(module_name, 'i18n', lang_code + '.po')
|
||||
if trans_file:
|
||||
translation_processed = self._process_translation_data(trans_file, code, xml_ids)
|
||||
self._process_translation_data(trans_file, code, xml_ids)
|
||||
|
||||
# If no translation data available to update, unlink custom translated terms linked to template
|
||||
if not translation_processed:
|
||||
trans_to_remove.append(code)
|
||||
|
||||
if trans_to_remove:
|
||||
self.env['ir.translation'].search([
|
||||
('name', 'like', f'{self._name},%'),
|
||||
('res_id', '=', self.id),
|
||||
('lang', 'in', trans_to_remove),
|
||||
('module', 'in', [module_name, False]),
|
||||
]).unlink()
|
||||
|
||||
def _process_translation_data(self, trans_file, lang, xml_ids):
|
||||
"""Populates the ir_translation table.
|
||||
"""Load translations.
|
||||
|
||||
:param trans_file: path to a translation file to open, e.g. {addon_path}/mail/i18n/es.po
|
||||
:param lang: language code of the translations contained in `trans_file`
|
||||
@@ -106,17 +93,9 @@ class TemplateResetMixin(models.AbstractModel):
|
||||
:return Boolean: True if translation data is available and processed, False otherwise
|
||||
"""
|
||||
with file_open(trans_file, mode='rb', filter_ext=(".po",)) as fileobj:
|
||||
translation_processed = False
|
||||
reader = TranslationFileReader(fileobj)
|
||||
# Process a single PO entry
|
||||
for row in reader:
|
||||
if row.get('imd_name') in xml_ids:
|
||||
translation_processed = True
|
||||
# copy Translation from Source to Destination object
|
||||
self.env['ir.translation']._set_ids(
|
||||
row['name'], 'model', lang, self._ids, row.get('value', ''), row['src'],
|
||||
)
|
||||
return translation_processed
|
||||
_trans_load_data(self.env.cr, reader, lang, overwrite=True, force_overwrite=True, xml_ids=xml_ids)
|
||||
|
||||
def reset_template(self):
|
||||
"""Resets the Template with values given in source file. We ignore the case of
|
||||
|
||||
@@ -1117,84 +1117,11 @@ class MailCommon(common.TransactionCase, MailCase):
|
||||
|
||||
# Make sure Spanish translations have not been altered
|
||||
if test_record:
|
||||
description_translations = cls.env['ir.translation'].search([
|
||||
('module', '=', 'test_mail'),
|
||||
('src', '=', test_record._description),
|
||||
('lang', '=', lang_code)
|
||||
])
|
||||
if description_translations:
|
||||
description_translations.update({'value': 'Spanish description'})
|
||||
else:
|
||||
description_translations.create({
|
||||
'lang': lang_code,
|
||||
'module': 'test_mail',
|
||||
'name': 'ir.model,name',
|
||||
'res_id': cls.env['ir.model']._get_id(test_record._name),
|
||||
'src': test_record._description,
|
||||
'state': 'translated',
|
||||
'type': 'model',
|
||||
'value': 'Spanish description',
|
||||
})
|
||||
|
||||
translations_tocreate = []
|
||||
# Have a TestStuff always available
|
||||
test_stuff_translations = cls.env['ir.translation'].search([
|
||||
('module', '=', 'test_mail'),
|
||||
('src', '=', 'TestStuff'),
|
||||
('lang', '=', lang_code)
|
||||
])
|
||||
if test_stuff_translations:
|
||||
test_stuff_translations.update({'value': 'TestSpanishStuff'})
|
||||
else:
|
||||
translations_tocreate.append({
|
||||
'lang': lang_code,
|
||||
'name': 'idontknow',
|
||||
'module': 'test_mail',
|
||||
'res_id': False,
|
||||
'src': 'TestStuff',
|
||||
'state': 'translated',
|
||||
'type': 'code',
|
||||
'value': 'TestSpanishStuff',
|
||||
})
|
||||
|
||||
view_translations = cls.env['ir.translation'].search([
|
||||
('module', '=', 'mail'),
|
||||
('src', '=', 'View %s'),
|
||||
('lang', '=', lang_code)
|
||||
])
|
||||
if view_translations:
|
||||
view_translations.update({'value': 'SpanishView'})
|
||||
else:
|
||||
translations_tocreate.append({
|
||||
'lang': lang_code,
|
||||
'name': 'idontknow',
|
||||
'module': 'mail',
|
||||
'res_id': False,
|
||||
'src': 'View %s',
|
||||
'state': 'translated',
|
||||
'type': 'code',
|
||||
'value': 'SpanishView %s',
|
||||
})
|
||||
cls.env['ir.model']._get(test_record._name).with_context(lang=lang_code).name = 'Spanish description'
|
||||
|
||||
# Prepare some translated value for template if given
|
||||
if test_template:
|
||||
translations_tocreate += [{
|
||||
'lang': lang_code,
|
||||
'module': 'mail',
|
||||
'name': 'mail.template,subject',
|
||||
'res_id': test_template.id,
|
||||
'state': 'translated',
|
||||
'type': 'model',
|
||||
'value': 'SpanishSubject for {{ object.name }}',
|
||||
}, {
|
||||
'lang': lang_code,
|
||||
'module': 'mail',
|
||||
'name': 'mail.template,body_html',
|
||||
'res_id': test_template.id,
|
||||
'state': 'translated',
|
||||
'type': 'model',
|
||||
'value': '<p>SpanishBody for <t t-out="object.name" /></p>',
|
||||
}]
|
||||
test_template.with_context(lang=lang_code).subject = 'SpanishSubject for {{ object.name }}'
|
||||
test_template.with_context(lang=lang_code).body_html = '<p>SpanishBody for <t t-out="object.name" /></p>'
|
||||
|
||||
# create a custom layout for email notification
|
||||
if not layout_arch_db:
|
||||
@@ -1233,17 +1160,11 @@ class MailCommon(common.TransactionCase, MailCase):
|
||||
'name': 'test_layout',
|
||||
'res_id': view.id
|
||||
})
|
||||
translations_tocreate.append({
|
||||
'lang': lang_code,
|
||||
'module': 'mail',
|
||||
'name': 'ir.ui.view,arch_db',
|
||||
'res_id': view.id,
|
||||
'src': 'English Layout for',
|
||||
'state': 'translated',
|
||||
'type': 'model_terms',
|
||||
'value': 'Spanish Layout para',
|
||||
view.update_field_translations('arch_db', {
|
||||
lang_code: {
|
||||
'English Layout for': 'Spanish Layout para'
|
||||
}
|
||||
})
|
||||
cls.env['ir.translation'].create(translations_tocreate)
|
||||
|
||||
def _generate_attachments_data(self, count, res_model=None, res_id=None, attach_values=None):
|
||||
# attachment visibility depends on what they are attached to
|
||||
|
||||
@@ -112,22 +112,9 @@ class TestMailRender(common.MailCommon):
|
||||
})
|
||||
|
||||
# some translations
|
||||
cls.env['ir.translation'].create({
|
||||
'type': 'model',
|
||||
'name': 'mail.template,subject',
|
||||
'lang': 'fr_FR',
|
||||
'res_id': cls.test_template.id,
|
||||
'src': cls.test_template.subject,
|
||||
'value': cls.base_qweb_bits_fr[0],
|
||||
})
|
||||
cls.env['ir.translation'].create({
|
||||
'type': 'model',
|
||||
'name': 'mail.template,body_html',
|
||||
'lang': 'fr_FR',
|
||||
'res_id': cls.test_template.id,
|
||||
'src': cls.test_template.body_html,
|
||||
'value': cls.base_qweb_bits_fr[1],
|
||||
})
|
||||
cls.test_template.with_context(lang='fr_FR').subject = cls.base_qweb_bits_fr[0]
|
||||
cls.test_template.with_context(lang='fr_FR').body_html = cls.base_qweb_bits_fr[1]
|
||||
|
||||
cls.env['ir.model.data'].create({
|
||||
'name': 'test_template_xmlid',
|
||||
'module': 'mail',
|
||||
|
||||
@@ -107,62 +107,29 @@ class TestMailTemplate(MailCommon):
|
||||
'body_html': '<p>foo</p>',
|
||||
})
|
||||
|
||||
Translation = self.env['ir.translation']
|
||||
|
||||
### check qweb dynamic
|
||||
Translation.insert_missing(employee_template._fields['body_html'], employee_template)
|
||||
employee_translations_of_body = Translation.with_user(self.user_employee).search(
|
||||
[('res_id', '=', employee_template.id), ('name', '=', 'mail.template,body_html'), ('lang', '=', 'fr_FR')],
|
||||
limit=1
|
||||
)
|
||||
# keep a copy to create new translation later
|
||||
body_translation_vals = employee_translations_of_body.read([])[0]
|
||||
|
||||
# write on translation for template without dynamic code is allowed
|
||||
employee_translations_of_body.value = 'non-qweb'
|
||||
employee_template.with_context(lang='fr_FR').body_html = 'non-qweb'
|
||||
|
||||
# cannot write dynamic code on mail_template translation for employee without the group mail_template_editor.
|
||||
with self.assertRaises(AccessError):
|
||||
employee_translations_of_body.value = '<t t-esc="foo"/>'
|
||||
employee_template.with_context(lang='fr_FR').body_html = '<t t-esc="foo"/>'
|
||||
|
||||
employee_translations_of_body.unlink() # delete old translation, to test the creation now
|
||||
body_translation_vals['value'] = '<p t-esc="foo"/>'
|
||||
|
||||
# admin can create
|
||||
new = Translation.create(body_translation_vals)
|
||||
new.unlink()
|
||||
|
||||
# Employee without mail_template_editor group cannot create dynamic translation for mail.render.mixin
|
||||
with self.assertRaises(AccessError):
|
||||
Translation.with_user(self.user_employee).create(body_translation_vals)
|
||||
employee_template.with_context(lang='fr_FR').sudo().body_html = '<t t-esc="foo"/>'
|
||||
|
||||
# reset the body_html to static
|
||||
employee_template.body_html = False
|
||||
employee_template.body_html = '<p>foo</p>'
|
||||
|
||||
### check qweb inline dynamic
|
||||
Translation.insert_missing(employee_template._fields['subject'], employee_template)
|
||||
employee_translations_of_subject = Translation.with_user(self.user_employee).search(
|
||||
[('res_id', '=', employee_template.id), ('name', '=', 'mail.template,subject'), ('lang', '=', 'fr_FR')],
|
||||
limit=1
|
||||
)
|
||||
# keep a copy to create new translation later
|
||||
subject_translation_vals = employee_translations_of_subject.read([])[0]
|
||||
|
||||
# write on translation for template without dynamic code is allowed
|
||||
employee_translations_of_subject.value = 'non-qweb'
|
||||
employee_template.with_context(lang='fr_FR').subject = 'non-qweb'
|
||||
|
||||
# cannot write dynamic code on mail_template translation for employee without the group mail_template_editor.
|
||||
with self.assertRaises(AccessError):
|
||||
employee_translations_of_subject.value = '{{ object.foo }}'
|
||||
employee_template.with_context(lang='fr_FR').subject = '{{ object.foo }}'
|
||||
|
||||
employee_translations_of_subject.unlink() # delete old translation, to test the creation now
|
||||
subject_translation_vals['value'] = '{{ object.foo }}'
|
||||
|
||||
# admin can create
|
||||
new = Translation.create(subject_translation_vals)
|
||||
new.unlink()
|
||||
|
||||
# Employee without mail_template_editor group cannot create dynamic translation for mail.render.mixin
|
||||
with self.assertRaises(AccessError):
|
||||
Translation.with_user(self.user_employee).create(subject_translation_vals)
|
||||
employee_template.with_context(lang='fr_FR').sudo().subject = '{{ object.foo }}'
|
||||
|
||||
def test_server_archived_usage_protection(self):
|
||||
""" Test the protection against using archived server (servers used cannot be archived) """
|
||||
|
||||
@@ -434,7 +434,7 @@ class MailPluginController(http.Controller):
|
||||
|
||||
def _prepare_translations(self):
|
||||
lang = request.env['res.users'].browse(request.uid).lang
|
||||
translations_per_module = request.env["ir.translation"].get_translations_for_webclient(
|
||||
translations_per_module = request.env["ir.http"].get_translations_for_webclient(
|
||||
self._translation_modules_whitelist(), lang)[0]
|
||||
translations_dict = {}
|
||||
for module in self._translation_modules_whitelist():
|
||||
|
||||
@@ -91,7 +91,7 @@ class CustomerPortal(portal.CustomerPortal):
|
||||
user_context = dict(request.env.context) if request.session.uid else {}
|
||||
mods = conf.server_wide_modules or []
|
||||
lang = user_context.get("lang")
|
||||
translation_hash = request.env['ir.translation'].get_web_translations_hash(mods, lang)
|
||||
translation_hash = request.env['ir.http'].get_web_translations_hash(mods, lang)
|
||||
cache_hashes = {
|
||||
"translations": translation_hash,
|
||||
}
|
||||
|
||||
@@ -131,6 +131,8 @@ class PrivacyLookupWizard(models.TransientModel):
|
||||
rec_name = model._rec_name or 'name'
|
||||
is_normalized = field_name == 'email_normalized' or (model_name == 'mailing.trace' and field_name == 'email')
|
||||
if rec_name in model and model._fields[model._rec_name].type == 'char':
|
||||
if model._fields[model._rec_name].translate:
|
||||
rec_name = f"jsonb_path_query_array({rec_name}, '$.*')::text"
|
||||
additional_query += """
|
||||
{field_name} {search_type} %s OR {rec_name} ilike %s
|
||||
""".format(
|
||||
|
||||
@@ -139,7 +139,7 @@ class ProjectCustomerPortal(CustomerPortal):
|
||||
# Update Cache
|
||||
user_context['lang'] = lang
|
||||
lang = user_context.get("lang")
|
||||
translation_hash = request.env['ir.translation'].get_web_translations_hash(mods, lang)
|
||||
translation_hash = request.env['ir.http'].get_web_translations_hash(mods, lang)
|
||||
cache_hashes = {
|
||||
"translations": translation_hash,
|
||||
}
|
||||
|
||||
@@ -576,8 +576,8 @@ class TestReorderingRule(TransactionCase):
|
||||
])],
|
||||
})
|
||||
self.env['res.lang']._activate_lang('fr_FR')
|
||||
self.env['ir.translation']._set_ids('product.template,name', 'model', 'fr_FR', product.product_tmpl_id.ids, 'produit en français')
|
||||
self.env['ir.translation']._set_ids('product.product,name', 'model', 'fr_FR', product.ids, 'produit en français')
|
||||
product.product_tmpl_id.with_context(lang='fr_FR').name = 'produit en français'
|
||||
product.with_context(lang='fr_FR').name = 'produit en français'
|
||||
default_vendor = self.env["res.partner"].create({
|
||||
"name": "Supplier A",
|
||||
})
|
||||
|
||||
@@ -94,33 +94,7 @@ class SaleOrderTemplate(models.Model):
|
||||
for lang in languages:
|
||||
for line in self.sale_order_template_line_ids:
|
||||
if line.name == line.product_id.get_product_multiline_description_sale():
|
||||
self.create_or_update_translations(
|
||||
model_name='sale.order.template.line,name', lang_code=lang.code,
|
||||
res_id=line.id, src=line.name,
|
||||
value=line.product_id.with_context(lang=lang.code).get_product_multiline_description_sale())
|
||||
line.with_context(lang=lang.code).name = line.product_id.with_context(lang=lang.code).get_product_multiline_description_sale()
|
||||
for option in self.sale_order_template_option_ids:
|
||||
if option.name == option.product_id.get_product_multiline_description_sale():
|
||||
self.create_or_update_translations(
|
||||
model_name='sale.order.template.option,name', lang_code=lang.code,
|
||||
res_id=option.id, src=option.name,
|
||||
value=option.product_id.with_context(lang=lang.code).get_product_multiline_description_sale())
|
||||
|
||||
def create_or_update_translations(self, model_name, lang_code, res_id, src, value):
|
||||
data = {
|
||||
'type': 'model',
|
||||
'name': model_name,
|
||||
'lang': lang_code,
|
||||
'res_id': res_id,
|
||||
'src': src,
|
||||
'value': value,
|
||||
'state': 'inprogress',
|
||||
}
|
||||
existing_trans = self.env['ir.translation'].search([
|
||||
('name', '=', model_name),
|
||||
('res_id', '=', res_id),
|
||||
('lang', '=', lang_code)
|
||||
])
|
||||
if not existing_trans:
|
||||
self.env['ir.translation'].create(data)
|
||||
else:
|
||||
existing_trans.write(data)
|
||||
option.with_context(lang=lang.code).name = option.product_id.with_context(lang=lang.code).get_product_multiline_description_sale()
|
||||
|
||||
@@ -19,6 +19,7 @@ from odoo.exceptions import AccessError
|
||||
from odoo.tests import tagged
|
||||
from odoo.tools import mute_logger, formataddr
|
||||
from odoo.tests.common import users
|
||||
from odoo.tools.translate import code_translations
|
||||
|
||||
|
||||
class TestMessagePostCommon(TestMailCommon, TestRecipients):
|
||||
@@ -1240,6 +1241,12 @@ class TestMessagePostLang(TestMailCommon, TestRecipients):
|
||||
@users('employee')
|
||||
@mute_logger('odoo.addons.mail.models.mail_mail')
|
||||
def test_layout_email_lang_context(self):
|
||||
# hack into code translations:
|
||||
code_translations.python_translations[('test_mail', 'es_ES')] = {'TestStuff': 'TestSpanishStuff'}
|
||||
self.addCleanup(code_translations.python_translations.pop, ('test_mail', 'es_ES'))
|
||||
code_translations.python_translations[('mail', 'es_ES')] = {'View %s': 'SpanishView %s'}
|
||||
self.addCleanup(code_translations.python_translations.pop, ('mail', 'es_ES'))
|
||||
|
||||
test_records = self.test_records.with_user(self.env.user).with_context(lang='es_ES')
|
||||
test_records[1].message_subscribe(self.partner_2.ids)
|
||||
|
||||
|
||||
@@ -415,14 +415,7 @@ class TestSMSComposerMass(TestSMSCommon):
|
||||
|
||||
def test_composer_mass_active_ids_w_template_and_lang(self):
|
||||
self.env['res.lang']._activate_lang('fr_FR')
|
||||
self.env['ir.translation'].create({
|
||||
'type': 'model',
|
||||
'name': 'sms.template,body',
|
||||
'lang': 'fr_FR',
|
||||
'res_id': self.sms_template.id,
|
||||
'src': self.sms_template.body,
|
||||
'value': 'Cher·e· {{ object.display_name }} ceci est un SMS.',
|
||||
})
|
||||
self.sms_template.with_context(lang='fr_FR').body = 'Cher·e· {{ object.display_name }} ceci est un SMS.'
|
||||
# set template to try to use customer lang
|
||||
self.sms_template.write({
|
||||
'lang': '{{ object.customer_id.lang }}',
|
||||
@@ -481,14 +474,7 @@ class TestSMSComposerMass(TestSMSCommon):
|
||||
and the usage with the sms composer """
|
||||
# Create the lang info
|
||||
self.env['res.lang']._activate_lang('fr_FR')
|
||||
self.env['ir.translation'].create({
|
||||
'type': 'model',
|
||||
'name': 'sms.template,body',
|
||||
'lang': 'fr_FR',
|
||||
'res_id': self.sms_template.id,
|
||||
'src': self.sms_template.body,
|
||||
'value': "Hello {{ object.display_name }} ceci est en français.",
|
||||
})
|
||||
self.sms_template.with_context(lang='fr_FR').body = 'Hello {{ object.display_name }} ceci est en français.'
|
||||
# set template to try to use customer lang
|
||||
self.sms_template.write({
|
||||
'lang': '{{ object.customer_id.lang }}',
|
||||
|
||||
@@ -29,13 +29,8 @@ class TestSmsTemplate(TestSMSCommon, TestSMSRecipients):
|
||||
def test_sms_template_lang(self):
|
||||
self.env['res.lang']._activate_lang('fr_FR')
|
||||
self.user_admin.write({'lang': 'en_US'})
|
||||
self.env['ir.translation'].create({
|
||||
'type': 'model',
|
||||
'name': 'sms.template,body',
|
||||
'lang': 'fr_FR',
|
||||
'res_id': self.sms_template.id,
|
||||
'src': self.sms_template.body,
|
||||
'value': self.body_fr,
|
||||
self.sms_template.update_field_translations('body', {
|
||||
'fr_FR': self.body_fr
|
||||
})
|
||||
# set template to try to use customer lang
|
||||
self.sms_template.write({
|
||||
|
||||
@@ -38,21 +38,10 @@ class TestIsMultiLang(odoo.tests.HttpCase):
|
||||
website.domain = self.base_url() # for _is_canonical_url
|
||||
website.default_lang_id = en
|
||||
website.language_ids = en + it + be
|
||||
params = {
|
||||
'src': country1.name,
|
||||
'value': country1.name + ' Italia',
|
||||
'type': 'model',
|
||||
'name': 'res.country,name',
|
||||
'res_id': country1.id,
|
||||
'lang': it.code,
|
||||
'state': 'translated',
|
||||
}
|
||||
self.env['ir.translation'].create(params)
|
||||
params.update({
|
||||
'value': country1.name + ' Belgium',
|
||||
'lang': be.code,
|
||||
country1.update_field_translations('name', {
|
||||
it.code: country1.name + ' Italia',
|
||||
be.code: country1.name + ' Belgium'
|
||||
})
|
||||
self.env['ir.translation'].create(params)
|
||||
|
||||
r = self.url_open(f'/test_lang_url/{country1.id}')
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
||||
@@ -1,29 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
'name': 'Transifex integration',
|
||||
'version': '1.0',
|
||||
'summary': 'Add a link to edit a translation in Transifex',
|
||||
'category': 'Hidden/Tools',
|
||||
'description':
|
||||
"""
|
||||
Transifex integration
|
||||
=====================
|
||||
This module will add a link to the Transifex project in the translation view.
|
||||
The purpose of this module is to speed up translations of the main modules.
|
||||
|
||||
To work, Odoo uses Transifex configuration files `.tx/config` to detec the
|
||||
project source. Custom modules will not be translated (as not published on
|
||||
the main Transifex project).
|
||||
|
||||
The language the user tries to translate must be activated on the Transifex
|
||||
project.
|
||||
""",
|
||||
'data': [
|
||||
'data/transifex_data.xml',
|
||||
'data/ir_translation_view.xml',
|
||||
],
|
||||
'depends': ['base'],
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="ir_translation_view_tree_transifex" model="ir.ui.view">
|
||||
<field name="name">ir.translation.transifex</field>
|
||||
<field name="model">ir.translation</field>
|
||||
<field name="inherit_id" ref="base.view_translation_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="state" position="after">
|
||||
<field name="transifex_url"
|
||||
widget="url"
|
||||
text="Contribute"
|
||||
string="Transifex" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="ir_translation_dialog_view_tree_transifex" model="ir.ui.view">
|
||||
<field name="name">ir.translation.transifex</field>
|
||||
<field name="model">ir.translation</field>
|
||||
<field name="inherit_id" ref="base.view_translation_dialog_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="state" position="after">
|
||||
<field name="transifex_url"
|
||||
widget="url"
|
||||
text="Contribute"
|
||||
string="Transifex" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="ir_translation_dialog_view_src_value_tree_transifex" model="ir.ui.view">
|
||||
<field name="name">ir.translation.src.value.transifex</field>
|
||||
<field name="model">ir.translation</field>
|
||||
<field name="inherit_id" ref="base.view_translation_lang_src_value_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="value" position="after">
|
||||
<field name="transifex_url"
|
||||
widget="url"
|
||||
text="Contribute"
|
||||
string="Transifex" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo noupdate="1">
|
||||
|
||||
<record id="transifex_project_url" model="ir.config_parameter">
|
||||
<field name="key">transifex.project_url</field>
|
||||
<field name="value">https://www.transifex.com/odoo</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -1,37 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Shaima Safar <shaima.safar@open-inside.com>, 2018
|
||||
# Mustafa Rawi <mustafa@cubexco.com>, 2019
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-08-24 09:33+0000\n"
|
||||
"Last-Translator: Mustafa Rawi <mustafa@cubexco.com>, 2019\n"
|
||||
"Language-Team: Arabic (https://www.transifex.com/odoo/teams/41243/ar/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: ar\n"
|
||||
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "رابط Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "الترجمة"
|
||||
@@ -1,32 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-08-24 09:33+0000\n"
|
||||
"Language-Team: Azerbaijani (https://www.transifex.com/odoo/teams/41243/az/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: az\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr ""
|
||||
@@ -1,35 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Martin Trigaux, 2018\n"
|
||||
"Language-Team: Bosnian (https://www.transifex.com/odoo/teams/41243/bs/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: bs\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Prevod"
|
||||
@@ -1,37 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux, 2018
|
||||
# Manel Fernandez <manelfera@outlook.com>, 2018
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-08-24 09:33+0000\n"
|
||||
"Last-Translator: Manel Fernandez <manelfera@outlook.com>, 2018\n"
|
||||
"Language-Team: Catalan (https://www.transifex.com/odoo/teams/41243/ca/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: ca\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "Transifex URL"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Traducció"
|
||||
@@ -1,36 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# trendspotter <j.podhorecky@volny.cz>, 2019
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2019-08-26 09:14+0000\n"
|
||||
"Last-Translator: trendspotter <j.podhorecky@volny.cz>, 2019\n"
|
||||
"Language-Team: Czech (https://www.transifex.com/odoo/teams/41243/cs/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: cs\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "Transifex URL"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Překlad"
|
||||
@@ -1,36 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux, 2018
|
||||
# lhmflexerp <lhm@flexerp.dk>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: lhmflexerp <lhm@flexerp.dk>, 2018\n"
|
||||
"Language-Team: Danish (https://www.transifex.com/odoo/teams/41243/da/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: da\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "Transifex URL"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Oversættelse"
|
||||
@@ -1,36 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# AppleMentalist <felix.schnatbaum@gmail.com>, 2018
|
||||
# darenkster <inactive+darenkster@transifex.com>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: darenkster <inactive+darenkster@transifex.com>, 2018\n"
|
||||
"Language-Team: German (https://www.transifex.com/odoo/teams/41243/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: de\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "Transifex URL"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Übersetzung"
|
||||
@@ -1,35 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Martin Trigaux, 2018\n"
|
||||
"Language-Team: Greek (https://www.transifex.com/odoo/teams/41243/el/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: el\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Μετάφραση"
|
||||
@@ -1,36 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# e2f <projects@e2f.com>, 2018
|
||||
# Jesús Alan Ramos Rodríguez <alan.ramos@jarsa.com.mx>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Jesús Alan Ramos Rodríguez <alan.ramos@jarsa.com.mx>, 2018\n"
|
||||
"Language-Team: Spanish (https://www.transifex.com/odoo/teams/41243/es/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: es\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "URL de Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Traducción"
|
||||
@@ -1,37 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Rivo Zängov <eraser@eraser.ee>, 2018
|
||||
# Martin Trigaux, 2018
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-08-24 09:33+0000\n"
|
||||
"Last-Translator: Martin Trigaux, 2018\n"
|
||||
"Language-Team: Estonian (https://www.transifex.com/odoo/teams/41243/et/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: et\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "Transifexi URL"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Tõlge"
|
||||
@@ -1,35 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Martin Trigaux, 2018\n"
|
||||
"Language-Team: Persian (https://www.transifex.com/odoo/teams/41243/fa/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: fa\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "ترجمه"
|
||||
@@ -1,35 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Tuomo Aura <tuomo.aura@web-veistamo.fi>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Tuomo Aura <tuomo.aura@web-veistamo.fi>, 2018\n"
|
||||
"Language-Team: Finnish (https://www.transifex.com/odoo/teams/41243/fi/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: fi\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Käännös"
|
||||
@@ -1,36 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# e2f <projects@e2f.com>, 2018
|
||||
# Lucas Deliege <lud@odoo.com>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Lucas Deliege <lud@odoo.com>, 2018\n"
|
||||
"Language-Team: French (https://www.transifex.com/odoo/teams/41243/fr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: fr\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "URL Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Traduction"
|
||||
@@ -1,32 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Language-Team: Gujarati (https://www.transifex.com/odoo/teams/41243/gu/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: gu\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr ""
|
||||
@@ -1,35 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Martin Trigaux, 2018\n"
|
||||
"Language-Team: Hebrew (https://www.transifex.com/odoo/teams/41243/he/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: he\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "תרגום"
|
||||
@@ -1,36 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Karolina Tonković <karolina.tonkovic@storm.hr>, 2019
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2019-08-26 09:14+0000\n"
|
||||
"Last-Translator: Karolina Tonković <karolina.tonkovic@storm.hr>, 2019\n"
|
||||
"Language-Team: Croatian (https://www.transifex.com/odoo/teams/41243/hr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: hr\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Prijevod"
|
||||
@@ -1,36 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# krnkris, 2018
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-08-24 09:33+0000\n"
|
||||
"Last-Translator: krnkris, 2018\n"
|
||||
"Language-Team: Hungarian (https://www.transifex.com/odoo/teams/41243/hu/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: hu\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Fordítás"
|
||||
@@ -1,35 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Rachmat Aditiya <raditiya@me.com>, 2017
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~18\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-10-02 11:26+0000\n"
|
||||
"PO-Revision-Date: 2017-10-02 11:26+0000\n"
|
||||
"Last-Translator: Rachmat Aditiya <raditiya@me.com>, 2017\n"
|
||||
"Language-Team: Indonesian (https://www.transifex.com/odoo/teams/41243/id/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: id\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation_transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "ir.translation"
|
||||
msgstr "ir.translation"
|
||||
@@ -1,36 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Bjorn Ingvarsson <boi@exigo.is>, 2018
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-08-24 09:33+0000\n"
|
||||
"Last-Translator: Bjorn Ingvarsson <boi@exigo.is>, 2018\n"
|
||||
"Language-Team: Icelandic (https://www.transifex.com/odoo/teams/41243/is/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: is\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Translation"
|
||||
@@ -1,37 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Sergio Zanchetta <primes2h@gmail.com>, 2018
|
||||
# Paolo Valier, 2018
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-08-24 09:33+0000\n"
|
||||
"Last-Translator: Paolo Valier, 2018\n"
|
||||
"Language-Team: Italian (https://www.transifex.com/odoo/teams/41243/it/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: it\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "URL di Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Traduzione"
|
||||
@@ -1,35 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Martin Trigaux, 2018\n"
|
||||
"Language-Team: Japanese (https://www.transifex.com/odoo/teams/41243/ja/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: ja\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "翻訳"
|
||||
@@ -1,32 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Language-Team: Khmer (https://www.transifex.com/odoo/teams/41243/km/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: km\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr ""
|
||||
@@ -1,36 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Link Up링크업 <linkup.way@gmail.com>, 2018
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-08-24 09:33+0000\n"
|
||||
"Last-Translator: Link Up링크업 <linkup.way@gmail.com>, 2018\n"
|
||||
"Language-Team: Korean (https://www.transifex.com/odoo/teams/41243/ko/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: ko\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "Transifex URL"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr ""
|
||||
@@ -1,32 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2019-08-26 09:14+0000\n"
|
||||
"Language-Team: Luxembourgish (https://www.transifex.com/odoo/teams/41243/lb/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: lb\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr ""
|
||||
@@ -1,37 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux, 2019
|
||||
# Silvija Butko <silvija.butko@gmail.com>, 2019
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2019-08-26 09:14+0000\n"
|
||||
"Last-Translator: Silvija Butko <silvija.butko@gmail.com>, 2019\n"
|
||||
"Language-Team: Lithuanian (https://www.transifex.com/odoo/teams/41243/lt/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: lt\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "Transifex URL"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Vertimas"
|
||||
@@ -1,32 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~18\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-10-02 11:26+0000\n"
|
||||
"PO-Revision-Date: 2017-10-02 11:26+0000\n"
|
||||
"Language-Team: Latvian (https://www.transifex.com/odoo/teams/41243/lv/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: lv\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation_transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "ir.translation"
|
||||
msgstr ""
|
||||
@@ -1,37 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux, 2019
|
||||
# nurbakhit nurka <nurbakhit@bumanit.mn>, 2019
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2019-08-26 09:14+0000\n"
|
||||
"Last-Translator: nurbakhit nurka <nurbakhit@bumanit.mn>, 2019\n"
|
||||
"Language-Team: Mongolian (https://www.transifex.com/odoo/teams/41243/mn/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: mn\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Трансфикс"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Орчуулга"
|
||||
@@ -1,36 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Jan Pedro Tumusok <jpt@eyenetworks.no>, 2018
|
||||
# Jorunn D. Newth, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Jorunn D. Newth, 2018\n"
|
||||
"Language-Team: Norwegian Bokmål (https://www.transifex.com/odoo/teams/41243/nb/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: nb\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "Transifex URL"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Oversettelse"
|
||||
@@ -1,36 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Yenthe Van Ginneken <yenthespam@gmail.com>, 2018
|
||||
# Pol Van Dingenen <pol.vandingenen@vanroey.be>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Pol Van Dingenen <pol.vandingenen@vanroey.be>, 2018\n"
|
||||
"Language-Team: Dutch (https://www.transifex.com/odoo/teams/41243/nl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: nl\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "Transifex URL"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Vertaling"
|
||||
@@ -1,36 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Piotr Szlązak <szlazakpiotr@gmail.com>, 2018
|
||||
# Tadeusz Karpiński <tadeuszkarpinski@gmail.com>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Tadeusz Karpiński <tadeuszkarpinski@gmail.com>, 2018\n"
|
||||
"Language-Team: Polish (https://www.transifex.com/odoo/teams/41243/pl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: pl\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "Strona Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Tłumaczenie"
|
||||
@@ -1,32 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2019-08-26 09:14+0000\n"
|
||||
"Language-Team: Portuguese (https://www.transifex.com/odoo/teams/41243/pt/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: pt\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr ""
|
||||
@@ -1,35 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Mateus Lopes <mateus1@gmail.com>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Mateus Lopes <mateus1@gmail.com>, 2018\n"
|
||||
"Language-Team: Portuguese (Brazil) (https://www.transifex.com/odoo/teams/41243/pt_BR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: pt_BR\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Tradução"
|
||||
@@ -1,32 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2019-08-26 09:14+0000\n"
|
||||
"Language-Team: Romanian (https://www.transifex.com/odoo/teams/41243/ro/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: ro\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr ""
|
||||
@@ -1,37 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Denis Trepalin <zekarious@gmail.com>, 2019
|
||||
# Vasiliy Korobatov <korobatov@gmail.com>, 2019
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2019-08-26 09:14+0000\n"
|
||||
"Last-Translator: Vasiliy Korobatov <korobatov@gmail.com>, 2019\n"
|
||||
"Language-Team: Russian (https://www.transifex.com/odoo/teams/41243/ru/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: ru\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "URL-адрес Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Перевод"
|
||||
@@ -1,35 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Jaroslav Bosansky <jaro.bosansky@ekoenergo.sk>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Jaroslav Bosansky <jaro.bosansky@ekoenergo.sk>, 2018\n"
|
||||
"Language-Team: Slovak (https://www.transifex.com/odoo/teams/41243/sk/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: sk\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Preklad"
|
||||
@@ -1,32 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~18\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-10-02 11:26+0000\n"
|
||||
"PO-Revision-Date: 2017-10-02 11:26+0000\n"
|
||||
"Language-Team: Slovenian (https://www.transifex.com/odoo/teams/41243/sl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: sl\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation_transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "ir.translation"
|
||||
msgstr ""
|
||||
@@ -1,35 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Martin Trigaux, 2018\n"
|
||||
"Language-Team: Serbian (https://www.transifex.com/odoo/teams/41243/sr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: sr\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Prevod"
|
||||
@@ -1,35 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux <mat@odoo.com>, 2017
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~18\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-10-02 11:26+0000\n"
|
||||
"PO-Revision-Date: 2017-10-02 11:26+0000\n"
|
||||
"Last-Translator: Martin Trigaux <mat@odoo.com>, 2017\n"
|
||||
"Language-Team: Serbian (Latin) (https://www.transifex.com/odoo/teams/41243/sr%40latin/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: sr@latin\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation_transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "ir.translation"
|
||||
msgstr "ir.translation"
|
||||
@@ -1,35 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Martin Trigaux, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-03-22 14:10+0000\n"
|
||||
"PO-Revision-Date: 2018-03-22 14:10+0000\n"
|
||||
"Last-Translator: Martin Trigaux, 2018\n"
|
||||
"Language-Team: Swedish (https://www.transifex.com/odoo/teams/41243/sv/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: sv\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "ir.translation"
|
||||
msgstr "ir.translation"
|
||||
@@ -1,36 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Khwunchai Jaengsawang <khwunchai.j@ku.th>, 2018
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-08-24 09:33+0000\n"
|
||||
"Last-Translator: Khwunchai Jaengsawang <khwunchai.j@ku.th>, 2018\n"
|
||||
"Language-Team: Thai (https://www.transifex.com/odoo/teams/41243/th/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: th\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "การแปล"
|
||||
@@ -1,36 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Murat Kaplan <muratk@projetgrup.com>, 2018
|
||||
# Ediz Duman <neps1192@gmail.com>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Ediz Duman <neps1192@gmail.com>, 2018\n"
|
||||
"Language-Team: Turkish (https://www.transifex.com/odoo/teams/41243/tr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: tr\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "Transifex URL"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Çeviri"
|
||||
@@ -1,45 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~14.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-09-14 10:29+0000\n"
|
||||
"PO-Revision-Date: 2021-09-14 10:29+0000\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_src_value_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Contribute"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,help:transifex.field_ir_translation__transifex_url
|
||||
msgid "Propose a modification in the official version of Odoo"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_src_value_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr ""
|
||||
@@ -1,36 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# Alina Lisnenko <alinasemeniuk1@gmail.com>, 2018
|
||||
# Bohdan Lisnenko, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Bohdan Lisnenko, 2018\n"
|
||||
"Language-Team: Ukrainian (https://www.transifex.com/odoo/teams/41243/uk/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: uk\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "Transifex URL"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Переклад"
|
||||
@@ -1,35 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# thanh nguyen <thanhnguyen.icsc@gmail.com>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: thanh nguyen <thanhnguyen.icsc@gmail.com>, 2018\n"
|
||||
"Language-Team: Vietnamese (https://www.transifex.com/odoo/teams/41243/vi/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: vi\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr ""
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "Bản dịch"
|
||||
@@ -1,37 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# e2f <projects@e2f.com>, 2018
|
||||
# e2f_cn c7 <e2f_cn_c7@outlook.com>, 2018
|
||||
# Jeffery CHEN Fan <jeffery9@gmail.com>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: Jeffery CHEN Fan <jeffery9@gmail.com>, 2018\n"
|
||||
"Language-Team: Chinese (China) (https://www.transifex.com/odoo/teams/41243/zh_CN/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: zh_CN\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "Transifex 网址"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "翻译"
|
||||
@@ -1,35 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * transifex
|
||||
#
|
||||
# Translators:
|
||||
# 敬雲 林 <chingyun@yuanchih-consult.com>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~11.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-09-21 13:17+0000\n"
|
||||
"PO-Revision-Date: 2018-09-21 13:17+0000\n"
|
||||
"Last-Translator: 敬雲 林 <chingyun@yuanchih-consult.com>, 2018\n"
|
||||
"Language-Team: Chinese (Taiwan) (https://www.transifex.com/odoo/teams/41243/zh_TW/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: zh_TW\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#. module: transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_dialog_view_tree_transifex
|
||||
#: model_terms:ir.ui.view,arch_db:transifex.ir_translation_view_tree_transifex
|
||||
msgid "Transifex"
|
||||
msgstr "Transifex"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model.fields,field_description:transifex.field_ir_translation__transifex_url
|
||||
msgid "Transifex URL"
|
||||
msgstr "Transifex 網址"
|
||||
|
||||
#. module: transifex
|
||||
#: model:ir.model,name:transifex.model_ir_translation
|
||||
msgid "Translation"
|
||||
msgstr "翻譯"
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import ir_translation
|
||||
@@ -1,86 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from configparser import ConfigParser
|
||||
from os.path import join as opj
|
||||
import os
|
||||
import werkzeug.urls
|
||||
|
||||
import odoo
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class IrTranslation(models.Model):
|
||||
|
||||
_inherit = 'ir.translation'
|
||||
|
||||
transifex_url = fields.Char("Transifex URL", compute='_get_transifex_url', help="Propose a modification in the official version of Odoo")
|
||||
|
||||
def _get_transifex_url(self):
|
||||
""" Construct transifex URL based on the module on configuration """
|
||||
# e.g. 'https://www.transifex.com/odoo/'
|
||||
base_url = self.env['ir.config_parameter'].sudo().get_param('transifex.project_url')
|
||||
|
||||
tx_config_file = ConfigParser()
|
||||
tx_sections = []
|
||||
for addon_path in odoo.addons.__path__:
|
||||
tx_path = opj(addon_path, '.tx', 'config')
|
||||
if os.path.isfile(tx_path):
|
||||
tx_config_file.read(tx_path)
|
||||
# first section is [main], after [odoo-11.sale]
|
||||
tx_sections.extend(tx_config_file.sections()[1:])
|
||||
|
||||
# parent directory ad .tx/config is root directory in odoo/odoo
|
||||
tx_path = opj(addon_path, os.pardir, '.tx', 'config')
|
||||
if os.path.isfile(tx_path):
|
||||
tx_config_file.read(tx_path)
|
||||
tx_sections.extend(tx_config_file.sections()[1:])
|
||||
|
||||
if not base_url or not tx_sections:
|
||||
self.update({'transifex_url': False})
|
||||
else:
|
||||
base_url = base_url.rstrip('/')
|
||||
|
||||
# will probably be the same for all terms, avoid multiple searches
|
||||
translation_languages = list(set(self.mapped('lang')))
|
||||
languages = self.env['res.lang'].with_context(active_test=False).search(
|
||||
[('code', 'in', translation_languages)])
|
||||
|
||||
language_codes = dict((l.code, l.iso_code) for l in languages)
|
||||
|
||||
# .tx/config files contains the project reference
|
||||
# using ini files like '[odoo-master.website_sale]'
|
||||
translation_modules = set(self.mapped('module'))
|
||||
project_modules = {}
|
||||
for module in translation_modules:
|
||||
for section in tx_sections:
|
||||
tx_project, tx_mod = section.split('.')
|
||||
if tx_mod == module:
|
||||
project_modules[module] = tx_project
|
||||
|
||||
for translation in self:
|
||||
if not translation.module or not translation.src or translation.lang == 'en_US':
|
||||
# custom or source term
|
||||
translation.transifex_url = False
|
||||
continue
|
||||
|
||||
lang_code = language_codes.get(translation.lang)
|
||||
if not lang_code:
|
||||
translation.transifex_url = False
|
||||
continue
|
||||
|
||||
project = project_modules.get(translation.module)
|
||||
if not project:
|
||||
translation.transifex_url = False
|
||||
continue
|
||||
|
||||
# e.g. https://www.transifex.com/odoo/odoo-10/translate/#fr/sale/42?q=text:'Sale+Order'
|
||||
src = werkzeug.urls.url_quote_plus(translation.src[:50].replace("\n", "").replace("'", "\\'"))
|
||||
src = f"'{src}'" if "+" in src else src
|
||||
translation.transifex_url = "%(url)s/%(project)s/translate/#%(lang)s/%(module)s/42?q=%(src)s" % {
|
||||
'url': base_url,
|
||||
'project': project,
|
||||
'lang': lang_code,
|
||||
'module': translation.module,
|
||||
'src': f"text%3A{src}",
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.2 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="70" height="70"><defs><path id="a" d="M4 0h61c4 0 5 1 5 5v60c0 4-1 5-5 5H4c-3 0-4-1-4-5V5c0-4 1-5 4-5z"/><linearGradient id="c" x1="100%" x2="0%" y1="0%" y2="98.616%"><stop offset="0%" stop-color="#797C79"/><stop offset="100%" stop-color="#545554"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><g mask="url(#b)"><path fill="url(#c)" d="M0 0H70V70H0z"/><path fill="#FFF" fill-opacity=".383" d="M4 1h61c2.667 0 4.333.667 5 2V0H0v3c.667-1.333 2-2 4-2z"/><path fill="#393939" d="M4 69c-2 0-4-1-4-4V36.095L18.936 13l5.025 8H30.5L41 28l7.5-7-5.564 10.127L55.577 49 36 69H4z" opacity=".324"/><path fill="#000" fill-opacity=".383" d="M4 69h61c2.667 0 4.333-1 5-3v4H0v-4c.667 2 2 3 4 3z"/><path fill="#000" fill-rule="nonzero" d="M19.077 15h5.5v8h4v5h-4v18h4v5H23.54c-3.026 0-4.513-1.667-4.462-5V28h-4.452v-5h4.452v-8zm11.5 36l9-14-9.5-14h7l5.5 9 6-9h7l-9.5 14 9.5 14h-7l-5.5-8.445-5.5 8.445h-7zm-15.54 2.642H14V53h2.833v.642h-1.037v2.832h-.76v-2.832zM17 53h1.07l.809 2.389h.01L19.652 53h1.07v3.474h-.711v-2.462h-.01l-.847 2.462h-.586l-.848-2.438h-.01v2.438H17V53z" opacity=".3"/><path fill="#FFF" fill-rule="nonzero" d="M19.077 13h5.5v8h4v5h-4v18h4v5H23.54c-3.026 0-4.513-1.667-4.462-5V26h-4.452v-5h4.452v-8zm11.5 36l9-14-9.5-14h7l5.5 9 6-9h7l-9.5 14 9.5 14h-7l-5.5-8.445-5.5 8.445h-7zm-15.54 2.642H14V51h2.833v.642h-1.037v2.832h-.76v-2.832zM17 51h1.07l.809 2.389h.01L19.652 51h1.07v3.474h-.711v-2.462h-.01l-.847 2.462h-.586l-.848-2.438h-.01v2.438H17V51z"/></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
@@ -96,7 +96,7 @@ class WebClient(http.Controller):
|
||||
elif mods is None:
|
||||
mods = list(request.env.registry._init_modules) + (odoo.conf.server_wide_modules or [])
|
||||
|
||||
translations_per_module, lang_params = request.env["ir.translation"].get_translations_for_webclient(mods, lang)
|
||||
translations_per_module, lang_params = request.env["ir.http"].get_translations_for_webclient(mods, lang)
|
||||
|
||||
body = json.dumps({
|
||||
'lang': lang,
|
||||
|
||||
@@ -104,7 +104,7 @@ class Http(models.AbstractModel):
|
||||
"max_file_upload_size": max_file_upload_size,
|
||||
"home_action_id": user.action_id.id,
|
||||
"cache_hashes": {
|
||||
"translations": request.env['ir.translation'].sudo().get_web_translations_hash(
|
||||
"translations": request.env['ir.http'].sudo().get_web_translations_hash(
|
||||
mods, request.session.context['lang']
|
||||
) if session_uid else None,
|
||||
},
|
||||
|
||||
@@ -944,25 +944,15 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
|
||||
}
|
||||
var record = this.model.get(ev.data.id, { raw: true });
|
||||
var res_id = record.res_id || record.res_ids[0];
|
||||
var result = await this._rpc({
|
||||
route: '/web/dataset/call_button',
|
||||
params: {
|
||||
model: 'ir.translation',
|
||||
method: 'translate_fields',
|
||||
args: [record.model, res_id, ev.data.fieldName],
|
||||
kwargs: { context: record.getContext() },
|
||||
}
|
||||
});
|
||||
|
||||
this.translationDialog = new TranslationDialog(this, {
|
||||
domain: result.domain,
|
||||
searchName: result.context.search_default_name,
|
||||
fieldName: ev.data.fieldName,
|
||||
resId: res_id,
|
||||
userLanguageValue: ev.target.value || '',
|
||||
dataPointModel: record.model,
|
||||
dataPointID: record.id,
|
||||
isComingFromTranslationAlert: ev.data.isComingFromTranslationAlert,
|
||||
isText: result.context.translation_type === 'text',
|
||||
showSrc: result.context.translation_show_src,
|
||||
context: record.getContext(),
|
||||
});
|
||||
return this.translationDialog.open();
|
||||
},
|
||||
|
||||
@@ -14,29 +14,24 @@ odoo.define('web.TranslationDialog', function (require) {
|
||||
* @constructor
|
||||
* @param {Widget} parent
|
||||
* @param {Object} [options]
|
||||
* @param {string} [options.domain] the domain needed to get the translation terms
|
||||
* @param {string} [options.fieldName] the name of the field currently translated (from the model of the form view)
|
||||
* @param {string} [options.searchName] the name of the actual field that is the reference for translation (in the form of model,field)
|
||||
* @param {integer} [options.resId] the ID of record currently translated
|
||||
* @param {string} [options.userLanguageValue] the value of the translation in the language of the user, as seen in the from view (might be empty)
|
||||
* @param {string} [options.dataPointID] the data point id of the record for which we do the translations
|
||||
* @param {boolean} [options.isComingFromTranslationAlert] the initiator of the dialog, might be a link on a field or the translation alert on top of the form
|
||||
* @param {boolean} [options.isText] is the field a text field (multiline) or char (single line)
|
||||
* @param {boolean} [options.showSrc] is the source of the translation should be rendered (for partial translations, i.e. XML content)
|
||||
*
|
||||
*/
|
||||
init: function (parent, options) {
|
||||
options = options || {};
|
||||
|
||||
this.fieldName = options.fieldName;
|
||||
this.domain = options.domain;
|
||||
this.searchName = options.searchName;
|
||||
this.resId = options.resId;
|
||||
this.userLanguageValue = options.userLanguageValue;
|
||||
this.domain.push(['name', "=", `${this.searchName}`]);
|
||||
this.dataPointModel = options.dataPointModel;
|
||||
this.dataPointID = options.dataPointID;
|
||||
this.isComingFromTranslationAlert = options.isComingFromTranslationAlert;
|
||||
this.currentInterfaceLanguage = session.user_context.lang;
|
||||
this.isText = options.isText;
|
||||
this.showSrc = options.showSrc;
|
||||
this.context = options.context;
|
||||
|
||||
this._super(parent, _.extend({
|
||||
size: 'large',
|
||||
@@ -56,31 +51,35 @@ odoo.define('web.TranslationDialog', function (require) {
|
||||
this._loadLanguages().then((l) => {
|
||||
this.languages = l;
|
||||
return this._loadTranslations().then((t) => {
|
||||
this.translations = t;
|
||||
[this.translations, this.context] = t;
|
||||
let id = 1;
|
||||
this.translations.forEach((t) => t['id'] = id++);
|
||||
this.isText = this.context.translation_type === 'text';
|
||||
this.showSource = this.context.translation_show_source;
|
||||
});
|
||||
}),
|
||||
]).then(() => {
|
||||
this.data = this.translations.map((term) => {
|
||||
let relatedLanguage = this.languages.find((language) => language[0] === term.lang);
|
||||
if (!term.value && !this.showSrc) {
|
||||
term.value = term.src;
|
||||
if (!term.value && !this.showSource) {
|
||||
term.value = term.source;
|
||||
}
|
||||
return {
|
||||
id: term.id,
|
||||
lang: term.lang,
|
||||
langName: relatedLanguage[1],
|
||||
source: term.src,
|
||||
source: term.source,
|
||||
// we set the translation value coming from the database, except for the language
|
||||
// the user is currently utilizing. Then we set the translation value coming
|
||||
// from the value of the field in the form
|
||||
value: (term.lang === this.currentInterfaceLanguage &&
|
||||
!this.showSrc &&
|
||||
!this.showSource &&
|
||||
!this.isComingFromTranslationAlert) ?
|
||||
this.userLanguageValue : term.value || ''
|
||||
};
|
||||
});
|
||||
this.data.sort((left, right) =>
|
||||
(left.langName < right.langName || (left.langName === right.langName && left.source < right.source)) ? -1 : 1);
|
||||
left.langName.localeCompare(right.langName));
|
||||
});
|
||||
},
|
||||
|
||||
@@ -92,12 +91,11 @@ odoo.define('web.TranslationDialog', function (require) {
|
||||
* @private
|
||||
*/
|
||||
_loadTranslations: function () {
|
||||
const domain = [...this.domain, ['lang', 'in', this.languages.map(l => l[0])]];
|
||||
return this._rpc({
|
||||
model: 'ir.translation',
|
||||
method: 'search_read',
|
||||
fields: ['lang', 'src', 'value'],
|
||||
domain: domain,
|
||||
model: this.dataPointModel,
|
||||
method: 'get_field_translations',
|
||||
args: [[this.resId], this.fieldName],
|
||||
context: this.context,
|
||||
});
|
||||
},
|
||||
/**
|
||||
@@ -137,16 +135,16 @@ odoo.define('web.TranslationDialog', function (require) {
|
||||
this.el.querySelectorAll('input[type=text],textarea').forEach((t) => {
|
||||
var initialValue = this.data.find((d) => d.id == t.dataset.id);
|
||||
if (initialValue.value !== t.value) {
|
||||
updatedTerm[t.dataset.id] = t.value;
|
||||
updatedTerm[t.dataset.id] = {lang: initialValue.lang, source: initialValue.source, value: t.value};
|
||||
|
||||
if (initialValue.lang === this.currentInterfaceLanguage && !this.showSrc) {
|
||||
if (initialValue.lang === this.currentInterfaceLanguage && !this.showSource) {
|
||||
// when the user has changed the term for the language he is
|
||||
// using in the interface, this change should be reflected
|
||||
// in the form view
|
||||
// partial translations being handled server side are
|
||||
// also ignored
|
||||
var changes = {};
|
||||
changes[this.fieldName] = updatedTerm[initialValue.id];
|
||||
changes[this.fieldName] = t.value;
|
||||
updateFormViewField = {
|
||||
dataPointID: this.dataPointID,
|
||||
changes: changes,
|
||||
@@ -158,16 +156,23 @@ odoo.define('web.TranslationDialog', function (require) {
|
||||
|
||||
// updatedTerm only contains the id and values of the terms that
|
||||
// have been updated by the user
|
||||
var saveUpdatedTermsProms = Object.keys(updatedTerm).map((id) => {
|
||||
var writeTranslation = {
|
||||
model: 'ir.translation',
|
||||
method: 'write',
|
||||
context: this.context,
|
||||
args: [[parseInt(id, 10)], { value: updatedTerm[id] }]
|
||||
};
|
||||
return this._rpc(writeTranslation);
|
||||
});
|
||||
return Promise.all(saveUpdatedTermsProms).then(() => {
|
||||
const translations = {};
|
||||
if (this.showSource) { // model terms translation
|
||||
Object.entries(updatedTerm).forEach(([id, term]) => {
|
||||
if (!translations[term.lang]) {
|
||||
translations[term.lang] = {};
|
||||
}
|
||||
translations[term.lang][term.source] = term.value;
|
||||
});
|
||||
}
|
||||
else { // model translation
|
||||
Object.entries(updatedTerm).forEach(([id, term]) => translations[term.lang] = term.value);
|
||||
}
|
||||
return this._rpc({
|
||||
model: this.dataPointModel,
|
||||
method: 'update_field_translations',
|
||||
args: [[this.resId], this.fieldName, translations],
|
||||
}).then(() => {
|
||||
// we might have to update the value of the field on the form
|
||||
// view that opened the translation dialog
|
||||
if (updateFormViewField) {
|
||||
|
||||
@@ -713,6 +713,20 @@ $o-form-label-margin-right: 0px;
|
||||
padding-right: 25px;
|
||||
}
|
||||
}
|
||||
.oe_no_translation_content {
|
||||
&:not(.btn) {
|
||||
display: none;
|
||||
}
|
||||
&.btn {
|
||||
width: 100% !important;
|
||||
margin-left: 0px;
|
||||
visibility: hidden;
|
||||
}
|
||||
&.btn:after {
|
||||
content: 'EN';
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
// Text field with oe_inline class
|
||||
.o_field_text.oe_inline {
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<templates id="template" xml:space="preserve">
|
||||
<div t-name="web.TranslationDialogWidget" class="o_translation_dialog">
|
||||
<div class="row" t-foreach="widget.data" t-as="term">
|
||||
<div t-attf-class="col-12 #{widget.showSrc ? 'col-lg-2' : 'col-lg-3'} #{widget.currentInterfaceLanguage == term.lang ? 'o_language_current' : ''}">
|
||||
<div t-attf-class="col-12 #{widget.showSource ? 'col-lg-2' : 'col-lg-3'} #{widget.currentInterfaceLanguage == term.lang ? 'o_language_current' : ''}">
|
||||
<t t-esc="term.langName"></t>
|
||||
</div>
|
||||
<div t-if="widget.showSrc" class="col-12 col-lg-3 source">
|
||||
<div t-if="widget.showSource" class="col-12 col-lg-3 source">
|
||||
<t t-esc="term.source"></t>
|
||||
</div>
|
||||
<div t-attf-class="col-12 #{widget.showSrc ? 'col-lg-7' : 'col-lg-9'} translation">
|
||||
<div t-attf-class="col-12 #{widget.showSource ? 'col-lg-7' : 'col-lg-9'} translation">
|
||||
<input t-if="!widget.isText" type="text"
|
||||
class="o_field_char o_input"
|
||||
t-att-value="term.value"
|
||||
@@ -17,7 +17,7 @@
|
||||
<textarea t-if="widget.isText"
|
||||
t-esc="term.value"
|
||||
t-att-data-id="term.id"
|
||||
t-att-rows="widget.showSrc ? 2 : 5"
|
||||
t-att-rows="widget.showSource ? 2 : 5"
|
||||
class="o_field_text o_field_translate o_field_widget o_input">
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,6 @@ const { Component, useEnv } = owl;
|
||||
*/
|
||||
export function useTranslationDialog() {
|
||||
const dialog = useService("dialog");
|
||||
const rpc = useService("rpc");
|
||||
const env = useEnv();
|
||||
|
||||
async function openTranslationDialog({ record, fieldName, updateField }) {
|
||||
@@ -43,22 +42,14 @@ export function useTranslationDialog() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const { resModel, resId, context } = record;
|
||||
const result = await rpc("/web/dataset/call_button", {
|
||||
model: "ir.translation",
|
||||
method: "translate_fields",
|
||||
args: [resModel, resId, fieldName],
|
||||
kwargs: { context },
|
||||
});
|
||||
const { resModel, resId } = record;
|
||||
|
||||
dialog.add(TranslationDialog, {
|
||||
domain: result.domain,
|
||||
searchName: result.context.search_default_name,
|
||||
fieldName: fieldName,
|
||||
resId: resId,
|
||||
resModel: resModel,
|
||||
userLanguageValue: record.data[fieldName] || "",
|
||||
isComingFromTranslationAlert: false,
|
||||
isText: result.context.translation_type === "text",
|
||||
showSource: result.context.translation_show_src,
|
||||
updateField,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20,18 +20,22 @@ export class TranslationDialog extends Component {
|
||||
|
||||
onWillStart(async () => {
|
||||
const languages = await loadLanguages(this.orm);
|
||||
const translations = await this.loadTranslations(languages);
|
||||
const [translations, context] = await this.loadTranslations(languages);
|
||||
let id = 1;
|
||||
translations.forEach((t) => (t.id = id++));
|
||||
this.props.isText = context.translation_type === "text";
|
||||
this.props.showSource = context.translation_show_source;
|
||||
|
||||
this.terms = translations.map((term) => {
|
||||
const relatedLanguage = languages.find((l) => l[0] === term.lang);
|
||||
if (!term.value && !this.props.showSource) {
|
||||
term.value = term.src;
|
||||
term.value = term.source;
|
||||
}
|
||||
return {
|
||||
id: term.id,
|
||||
lang: term.lang,
|
||||
langName: relatedLanguage[1],
|
||||
source: term.src,
|
||||
source: term.source,
|
||||
// we set the translation value coming from the database, except for the language
|
||||
// the user is currently utilizing. Then we set the translation value coming
|
||||
// from the value of the field in the form
|
||||
@@ -43,11 +47,7 @@ export class TranslationDialog extends Component {
|
||||
: term.value || "",
|
||||
};
|
||||
});
|
||||
this.terms.sort((a, b) =>
|
||||
a.langName < b.langName || (a.langName === b.langName && a.source < b.source)
|
||||
? -1
|
||||
: 1
|
||||
);
|
||||
this.terms.sort((a, b) => a.langName.localeCompare(b.langName));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -63,23 +63,37 @@ export class TranslationDialog extends Component {
|
||||
* Load the translation terms for the installed language, for the current model and res_id
|
||||
*/
|
||||
async loadTranslations(languages) {
|
||||
const domain = [...this.domain, ["lang", "in", languages.map((l) => l[0])]];
|
||||
return this.orm.searchRead("ir.translation", domain, ["lang", "src", "value"]);
|
||||
return this.orm.call(this.props.resModel, "get_field_translations", [
|
||||
[this.props.resId],
|
||||
this.props.fieldName,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save all the terms that have been updated
|
||||
*/
|
||||
async onSave() {
|
||||
await Promise.all(
|
||||
this.terms.map(async (term) => {
|
||||
if (term.id in this.updatedTerms && term.value !== this.updatedTerms[term.id]) {
|
||||
await this.orm.write("ir.translation", [term.id], {
|
||||
value: this.updatedTerms[term.id],
|
||||
});
|
||||
const translations = {};
|
||||
|
||||
this.terms.map((term) => {
|
||||
const updatedTermValue = this.updatedTerms[term.id];
|
||||
if (term.id in this.updatedTerms && term.value !== updatedTermValue) {
|
||||
if (this.props.showSource) {
|
||||
if (!translations[term.lang]) {
|
||||
translations[term.lang] = {};
|
||||
}
|
||||
translations[term.lang][term.source] = updatedTermValue;
|
||||
} else {
|
||||
translations[term.lang] = updatedTermValue;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
await this.orm.call(this.props.resModel, "update_field_translations", [
|
||||
[this.props.resId],
|
||||
this.props.fieldName,
|
||||
translations,
|
||||
]);
|
||||
|
||||
// we might have to update the value of the field on the form
|
||||
// view that opened the translation dialog
|
||||
|
||||
@@ -436,6 +436,20 @@ $o-form-label-margin-right: 0px;
|
||||
padding-right: 25px;
|
||||
}
|
||||
}
|
||||
.oe_no_translation_content {
|
||||
:not(.btn) {
|
||||
display: none;
|
||||
}
|
||||
.btn {
|
||||
width: 100% !important;
|
||||
margin-left: 0px;
|
||||
visibility: hidden;
|
||||
}
|
||||
.btn:after {
|
||||
content: 'EN';
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
iframe.wysiwyg_iframe + .o_field_translate {
|
||||
right: 30px !important;
|
||||
top: 7px !important;
|
||||
|
||||
@@ -101,25 +101,6 @@ function manageFilters({ action, env }) {
|
||||
};
|
||||
}
|
||||
|
||||
function technicalTranslation({ action, env }) {
|
||||
if (!action.res_model) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
type: "item",
|
||||
description: env._t("Technical Translation"),
|
||||
callback: async () => {
|
||||
const result = await env.services.orm.call(
|
||||
"ir.translation",
|
||||
"get_technical_translations",
|
||||
[action.res_model]
|
||||
);
|
||||
env.services.action.doAction(result);
|
||||
},
|
||||
sequence: 140,
|
||||
};
|
||||
}
|
||||
|
||||
function viewAccessRights({ accessRights, action, env }) {
|
||||
if (!action.res_model || !accessRights.canSeeModelAccess) {
|
||||
return null;
|
||||
@@ -190,7 +171,6 @@ debugRegistry
|
||||
.add("editAction", editAction)
|
||||
.add("viewFields", viewFields)
|
||||
.add("manageFilters", manageFilters)
|
||||
.add("technicalTranslation", technicalTranslation)
|
||||
.add("accessSeparator", accessSeparator)
|
||||
.add("viewAccessRights", viewAccessRights)
|
||||
.add("viewRecordRules", viewRecordRules);
|
||||
|
||||
@@ -160,19 +160,6 @@ QUnit.module('Legacy basic_fields', {
|
||||
position: "after",
|
||||
}]
|
||||
},
|
||||
"ir.translation": {
|
||||
fields: {
|
||||
lang: {type: "char"},
|
||||
value: {type: "char"},
|
||||
res_id: {type: "integer"}
|
||||
},
|
||||
records: [{
|
||||
id: 99,
|
||||
res_id: 37,
|
||||
value: '',
|
||||
lang: 'en_US'
|
||||
}]
|
||||
},
|
||||
};
|
||||
|
||||
target = getFixture();
|
||||
@@ -1653,25 +1640,18 @@ QUnit.module('Legacy basic_fields', {
|
||||
user_context: {lang: 'en_US'},
|
||||
},
|
||||
mockRPC: function (route, args) {
|
||||
if (route === "/web/dataset/call_button" && args.method === 'translate_fields') {
|
||||
assert.deepEqual(args.args, ["partner",1,"foo"], 'should call "call_button" route');
|
||||
return Promise.resolve({
|
||||
domain: [],
|
||||
context: {search_default_name: 'partnes,foo'},
|
||||
});
|
||||
if (route === "/web/dataset/call_kw/partner/get_field_translations") {
|
||||
assert.deepEqual(args.args, [[1],"foo"], "should translate the foo field of the record");
|
||||
return Promise.resolve([
|
||||
[{lang: "en_US", source: "yop", value: "yop"}, {lang: "fr_BE", source: "yop", value: "valeur français"}],
|
||||
{translation_type: "char", translation_show_source: false},
|
||||
]);
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/res.lang/get_installed") {
|
||||
return Promise.resolve([["en_US", "English"], ["fr_BE", "French (Belgium)"]]);
|
||||
}
|
||||
if (args.method === "search_read" && args.model == "ir.translation") {
|
||||
return Promise.resolve([
|
||||
{lang: 'en_US', src: 'yop', value: 'yop', id: 42},
|
||||
{lang: 'fr_BE', src: 'yop', value: 'valeur français', id: 43}
|
||||
]);
|
||||
}
|
||||
if (args.method === "write" && args.model == "ir.translation") {
|
||||
assert.deepEqual(args.args[1], {value: "english value"},
|
||||
"the new translation value should be written");
|
||||
if (route === "/web/dataset/call_kw/partner/update_field_translations") {
|
||||
assert.deepEqual(args.args, [[1], "foo", {"en_US": "english value"}], "the new translation value should be written");
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
@@ -1741,31 +1721,21 @@ QUnit.module('Legacy basic_fields', {
|
||||
user_context: {lang: 'en_US'},
|
||||
},
|
||||
mockRPC: function (route, args) {
|
||||
if (route === "/web/dataset/call_button" && args.method === 'translate_fields') {
|
||||
assert.deepEqual(args.args, ["partner",1,"foo"], 'should call "call_button" route');
|
||||
return Promise.resolve({
|
||||
domain: [],
|
||||
context: {
|
||||
search_default_name: 'partner,foo',
|
||||
translation_type: 'char',
|
||||
translation_show_src: true,
|
||||
},
|
||||
});
|
||||
if (route === "/web/dataset/call_kw/partner/get_field_translations") {
|
||||
assert.deepEqual(args.args, [[1],"foo"], "should translate the foo field of the record");
|
||||
return Promise.resolve([
|
||||
[{lang: "en_US", source: "first paragraph", value: "first paragraph"},
|
||||
{lang: "en_US", source: "second paragraph", value: "second paragraph"},
|
||||
{lang: "fr_BE", source: "first paragraph", value: "premier paragraphe"},
|
||||
{lang: "fr_BE", source: "second paragraph", value: "deuxième paragraphe"}],
|
||||
{translation_type: "char", translation_show_source: true},
|
||||
]);
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/res.lang/get_installed") {
|
||||
return Promise.resolve([["en_US", "English"], ["fr_BE", "French (Belgium)"]]);
|
||||
}
|
||||
if (args.method === "search_read" && args.model == "ir.translation") {
|
||||
return Promise.resolve([
|
||||
{lang: 'en_US', src: 'first paragraph', value: 'first paragraph', id: 42},
|
||||
{lang: 'en_US', src: 'second paragraph', value: 'second paragraph', id: 43},
|
||||
{lang: 'fr_BE', src: 'first paragraph', value: 'premier paragraphe', id: 44},
|
||||
{lang: 'fr_BE', src: 'second paragraph', value: 'deuxième paragraphe', id: 45},
|
||||
]);
|
||||
}
|
||||
if (args.method === "write" && args.model == "ir.translation") {
|
||||
assert.deepEqual(args.args[1], {value: "first paragraph modified"},
|
||||
"Wrong update on translation");
|
||||
if (route === "/web/dataset/call_kw/partner/update_field_translations") {
|
||||
assert.deepEqual(args.args, [[1], "foo", {"en_US": {"first paragraph": "first paragraph modified"}}], "the new translation value should be written");
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
@@ -2694,15 +2664,15 @@ QUnit.module('Legacy basic_fields', {
|
||||
'</form>',
|
||||
res_id: 1,
|
||||
mockRPC: function (route, args) {
|
||||
if (route === "/web/dataset/call_button" && args.method === 'translate_fields') {
|
||||
assert.deepEqual(args.args, ["partner",1,"txt"], 'should call "call_button" route');
|
||||
return Promise.resolve({
|
||||
domain: [],
|
||||
context: {search_default_name: 'partnes,foo'},
|
||||
});
|
||||
if (route === "/web/dataset/call_kw/partner/get_field_translations") {
|
||||
assert.deepEqual(args.args, [[1],"txt"], "should translate the txt field of the record");
|
||||
return Promise.resolve([
|
||||
[{lang: "en_US", source: "yop", value: "yop"}, {lang: "fr_BE", source: "yop", value: "valeur français"}],
|
||||
{translation_type: "text", translation_show_source: false},
|
||||
]);
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/res.lang/get_installed") {
|
||||
return Promise.resolve([["en_US"], ["fr_BE"]]);
|
||||
return Promise.resolve([["en_US", "English"], ["fr_BE", "French (Belgium)"]]);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
@@ -140,19 +140,6 @@ QUnit.module('LegacyViews', {
|
||||
{id: 14, display_name: "silver", color: 5},
|
||||
]
|
||||
},
|
||||
"ir.translation": {
|
||||
fields: {
|
||||
lang_code: {type: "char"},
|
||||
value: {type: "char"},
|
||||
res_id: {type: "integer"}
|
||||
},
|
||||
records: [{
|
||||
id: 99,
|
||||
res_id: 12,
|
||||
value: '',
|
||||
lang_code: 'en_US'
|
||||
}]
|
||||
},
|
||||
user: {
|
||||
fields: {
|
||||
name: {string: "Name", type: "char"},
|
||||
@@ -7382,16 +7369,7 @@ QUnit.module('LegacyViews', {
|
||||
});
|
||||
|
||||
QUnit.test('translation alerts preserved on reverse breadcrumb', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
serverData.models['ir.translation'] = {
|
||||
fields: {
|
||||
name: { string: "name", type: "char" },
|
||||
source: {string: "Source", type: "char"},
|
||||
value: {string: "Value", type: "char"},
|
||||
},
|
||||
records: [],
|
||||
};
|
||||
assert.expect(1);
|
||||
|
||||
serverData.models.partner.fields.foo.translate = true;
|
||||
|
||||
@@ -7402,12 +7380,6 @@ QUnit.module('LegacyViews', {
|
||||
'</sheet>' +
|
||||
'</form>',
|
||||
'partner,false,search': '<search></search>',
|
||||
'ir.translation,false,list': '<tree>' +
|
||||
'<field name="name"/>' +
|
||||
'<field name="source"/>' +
|
||||
'<field name="value"/>' +
|
||||
'</tree>',
|
||||
'ir.translation,false,search': '<search></search>',
|
||||
};
|
||||
|
||||
serverData.actions = {
|
||||
@@ -7418,14 +7390,6 @@ QUnit.module('LegacyViews', {
|
||||
type: 'ir.actions.act_window',
|
||||
views: [[false, 'form']],
|
||||
},
|
||||
2: {
|
||||
id: 2,
|
||||
name: 'Translate',
|
||||
res_model: 'ir.translation',
|
||||
type: 'ir.actions.act_window',
|
||||
views: [[false, 'list']],
|
||||
target: 'current',
|
||||
}
|
||||
};
|
||||
|
||||
const webClient = await createWebClient({ serverData });
|
||||
@@ -7440,13 +7404,6 @@ QUnit.module('LegacyViews', {
|
||||
|
||||
assert.containsOnce(target, '.o_legacy_form_view .alert > div',
|
||||
"should have a translation alert");
|
||||
|
||||
await doAction(webClient, 2);
|
||||
|
||||
await testUtils.dom.click($('.o_control_panel .breadcrumb a:first'));
|
||||
await legacyExtraNextTick();
|
||||
assert.containsOnce(target, '.o_legacy_form_view .alert > div',
|
||||
"should have a translation alert");
|
||||
});
|
||||
|
||||
QUnit.test('translate event correctly handled with multiple controllers', async function (assert) {
|
||||
@@ -7485,16 +7442,16 @@ QUnit.module('LegacyViews', {
|
||||
if (route === '/web/dataset/call_kw/product/get_formview_id') {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
if (route === "/web/dataset/call_button" && args.method === 'translate_fields') {
|
||||
assert.deepEqual(args.args, ["product",37,"name"], 'should call "call_button" route');
|
||||
if (route === "/web/dataset/call_kw/product/get_field_translations") {
|
||||
assert.deepEqual(args.args, [[37],"name"], "should translate the name field of the record");
|
||||
nbTranslateCalls++;
|
||||
return Promise.resolve({
|
||||
domain: [],
|
||||
context: {search_default_name: 'partnes,foo'},
|
||||
});
|
||||
return Promise.resolve([
|
||||
[{lang: "en_US", source: "yop", value: "yop"}, {lang: "fr_BE", source: "yop", value: "valeur français"}],
|
||||
{translation_type: "char", translation_show_source: false},
|
||||
]);
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/res.lang/get_installed") {
|
||||
return Promise.resolve([["en_US"], ["fr_BE"]]);
|
||||
return Promise.resolve([["en_US", "English"], ["fr_BE", "French (Belgium)"]]);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
@@ -123,31 +123,6 @@ QUnit.module('LegacyViews', {
|
||||
{id: "2-20170808020000", name: "virtual"},
|
||||
]
|
||||
},
|
||||
"ir.translation": {
|
||||
fields: {
|
||||
lang_code: {type: "char"},
|
||||
src: {type: "char"},
|
||||
value: {type: "char"},
|
||||
res_id: {type: "integer"},
|
||||
name: {type: "char"},
|
||||
lang: {type: "char"},
|
||||
},
|
||||
records: [{
|
||||
id: 99,
|
||||
res_id: 1,
|
||||
value: '',
|
||||
lang_code: 'en_US',
|
||||
lang: 'en_US',
|
||||
name: 'foo,foo'
|
||||
},{
|
||||
id: 100,
|
||||
res_id: 1,
|
||||
value: '',
|
||||
lang_code: 'fr_BE',
|
||||
lang: 'fr_BE',
|
||||
name: 'foo,foo'
|
||||
}]
|
||||
},
|
||||
};
|
||||
|
||||
serverData = { models: this.data };
|
||||
@@ -3620,11 +3595,11 @@ QUnit.module('LegacyViews', {
|
||||
model: 'foo',
|
||||
data: this.data,
|
||||
mockRPC: function (route, args) {
|
||||
if (route === "/web/dataset/call_button" && args.method === 'translate_fields') {
|
||||
return Promise.resolve({
|
||||
domain: [],
|
||||
context: {search_default_name: 'foo,foo'},
|
||||
});
|
||||
if (route === "/web/dataset/call_kw/foo/get_field_translations") {
|
||||
return Promise.resolve([
|
||||
[{lang: "en_US", source: "yop", value: "yop"}, {lang: "fr_BE", source: "yop", value: "valeur français"}],
|
||||
{translation_type: "char", translation_show_source: false},
|
||||
]);
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/res.lang/get_installed") {
|
||||
return Promise.resolve([["en_US","English"], ["fr_BE", "Frenglish"]]);
|
||||
|
||||
@@ -123,21 +123,6 @@ QUnit.module("Fields", (hooks) => {
|
||||
},
|
||||
],
|
||||
},
|
||||
"ir.translation": {
|
||||
fields: {
|
||||
lang: { type: "char" },
|
||||
value: { type: "char" },
|
||||
res_id: { type: "integer" },
|
||||
},
|
||||
records: [
|
||||
{
|
||||
id: 99,
|
||||
res_id: 37,
|
||||
value: "",
|
||||
lang: "en_US",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -301,7 +286,7 @@ QUnit.module("Fields", (hooks) => {
|
||||
});
|
||||
|
||||
QUnit.test("char field translatable", async function (assert) {
|
||||
assert.expect(13);
|
||||
assert.expect(11);
|
||||
|
||||
serverData.models.partner.fields.foo.translate = true;
|
||||
serviceRegistry.add("localization", makeFakeLocalizationService({ multiLang: true }), {
|
||||
@@ -325,33 +310,25 @@ QUnit.module("Fields", (hooks) => {
|
||||
</sheet>
|
||||
</form>`,
|
||||
mockRPC(route, { args, method, model }) {
|
||||
if (route === "/web/dataset/call_button" && method === "translate_fields") {
|
||||
assert.deepEqual(
|
||||
args,
|
||||
["partner", 1, "foo"],
|
||||
'should call "call_button" route'
|
||||
);
|
||||
return Promise.resolve({
|
||||
domain: [],
|
||||
context: { search_default_name: "partnes,foo" },
|
||||
});
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/res.lang/get_installed") {
|
||||
return Promise.resolve([
|
||||
["en_US", "English"],
|
||||
["fr_BE", "French (Belgium)"],
|
||||
]);
|
||||
}
|
||||
if (method === "search_read" && model === "ir.translation") {
|
||||
if (route === "/web/dataset/call_kw/partner/get_field_translations") {
|
||||
return Promise.resolve([
|
||||
{ lang: "en_US", src: "yop", value: "yop", id: 42 },
|
||||
{ lang: "fr_BE", src: "yop", value: "valeur français", id: 43 },
|
||||
[
|
||||
{ lang: "en_US", source: "yop", value: "yop" },
|
||||
{ lang: "fr_BE", source: "yop", value: "valeur français" },
|
||||
],
|
||||
{ translation_type: "char", translation_show_source: false },
|
||||
]);
|
||||
}
|
||||
if (method === "write" && model === "ir.translation") {
|
||||
if (route === "/web/dataset/call_kw/partner/update_field_translations") {
|
||||
assert.deepEqual(
|
||||
args[1],
|
||||
{ value: "english value" },
|
||||
args[2],
|
||||
{ en_US: "english value" },
|
||||
"the new translation value should be written"
|
||||
);
|
||||
return Promise.resolve(null);
|
||||
@@ -417,7 +394,7 @@ QUnit.module("Fields", (hooks) => {
|
||||
});
|
||||
|
||||
QUnit.test("html field translatable", async function (assert) {
|
||||
assert.expect(6);
|
||||
assert.expect(5);
|
||||
|
||||
serverData.models.partner.fields.foo.translate = true;
|
||||
serviceRegistry.add("localization", makeFakeLocalizationService({ multiLang: true }), {
|
||||
@@ -441,55 +418,48 @@ QUnit.module("Fields", (hooks) => {
|
||||
</sheet>
|
||||
</form>`,
|
||||
mockRPC(route, { args, method, model }) {
|
||||
if (route === "/web/dataset/call_button" && method === "translate_fields") {
|
||||
assert.deepEqual(
|
||||
args,
|
||||
["partner", 1, "foo"],
|
||||
`should call "call_button" route`
|
||||
);
|
||||
return Promise.resolve({
|
||||
domain: [],
|
||||
context: {
|
||||
search_default_name: "partner,foo",
|
||||
translation_type: "char",
|
||||
translation_show_src: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/res.lang/get_installed") {
|
||||
return Promise.resolve([
|
||||
["en_US", "English"],
|
||||
["fr_BE", "French (Belgium)"],
|
||||
]);
|
||||
}
|
||||
if (method === "search_read" && model === "ir.translation") {
|
||||
if (route === "/web/dataset/call_kw/partner/get_field_translations") {
|
||||
return Promise.resolve([
|
||||
{ lang: "en_US", src: "first paragraph", value: "first paragraph", id: 42 },
|
||||
[
|
||||
{
|
||||
lang: "en_US",
|
||||
source: "first paragraph",
|
||||
value: "first paragraph",
|
||||
},
|
||||
{
|
||||
lang: "en_US",
|
||||
source: "second paragraph",
|
||||
value: "second paragraph",
|
||||
},
|
||||
{
|
||||
lang: "fr_BE",
|
||||
source: "first paragraph",
|
||||
value: "premier paragraphe",
|
||||
},
|
||||
{
|
||||
lang: "fr_BE",
|
||||
source: "second paragraph",
|
||||
value: "deuxième paragraphe",
|
||||
},
|
||||
],
|
||||
{
|
||||
lang: "en_US",
|
||||
src: "second paragraph",
|
||||
value: "second paragraph",
|
||||
id: 43,
|
||||
},
|
||||
{
|
||||
lang: "fr_BE",
|
||||
src: "first paragraph",
|
||||
value: "premier paragraphe",
|
||||
id: 44,
|
||||
},
|
||||
{
|
||||
lang: "fr_BE",
|
||||
src: "second paragraph",
|
||||
value: "deuxième paragraphe",
|
||||
id: 45,
|
||||
translation_type: "char",
|
||||
translation_show_source: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
if (method === "write" && model === "ir.translation") {
|
||||
|
||||
if (route === "/web/dataset/call_kw/partner/update_field_translations") {
|
||||
assert.deepEqual(
|
||||
args[1],
|
||||
{ value: "first paragraph modified" },
|
||||
"Wrong update on translation"
|
||||
args[2],
|
||||
{ en_US: { "first paragraph": "first paragraph modified" } },
|
||||
"the new translation value should be written"
|
||||
);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
@@ -49,21 +49,6 @@ QUnit.module("Fields", (hooks) => {
|
||||
},
|
||||
],
|
||||
},
|
||||
"ir.translation": {
|
||||
fields: {
|
||||
lang: { type: "char" },
|
||||
value: { type: "char" },
|
||||
res_id: { type: "integer" },
|
||||
},
|
||||
records: [
|
||||
{
|
||||
id: 99,
|
||||
res_id: 37,
|
||||
value: "",
|
||||
lang: "en_US",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -370,7 +355,7 @@ QUnit.module("Fields", (hooks) => {
|
||||
});
|
||||
|
||||
QUnit.test("text field translatable", async function (assert) {
|
||||
assert.expect(4);
|
||||
assert.expect(3);
|
||||
|
||||
serverData.models.partner.fields.txt.translate = true;
|
||||
serviceRegistry.add("localization", makeFakeLocalizationService({ multiLang: true }), {
|
||||
@@ -391,19 +376,20 @@ QUnit.module("Fields", (hooks) => {
|
||||
</sheet>
|
||||
</form>`,
|
||||
mockRPC(route, { args, method }) {
|
||||
if (route === "/web/dataset/call_button" && method === "translate_fields") {
|
||||
assert.deepEqual(
|
||||
args,
|
||||
["partner", 1, "txt"],
|
||||
`should call "call_button" route`
|
||||
);
|
||||
return Promise.resolve({
|
||||
domain: [],
|
||||
context: { search_default_name: "partnes,foo" },
|
||||
});
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/res.lang/get_installed") {
|
||||
return Promise.resolve([["en_US"], ["fr_BE"]]);
|
||||
return Promise.resolve([
|
||||
["en_US", "English"],
|
||||
["fr_BE", "French (Belgium)"],
|
||||
]);
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/partner/get_field_translations") {
|
||||
return Promise.resolve([
|
||||
[
|
||||
{ lang: "en_US", source: "yop", value: "yop" },
|
||||
{ lang: "fr_BE", source: "yop", value: "valeur français" },
|
||||
],
|
||||
{ translation_type: "text", translation_show_source: false },
|
||||
]);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -180,21 +180,6 @@ QUnit.module("Views", (hooks) => {
|
||||
{ id: 14, display_name: "silver", color: 5 },
|
||||
],
|
||||
},
|
||||
"ir.translation": {
|
||||
fields: {
|
||||
lang_code: { type: "char" },
|
||||
value: { type: "char" },
|
||||
res_id: { type: "integer" },
|
||||
},
|
||||
records: [
|
||||
{
|
||||
id: 99,
|
||||
res_id: 12,
|
||||
value: "",
|
||||
lang_code: "en_US",
|
||||
},
|
||||
],
|
||||
},
|
||||
user: {
|
||||
fields: {
|
||||
name: { string: "Name", type: "char" },
|
||||
@@ -8466,20 +8451,16 @@ QUnit.module("Views", (hooks) => {
|
||||
["CUST2", "second custom"],
|
||||
];
|
||||
}
|
||||
if (args.method === "translate_fields") {
|
||||
if (route === "/web/dataset/call_kw/partner/get_field_translations") {
|
||||
assert.step(`translate args ${JSON.stringify(args.args)}`);
|
||||
assert.step(`translate context ${JSON.stringify(args.kwargs.context)}`);
|
||||
return {
|
||||
domain: [["res_id", "=", args.args[1]]],
|
||||
context: { search_default_name: "partner_type,foo" },
|
||||
};
|
||||
}
|
||||
if (args.method === "search_read" && args.model === "ir.translation") {
|
||||
assert.step(
|
||||
`search_read translations args: ${JSON.stringify(
|
||||
args.args
|
||||
)} ; kwargs: ${JSON.stringify(args.kwargs)}`
|
||||
);
|
||||
return Promise.resolve([
|
||||
[
|
||||
{ lang: "CUST", source: "yop", value: "yop" },
|
||||
{ lang: "CUST2", source: "yop", value: "valeur français" },
|
||||
],
|
||||
{ translation_type: "char", translation_show_source: false },
|
||||
]);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -8487,9 +8468,8 @@ QUnit.module("Views", (hooks) => {
|
||||
|
||||
await click(target, ".o_field_translate.btn-link");
|
||||
assert.verifySteps([
|
||||
`translate args ["partner",1,"foo"]`,
|
||||
`translate args [[1],"foo"]`,
|
||||
`translate context {"lang":"en","uid":7,"tz":"taht"}`,
|
||||
`search_read translations args: [] ; kwargs: {"domain":[["res_id","=",1],["name","=","partner_type,foo"],["lang","in",["CUST","CUST2"]]],"fields":["lang","src","value"],"context":{"lang":"en","uid":7,"tz":"taht"}}`,
|
||||
]);
|
||||
|
||||
assert.containsOnce(target, ".modal");
|
||||
@@ -8522,6 +8502,15 @@ QUnit.module("Views", (hooks) => {
|
||||
["CUST2", "second custom"],
|
||||
];
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/partner/get_field_translations") {
|
||||
return Promise.resolve([
|
||||
[
|
||||
{ lang: "CUST", source: "yop", value: "yop" },
|
||||
{ lang: "CUST2", source: "yop", value: "valeur français" },
|
||||
],
|
||||
{ translation_type: "char", translation_show_source: false },
|
||||
]);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -8536,7 +8525,7 @@ QUnit.module("Views", (hooks) => {
|
||||
|
||||
await click(target, ".o_field_translate.btn-link");
|
||||
await click(target.querySelectorAll(".modal-footer button")[0]); // save
|
||||
assert.verifySteps(["create", "read", "translate_fields", "get_installed", "search_read"]);
|
||||
assert.verifySteps(["create", "read", "get_installed", "get_field_translations"]);
|
||||
assert.containsOnce(target, ".modal");
|
||||
assert.strictEqual(target.querySelector(".modal-title").textContent, "Translate: foo");
|
||||
});
|
||||
@@ -8583,12 +8572,21 @@ QUnit.module("Views", (hooks) => {
|
||||
["CUST2", "second custom"],
|
||||
];
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/partner/get_field_translations") {
|
||||
return Promise.resolve([
|
||||
[
|
||||
{ lang: "CUST", source: "yop", value: "yop" },
|
||||
{ lang: "CUST2", source: "yop", value: "valeur français" },
|
||||
],
|
||||
{ translation_type: "char", translation_show_source: false },
|
||||
]);
|
||||
}
|
||||
},
|
||||
});
|
||||
assert.verifySteps(["get_views", "read"]);
|
||||
await clickEdit(target);
|
||||
await click(target, ".o_field_legacy_char .o_field_translate.btn-link");
|
||||
assert.verifySteps(["translate_fields", "get_installed", "search_read"]);
|
||||
assert.verifySteps(["get_installed", "get_field_translations"]);
|
||||
assert.containsOnce(target, ".modal");
|
||||
assert.strictEqual(target.querySelector(".modal-title").textContent, "Translate: foo");
|
||||
});
|
||||
@@ -8644,22 +8642,11 @@ QUnit.module("Views", (hooks) => {
|
||||
});
|
||||
|
||||
QUnit.test("translation alerts preserved on reverse breadcrumb", async function (assert) {
|
||||
serverData.models["ir.translation"] = {
|
||||
fields: {
|
||||
name: { string: "name", type: "char" },
|
||||
source: { string: "Source", type: "char" },
|
||||
value: { string: "Value", type: "char" },
|
||||
},
|
||||
records: [],
|
||||
};
|
||||
|
||||
serverData.models.partner.fields.foo.translate = true;
|
||||
|
||||
serverData.views = {
|
||||
"partner,false,form": `<form><sheet><field name="foo"/></sheet></form>`,
|
||||
"partner,false,search": "<search></search>",
|
||||
"ir.translation,false,list": `<tree><field name="name"/><field name="source"/><field name="value"/></tree>`,
|
||||
"ir.translation,false,search": "<search></search>",
|
||||
};
|
||||
|
||||
serverData.actions = {
|
||||
@@ -8670,15 +8657,6 @@ QUnit.module("Views", (hooks) => {
|
||||
type: "ir.actions.act_window",
|
||||
views: [[false, "form"]],
|
||||
},
|
||||
2: {
|
||||
id: 2,
|
||||
name: "Translate",
|
||||
res_model: "ir.translation",
|
||||
type: "ir.actions.act_window",
|
||||
views: [[false, "list"]],
|
||||
target: "current",
|
||||
flags: { search_view: true, action_buttons: true },
|
||||
},
|
||||
};
|
||||
|
||||
const webClient = await createWebClient({ serverData });
|
||||
@@ -8692,17 +8670,12 @@ QUnit.module("Views", (hooks) => {
|
||||
await clickSave(target);
|
||||
|
||||
assert.containsOnce(target, ".alert .o_field_translate", "should have a translation alert");
|
||||
|
||||
await doAction(webClient, 2);
|
||||
|
||||
await click(target.querySelector(".o_control_panel .breadcrumb a:nth-child(1)"));
|
||||
assert.containsOnce(target, ".alert .o_field_translate", "should have a translation alert");
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"translate event correctly handled with multiple controllers",
|
||||
async function (assert) {
|
||||
assert.expect(3);
|
||||
assert.expect(2);
|
||||
|
||||
serverData.models.product.fields.name.translate = true;
|
||||
serverData.models.partner.records[0].product_id = 37;
|
||||
@@ -8742,23 +8715,21 @@ QUnit.module("Views", (hooks) => {
|
||||
if (route === "/web/dataset/call_kw/product/get_formview_id") {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
route === "/web/dataset/call_button" &&
|
||||
args.method === "translate_fields"
|
||||
) {
|
||||
assert.deepEqual(
|
||||
args.args,
|
||||
["product", 37, "name"],
|
||||
'should call "call_button" route'
|
||||
);
|
||||
nbTranslateCalls++;
|
||||
return {
|
||||
domain: [],
|
||||
context: { search_default_name: "partnes,foo" },
|
||||
};
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/res.lang/get_installed") {
|
||||
return [["en_US"], ["fr_BE"]];
|
||||
return [
|
||||
["en_US", "English"],
|
||||
["fr_BE", "French (Belgium)"],
|
||||
];
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/product/get_field_translations") {
|
||||
nbTranslateCalls++;
|
||||
return Promise.resolve([
|
||||
[
|
||||
{ lang: "en_US", source: "yop", value: "yop" },
|
||||
{ lang: "fr_BE", source: "yop", value: "valeur français" },
|
||||
],
|
||||
{ translation_type: "char", translation_show_source: false },
|
||||
]);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -197,34 +197,6 @@ QUnit.module("Views", (hooks) => {
|
||||
},
|
||||
records: [{ id: "2-20170808020000", name: "virtual" }],
|
||||
},
|
||||
"ir.translation": {
|
||||
fields: {
|
||||
lang_code: { type: "char" },
|
||||
src: { type: "char" },
|
||||
value: { type: "char" },
|
||||
res_id: { type: "integer" },
|
||||
name: { type: "char" },
|
||||
lang: { type: "char" },
|
||||
},
|
||||
records: [
|
||||
{
|
||||
id: 99,
|
||||
res_id: 1,
|
||||
value: "",
|
||||
lang_code: "en_US",
|
||||
lang: "en_US",
|
||||
name: "foo,foo",
|
||||
},
|
||||
{
|
||||
id: 100,
|
||||
res_id: 1,
|
||||
value: "",
|
||||
lang_code: "fr_BE",
|
||||
lang: "fr_BE",
|
||||
name: "foo,foo",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
setupViewRegistries();
|
||||
@@ -4096,18 +4068,21 @@ QUnit.module("Views", (hooks) => {
|
||||
resModel: "foo",
|
||||
serverData,
|
||||
mockRPC(route, args) {
|
||||
if (route === "/web/dataset/call_button" && args.method === "translate_fields") {
|
||||
return Promise.resolve({
|
||||
domain: [],
|
||||
context: { search_default_name: "foo,foo" },
|
||||
});
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/res.lang/get_installed") {
|
||||
return Promise.resolve([
|
||||
["en_US", "English"],
|
||||
["fr_BE", "Frenglish"],
|
||||
]);
|
||||
}
|
||||
if (route === "/web/dataset/call_kw/foo/get_field_translations") {
|
||||
return Promise.resolve([
|
||||
[
|
||||
{ lang: "en_US", source: "yop", value: "yop" },
|
||||
{ lang: "fr_BE", source: "yop", value: "valeur français" },
|
||||
],
|
||||
{ translation_type: "char", translation_show_source: false },
|
||||
]);
|
||||
}
|
||||
},
|
||||
arch: '<tree editable="top">' + '<field name="foo" required="1"/>' + "</tree>",
|
||||
});
|
||||
|
||||
@@ -5,7 +5,6 @@ from . import ir_attachment
|
||||
from . import ir_qweb_fields
|
||||
from . import ir_ui_view
|
||||
from . import ir_http
|
||||
from . import ir_translation
|
||||
from . import ir_websocket
|
||||
from . import models
|
||||
|
||||
|
||||
@@ -155,10 +155,13 @@ class Field(models.AbstractModel):
|
||||
attrs['placeholder'] = placeholder
|
||||
|
||||
if options['translate'] and field.type in ('char', 'text'):
|
||||
name = "%s,%s" % (record._name, field_name)
|
||||
domain = [('name', '=', name), ('res_id', '=', record.id), ('type', '=', 'model'), ('lang', '=', options.get('lang'))]
|
||||
translation = record.env['ir.translation'].search(domain, limit=1)
|
||||
attrs['data-oe-translation-state'] = translation and translation.state or 'to_translate'
|
||||
lang = record.env.lang or 'en_US'
|
||||
if lang == 'en_US':
|
||||
attrs['data-oe-translation-state'] = 'translated'
|
||||
else:
|
||||
value_en = record.with_context(lang='en_US')[field_name]
|
||||
value_lang = record.with_context(lang=lang)[field_name]
|
||||
attrs['data-oe-translation-state'] = 'translated' if value_en != value_lang else 'to_translate'
|
||||
|
||||
return attrs
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from odoo import models, api
|
||||
from odoo.tools.translate import encode, xml_translate, html_translate
|
||||
|
||||
|
||||
def edit_translation_mapping(data):
|
||||
data = dict(data, model=data['name'].partition(',')[0], value=data['value'] or data['src'])
|
||||
return '<span data-oe-model="%(model)s" data-oe-translation-id="%(id)s" data-oe-translation-state="%(state)s">%(value)s</span>' % data
|
||||
|
||||
|
||||
class IrTranslation(models.Model):
|
||||
_inherit = 'ir.translation'
|
||||
|
||||
@api.model
|
||||
def _get_terms_mapping(self, field, records):
|
||||
if self._context.get('edit_translations'):
|
||||
self.insert_missing(field, records)
|
||||
return edit_translation_mapping
|
||||
return super(IrTranslation, self)._get_terms_mapping(field, records)
|
||||
|
||||
def save_html(self, value):
|
||||
""" Convert the HTML fragment ``value`` to XML if necessary, and write
|
||||
it as the value of translation ``self``.
|
||||
"""
|
||||
assert len(self) == 1 and self.type == 'model_terms'
|
||||
mname, fname = self.name.split(',')
|
||||
field = self.env[mname]._fields[fname]
|
||||
if field.translate == xml_translate:
|
||||
# wrap value inside a div and parse it as HTML
|
||||
div = "<div>%s</div>" % encode(value)
|
||||
root = etree.fromstring(div, etree.HTMLParser(encoding='utf-8'))
|
||||
# root is html > body > div
|
||||
# serialize div as XML and discard surrounding tags
|
||||
value = etree.tostring(root[0][0], encoding='utf-8')[5:-6]
|
||||
elif field.translate == html_translate:
|
||||
# wrap value inside a div and parse it as HTML
|
||||
div = "<div>%s</div>" % encode(value)
|
||||
root = etree.fromstring(div, etree.HTMLParser(encoding='utf-8'))
|
||||
# root is html > body > div
|
||||
# serialize div as HTML and discard surrounding tags
|
||||
value = etree.tostring(root[0][0], encoding='utf-8', method='html')[5:-6]
|
||||
return self.write({'value': value})
|
||||
@@ -1,5 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from hashlib import sha256
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
@@ -12,3 +14,10 @@ class Base(models.AbstractModel):
|
||||
keys.append('sanitize')
|
||||
keys.append('sanitize_tags')
|
||||
return keys
|
||||
|
||||
|
||||
class BaseModel(models.AbstractModel):
|
||||
_inherit = 'base'
|
||||
|
||||
def update_field_translations_sha(self, fname, translations):
|
||||
return self._update_field_translations(fname, translations, lambda old_term: sha256(old_term.encode()).hexdigest())
|
||||
|
||||
@@ -3818,8 +3818,8 @@ var SnippetsMenu = Widget.extend({
|
||||
}
|
||||
if (!range ||
|
||||
!$currentSelectionTarget.parents('#wrapwrap, .iframe-editor-wrapper .o_editable').length ||
|
||||
$(selection.anchorNode).parent('[data-oe-model]:not([data-oe-type="html"]):not([data-oe-field="arch"]):not([data-oe-translation-id])').length ||
|
||||
$(selection.focusNode).parent('[data-oe-model]:not([data-oe-type="html"]):not([data-oe-field="arch"]):not([data-oe-translation-id])').length ||
|
||||
$(selection.anchorNode).parent('[data-oe-model]:not([data-oe-type="html"]):not([data-oe-field="arch"]):not([data-oe-translation-initial-sha])').length ||
|
||||
$(selection.focusNode).parent('[data-oe-model]:not([data-oe-type="html"]):not([data-oe-field="arch"]):not([data-oe-translation-initial-sha])').length ||
|
||||
(e && $(e.target).closest('.fa, img').length ||
|
||||
this.options.wysiwyg.lastMediaClicked && $(this.options.wysiwyg.lastMediaClicked).is('.fa, img')) ||
|
||||
(this.options.wysiwyg.lastElement && !this.options.wysiwyg.lastElement.isContentEditable)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user