/usr/share/pyshared/zope/i18n/translationdomain.py is in python-zope.i18n 3.8.0-0ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | ##############################################################################
#
# Copyright (c) 2001-2008 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Global Translation Service for providing I18n to file-based code.
"""
import zope.component
from zope.i18nmessageid import Message
from zope.i18n import translate, interpolate
from zope.i18n.simpletranslationdomain import SimpleTranslationDomain
from zope.i18n.interfaces import ITranslationDomain, INegotiator
# The configuration should specify a list of fallback languages for the
# site. If a particular catalog for a negotiated language is not available,
# then the zcml specified order should be tried. If that fails, then as a
# last resort the languages in the following list are tried. If these fail
# too, then the msgid is returned.
#
# Note that these fallbacks are used only to find a catalog. If a particular
# message in a catalog is not translated, tough luck, you get the msgid.
LANGUAGE_FALLBACKS = ['en']
class TranslationDomain(SimpleTranslationDomain):
def __init__(self, domain, fallbacks=None):
self.domain = domain
# _catalogs maps (language, domain) to IMessageCatalog instances
self._catalogs = {}
# _data maps IMessageCatalog.getIdentifier() to IMessageCatalog
self._data = {}
# What languages to fallback to, if there is no catalog for the
# requested language (no fallback on individual messages)
if fallbacks is None:
fallbacks = LANGUAGE_FALLBACKS
self._fallbacks = fallbacks
def _registerMessageCatalog(self, language, catalog_name):
key = language
mc = self._catalogs.setdefault(key, [])
mc.append(catalog_name)
def addCatalog(self, catalog):
self._data[catalog.getIdentifier()] = catalog
self._registerMessageCatalog(catalog.language,
catalog.getIdentifier())
def setLanguageFallbacks(self, fallbacks=None):
if fallbacks is None:
fallbacks = LANGUAGE_FALLBACKS
self._fallbacks = fallbacks
def translate(self, msgid, mapping=None, context=None,
target_language=None, default=None):
"""See zope.i18n.interfaces.ITranslationDomain"""
# if the msgid is empty, let's save a lot of calculations and return
# an empty string.
if msgid == u'':
return u''
if target_language is None and context is not None:
langs = self._catalogs.keys()
# invoke local or global unnamed 'INegotiator' utilities
negotiator = zope.component.getUtility(INegotiator)
# try to determine target language from negotiator utility
target_language = negotiator.getLanguage(langs, context)
return self._recursive_translate(
msgid, mapping, target_language, default, context)
def _recursive_translate(self, msgid, mapping, target_language, default,
context, seen=None):
"""Recursively translate msg."""
# MessageID attributes override arguments
if isinstance(msgid, Message):
if msgid.domain != self.domain:
return translate(msgid, msgid.domain, mapping, context,
target_language, default)
default = msgid.default
mapping = msgid.mapping
# Recursively translate mappings, if they are translatable
if (mapping is not None
and Message in (type(m) for m in mapping.values())):
if seen is None:
seen = set()
seen.add(msgid)
mapping = mapping.copy()
for key, value in mapping.items():
if isinstance(value, Message):
# TODO Why isn't there an IMessage interface?
# https://bugs.launchpad.net/zope3/+bug/220122
if value in seen:
raise ValueError(
"Circular reference in mappings detected: %s" %
value)
mapping[key] = self._recursive_translate(
value, mapping, target_language,
default, context, seen)
if default is None:
default = unicode(msgid)
# Get the translation. Use the specified fallbacks if this fails
catalog_names = self._catalogs.get(target_language)
if catalog_names is None:
for language in self._fallbacks:
catalog_names = self._catalogs.get(language)
if catalog_names is not None:
break
text = default
if catalog_names:
if len(catalog_names) == 1:
# this is a slight optimization for the case when there is a
# single catalog. More importantly, it is extremely helpful
# when testing and the test language is used, because it
# allows the test language to get the default.
text = self._data[catalog_names[0]].queryMessage(
msgid, default)
else:
for name in catalog_names:
catalog = self._data[name]
s = catalog.queryMessage(msgid)
if s is not None:
text = s
break
# Now we need to do the interpolation
if text and mapping:
text = interpolate(text, mapping)
return text
def getCatalogsInfo(self):
return self._catalogs
def reloadCatalogs(self, catalogNames):
for catalogName in catalogNames:
self._data[catalogName].reload()
|