Fixing translation problems

ipa rpc server did set the LANG environment variable on each
request and it was not thread safe which led to unpredictable
mixed languages output. Also, there were mistakes regarding
setting the Accept-Language HTTP header.

Now on each request we're setting the "languages" property
in the context thread local variable and client is setting
the Accept-Language HTTP header correctly.

Also, as the server is caching the schema and the schema can
be generated for several languages it's good to store different
schema fingerprint for each language separately.

pagure: https://pagure.io/freeipa/issue/7238
Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
Reviewed-By: Tibor Dudlak <tdudlak@redhat.com>
This commit is contained in:
Aleksei Slaikovskii 2018-01-23 14:41:25 +01:00 committed by Tibor Dudlák
parent 1235f5958d
commit 6c5a7464b2
No known key found for this signature in database
GPG Key ID: 12B8BD343576CDF5
4 changed files with 21 additions and 16 deletions

View File

@ -30,9 +30,9 @@ class ServerInfo(collections.MutableMapping):
# copy-paste from ipalib/rpc.py # copy-paste from ipalib/rpc.py
try: try:
self._language = ( self._language = locale.setlocale(
locale.setlocale(locale.LC_ALL, '').split('.')[0].lower() locale.LC_MESSAGES, ''
) ).split('.')[0].lower()
except locale.Error: except locale.Error:
self._language = 'en_us' self._language = 'en_us'

View File

@ -536,7 +536,9 @@ class LanguageAwareTransport(MultiProtocolTransport):
self, host) self, host)
try: try:
lang = locale.setlocale(locale.LC_ALL, '').split('.')[0].lower() lang = locale.setlocale(
locale.LC_MESSAGES, ''
).split('.')[0].lower()
except locale.Error: except locale.Error:
# fallback to default locale # fallback to default locale
lang = 'en_us' lang = 'en_us'

View File

@ -16,6 +16,7 @@ from ipalib.frontend import Command, Local, Method, Object
from ipalib.output import Entry, ListOfEntries, ListOfPrimaryKeys, PrimaryKey from ipalib.output import Entry, ListOfEntries, ListOfPrimaryKeys, PrimaryKey
from ipalib.parameters import Bool, Dict, Flag, Str from ipalib.parameters import Bool, Dict, Flag, Str
from ipalib.plugable import Registry from ipalib.plugable import Registry
from ipalib.request import context
from ipalib.text import _ from ipalib.text import _
from ipapython.version import API_VERSION from ipapython.version import API_VERSION
@ -833,11 +834,15 @@ class schema(Command):
return schema return schema
def execute(self, *args, **kwargs): def execute(self, *args, **kwargs):
try: langs = "".join(getattr(context, "languages", []))
schema = self.api._schema
except AttributeError: if getattr(self.api, "_schema", None) is None:
setattr(self.api, "_schema", {})
schema = self.api._schema.get(langs)
if schema is None:
schema = self._generate_schema(**kwargs) schema = self._generate_schema(**kwargs)
setattr(self.api, '_schema', schema) self.api._schema[langs] = schema
schema['ttl'] = SCHEMA_TTL schema['ttl'] = SCHEMA_TTL

View File

@ -334,7 +334,6 @@ class WSGIExecutioner(Executioner):
result = None result = None
error = None error = None
_id = None _id = None
lang = os.environ['LANG']
name = None name = None
args = () args = ()
options = {} options = {}
@ -349,12 +348,9 @@ class WSGIExecutioner(Executioner):
if ('HTTP_ACCEPT_LANGUAGE' in environ): if ('HTTP_ACCEPT_LANGUAGE' in environ):
lang_reg_w_q = environ['HTTP_ACCEPT_LANGUAGE'].split(',')[0] lang_reg_w_q = environ['HTTP_ACCEPT_LANGUAGE'].split(',')[0]
lang_reg = lang_reg_w_q.split(';')[0] lang_reg = lang_reg_w_q.split(';')[0]
lang_ = lang_reg.split('-')[0] lang = lang_reg.split('-')[0]
if '-' in lang_reg: setattr(context, "languages", [lang])
reg = lang_reg.split('-')[1].upper()
else:
reg = lang_.upper()
os.environ['LANG'] = '%s_%s' % (lang_, reg)
if ( if (
environ.get('CONTENT_TYPE', '').startswith(self.content_type) environ.get('CONTENT_TYPE', '').startswith(self.content_type)
and environ['REQUEST_METHOD'] == 'POST' and environ['REQUEST_METHOD'] == 'POST'
@ -363,6 +359,7 @@ class WSGIExecutioner(Executioner):
(name, args, options, _id) = self.unmarshal(data) (name, args, options, _id) = self.unmarshal(data)
else: else:
(name, args, options, _id) = self.simple_unmarshal(environ) (name, args, options, _id) = self.simple_unmarshal(environ)
if name in self._system_commands: if name in self._system_commands:
result = self._system_commands[name](self, *args, **options) result = self._system_commands[name](self, *args, **options)
else: else:
@ -379,7 +376,8 @@ class WSGIExecutioner(Executioner):
) )
error = InternalError() error = InternalError()
finally: finally:
os.environ['LANG'] = lang if hasattr(context, "languages"):
delattr(context, "languages")
principal = getattr(context, 'principal', 'UNKNOWN') principal = getattr(context, 'principal', 'UNKNOWN')
if command is not None: if command is not None: