1 # -*- coding: utf-8 ; test-case-name: bridgedb.test.test_translations -*-
3 # This file is part of BridgeDB, a Tor bridge distribution system.
5 # :authors: Isis Lovecruft 0xA3ADB67A2CDB8B35 <isis@torproject.org>
6 # :copyright: (c) 2013-2017, Isis Lovecruft
7 # (c) 2007-2017, The Tor Project, Inc.
8 # :license: 3-Clause BSD, see LICENSE for licensing information
17 from bridgedb
import _langs
18 from bridgedb
import safelog
19 from bridgedb
.parse
import headers
22 TRANSLATIONS_DIR
= os
.path
.join(os
.path
.abspath(os
.path
.dirname(__file__
)), 'i18n')
25 def isLangOverridden(request
):
27 Return True if the `lang' HTTP GET argument is set in the given request.
29 :type request: :api:`twisted.web.server.Request`
30 :param request: An incoming request from a client.
32 :returns: ``True`` if the given request has a `lang` argument and ``False``
36 return request
.args
.get("lang", [None])[0] is not None
38 def getSupportedLangs():
39 """Return all supported languages.
42 :returns: A set of language locales, e.g.: set(['el', 'eo', ..., ]).
45 return _langs
.get_langs()
47 def getFirstSupportedLang(langs
):
48 """Return the first language in **langs** that we support.
50 :param list langs: All requested languages
52 :returns: A country code for the client's preferred language.
55 supported
= _langs
.get_langs()
62 # crop locales (like 'en-US') to just the language
64 return lang
.split('-')[0]
66 def getLocaleFromHTTPRequest(request
):
67 """Retrieve the languages from an HTTP ``Accept-Language:`` header.
69 Parse the languages from the header, use them to install a
70 ``gettext.translation`` chain via :func:`installTranslations`, and lastly
71 return the requested languages.
73 :type request: :api:`twisted.web.server.Request`
74 :param request: An incoming request from a client.
76 :returns: All requested languages.
78 header
= request
.getHeader('accept-language')
80 logging
.debug("Client sent no 'Accept-Language' header. Using fallback.")
83 langs
= list(headers
.parseAcceptLanguage(header
))
84 if not safelog
.safe_logging
: # pragma: no cover
85 logging
.debug("Client Accept-Language (top 5): %s" % langs
[:5])
87 # Check if we got a ?lang=foo argument, and if we did, insert it first
88 chosenLang
= request
.args
.get("lang", [None,])[0]
90 logging
.debug("Client requested language: %r" % chosenLang
)
91 langs
.insert(0, chosenLang
)
93 # normalize languages to be unicode
95 langs
= list(map(lambda l
: l
if isinstance(l
, str) else l
.decode('utf-8'), langs
))
97 installTranslations(langs
)
100 def getLocaleFromPlusAddr(address
):
101 """See whether the user sent his email to a 'plus' address, for instance to
102 bridges+fa@bridges.torproject.org. Plus addresses are the current
103 mechanism to set the reply language.
106 r
= '.*(<)?(\w+\+(\w+)@\w+(?:\.\w+)+)(?(1)>)'
107 match
= re
.match(r
, address
)
109 replyLocale
= match
.group(3)
113 def installTranslations(langs
):
114 """Create a ``gettext.translation`` chain for all **langs**.
116 Attempt to install the first language in the **langs** list. If that
117 fails, we receive a ``gettext.NullTranslation`` object, and if it worked
118 then we have a ``gettext.GNUTranslation`` object. Whichever one we end up
119 with, get the other languages and add them as fallbacks to the
120 first. Lastly, install this chain of translations.
122 :param list langs: A list of language codes.
123 :returns: A ``gettext.NullTranslation`` or ``gettext.GNUTranslation`` with
124 fallback languages set.
127 language
= gettext
.translation("bridgedb", localedir
=TRANSLATIONS_DIR
,
128 languages
=langs
, fallback
=True)
130 language
.add_fallback(
131 gettext
.translation("bridgedb", localedir
=TRANSLATIONS_DIR
,
132 languages
=langs
, fallback
=True))
133 except IOError as error
:
134 logging
.error(str(error
))
139 def usingRTLLang(langs
):
140 """Check if we should translate the text into a RTL language.
142 Choose the first language from the **langs** list that we support and
143 return True if it is a RTL language, else return False.
145 :param list langs: An incoming request.
147 :returns: ``True`` if the preferred language is right-to-left; ``False``
151 lang
= getFirstSupportedLang(langs
)
154 return babel
.core
.Locale
.parse(lang
).text_direction
== "rtl"
155 except ValueError as err
:
156 logging
.warning("Couldn't parse locale %s: %s" % (lang
, err
))