Skip to content

Commit 656fb8f

Browse files
committed
Add i18n object to roundupdb.Database
This makes the i18n object accessible everywhere (including in detectors where localized error messages were impossible). See issue2551184
1 parent 9a917e1 commit 656fb8f

File tree

14 files changed

+86
-35
lines changed

14 files changed

+86
-35
lines changed

doc/developers.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,22 @@ Template markup examples:
290290
fine) % fine"
291291
/>
292292

293+
Detectors and extensions
294+
^^^^^^^^^^^^^^^^^^^^^^^^
295+
296+
The correct ``i18n`` objects gets automatically injected in the hyperdb.
297+
In a detector you can access the i18n object and do translation like
298+
this::
299+
300+
def statusfail(db, cl, nodeid, newvalues):
301+
_ = db.i18n.gettext
302+
raise ValueError(_("this does not work"))
303+
304+
def init(db):
305+
# fire before changes are made
306+
db.status.audit('create', statusfail)
307+
308+
293309
Extracting Translatable Messages
294310
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
295311

roundup/admin.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import roundup.instance
3131
from roundup.configuration import (CoreConfig, NoConfigError,
3232
ParsingOptionError, UserConfig)
33-
from roundup.i18n import _
33+
from roundup.i18n import _, get_translation
3434
from roundup.exceptions import UsageError
3535
from roundup.anypy.my_input import my_input
3636
from roundup.anypy.strings import repr_export
@@ -1719,6 +1719,11 @@ def run_command(self, args):
17191719
# only open the database once!
17201720
if not self.db:
17211721
self.db = tracker.open(self.name)
1722+
# dont use tracker.config["TRACKER_LANGUAGE"] here as the
1723+
# cli operator likely wants to have i18n as set in the
1724+
# environment.
1725+
# This is needed to fetch the locale's of the tracker's home dir.
1726+
self.db.i18n = get_translation (tracker_home = tracker.tracker_home)
17221727

17231728
self.db.tx_Source = 'cli'
17241729

roundup/backends/back_anydbm.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ def __init__(self, config, journaltag=None):
9090
disabled.
9191
"""
9292
FileStorage.__init__(self, config.UMASK)
93+
roundupdb.Database.__init__(self)
9394
self.config, self.journaltag = config, journaltag
9495
self.dir = config.DATABASE
9596
self.classes = {}

roundup/backends/rdbms_common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ def __init__(self, config, journaltag=None):
170170
""" Open the database and load the schema from it.
171171
"""
172172
FileStorage.__init__(self, config.UMASK)
173+
roundupdb.Database.__init__(self)
173174
self.config, self.journaltag = config, journaltag
174175
self.dir = config.DATABASE
175176
self.classes = {}

roundup/cgi/PageTemplates/TALES.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -257,16 +257,6 @@ def setSourceFile(self, source_file):
257257
def setPosition(self, position):
258258
self.position = position
259259

260-
def translate(self, domain, msgid, mapping=None,
261-
context=None, target_language=None, default=None):
262-
if context is None:
263-
context = self.contexts.get('here')
264-
return getGlobalTranslationService().translate(
265-
domain, msgid, mapping=mapping,
266-
context=context,
267-
default=default,
268-
target_language=target_language)
269-
270260
class TALESTracebackSupplement:
271261
"""Implementation of ITracebackSupplement"""
272262
def __init__(self, context, expression):

roundup/cgi/client.py

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,15 @@ def __init__(self, instance, request, env, form=None, translator=None):
387387
self.instance = instance
388388
self.request = request
389389
self.env = env
390-
self.setTranslator(translator)
390+
if translator is not None :
391+
self.setTranslator(translator)
392+
# XXX we should set self.language to "translator"'s language,
393+
# but how to get it ?
394+
self.language = ""
395+
else :
396+
self.setTranslator(TranslationService.NullTranslationService())
397+
self.language = "" # as is the default from determine_language
398+
391399
self.mailer = Mailer(instance.config)
392400
# If True the form contents wins over the database contents when
393401
# rendering html properties. This is set when an error occurs so
@@ -540,11 +548,13 @@ def handle_xmlrpc(self):
540548
# Set the charset and language, since other parts of
541549
# Roundup may depend upon that.
542550
self.determine_charset()
543-
self.determine_language()
551+
if self.instance.config["WEB_TRANSLATE_XMLRPC"] :
552+
self.determine_language()
544553
# Open the database as the correct user.
545554
try:
546555
self.determine_user()
547556
self.db.tx_Source = "xmlrpc"
557+
self.db.i18n = self.translator
548558
except LoginError as msg:
549559
output = xmlrpc_.client.dumps(
550560
xmlrpc_.client.Fault(401, "%s" % msg),
@@ -594,12 +604,14 @@ def handle_xmlrpc(self):
594604
def handle_rest(self):
595605
# Set the charset and language
596606
self.determine_charset()
597-
self.determine_language()
607+
if self.instance.config["WEB_TRANSLATE_REST"] :
608+
self.determine_language()
598609
# Open the database as the correct user.
599610
# TODO: add everything to RestfulDispatcher
600611
try:
601612
self.determine_user()
602613
self.db.tx_Source = "rest"
614+
self.db.i18n = self.translator
603615
except LoginError as err:
604616
self.response_code = http_.client.UNAUTHORIZED
605617
output = s2b("Invalid Login - %s"%str(err))
@@ -622,7 +634,7 @@ def handle_rest(self):
622634
# Call csrf with xmlrpc checks enabled.
623635
# It will return True if everything is ok,
624636
# raises exception on check failure.
625-
csrf_ok = self.handle_csrf(xmlrpc=True)
637+
csrf_ok = self.handle_csrf(xmlrpc=True)
626638
except (Unauthorised, UsageError) as msg:
627639
# report exception back to server
628640
exc_type, exc_value, exc_tb = sys.exc_info()
@@ -699,7 +711,6 @@ def inner_main(self):
699711
self._error_message = []
700712
try:
701713
self.determine_charset()
702-
self.determine_language()
703714

704715
try:
705716
# make sure we're identified (even anonymously)
@@ -708,6 +719,9 @@ def inner_main(self):
708719
# figure out the context and desired content template
709720
self.determine_context()
710721

722+
self.determine_language()
723+
self.db.i18n = self.translator
724+
711725
# if we've made it this far the context is to a bit of
712726
# Roundup's real web interface (not a file being served up)
713727
# so do the Anonymous Web Acess check now
@@ -764,6 +778,9 @@ def inner_main(self):
764778
# exception or a NotModified exception. Those
765779
# exceptions will be handled by the outermost set of
766780
# exception handlers.
781+
self.determine_language()
782+
self.db.i18n = self.translator
783+
767784
self.serve_file(designator)
768785
except SendStaticFile as file:
769786
self.serve_static_file(str(file))
@@ -985,11 +1002,18 @@ def determine_language(self):
9851002
else:
9861003
language = ""
9871004

1005+
if not language :
1006+
# default to tracker language
1007+
language = self.instance.config["TRACKER_LANGUAGE"]
1008+
1009+
# this maybe is not correct, as get_translation could not
1010+
# find desired locale and switch back to "en" but we set
1011+
# self.language to the desired language !
9881012
self.language = language
989-
if language:
990-
self.setTranslator(TranslationService.get_translation(
991-
language,
992-
tracker_home=self.instance.config["TRACKER_HOME"]))
1013+
1014+
self.setTranslator(TranslationService.get_translation(
1015+
language,
1016+
tracker_home=self.instance.config["TRACKER_HOME"]))
9931017

9941018
def authenticate_bearer_token(self, challenge):
9951019
''' authenticate the bearer token. Refactored from determine_user()

roundup/cgi/engine_zopetal.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@
88
import os
99
import os.path
1010

11-
from roundup.cgi.templating import StringIO, context, translationService, TALLoaderBase
11+
from roundup.cgi.templating import StringIO, context, TALLoaderBase
1212
from roundup.cgi.PageTemplates import PageTemplate, GlobalTranslationService
1313
from roundup.cgi.PageTemplates.Expressions import getEngine
1414
from roundup.cgi.TAL import TALInterpreter
1515

16-
GlobalTranslationService.setGlobalTranslationService(translationService)
17-
1816

1917
class Loader(TALLoaderBase):
2018
templates = {}

roundup/cgi/form_parser.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import re, mimetypes
22

33
from roundup import hyperdb, date, password
4-
from roundup.cgi import templating
4+
from roundup.cgi import templating, TranslationService
55
from roundup.cgi.exceptions import FormError
66

77

@@ -38,7 +38,7 @@ def __init__(self, client):
3838
self._ = self.gettext = client.gettext
3939
self.ngettext = client.ngettext
4040
except AttributeError:
41-
_translator = templating.translationService
41+
_translator = TranslationService.get_translation()
4242
self._ = self.gettext = _translator.gettext
4343
self.ngettext = _translator.ngettext
4444

roundup/cgi/templating.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -197,13 +197,7 @@ def _options(config):
197197
markdown = _import_markdown2() or _import_markdown() or _import_mistune()
198198

199199
# bring in the templating support
200-
from roundup.cgi import TranslationService, ZTUtils
201-
202-
### i18n services
203-
# this global translation service is not thread-safe.
204-
# it is left here for backward compatibility
205-
# until all Web UI translations are done via client.translator object
206-
translationService = TranslationService.get_translation()
200+
from roundup.cgi import ZTUtils
207201

208202
def anti_csrf_nonce(client, lifetime=None):
209203
''' Create a nonce for defending against CSRF attack.

roundup/configuration.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,12 +1080,20 @@ def str2value(self, value):
10801080
after the roundup web url configured in the 'tracker' section.
10811081
If this variable is set to 'no', the xmlrpc path has no special meaning
10821082
and will yield an error message."""),
1083+
(BooleanOption, 'translate_xmlrpc', 'no',
1084+
"""Whether to enable i18n for the xmlrpc endpoint. Enable it if
1085+
you want to enable translation based on browsers lang (if enabled), trackers
1086+
lang (if set) or environment."""),
10831087
(BooleanOption, 'enable_rest', "yes",
10841088
"""Whether to enable the REST API in the roundup web
10851089
interface. By default the REST endpoint is the string 'rest' plus any
10861090
additional REST-API parameters after the roundup web url configured in
10871091
the tracker section. If this variable is set to 'no', the rest path has
10881092
no special meaning and will yield an error message."""),
1093+
(BooleanOption, 'translate_rest', 'no',
1094+
"""Whether to enable i18n for the rest endpoint. Enable it if
1095+
you want to enable translation based on browsers lang (if enabled), trackers
1096+
lang (if set) or environment."""),
10891097
(IntegerNumberGeqZeroOption, 'api_calls_per_interval', "0",
10901098
"Limit API calls per api_interval_in_sec seconds to\n"
10911099
"this number.\n"

0 commit comments

Comments
 (0)