1b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# -*- coding: utf-8 -*-
2b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik"""
3b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    webapp2_extras.i18n
4b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    ===================
5b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
6b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Internationalization support for webapp2.
7b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
8b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Several ideas borrowed from tipfy.i18n and Flask-Babel.
9b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
10b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :copyright: 2011 by tipfy.org.
11b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :license: Apache Sotware License, see LICENSE for details.
12b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik"""
13b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport datetime
14b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport gettext as gettext_stdlib
15b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
16b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport babel
17b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikfrom babel import dates
18b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikfrom babel import numbers
19b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikfrom babel import support
20b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
21b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craiktry:
22b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    # Monkeypatches pytz for gae.
23b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    import pytz.gae
24b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikexcept ImportError: # pragma: no cover
25b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    pass
26b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
27b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport pytz
28b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
29b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport webapp2
30b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
31b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#: Default configuration values for this module. Keys are:
32b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:
33b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#: translations_path
34b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:     Path to the translations directory. Default is `locale`.
35b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:
36b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#: domains
37b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:     List of gettext domains to be used. Default is ``['messages']``.
38b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:
39b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#: default_locale
40b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:     A locale code to be used as fallback. Default is ``'en_US'``.
41b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:
42b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#: default_timezone
43b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:     The application default timezone according to the Olson
44b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:     database. Default is ``'UTC'``.
45b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:
46b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#: locale_selector
47b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:     A function that receives (store, request) and returns a locale
48b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:     to be used for a request. If not defined, uses `default_locale`.
49b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:     Can also be a string in dotted notation to be imported.
50b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:
51b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#: timezone_selector
52b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:     A function that receives (store, request) and returns a timezone
53b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:     to be used for a request. If not defined, uses `default_timezone`.
54b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:     Can also be a string in dotted notation to be imported.
55b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:
56b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#: date_formats
57b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#:     Default date formats for datetime, date and time.
58b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdefault_config = {
59b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    'translations_path':   'locale',
60b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    'domains':             ['messages'],
61b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    'default_locale':      'en_US',
62b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    'default_timezone':    'UTC',
63b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    'locale_selector':     None,
64b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    'timezone_selector':   None,
65b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    'date_formats': {
66b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'time':            'medium',
67b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'date':            'medium',
68b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'datetime':        'medium',
69b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'time.short':      None,
70b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'time.medium':     None,
71b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'time.full':       None,
72b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'time.long':       None,
73b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'time.iso':        "HH':'mm':'ss",
74b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'date.short':      None,
75b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'date.medium':     None,
76b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'date.full':       None,
77b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'date.long':       None,
78b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'date.iso':        "yyyy'-'MM'-'dd",
79b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'datetime.short':  None,
80b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'datetime.medium': None,
81b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'datetime.full':   None,
82b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'datetime.long':   None,
83b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        'datetime.iso':    "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ",
84b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    },
85b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik}
86b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
87b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris CraikNullTranslations = gettext_stdlib.NullTranslations
88b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
89b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
90b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass I18nStore(object):
91b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Internalization store.
92b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
93b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Caches loaded translations and configuration to be used between requests.
94b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
95b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
96b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Configuration key.
97b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    config_key = __name__
98b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A dictionary with all loaded translations.
99b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    translations = None
100b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Path to where traslations are stored.
101b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    translations_path = None
102b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Translation domains to merge.
103b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    domains = None
104b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Default locale code.
105b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    default_locale = None
106b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Default timezone code.
107b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    default_timezone = None
108b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: Dictionary of default date formats.
109b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    date_formats = None
110b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A callable that returns the locale for a request.
111b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    locale_selector = None
112b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A callable that returns the timezone for a request.
113b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    timezone_selector = None
114b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
115b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, app, config=None):
116b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Initializes the i18n store.
117b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
118b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param app:
119b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`webapp2.WSGIApplication` instance.
120b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param config:
121b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A dictionary of configuration values to be overridden. See
122b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            the available keys in :data:`default_config`.
123b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
124b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        config = app.config.load_config(self.config_key,
125b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            default_values=default_config, user_values=config,
126b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            required_keys=None)
127b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.translations = {}
128b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.translations_path = config['translations_path']
129b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.domains = config['domains']
130b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.default_locale = config['default_locale']
131b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.default_timezone = config['default_timezone']
132b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.date_formats = config['date_formats']
133b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.set_locale_selector(config['locale_selector'])
134b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.set_timezone_selector(config['timezone_selector'])
135b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
136b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def set_locale_selector(self, func):
137b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Sets the function that defines the locale for a request.
138b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
139b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param func:
140b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A callable that receives (store, request) and returns the locale
141b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            for a request.
142b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
143b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if func is None:
144b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.locale_selector = self.default_locale_selector
145b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
146b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if isinstance(func, basestring):
147b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                func = webapp2.import_string(func)
148b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
149b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # Functions are descriptors, so bind it to this instance with
150b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            # __get__.
151b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.locale_selector = func.__get__(self, self.__class__)
152b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
153b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def set_timezone_selector(self, func):
154b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Sets the function that defines the timezone for a request.
155b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
156b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param func:
157b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A callable that receives (store, request) and returns the timezone
158b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            for a request.
159b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
160b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if func is None:
161b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.timezone_selector = self.default_timezone_selector
162b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
163b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if isinstance(func, basestring):
164b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                func = webapp2.import_string(func)
165b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
166b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.timezone_selector = func.__get__(self, self.__class__)
167b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
168b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def default_locale_selector(self, request):
169b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self.default_locale
170b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
171b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def default_timezone_selector(self, request):
172b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self.default_timezone
173b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
174b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def get_translations(self, locale):
175b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns a translation catalog for a locale.
176b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
177b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param locale:
178b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A locale code.
179b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
180b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A ``babel.support.Translations`` instance, or
181b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            ``gettext.NullTranslations`` if none was found.
182b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
183b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        trans = self.translations.get(locale)
184b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if not trans:
185b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            locales = (locale, self.default_locale)
186b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            trans = self.load_translations(self.translations_path, locales,
187b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                                           self.domains)
188b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if not webapp2.get_app().debug:
189b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                self.translations[locale] = trans
190b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
191b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return trans
192b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
193b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def load_translations(self, dirname, locales, domains):
194b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Loads a translation catalog.
195b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
196b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param dirname:
197b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Path to where translations are stored.
198b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param locales:
199b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A list of locale codes.
200b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param domains:
201b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A list of domains to be merged.
202b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
203b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A ``babel.support.Translations`` instance, or
204b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            ``gettext.NullTranslations`` if none was found.
205b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
206b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        trans = None
207b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        trans_null = None
208b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for domain in domains:
209b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            _trans = support.Translations.load(dirname, locales, domain)
210b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if isinstance(_trans, NullTranslations):
211b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                trans_null = _trans
212b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                continue
213b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            elif trans is None:
214b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                trans = _trans
215b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            else:
216b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                trans.merge(_trans)
217b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
218b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return trans or trans_null or NullTranslations()
219b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
220b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
221b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass I18n(object):
222b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Internalization provider for a single request."""
223b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
224b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: A reference to :class:`I18nStore`.
225b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    store = None
226b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: The current locale code.
227b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    locale = None
228b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: The current translations.
229b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    translations = None
230b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: The current timezone code.
231b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    timezone = None
232b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    #: The current tzinfo object.
233b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    tzinfo = None
234b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
235b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, request):
236b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Initializes the i18n provider for a request.
237b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
238b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param request:
239b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A :class:`webapp2.Request` instance.
240b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
241b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.store = store = get_store(app=request.app)
242b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.set_locale(store.locale_selector(request))
243b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.set_timezone(store.timezone_selector(request))
244b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
245b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def set_locale(self, locale):
246b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Sets the locale code for this request.
247b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
248b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param locale:
249b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A locale code.
250b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
251b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.locale = locale
252b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.translations = self.store.get_translations(locale)
253b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
254b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def set_timezone(self, timezone):
255b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Sets the timezone code for this request.
256b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
257b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param timezone:
258b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A timezone code.
259b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
260b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.timezone = timezone
261b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.tzinfo = pytz.timezone(timezone)
262b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
263b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def gettext(self, string, **variables):
264b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Translates a given string according to the current locale.
265b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
266b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param string:
267b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The string to be translated.
268b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param variables:
269b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Variables to format the returned string.
270b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
271b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The translated string.
272b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
273b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if variables:
274b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return self.translations.ugettext(string) % variables
275b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
276b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self.translations.ugettext(string)
277b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
278b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def ngettext(self, singular, plural, n, **variables):
279b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Translates a possible pluralized string according to the current
280b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        locale.
281b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
282b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param singular:
283b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The singular for of the string to be translated.
284b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param plural:
285b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The plural for of the string to be translated.
286b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param n:
287b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            An integer indicating if this is a singular or plural. If greater
288b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            than 1, it is a plural.
289b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param variables:
290b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Variables to format the returned string.
291b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
292b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The translated string.
293b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
294b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if variables:
295b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return self.translations.ungettext(singular, plural, n) % variables
296b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
297b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self.translations.ungettext(singular, plural, n)
298b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
299b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def to_local_timezone(self, datetime):
300b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns a datetime object converted to the local timezone.
301b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
302b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param datetime:
303b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A ``datetime`` object.
304b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
305b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A ``datetime`` object normalized to a timezone.
306b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
307b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if datetime.tzinfo is None:
308b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            datetime = datetime.replace(tzinfo=pytz.UTC)
309b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
310b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self.tzinfo.normalize(datetime.astimezone(self.tzinfo))
311b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
312b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def to_utc(self, datetime):
313b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns a datetime object converted to UTC and without tzinfo.
314b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
315b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param datetime:
316b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A ``datetime`` object.
317b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
318b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A naive ``datetime`` object (no timezone), converted to UTC.
319b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
320b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if datetime.tzinfo is None:
321b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            datetime = self.tzinfo.localize(datetime)
322b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
323b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return datetime.astimezone(pytz.UTC).replace(tzinfo=None)
324b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
325b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def _get_format(self, key, format):
326b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """A helper for the datetime formatting functions. Returns a format
327b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        name or pattern to be used by Babel date format functions.
328b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
329b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param key:
330b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A format key to be get from config. Valid values are "date",
331b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            "datetime" or "time".
332b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param format:
333b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The format to be returned. Valid values are "short", "medium",
334b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            "long", "full" or a custom date/time pattern.
335b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
336b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A format name or pattern to be used by Babel date format functions.
337b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
338b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if format is None:
339b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            format = self.store.date_formats.get(key)
340b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
341b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if format in ('short', 'medium', 'full', 'long', 'iso'):
342b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            rv = self.store.date_formats.get('%s.%s' % (key, format))
343b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if rv is not None:
344b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                format = rv
345b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
346b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return format
347b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
348b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def format_date(self, date=None, format=None, rebase=True):
349b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns a date formatted according to the given pattern and
350b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        following the current locale.
351b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
352b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param date:
353b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A ``date`` or ``datetime`` object. If None, the current date in
354b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            UTC is used.
355b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param format:
356b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The format to be returned. Valid values are "short", "medium",
357b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            "long", "full" or a custom date/time pattern. Example outputs:
358b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
359b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - short:  11/10/09
360b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - medium: Nov 10, 2009
361b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - long:   November 10, 2009
362b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - full:   Tuesday, November 10, 2009
363b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
364b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param rebase:
365b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            If True, converts the date to the current :attr:`timezone`.
366b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
367b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A formatted date in unicode.
368b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
369b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        format = self._get_format('date', format)
370b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
371b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if rebase and isinstance(date, datetime.datetime):
372b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            date = self.to_local_timezone(date)
373b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
374b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return dates.format_date(date, format, locale=self.locale)
375b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
376b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def format_datetime(self, datetime=None, format=None, rebase=True):
377b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns a date and time formatted according to the given pattern
378b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        and following the current locale and timezone.
379b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
380b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param datetime:
381b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A ``datetime`` object. If None, the current date and time in UTC
382b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            is used.
383b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param format:
384b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The format to be returned. Valid values are "short", "medium",
385b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            "long", "full" or a custom date/time pattern. Example outputs:
386b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
387b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - short:  11/10/09 4:36 PM
388b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - medium: Nov 10, 2009 4:36:05 PM
389b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - long:   November 10, 2009 4:36:05 PM +0000
390b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - full:   Tuesday, November 10, 2009 4:36:05 PM World (GMT) Time
391b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
392b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param rebase:
393b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            If True, converts the datetime to the current :attr:`timezone`.
394b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
395b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A formatted date and time in unicode.
396b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
397b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        format = self._get_format('datetime', format)
398b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
399b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        kwargs = {}
400b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if rebase:
401b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            kwargs['tzinfo'] = self.tzinfo
402b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
403b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return dates.format_datetime(datetime, format, locale=self.locale,
404b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                                     **kwargs)
405b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
406b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def format_time(self, time=None, format=None, rebase=True):
407b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns a time formatted according to the given pattern and
408b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        following the current locale and timezone.
409b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
410b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param time:
411b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A ``time`` or ``datetime`` object. If None, the current
412b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            time in UTC is used.
413b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param format:
414b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The format to be returned. Valid values are "short", "medium",
415b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            "long", "full" or a custom date/time pattern. Example outputs:
416b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
417b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - short:  4:36 PM
418b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - medium: 4:36:05 PM
419b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - long:   4:36:05 PM +0000
420b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            - full:   4:36:05 PM World (GMT) Time
421b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
422b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param rebase:
423b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            If True, converts the time to the current :attr:`timezone`.
424b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
425b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A formatted time in unicode.
426b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
427b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        format = self._get_format('time', format)
428b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
429b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        kwargs = {}
430b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if rebase:
431b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            kwargs['tzinfo'] = self.tzinfo
432b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
433b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return dates.format_time(time, format, locale=self.locale, **kwargs)
434b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
435b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def format_timedelta(self, datetime_or_timedelta, granularity='second',
436b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                         threshold=.85):
437b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Formats the elapsed time from the given date to now or the given
438b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        timedelta. This currently requires an unreleased development version
439b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        of Babel.
440b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
441b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param datetime_or_timedelta:
442b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A ``timedelta`` object representing the time difference to format,
443b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            or a ``datetime`` object in UTC.
444b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param granularity:
445b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Determines the smallest unit that should be displayed, the value
446b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            can be one of "year", "month", "week", "day", "hour", "minute" or
447b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            "second".
448b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param threshold:
449b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Factor that determines at which point the presentation switches to
450b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            the next higher unit.
451b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
452b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            A string with the elapsed time.
453b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
454b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if isinstance(datetime_or_timedelta, datetime.datetime):
455b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            datetime_or_timedelta = datetime.datetime.utcnow() - \
456b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                datetime_or_timedelta
457b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
458b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return dates.format_timedelta(datetime_or_timedelta, granularity,
459b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                                      threshold=threshold,
460b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                                      locale=self.locale)
461b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
462b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def format_number(self, number):
463b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns the given number formatted for the current locale. Example::
464b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
465b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_number(1099, locale='en_US')
466b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'1,099'
467b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
468b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param number:
469b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The number to format.
470b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
471b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The formatted number.
472b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
473b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return numbers.format_number(number, locale=self.locale)
474b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
475b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def format_decimal(self, number, format=None):
476b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns the given decimal number formatted for the current locale.
477b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Example::
478b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
479b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_decimal(1.2345, locale='en_US')
480b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'1.234'
481b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_decimal(1.2346, locale='en_US')
482b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'1.235'
483b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_decimal(-1.2346, locale='en_US')
484b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'-1.235'
485b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_decimal(1.2345, locale='sv_SE')
486b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'1,234'
487b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_decimal(12345, locale='de')
488b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'12.345'
489b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
490b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The appropriate thousands grouping and the decimal separator are used
491b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for each locale::
492b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
493b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_decimal(12345.5, locale='en_US')
494b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'12,345.5'
495b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
496b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param number:
497b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The number to format.
498b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param format:
499b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Notation format.
500b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
501b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The formatted decimal number.
502b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
503b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return numbers.format_decimal(number, format=format,
504b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                                      locale=self.locale)
505b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
506b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def format_currency(self, number, currency, format=None):
507b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns a formatted currency value. Example::
508b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
509b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_currency(1099.98, 'USD', locale='en_US')
510b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'$1,099.98'
511b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_currency(1099.98, 'USD', locale='es_CO')
512b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'US$\\xa01.099,98'
513b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_currency(1099.98, 'EUR', locale='de_DE')
514b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'1.099,98\\xa0\\u20ac'
515b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
516b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The pattern can also be specified explicitly::
517b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
518b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_currency(1099.98, 'EUR', u'\\xa4\\xa4 #,##0.00',
519b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            ...                 locale='en_US')
520b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'EUR 1,099.98'
521b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
522b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param number:
523b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The number to format.
524b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param currency:
525b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The currency code.
526b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param format:
527b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Notation format.
528b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
529b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The formatted currency value.
530b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
531b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return numbers.format_currency(number, currency, format=format,
532b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                                       locale=self.locale)
533b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
534b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def format_percent(self, number, format=None):
535b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns formatted percent value for the current locale. Example::
536b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
537b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_percent(0.34, locale='en_US')
538b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'34%'
539b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_percent(25.1234, locale='en_US')
540b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'2,512%'
541b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_percent(25.1234, locale='sv_SE')
542b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'2\\xa0512\\xa0%'
543b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
544b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The format pattern can also be specified explicitly::
545b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
546b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_percent(25.1234, u'#,##0\u2030', locale='en_US')
547b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'25,123\u2030'
548b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
549b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param number:
550b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The percent number to format
551b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param format:
552b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Notation format.
553b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
554b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The formatted percent number.
555b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
556b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return numbers.format_percent(number, format=format,
557b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                                      locale=self.locale)
558b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
559b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def format_scientific(self, number, format=None):
560b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns value formatted in scientific notation for the current
561b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        locale. Example::
562b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
563b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_scientific(10000, locale='en_US')
564b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'1E4'
565b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
566b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The format pattern can also be specified explicitly::
567b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
568b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> format_scientific(1234567, u'##0E00', locale='en_US')
569b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'1.23E06'
570b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
571b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param number:
572b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The number to format.
573b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param format:
574b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Notation format.
575b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
576b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Value formatted in scientific notation.
577b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
578b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return numbers.format_scientific(number, format=format,
579b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                                         locale=self.locale)
580b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
581b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def parse_date(self, string):
582b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Parses a date from a string.
583b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
584b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        This function uses the date format for the locale as a hint to
585b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        determine the order in which the date fields appear in the string.
586b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Example::
587b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
588b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> parse_date('4/1/04', locale='en_US')
589b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            datetime.date(2004, 4, 1)
590b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> parse_date('01.04.2004', locale='de_DE')
591b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            datetime.date(2004, 4, 1)
592b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
593b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param string:
594b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The string containing the date.
595b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
596b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The parsed date object.
597b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
598b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return dates.parse_date(string, locale=self.locale)
599b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
600b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def parse_datetime(self, string):
601b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Parses a date and time from a string.
602b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
603b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        This function uses the date and time formats for the locale as a hint
604b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        to determine the order in which the time fields appear in the string.
605b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
606b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param string:
607b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The string containing the date and time.
608b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
609b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The parsed datetime object.
610b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
611b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return dates.parse_datetime(string, locale=self.locale)
612b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
613b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def parse_time(self, string):
614b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Parses a time from a string.
615b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
616b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        This function uses the time format for the locale as a hint to
617b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        determine the order in which the time fields appear in the string.
618b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Example::
619b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
620b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> parse_time('15:30:00', locale='en_US')
621b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            datetime.time(15, 30)
622b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
623b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param string:
624b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The string containing the time.
625b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
626b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The parsed time object.
627b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
628b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return dates.parse_time(string, locale=self.locale)
629b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
630b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def parse_number(self, string):
631b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Parses localized number string into a long integer. Example::
632b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
633b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> parse_number('1,099', locale='en_US')
634b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            1099L
635b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> parse_number('1.099', locale='de_DE')
636b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            1099L
637b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
638b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        When the given string cannot be parsed, an exception is raised::
639b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
640b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> parse_number('1.099,98', locale='de')
641b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Traceback (most recent call last):
642b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik               ...
643b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            NumberFormatError: '1.099,98' is not a valid number
644b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
645b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param string:
646b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The string to parse.
647b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
648b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The parsed number.
649b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :raises:
650b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            ``NumberFormatError`` if the string can not be converted to a
651b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            number.
652b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
653b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return numbers.parse_number(string, locale=self.locale)
654b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
655b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def parse_decimal(self, string):
656b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Parses localized decimal string into a float. Example::
657b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
658b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> parse_decimal('1,099.98', locale='en_US')
659b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            1099.98
660b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> parse_decimal('1.099,98', locale='de')
661b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            1099.98
662b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
663b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        When the given string cannot be parsed, an exception is raised::
664b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
665b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> parse_decimal('2,109,998', locale='de')
666b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            Traceback (most recent call last):
667b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik               ...
668b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            NumberFormatError: '2,109,998' is not a valid decimal number
669b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
670b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param string:
671b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The string to parse.
672b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
673b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The parsed decimal number.
674b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :raises:
675b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            ``NumberFormatError`` if the string can not be converted to a
676b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            decimal number.
677b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
678b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return numbers.parse_decimal(string, locale=self.locale)
679b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
680b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def get_timezone_location(self, dt_or_tzinfo):
681b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """Returns a representation of the given timezone using "location
682b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        format".
683b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
684b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The result depends on both the local display name of the country and
685b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        the city assocaited with the time zone::
686b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
687b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> from pytz import timezone
688b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> tz = timezone('America/St_Johns')
689b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> get_timezone_location(tz, locale='de_DE')
690b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u"Kanada (St. John's)"
691b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> tz = timezone('America/Mexico_City')
692b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> get_timezone_location(tz, locale='de_DE')
693b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'Mexiko (Mexiko-Stadt)'
694b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
695b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        If the timezone is associated with a country that uses only a single
696b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        timezone, just the localized country name is returned::
697b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
698b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> tz = timezone('Europe/Berlin')
699b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            >>> get_timezone_name(tz, locale='de_DE')
700b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            u'Deutschland'
701b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
702b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :param dt_or_tzinfo:
703b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The ``datetime`` or ``tzinfo`` object that determines
704b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            the timezone; if None, the current date and time in UTC is assumed.
705b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        :returns:
706b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            The localized timezone name using location format.
707b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
708b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return dates.get_timezone_name(dt_or_tzinfo, locale=self.locale)
709b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
710b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
711b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef gettext(string, **variables):
712b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.gettext`."""
713b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().gettext(string, **variables)
714b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
715b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
716b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef ngettext(singular, plural, n, **variables):
717b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.ngettext`."""
718b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().ngettext(singular, plural, n, **variables)
719b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
720b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
721b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef to_local_timezone(datetime):
722b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.to_local_timezone`."""
723b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().to_local_timezone(datetime)
724b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
725b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
726b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef to_utc(datetime):
727b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.to_utc`."""
728b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().to_utc(datetime)
729b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
730b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
731b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef format_date(date=None, format=None, rebase=True):
732b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.format_date`."""
733b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().format_date(date, format, rebase)
734b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
735b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
736b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef format_datetime(datetime=None, format=None, rebase=True):
737b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.format_datetime`."""
738b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().format_datetime(datetime, format, rebase)
739b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
740b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
741b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef format_time(time=None, format=None, rebase=True):
742b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.format_time`."""
743b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().format_time(time, format, rebase)
744b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
745b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
746b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef format_timedelta(datetime_or_timedelta, granularity='second',
747b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    threshold=.85):
748b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.format_timedelta`."""
749b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().format_timedelta(datetime_or_timedelta,
750b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                                       granularity, threshold)
751b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
752b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
753b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef format_number(number):
754b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.format_number`."""
755b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().format_number(number)
756b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
757b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
758b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef format_decimal(number, format=None):
759b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.format_decimal`."""
760b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().format_decimal(number, format)
761b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
762b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
763b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef format_currency(number, currency, format=None):
764b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.format_currency`."""
765b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().format_currency(number, currency, format)
766b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
767b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
768b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef format_percent(number, format=None):
769b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.format_percent`."""
770b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().format_percent(number, format)
771b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
772b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
773b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef format_scientific(number, format=None):
774b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.format_scientific`."""
775b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().format_scientific(number, format)
776b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
777b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
778b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef parse_date(string):
779b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.parse_date`"""
780b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().parse_date(string)
781b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
782b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
783b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef parse_datetime(string):
784b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.parse_datetime`."""
785b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().parse_datetime(string)
786b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
787b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
788b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef parse_time(string):
789b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.parse_time`."""
790b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().parse_time(string)
791b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
792b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
793b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef parse_number(string):
794b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.parse_number`."""
795b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().parse_number(string)
796b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
797b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
798b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef parse_decimal(string):
799b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.parse_decimal`."""
800b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().parse_decimal(string)
801b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
802b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
803b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef get_timezone_location(dt_or_tzinfo):
804b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """See :meth:`I18n.get_timezone_location`."""
805b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return get_i18n().get_timezone_location(dt_or_tzinfo)
806b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
807b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
808b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef lazy_gettext(string, **variables):
809b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """A lazy version of :func:`gettext`.
810b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
811b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param string:
812b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The string to be translated.
813b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param variables:
814b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Variables to format the returned string.
815b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :returns:
816b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        A ``babel.support.LazyProxy`` object that when accessed translates
817b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        the string.
818b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
819b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return support.LazyProxy(gettext, string, **variables)
820b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
821b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
822b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# Aliases.
823b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik_ = gettext
824b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik_lazy = lazy_gettext
825b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
826b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
827b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# Factories -------------------------------------------------------------------
828b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
829b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
830b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#: Key used to store :class:`I18nStore` in the app registry.
831b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik_store_registry_key = 'webapp2_extras.i18n.I18nStore'
832b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#: Key used to store :class:`I18n` in the request registry.
833b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik_i18n_registry_key = 'webapp2_extras.i18n.I18n'
834b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
835b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
836b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef get_store(factory=I18nStore, key=_store_registry_key, app=None):
837b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Returns an instance of :class:`I18nStore` from the app registry.
838b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
839b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    It'll try to get it from the current app registry, and if it is not
840b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    registered it'll be instantiated and registered. A second call to this
841b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    function will return the same instance.
842b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
843b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param factory:
844b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The callable used to build and register the instance if it is not yet
845b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        registered. The default is the class :class:`I18nStore` itself.
846b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param key:
847b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The key used to store the instance in the registry. A default is used
848b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if it is not set.
849b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param app:
850b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        A :class:`webapp2.WSGIApplication` instance used to store the instance.
851b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The active app is used if it is not set.
852b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
853b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    app = app or webapp2.get_app()
854b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    store = app.registry.get(key)
855b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if not store:
856b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        store = app.registry[key] = factory(app)
857b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
858b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return store
859b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
860b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
861b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef set_store(store, key=_store_registry_key, app=None):
862b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Sets an instance of :class:`I18nStore` in the app registry.
863b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
864b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param store:
865b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        An instance of :class:`I18nStore`.
866b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param key:
867b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The key used to retrieve the instance from the registry. A default
868b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        is used if it is not set.
869b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param request:
870b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        A :class:`webapp2.WSGIApplication` instance used to retrieve the
871b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        instance. The active app is used if it is not set.
872b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
873b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    app = app or webapp2.get_app()
874b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    app.registry[key] = store
875b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
876b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
877b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef get_i18n(factory=I18n, key=_i18n_registry_key, request=None):
878b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Returns an instance of :class:`I18n` from the request registry.
879b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
880b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    It'll try to get it from the current request registry, and if it is not
881b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    registered it'll be instantiated and registered. A second call to this
882b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    function will return the same instance.
883b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
884b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param factory:
885b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The callable used to build and register the instance if it is not yet
886b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        registered. The default is the class :class:`I18n` itself.
887b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param key:
888b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The key used to store the instance in the registry. A default is used
889b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if it is not set.
890b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param request:
891b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        A :class:`webapp2.Request` instance used to store the instance. The
892b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        active request is used if it is not set.
893b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
894b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    request = request or webapp2.get_request()
895b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    i18n = request.registry.get(key)
896b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if not i18n:
897b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        i18n = request.registry[key] = factory(request)
898b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
899b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    return i18n
900b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
901b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
902b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef set_i18n(i18n, key=_i18n_registry_key, request=None):
903b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """Sets an instance of :class:`I18n` in the request registry.
904b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
905b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param store:
906b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        An instance of :class:`I18n`.
907b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param key:
908b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        The key used to retrieve the instance from the registry. A default
909b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        is used if it is not set.
910b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    :param request:
911b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        A :class:`webapp2.Request` instance used to retrieve the instance. The
912b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        active request is used if it is not set.
913b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
914b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    request = request or webapp2.get_request()
915b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    request.registry[key] = i18n
916