From 82ca092bd1e047f6b636e60d5e2e28759c344d48 Mon Sep 17 00:00:00 2001 From: "Nasreddin (bon)" Date: Wed, 6 Jan 2021 16:17:24 +0000 Subject: [PATCH] [FIX] misc: Babel; handle 'kur' (kurdish) locale Issue - add a new language with locale code KUR (for Kurdish) - print any report with a datetime on it (RFQ for example) Cause Babel (version < 2.7.0) does not handle locale "KUR". Solution If wrong locale or not managed by Babel, try to fallback on server default locale. If still wrong locale or not managed, then fallback on "en_US" as locale. opw-2416482 closes odoo/odoo#64304 X-original-commit: e6ccdb397792db62c3b08d96435b3c1667c1aa9d Signed-off-by: Nicolas Lempereur (nle) Signed-off-by: bon-odoo --- addons/web_editor/models/ir_qweb.py | 6 +++--- .../controllers/event_track.py | 3 ++- odoo/addons/base/models/ir_qweb_fields.py | 8 ++++---- odoo/tools/misc.py | 19 +++++++++++++------ 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/addons/web_editor/models/ir_qweb.py b/addons/web_editor/models/ir_qweb.py index 7bd21dff430..0dc6db13315 100644 --- a/addons/web_editor/models/ir_qweb.py +++ b/addons/web_editor/models/ir_qweb.py @@ -32,7 +32,7 @@ import odoo.modules from odoo import api, models, fields from odoo.tools import ustr, posix_to_ldml, pycompat from odoo.tools import html_escape as escape -from odoo.tools.misc import get_lang +from odoo.tools.misc import get_lang, babel_locale_parse from odoo.addons.base.models import ir_qweb REMOTE_CONNECTION_TIMEOUT = 2.5 @@ -248,7 +248,7 @@ class Date(models.AbstractModel): return attrs lg = self.env['res.lang']._lang_get(self.env.user.lang) or get_lang(self.env) - locale = babel.Locale.parse(lg.code) + locale = babel_locale_parse(lg.code) babel_format = value_format = posix_to_ldml(lg.date_format, locale=locale) if record[field_name]: @@ -282,7 +282,7 @@ class DateTime(models.AbstractModel): value = record[field_name] lg = self.env['res.lang']._lang_get(self.env.user.lang) or get_lang(self.env) - locale = babel.Locale.parse(lg.code) + locale = babel_locale_parse(lg.code) babel_format = value_format = posix_to_ldml('%s %s' % (lg.date_format, lg.time_format), locale=locale) tz = record.env.context.get('tz') or self.env.user.tz diff --git a/addons/website_event_track/controllers/event_track.py b/addons/website_event_track/controllers/event_track.py index 782b1e839ee..290521a771c 100644 --- a/addons/website_event_track/controllers/event_track.py +++ b/addons/website_event_track/controllers/event_track.py @@ -15,6 +15,7 @@ from odoo import exceptions, http, fields, _ from odoo.http import request from odoo.osv import expression from odoo.tools import is_html_empty, plaintext2html +from odoo.tools.misc import babel_locale_parse class EventTrackController(http.Controller): @@ -255,7 +256,7 @@ class EventTrackController(http.Controller): :param dt_time: datetime object :param lang_code: language code (eg. en_US) """ - locale = babel.Locale.parse(lang_code) + locale = babel_locale_parse(lang_code) return babel.dates.format_time(dt_time, format='short', locale=locale) def time_slot_rounder(self, time, rounded_minutes): diff --git a/odoo/addons/base/models/ir_qweb_fields.py b/odoo/addons/base/models/ir_qweb_fields.py index 0f9cd701ac5..653533ebf1e 100644 --- a/odoo/addons/base/models/ir_qweb_fields.py +++ b/odoo/addons/base/models/ir_qweb_fields.py @@ -11,7 +11,7 @@ from lxml import etree import math from odoo.tools import html_escape as escape, posix_to_ldml, float_utils, format_date, format_duration, pycompat -from odoo.tools.misc import get_lang +from odoo.tools.misc import get_lang, babel_locale_parse import logging _logger = logging.getLogger(__name__) @@ -236,7 +236,7 @@ class DateTimeConverter(models.AbstractModel): options = options or {} lang = self.user_lang() - locale = babel.Locale.parse(lang.code) + locale = babel_locale_parse(lang.code) format_func = babel.dates.format_datetime if isinstance(value, str): value = fields.Datetime.from_string(value) @@ -559,7 +559,7 @@ class DurationConverter(models.AbstractModel): def value_to_html(self, value, options): units = {unit: duration for unit, label, duration in TIMEDELTA_UNITS} - locale = babel.Locale.parse(self.user_lang().code) + locale = babel_locale_parse(self.user_lang().code) factor = units[options.get('unit', 'second')] round_to = units[options.get('round', 'second')] @@ -617,7 +617,7 @@ class RelativeDatetimeConverter(models.AbstractModel): @api.model def value_to_html(self, value, options): - locale = babel.Locale.parse(self.user_lang().code) + locale = babel_locale_parse(self.user_lang().code) if isinstance(value, str): value = fields.Datetime.from_string(value) diff --git a/odoo/tools/misc.py b/odoo/tools/misc.py index 1017d3e0633..8aa037d0877 100644 --- a/odoo/tools/misc.py +++ b/odoo/tools/misc.py @@ -1229,7 +1229,6 @@ else: def html_escape(text): return werkzeug.utils.escape(text) - def get_lang(env, lang_code=False): """ Retrieve the first lang object installed, by checking the parameter lang_code, @@ -1248,6 +1247,14 @@ def get_lang(env, lang_code=False): lang = env.user.company_id.partner_id.lang return env['res.lang']._lang_get(lang) +def babel_locale_parse(lang_code): + try: + return babel.Locale.parse(lang_code) + except: + try: + return babel.Locale.default() + except: + return babel.Locale.parse("en_US") def formatLang(env, value, digits=None, grouping=True, monetary=False, dp=False, currency_obj=False): """ @@ -1307,7 +1314,7 @@ def format_date(env, value, lang_code=False, date_format=False): value = odoo.fields.Datetime.from_string(value) lang = get_lang(env, lang_code) - locale = babel.Locale.parse(lang.code) + locale = babel_locale_parse(lang.code) if not date_format: date_format = posix_to_ldml(lang.date_format, locale=locale) @@ -1326,7 +1333,7 @@ def parse_date(env, value, lang_code=False): :rtype: datetime.date ''' lang = get_lang(env, lang_code) - locale = babel.Locale.parse(lang.code) + locale = babel_locale_parse(lang.code) try: return babel.dates.parse_date(value, locale=locale) except: @@ -1358,7 +1365,7 @@ def format_datetime(env, value, tz=False, dt_format='medium', lang_code=False): lang = get_lang(env, lang_code) - locale = babel.Locale.parse(lang.code or lang_code) # lang can be inactive, so `lang`is empty + locale = babel_locale_parse(lang.code or lang_code) # lang can be inactive, so `lang`is empty if not dt_format: date_format = posix_to_ldml(lang.date_format, locale=locale) time_format = posix_to_ldml(lang.time_format, locale=locale) @@ -1387,7 +1394,7 @@ def format_time(env, value, tz=False, time_format='medium', lang_code=False): return '' lang = get_lang(env, lang_code) - locale = babel.Locale.parse(lang.code) + locale = babel_locale_parse(lang.code) if not time_format: time_format = posix_to_ldml(lang.time_format, locale=locale) @@ -1398,7 +1405,7 @@ def _format_time_ago(env, time_delta, lang_code=False, add_direction=True): if not lang_code: langs = [code for code, _ in env['res.lang'].get_installed()] lang_code = env.context['lang'] if env.context.get('lang') in langs else (env.user.company_id.partner_id.lang or langs[0]) - locale = babel.Locale.parse(lang_code) + locale = babel_locale_parse(lang_code) return babel.dates.format_timedelta(-time_delta, add_direction=add_direction, locale=locale)