From 924e97c457bacc033f8cb517bb0b59e717947022 Mon Sep 17 00:00:00 2001 From: Aleksei Slaikovskii Date: Feb 01 2018 09:49:56 +0000 Subject: 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: Tibor Dudlak Reviewed-By: Stanislav Laznicka --- diff --git a/ipaclient/remote_plugins/__init__.py b/ipaclient/remote_plugins/__init__.py index 0dff001..f1ff22e 100644 --- a/ipaclient/remote_plugins/__init__.py +++ b/ipaclient/remote_plugins/__init__.py @@ -30,9 +30,9 @@ class ServerInfo(collections.MutableMapping): # copy-paste from ipalib/rpc.py try: - self._language = ( - locale.setlocale(locale.LC_ALL, '').split('.')[0].lower() - ) + self._language = locale.setlocale( + locale.LC_MESSAGES, '' + ).split('.')[0].lower() except locale.Error: self._language = 'en_us' diff --git a/ipalib/rpc.py b/ipalib/rpc.py index 539d4cf..c6a8989 100644 --- a/ipalib/rpc.py +++ b/ipalib/rpc.py @@ -536,7 +536,9 @@ class LanguageAwareTransport(MultiProtocolTransport): self, host) try: - lang = locale.setlocale(locale.LC_ALL, '').split('.')[0].lower() + lang = locale.setlocale( + locale.LC_MESSAGES, '' + ).split('.')[0].lower() except locale.Error: # fallback to default locale lang = 'en_us' diff --git a/ipaserver/plugins/schema.py b/ipaserver/plugins/schema.py index cc1c2a5..e4744c9 100644 --- a/ipaserver/plugins/schema.py +++ b/ipaserver/plugins/schema.py @@ -16,6 +16,7 @@ from ipalib.frontend import Command, Local, Method, Object from ipalib.output import Entry, ListOfEntries, ListOfPrimaryKeys, PrimaryKey from ipalib.parameters import Bool, Dict, Flag, Str from ipalib.plugable import Registry +from ipalib.request import context from ipalib.text import _ from ipapython.version import API_VERSION @@ -833,11 +834,15 @@ class schema(Command): return schema def execute(self, *args, **kwargs): - try: - schema = self.api._schema - except AttributeError: + langs = "".join(getattr(context, "languages", [])) + + 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) - setattr(self.api, '_schema', schema) + self.api._schema[langs] = schema schema['ttl'] = SCHEMA_TTL diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py index 5cbacf4..f14e784 100644 --- a/ipaserver/rpcserver.py +++ b/ipaserver/rpcserver.py @@ -334,7 +334,6 @@ class WSGIExecutioner(Executioner): result = None error = None _id = None - lang = os.environ['LANG'] name = None args = () options = {} @@ -349,12 +348,9 @@ class WSGIExecutioner(Executioner): if ('HTTP_ACCEPT_LANGUAGE' in environ): lang_reg_w_q = environ['HTTP_ACCEPT_LANGUAGE'].split(',')[0] lang_reg = lang_reg_w_q.split(';')[0] - lang_ = lang_reg.split('-')[0] - if '-' in lang_reg: - reg = lang_reg.split('-')[1].upper() - else: - reg = lang_.upper() - os.environ['LANG'] = '%s_%s' % (lang_, reg) + lang = lang_reg.split('-')[0] + setattr(context, "languages", [lang]) + if ( environ.get('CONTENT_TYPE', '').startswith(self.content_type) and environ['REQUEST_METHOD'] == 'POST' @@ -363,6 +359,7 @@ class WSGIExecutioner(Executioner): (name, args, options, _id) = self.unmarshal(data) else: (name, args, options, _id) = self.simple_unmarshal(environ) + if name in self._system_commands: result = self._system_commands[name](self, *args, **options) else: @@ -379,7 +376,8 @@ class WSGIExecutioner(Executioner): ) error = InternalError() finally: - os.environ['LANG'] = lang + if hasattr(context, "languages"): + delattr(context, "languages") principal = getattr(context, 'principal', 'UNKNOWN') if command is not None: