[FIX] *: remove en_US as fallback for lang code
en_US may not be activated as it is possible to create a database in another language using the database manager. When trying to install a chart of account, the tax return entry tried to format a date at the installation of the module, with no lang in the context. The fallback was made on en_US but an error is raised if that language is not activated. As it is a very common scenario to retrieve a language from the context, add a generic tool method to do it. Replace and closes odoo/odoo#37629 closes odoo/odoo#37568 Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
This commit is contained in:
@@ -6,7 +6,7 @@ from odoo import models, api, _, fields
|
||||
from odoo.osv import expression
|
||||
from odoo.release import version
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF, safe_eval
|
||||
from odoo.tools.misc import formatLang, format_date as odoo_format_date
|
||||
from odoo.tools.misc import formatLang, format_date as odoo_format_date, get_lang
|
||||
import random
|
||||
|
||||
import ast
|
||||
@@ -90,7 +90,7 @@ class account_journal(models.Model):
|
||||
data = []
|
||||
today = datetime.today()
|
||||
last_month = today + timedelta(days=-30)
|
||||
locale = self._context.get('lang') or 'en_US'
|
||||
locale = get_lang(self.env).code
|
||||
|
||||
#starting point of the graph is the last statement
|
||||
last_stmt = BankStatement.search([('journal_id', '=', self.id), ('date', '<=', today.strftime(DF))], order='date desc, id desc', limit=1)
|
||||
@@ -139,7 +139,7 @@ class account_journal(models.Model):
|
||||
data = []
|
||||
today = fields.Datetime.now(self)
|
||||
data.append({'label': _('Due'), 'value':0.0, 'type': 'past'})
|
||||
day_of_week = int(format_datetime(today, 'e', locale=self._context.get('lang') or 'en_US'))
|
||||
day_of_week = int(format_datetime(today, 'e', locale=get_lang(self.env).code))
|
||||
first_day_of_week = today + timedelta(days=-day_of_week+1)
|
||||
for i in range(-1,4):
|
||||
if i==0:
|
||||
@@ -150,9 +150,9 @@ class account_journal(models.Model):
|
||||
start_week = first_day_of_week + timedelta(days=i*7)
|
||||
end_week = start_week + timedelta(days=6)
|
||||
if start_week.month == end_week.month:
|
||||
label = str(start_week.day) + '-' +str(end_week.day)+ ' ' + format_date(end_week, 'MMM', locale=self._context.get('lang') or 'en_US')
|
||||
label = str(start_week.day) + '-' + str(end_week.day) + ' ' + format_date(end_week, 'MMM', locale=get_lang(self.env).code)
|
||||
else:
|
||||
label = format_date(start_week, 'd MMM', locale=self._context.get('lang') or 'en_US')+'-'+format_date(end_week, 'd MMM', locale=self._context.get('lang') or 'en_US')
|
||||
label = format_date(start_week, 'd MMM', locale=get_lang(self.env).code) + '-' + format_date(end_week, 'd MMM', locale=get_lang(self.env).code)
|
||||
data.append({'label':label,'value':0.0, 'type': 'past' if i<0 else 'future'})
|
||||
|
||||
# Build SQL query to find amount aggregated by week
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.addons.mail.wizard.mail_compose_message import _reopen
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
|
||||
class AccountInvoiceSend(models.TransientModel):
|
||||
@@ -103,7 +104,7 @@ class AccountInvoiceSend(models.TransientModel):
|
||||
active_ids = self.env.context.get('active_ids', self.res_id)
|
||||
active_records = self.env[self.model].browse(active_ids)
|
||||
langs = active_records.mapped('partner_id.lang')
|
||||
default_lang = self.env.context.get('lang', 'en_US')
|
||||
default_lang = get_lang(self.env)
|
||||
for lang in (set(langs) or [default_lang]):
|
||||
active_ids_lang = active_records.filtered(lambda r: r.partner_id.lang == lang).ids
|
||||
self_lang = self.with_context(active_ids=active_ids_lang, lang=lang)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
|
||||
class AccountCommonReport(models.TransientModel):
|
||||
@@ -43,5 +44,5 @@ class AccountCommonReport(models.TransientModel):
|
||||
data['model'] = self.env.context.get('active_model', 'ir.ui.menu')
|
||||
data['form'] = self.read(['date_from', 'date_to', 'journal_ids', 'target_move', 'company_id'])[0]
|
||||
used_context = self._build_contexts(data)
|
||||
data['form']['used_context'] = dict(used_context, lang=self.env.context.get('lang') or 'en_US')
|
||||
data['form']['used_context'] = dict(used_context, lang=get_lang(self.env).code)
|
||||
return self.with_context(discard_logo_check=True)._print_report(data)
|
||||
|
||||
@@ -8,6 +8,7 @@ import uuid
|
||||
|
||||
from odoo import api, fields, models, tools, _
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -31,9 +32,7 @@ class BaseGengoTranslations(models.TransientModel):
|
||||
res = super(BaseGengoTranslations, self).default_get(fields)
|
||||
res['authorized_credentials'], gengo = self.gengo_authentication()
|
||||
if 'lang_id' in fields:
|
||||
res['lang_id'] = self.env['res.lang']._lang_get_id(
|
||||
self.env.context.get('lang') or 'en_US'
|
||||
)
|
||||
res['lang_id'] = get_lang(self.env).id
|
||||
return res
|
||||
|
||||
sync_type = fields.Selection([
|
||||
|
||||
@@ -9,6 +9,7 @@ import odoo.http as http
|
||||
from odoo.http import request
|
||||
from odoo import SUPERUSER_ID
|
||||
from odoo import registry as registry_get
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
|
||||
class CalendarController(http.Controller):
|
||||
@@ -43,7 +44,7 @@ class CalendarController(http.Controller):
|
||||
if not attendee:
|
||||
return request.not_found()
|
||||
timezone = attendee.partner_id.tz
|
||||
lang = attendee.partner_id.lang or 'en_US'
|
||||
lang = attendee.partner_id.lang or get_lang(request.env).code
|
||||
event = env['calendar.event'].with_context(tz=timezone, lang=lang).browse(int(id))
|
||||
|
||||
# If user is internal and logged, redirect to form view of event
|
||||
|
||||
@@ -20,6 +20,7 @@ from odoo import tools
|
||||
from odoo.addons.base.models.res_partner import _tz_get
|
||||
from odoo.osv import expression
|
||||
from odoo.tools.translate import _
|
||||
from odoo.tools.misc import get_lang
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT, pycompat
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
|
||||
@@ -1352,11 +1353,11 @@ class Meeting(models.Model):
|
||||
|
||||
elif interval == 'month':
|
||||
# Localized month name and year
|
||||
result = babel.dates.format_date(date=date, format='MMMM y', locale=self._context.get('lang') or 'en_US')
|
||||
result = babel.dates.format_date(date=date, format='MMMM y', locale=get_lang(self.env).code)
|
||||
|
||||
elif interval == 'dayname':
|
||||
# Localized day name
|
||||
result = babel.dates.format_date(date=date, format='EEEE', locale=self._context.get('lang') or 'en_US')
|
||||
result = babel.dates.format_date(date=date, format='EEEE', locale=get_lang(self.env).code)
|
||||
|
||||
elif interval == 'time':
|
||||
# Localized time
|
||||
|
||||
@@ -5,6 +5,7 @@ from itertools import chain
|
||||
|
||||
from odoo import api, fields, models, tools, _
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
|
||||
class Pricelist(models.Model):
|
||||
@@ -40,7 +41,7 @@ class Pricelist(models.Model):
|
||||
if name and operator == '=' and not args:
|
||||
# search on the name of the pricelist and its currency, opposite of name_get(),
|
||||
# Used by the magic context filter in the product search view.
|
||||
query_args = {'name': name, 'limit': limit, 'lang': self._context.get('lang') or 'en_US'}
|
||||
query_args = {'name': name, 'limit': limit, 'lang': get_lang(self.env).code}
|
||||
query = """SELECT p.id
|
||||
FROM ((
|
||||
SELECT pr.id, pr.name
|
||||
|
||||
@@ -6,6 +6,7 @@ import werkzeug
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
from odoo.tools.translate import _
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
|
||||
class Rating(http.Controller):
|
||||
@@ -22,7 +23,7 @@ class Rating(http.Controller):
|
||||
10: _("satisfied")
|
||||
}
|
||||
rating.write({'rating': rate, 'consumed': True})
|
||||
lang = rating.partner_id.lang or 'en_US'
|
||||
lang = rating.partner_id.lang or get_lang(request.env).code
|
||||
return request.env['ir.ui.view'].with_context(lang=lang).render_template('rating.rating_external_page_submit', {
|
||||
'rating': rating, 'token': token,
|
||||
'rate_name': rate_names[rate], 'rate': rate
|
||||
@@ -35,7 +36,7 @@ class Rating(http.Controller):
|
||||
return request.not_found()
|
||||
record_sudo = request.env[rating.res_model].sudo().browse(rating.res_id)
|
||||
record_sudo.rating_apply(rate, token=token, feedback=kwargs.get('feedback'))
|
||||
lang = rating.partner_id.lang or 'en_US'
|
||||
lang = rating.partner_id.lang or get_lang(request.env).code
|
||||
return request.env['ir.ui.view'].with_context(lang=lang).render_template('rating.rating_external_page_view', {
|
||||
'web_base_url': request.env['ir.config_parameter'].sudo().get_param('web.base.url'),
|
||||
'rating': rating,
|
||||
|
||||
@@ -6,6 +6,7 @@ import json
|
||||
|
||||
from odoo import fields, _, models
|
||||
from odoo.tools import float_round
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
from odoo.addons.web.controllers.main import clean_action
|
||||
|
||||
@@ -256,7 +257,7 @@ class Project(models.Model):
|
||||
|
||||
def _to_short_month_name(date):
|
||||
month_index = fields.Date.from_string(date).month
|
||||
return babel.dates.get_month_names('abbreviated', locale=self.env.context.get('lang', 'en_US'))[month_index]
|
||||
return babel.dates.get_month_names('abbreviated', locale=get_lang(self.env).code)[month_index]
|
||||
|
||||
header_names = [_('Name'), _('Before')] + [_to_short_month_name(date) for date in ts_months] + [_('Total'), _('Sold'), _('Remaining')]
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import pytz
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.osv.expression import AND
|
||||
from odoo.tools import lazy
|
||||
from odoo.tools.misc import get_lang
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
@@ -142,7 +143,7 @@ class Base(models.AbstractModel):
|
||||
|
||||
# Again, imitating what _read_group_format_result and _read_group_prepare_data do
|
||||
if group_by_value and field_type in ['date', 'datetime']:
|
||||
locale = self._context.get('lang') or 'en_US'
|
||||
locale = get_lang(self.env).code
|
||||
group_by_value = fields.Datetime.to_datetime(group_by_value)
|
||||
group_by_value = pytz.timezone('UTC').localize(group_by_value)
|
||||
tz_info = None
|
||||
|
||||
@@ -13,6 +13,7 @@ from odoo.addons.http_routing.models.ir_http import slug, unslug
|
||||
from odoo.addons.website.controllers.main import QueryURL
|
||||
from odoo.http import request
|
||||
from odoo.tools import html2plaintext
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
|
||||
class WebsiteBlog(http.Controller):
|
||||
@@ -43,7 +44,7 @@ class WebsiteBlog(http.Controller):
|
||||
group['date_begin'] = start
|
||||
group['date_end'] = end
|
||||
|
||||
locale = request.context.get('lang') or 'en_US'
|
||||
locale = get_lang(request.env).code
|
||||
start = pytz.UTC.localize(fields.Datetime.from_string(start))
|
||||
tzinfo = pytz.timezone(request.context.get('tz', 'utc') or 'utc')
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ from odoo import fields, http, _
|
||||
from odoo.addons.http_routing.models.ir_http import slug
|
||||
from odoo.addons.website.controllers.main import QueryURL
|
||||
from odoo.http import request
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
|
||||
class WebsiteEventController(http.Controller):
|
||||
@@ -229,7 +230,7 @@ class WebsiteEventController(http.Controller):
|
||||
def get_formated_date(self, event):
|
||||
start_date = fields.Datetime.from_string(event.date_begin).date()
|
||||
end_date = fields.Datetime.from_string(event.date_end).date()
|
||||
month = babel.dates.get_month_names('abbreviated', locale=event.env.context.get('lang') or 'en_US')[start_date.month]
|
||||
month = babel.dates.get_month_names('abbreviated', locale=get_lang(event.env).code)[start_date.month]
|
||||
return ('%s %s%s') % (month, start_date.strftime("%e"), (end_date != start_date and ("-" + end_date.strftime("%e")) or ""))
|
||||
|
||||
@http.route('/event/get_country_event_list', type='json', auth='public', website=True)
|
||||
|
||||
@@ -7,6 +7,7 @@ from datetime import datetime, timedelta, time
|
||||
from odoo import fields, http, _
|
||||
from odoo.addons.website.controllers.backend import WebsiteBackend
|
||||
from odoo.http import request
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
|
||||
class WebsiteSaleBackend(WebsiteBackend):
|
||||
@@ -175,7 +176,7 @@ class WebsiteSaleBackend(WebsiteBackend):
|
||||
sales_graph = [{
|
||||
'0': fields.Date.to_string(d) if not previous else fields.Date.to_string(d + timedelta(days=days_between)),
|
||||
# Respect read_group format in models.py
|
||||
'1': daily_sales_dict.get(babel.dates.format_date(d, format='dd MMM yyyy', locale=request.env.context.get('lang') or 'en_US'), 0)
|
||||
'1': daily_sales_dict.get(babel.dates.format_date(d, format='dd MMM yyyy', locale=get_lang(request.env).code), 0)
|
||||
} for d in date_list]
|
||||
|
||||
return sales_graph
|
||||
|
||||
@@ -13,6 +13,7 @@ from werkzeug import urls
|
||||
|
||||
from odoo import api, models, tools
|
||||
from odoo.tools.safe_eval import assert_valid_codeobj, _BUILTINS, _SAFE_OPCODES
|
||||
from odoo.tools.misc import get_lang
|
||||
from odoo.http import request
|
||||
from odoo.modules.module import get_resource_path
|
||||
|
||||
@@ -112,7 +113,7 @@ class IrQWeb(models.AbstractModel, QWeb):
|
||||
return super(IrQWeb, self).compile(id_or_xml_id, options=options)
|
||||
|
||||
def load(self, name, options):
|
||||
lang = options.get('lang', 'en_US')
|
||||
lang = options.get('lang', get_lang(self.env).code)
|
||||
env = self.env
|
||||
if lang != env.context.get('lang'):
|
||||
env = env(context=dict(env.context, lang=lang))
|
||||
@@ -148,7 +149,7 @@ class IrQWeb(models.AbstractModel, QWeb):
|
||||
# compile directives
|
||||
|
||||
def _compile_directive_lang(self, el, options):
|
||||
lang = el.attrib.pop('t-lang', 'en_US')
|
||||
lang = el.attrib.pop('t-lang', get_lang(self.env).code)
|
||||
if el.get('t-call-options'):
|
||||
el.set('t-call-options', el.get('t-call-options')[0:-1] + u', "lang": %s}' % lang)
|
||||
else:
|
||||
|
||||
@@ -10,6 +10,7 @@ from lxml import etree
|
||||
import math
|
||||
|
||||
from odoo.tools import html_escape as escape, posix_to_ldml, safe_eval, float_utils, format_date, format_duration, pycompat
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
@@ -130,13 +131,11 @@ class FieldConverter(models.AbstractModel):
|
||||
""" user_lang()
|
||||
|
||||
Fetches the res.lang record corresponding to the language code stored
|
||||
in the user's context. Fallbacks to en_US if no lang is present in the
|
||||
context *or the language code is not valid*.
|
||||
in the user's context.
|
||||
|
||||
:returns: Model[res.lang]
|
||||
"""
|
||||
lang_code = self._context.get('lang') or 'en_US'
|
||||
return self.env['res.lang']._lang_get(lang_code)
|
||||
return get_lang(self.env)
|
||||
|
||||
|
||||
class IntegerConverter(models.AbstractModel):
|
||||
|
||||
+2
-2
@@ -56,7 +56,7 @@ from .tools import frozendict, lazy_classproperty, lazy_property, ormcache, \
|
||||
groupby
|
||||
from .tools.config import config
|
||||
from .tools.func import frame_codeinfo
|
||||
from .tools.misc import CountingStream, clean_context, DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
|
||||
from .tools.misc import CountingStream, clean_context, DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT, get_lang
|
||||
from .tools.safe_eval import safe_eval
|
||||
from .tools.translate import _
|
||||
from .tools import date_utils
|
||||
@@ -1991,7 +1991,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
if ftype == 'many2one':
|
||||
value = value[0]
|
||||
elif ftype in ('date', 'datetime'):
|
||||
locale = self._context.get('lang') or 'en_US'
|
||||
locale = get_lang(self.env).code
|
||||
fmt = DEFAULT_SERVER_DATETIME_FORMAT if ftype == 'datetime' else DEFAULT_SERVER_DATE_FORMAT
|
||||
tzinfo = None
|
||||
range_start = value
|
||||
|
||||
@@ -123,6 +123,7 @@ from zlib import crc32
|
||||
from datetime import date, datetime, time
|
||||
import odoo.modules
|
||||
from odoo.tools import pycompat
|
||||
from odoo.tools.misc import get_lang
|
||||
from ..models import MAGIC_COLUMNS, BaseModel
|
||||
import odoo.tools as tools
|
||||
|
||||
@@ -1145,7 +1146,7 @@ class expression(object):
|
||||
|
||||
params = (
|
||||
model._name + ',' + left,
|
||||
model.env.lang or 'en_US',
|
||||
get_lang(model.env).code,
|
||||
'model',
|
||||
right,
|
||||
)
|
||||
|
||||
+21
-9
@@ -1162,6 +1162,21 @@ 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,
|
||||
the context and then the company. If no lang is installed from those variables,
|
||||
fallback on the first lang installed in the system.
|
||||
:param str lang_code: the locale (i.e. en_US)
|
||||
:return res.lang: the first lang found that is installed on the system.
|
||||
"""
|
||||
langs = [code for code, _ in env['res.lang'].get_installed()]
|
||||
for code in [lang_code, env.context.get('lang'), env.user.company_id.partner_id.lang, langs[0]]:
|
||||
if code in langs:
|
||||
return env['res.lang']._lang_get(code)
|
||||
|
||||
|
||||
def formatLang(env, value, digits=None, grouping=True, monetary=False, dp=False, currency_obj=False):
|
||||
"""
|
||||
Assuming 'Account' decimal.precision=3:
|
||||
@@ -1182,9 +1197,7 @@ def formatLang(env, value, digits=None, grouping=True, monetary=False, dp=False,
|
||||
if isinstance(value, str) and not value:
|
||||
return ''
|
||||
|
||||
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])
|
||||
lang_obj = env['res.lang']._lang_get(lang_code)
|
||||
lang_obj = get_lang(env)
|
||||
|
||||
res = lang_obj.format('%.' + str(digits) + 'f', value, grouping=grouping, monetary=monetary)
|
||||
|
||||
@@ -1221,7 +1234,7 @@ def format_date(env, value, lang_code=False, date_format=False):
|
||||
else:
|
||||
value = odoo.fields.Datetime.from_string(value)
|
||||
|
||||
lang = env['res.lang']._lang_get(lang_code or env.context.get('lang') or 'en_US')
|
||||
lang = get_lang(env, lang_code)
|
||||
locale = babel.Locale.parse(lang.code)
|
||||
if not date_format:
|
||||
date_format = posix_to_ldml(lang.date_format, locale=locale)
|
||||
@@ -1240,7 +1253,7 @@ def parse_date(env, value, lang_code=False):
|
||||
:return: date object from the localized string
|
||||
:rtype: datetime.date
|
||||
'''
|
||||
lang = env['res.lang']._lang_get(lang_code or env.context.get('lang') or 'en_US')
|
||||
lang = get_lang(env, lang_code)
|
||||
locale = babel.Locale.parse(lang.code)
|
||||
try:
|
||||
return babel.dates.parse_date(value, locale=locale)
|
||||
@@ -1271,8 +1284,7 @@ def format_datetime(env, value, tz=False, dt_format='medium', lang_code=False):
|
||||
except Exception:
|
||||
localized_datetime = utc_datetime
|
||||
|
||||
lang_code = lang_code or env.context.get('lang') or 'en_US'
|
||||
lang = env['res.lang']._lang_get(lang_code)
|
||||
lang = get_lang(env, lang_code)
|
||||
|
||||
locale = babel.Locale.parse(lang.code or lang_code) # lang can be inactive, so `lang`is empty
|
||||
if not dt_format:
|
||||
@@ -1302,7 +1314,7 @@ def format_time(env, value, tz=False, time_format='medium', lang_code=False):
|
||||
if not value:
|
||||
return ''
|
||||
|
||||
lang = env['res.lang']._lang_get(lang_code or env.context.get('lang') or 'en_US')
|
||||
lang = get_lang(env, lang_code)
|
||||
locale = babel.Locale.parse(lang.code)
|
||||
if not time_format:
|
||||
time_format = posix_to_ldml(lang.time_format, locale=locale)
|
||||
@@ -1320,7 +1332,7 @@ def _format_time_ago(env, time_delta, lang_code=False, add_direction=True):
|
||||
|
||||
def format_amount(env, amount, currency, lang_code=False):
|
||||
fmt = "%.{0}f".format(currency.decimal_places)
|
||||
lang = env['res.lang']._lang_get(lang_code or env.context.get('lang') or 'en_US')
|
||||
lang = get_lang(env, lang_code)
|
||||
|
||||
formatted_amount = lang.format(fmt, currency.round(amount), grouping=True, monetary=True)\
|
||||
.replace(r' ', u'\N{NO-BREAK SPACE}').replace(r'-', u'-\N{ZERO WIDTH NO-BREAK SPACE}')
|
||||
|
||||
Reference in New Issue
Block a user