We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
provide a way to browse/search teams
I want to be able to easily find teams to contribute to.

<bountysource-plugin>

---

Want to back this issue? **[Place a bounty on it!](https://www.bountysource.com/issues/950213-gittip-com-teams?utm_campaign=plugin&utm_content=tracker%2F85909&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F85909&utm_medium=issues&utm_source=github).
</bountysource-plugin>


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `gratipay/utils/i18n.py`
Content:
```
1 # encoding: utf8
2 from __future__ import print_function, unicode_literals
3 
4 from io import BytesIO
5 import re
6 from unicodedata import combining, normalize
7 
8 from aspen.resources.pagination import parse_specline, split_and_escape
9 from aspen.utils import utcnow
10 from babel.core import LOCALE_ALIASES, Locale
11 from babel.dates import format_timedelta
12 from babel.messages.extract import extract_python
13 from babel.messages.pofile import Catalog
14 from babel.numbers import (
15     format_currency, format_decimal, format_number, format_percent,
16     get_decimal_symbol, parse_decimal
17 )
18 from collections import OrderedDict
19 import jinja2.ext
20 
21 
22 ALIASES = {k: v.lower() for k, v in LOCALE_ALIASES.items()}
23 ALIASES_R = {v: k for k, v in ALIASES.items()}
24 
25 
26 def strip_accents(s):
27     return ''.join(c for c in normalize('NFKD', s) if not combining(c))
28 
29 
30 def make_sorted_dict(keys, d):
31     items = ((k, d[k]) for k in keys)
32     return OrderedDict(sorted(items, key=lambda t: strip_accents(t[1])))
33 
34 
35 COUNTRY_CODES = """
36     AD AE AF AG AI AL AM AO AQ AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ
37     BL BM BN BO BQ BR BS BT BV BW BY BZ CA CC CD CF CG CH CI CK CL CM CN CO CR
38     CU CV CW CX CY CZ DE DJ DK DM DO DZ EC EE EG EH ER ES ET FI FJ FK FM FO FR
39     GA GB GD GE GF GG GH GI GL GM GN GP GQ GR GS GT GU GW GY HK HM HN HR HT HU
40     ID IE IL IM IN IO IQ IR IS IT JE JM JO JP KE KG KH KI KM KN KP KR KW KY KZ
41     LA LB LC LI LK LR LS LT LU LV LY MA MC MD ME MF MG MH MK ML MM MN MO MP MQ
42     MR MS MT MU MV MW MX MY MZ NA NC NE NF NG NI NL NO NP NR NU NZ OM PA PE PF
43     PG PH PK PL PM PN PR PS PT PW PY QA RE RO RS RU RW SA SB SC SD SE SG SH SI
44     SJ SK SL SM SN SO SR SS ST SV SX SY SZ TC TD TF TG TH TJ TK TL TM TN TO TR
45     TT TV TW TZ UA UG UM US UY UZ VA VC VE VG VI VN VU WF WS YE YT ZA ZM ZW
46 """.split()
47 
48 COUNTRIES = make_sorted_dict(COUNTRY_CODES, Locale('en').territories)
49 
50 LANGUAGE_CODES_2 = """
51     aa af ak am ar as az be bg bm bn bo br bs ca cs cy da de dz ee el en eo es
52     et eu fa ff fi fo fr ga gd gl gu gv ha he hi hr hu hy ia id ig ii is it ja
53     ka ki kk kl km kn ko ks kw ky lg ln lo lt lu lv mg mk ml mn mr ms mt my nb
54     nd ne nl nn nr om or os pa pl ps pt rm rn ro ru rw se sg si sk sl sn so sq
55     sr ss st sv sw ta te tg th ti tn to tr ts uk ur uz ve vi vo xh yo zh zu
56 """.split()
57 
58 LANGUAGES_2 = make_sorted_dict(LANGUAGE_CODES_2, Locale('en').languages)
59 
60 LOCALES = {}
61 LOCALE_EN = LOCALES['en'] = Locale('en')
62 LOCALE_EN.catalog = Catalog('en')
63 LOCALE_EN.catalog.plural_func = lambda n: n != 1
64 LOCALE_EN.countries = COUNTRIES
65 LOCALE_EN.languages_2 = LANGUAGES_2
66 
67 
68 SEARCH_CONFS = dict((
69     ('da', 'danish'),
70     ('de', 'german'),
71     ('en', 'english'),
72     ('es', 'spanish'),
73     ('fi', 'finnish'),
74     ('fr', 'french'),
75     ('hu', 'hungarian'),
76     ('it', 'italian'),
77     ('nb', 'norwegian'),
78     ('nl', 'dutch'),
79     ('nn', 'norwegian'),
80     ('pt', 'portuguese'),
81     ('ro', 'romanian'),
82     ('ru', 'russian'),
83     ('sv', 'swedish'),
84     ('tr', 'turkish'),
85 ))
86 
87 
88 ternary_re = re.compile(r'^\(? *(.+?) *\? *(.+?) *: *(.+?) *\)?$')
89 and_re = re.compile(r' *&& *')
90 or_re = re.compile(r' *\|\| *')
91 
92 
93 def ternary_sub(m):
94     g1, g2, g3 = m.groups()
95     return '%s if %s else %s' % (g2, g1, ternary_re.sub(ternary_sub, g3))
96 
97 
98 def get_function_from_rule(rule):
99     rule = ternary_re.sub(ternary_sub, rule.strip())
100     rule = and_re.sub(' and ', rule)
101     rule = or_re.sub(' or ', rule)
102     return eval('lambda n: ' + rule, {'__builtins__': {}})
103 
104 
105 def get_text(context, loc, s, *a, **kw):
106     escape = context['escape']
107     msg = loc.catalog.get(s)
108     if msg:
109         s = msg.string or s
110     if a or kw:
111         if isinstance(s, bytes):
112             s = s.decode('ascii')
113         return escape(s).format(*a, **kw)
114     return escape(s)
115 
116 
117 def n_get_text(tell_sentry, context, loc, s, p, n, *a, **kw):
118     escape = context['escape']
119     n = n or 0
120     msg = loc.catalog.get((s, p))
121     s2 = None
122     if msg:
123         try:
124             s2 = msg.string[loc.catalog.plural_func(n)]
125         except Exception as e:
126             tell_sentry(e, context.get('request'))
127     if not s2:
128         loc = 'en'
129         s2 = s if n == 1 else p
130     kw['n'] = format_number(n, locale=loc) or n
131     if isinstance(s2, bytes):
132         s2 = s2.decode('ascii')
133     return escape(s2).format(*a, **kw)
134 
135 
136 def to_age(dt, loc, **kw):
137     return format_timedelta(dt - utcnow(), locale=loc, **kw)
138 
139 
140 def regularize_locale(loc):
141     if loc == 'no':
142 
143         # There are two forms of written Norwegian, Bokmål and Nynorsk, and
144         # while ISO 639 includes `no` as a "macrolanguage", the CLDR (upon
145         # which Babel, our i18n/l10n library, depends), does not include it at
146         # all. Therefore, if a client sends `no` we interpret it as `nb_NO`.
147 
148         loc = 'nb_NO'
149     return loc.replace('-', '_').lower()
150 
151 
152 def regularize_locales(locales):
153     """Yield locale strings in the same format as they are in LOCALES.
154     """
155     locales = [regularize_locale(loc) for loc in locales]
156     locales_set = set(locales)
157     for loc in locales:
158         yield loc
159         parts = loc.split('_')
160         if len(parts) > 1 and parts[0] not in locales_set:
161             # Insert "fr" after "fr_fr" if it's not somewhere in the list
162             yield parts[0]
163         alias = ALIASES.get(loc)
164         if alias and alias not in locales_set:
165             # Insert "fr_fr" after "fr" if it's not somewhere in the list
166             yield alias
167     if 'en' not in locales_set and 'en_us' not in locales_set:
168         yield 'en'
169         yield 'en_us'
170 
171 
172 def parse_accept_lang(accept_lang):
173     languages = (lang.split(";", 1)[0] for lang in accept_lang.split(","))
174     return regularize_locales(languages)
175 
176 
177 def match_lang(languages):
178     for lang in languages:
179         loc = LOCALES.get(lang)
180         if loc:
181             return loc
182     return LOCALE_EN
183 
184 
185 def format_currency_with_options(number, currency, locale='en', trailing_zeroes=True):
186     s = format_currency(number, currency, locale=locale)
187     if not trailing_zeroes:
188         s = s.replace(get_decimal_symbol(locale)+'00', '')
189     return s
190 
191 
192 def set_up_i18n(website, request):
193     accept_lang = request.headers.get("Accept-Language", "")
194     langs = request.accept_langs = list(parse_accept_lang(accept_lang))
195     loc = match_lang(langs)
196     add_helpers_to_context(website.tell_sentry, request.context, loc, request)
197 
198 
199 def add_helpers_to_context(tell_sentry, context, loc, request=None):
200     context['escape'] = lambda s: s  # to be overriden by renderers
201     context['locale'] = loc
202     context['decimal_symbol'] = get_decimal_symbol(locale=loc)
203     context['_'] = lambda s, *a, **kw: get_text(context, loc, s, *a, **kw)
204     context['ngettext'] = lambda *a, **kw: n_get_text(tell_sentry, context, loc, *a, **kw)
205     context['format_number'] = lambda *a: format_number(*a, locale=loc)
206     context['format_decimal'] = lambda *a: format_decimal(*a, locale=loc)
207     context['format_currency'] = lambda *a, **kw: format_currency_with_options(*a, locale=loc, **kw)
208     context['format_percent'] = lambda *a: format_percent(*a, locale=loc)
209     context['parse_decimal'] = lambda *a: parse_decimal(*a, locale=loc)
210     def _to_age(delta, **kw):
211         try:
212             return to_age(delta, loc, **kw)
213         except:
214             return to_age(delta, 'en', **kw)
215     context['to_age'] = _to_age
216 
217 
218 def extract_spt(fileobj, *args, **kw):
219     pages = list(split_and_escape(fileobj.read()))
220     npages = len(pages)
221     for i, page in enumerate(pages, 1):
222         f = BytesIO(b'\n' * page.offset + page.content)
223         content_type, renderer = parse_specline(page.header)
224         extractor = None
225         if (i == npages and not page.header) or content_type in ('text/html', 'text/plain'):
226             extractor = jinja2.ext.babel_extract
227         elif i < 3:
228             extractor = extract_python
229         if extractor:
230             for match in extractor(f, *args, **kw):
231                 yield match
232
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/gratipay/utils/i18n.py b/gratipay/utils/i18n.py
--- a/gratipay/utils/i18n.py
+++ b/gratipay/utils/i18n.py
@@ -182,8 +182,8 @@
     return LOCALE_EN
 
 
-def format_currency_with_options(number, currency, locale='en', trailing_zeroes=True):
-    s = format_currency(number, currency, locale=locale)
+def format_currency_with_options(number, currency, format=None, locale='en', trailing_zeroes=True):
+    s = format_currency(number, currency, format, locale=locale)
     if not trailing_zeroes:
         s = s.replace(get_decimal_symbol(locale)+'00', '')
     return s

{"golden_diff": "diff --git a/gratipay/utils/i18n.py b/gratipay/utils/i18n.py\n--- a/gratipay/utils/i18n.py\n+++ b/gratipay/utils/i18n.py\n@@ -182,8 +182,8 @@\n     return LOCALE_EN\n \n \n-def format_currency_with_options(number, currency, locale='en', trailing_zeroes=True):\n-    s = format_currency(number, currency, locale=locale)\n+def format_currency_with_options(number, currency, format=None, locale='en', trailing_zeroes=True):\n+    s = format_currency(number, currency, format, locale=locale)\n     if not trailing_zeroes:\n         s = s.replace(get_decimal_symbol(locale)+'00', '')\n     return s\n", "issue": "provide a way to browse/search teams\nI want to be able to easily find teams to contribute to.\n\n<bountysource-plugin>\n\n---\n\nWant to back this issue? **[Place a bounty on it!](https://www.bountysource.com/issues/950213-gittip-com-teams?utm_campaign=plugin&utm_content=tracker%2F85909&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F85909&utm_medium=issues&utm_source=github).\n</bountysource-plugin>\n\n", "before_files": [{"content": "# encoding: utf8\nfrom __future__ import print_function, unicode_literals\n\nfrom io import BytesIO\nimport re\nfrom unicodedata import combining, normalize\n\nfrom aspen.resources.pagination import parse_specline, split_and_escape\nfrom aspen.utils import utcnow\nfrom babel.core import LOCALE_ALIASES, Locale\nfrom babel.dates import format_timedelta\nfrom babel.messages.extract import extract_python\nfrom babel.messages.pofile import Catalog\nfrom babel.numbers import (\n    format_currency, format_decimal, format_number, format_percent,\n    get_decimal_symbol, parse_decimal\n)\nfrom collections import OrderedDict\nimport jinja2.ext\n\n\nALIASES = {k: v.lower() for k, v in LOCALE_ALIASES.items()}\nALIASES_R = {v: k for k, v in ALIASES.items()}\n\n\ndef strip_accents(s):\n    return ''.join(c for c in normalize('NFKD', s) if not combining(c))\n\n\ndef make_sorted_dict(keys, d):\n    items = ((k, d[k]) for k in keys)\n    return OrderedDict(sorted(items, key=lambda t: strip_accents(t[1])))\n\n\nCOUNTRY_CODES = \"\"\"\n    AD AE AF AG AI AL AM AO AQ AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ\n    BL BM BN BO BQ BR BS BT BV BW BY BZ CA CC CD CF CG CH CI CK CL CM CN CO CR\n    CU CV CW CX CY CZ DE DJ DK DM DO DZ EC EE EG EH ER ES ET FI FJ FK FM FO FR\n    GA GB GD GE GF GG GH GI GL GM GN GP GQ GR GS GT GU GW GY HK HM HN HR HT HU\n    ID IE IL IM IN IO IQ IR IS IT JE JM JO JP KE KG KH KI KM KN KP KR KW KY KZ\n    LA LB LC LI LK LR LS LT LU LV LY MA MC MD ME MF MG MH MK ML MM MN MO MP MQ\n    MR MS MT MU MV MW MX MY MZ NA NC NE NF NG NI NL NO NP NR NU NZ OM PA PE PF\n    PG PH PK PL PM PN PR PS PT PW PY QA RE RO RS RU RW SA SB SC SD SE SG SH SI\n    SJ SK SL SM SN SO SR SS ST SV SX SY SZ TC TD TF TG TH TJ TK TL TM TN TO TR\n    TT TV TW TZ UA UG UM US UY UZ VA VC VE VG VI VN VU WF WS YE YT ZA ZM ZW\n\"\"\".split()\n\nCOUNTRIES = make_sorted_dict(COUNTRY_CODES, Locale('en').territories)\n\nLANGUAGE_CODES_2 = \"\"\"\n    aa af ak am ar as az be bg bm bn bo br bs ca cs cy da de dz ee el en eo es\n    et eu fa ff fi fo fr ga gd gl gu gv ha he hi hr hu hy ia id ig ii is it ja\n    ka ki kk kl km kn ko ks kw ky lg ln lo lt lu lv mg mk ml mn mr ms mt my nb\n    nd ne nl nn nr om or os pa pl ps pt rm rn ro ru rw se sg si sk sl sn so sq\n    sr ss st sv sw ta te tg th ti tn to tr ts uk ur uz ve vi vo xh yo zh zu\n\"\"\".split()\n\nLANGUAGES_2 = make_sorted_dict(LANGUAGE_CODES_2, Locale('en').languages)\n\nLOCALES = {}\nLOCALE_EN = LOCALES['en'] = Locale('en')\nLOCALE_EN.catalog = Catalog('en')\nLOCALE_EN.catalog.plural_func = lambda n: n != 1\nLOCALE_EN.countries = COUNTRIES\nLOCALE_EN.languages_2 = LANGUAGES_2\n\n\nSEARCH_CONFS = dict((\n    ('da', 'danish'),\n    ('de', 'german'),\n    ('en', 'english'),\n    ('es', 'spanish'),\n    ('fi', 'finnish'),\n    ('fr', 'french'),\n    ('hu', 'hungarian'),\n    ('it', 'italian'),\n    ('nb', 'norwegian'),\n    ('nl', 'dutch'),\n    ('nn', 'norwegian'),\n    ('pt', 'portuguese'),\n    ('ro', 'romanian'),\n    ('ru', 'russian'),\n    ('sv', 'swedish'),\n    ('tr', 'turkish'),\n))\n\n\nternary_re = re.compile(r'^\\(? *(.+?) *\\? *(.+?) *: *(.+?) *\\)?$')\nand_re = re.compile(r' *&& *')\nor_re = re.compile(r' *\\|\\| *')\n\n\ndef ternary_sub(m):\n    g1, g2, g3 = m.groups()\n    return '%s if %s else %s' % (g2, g1, ternary_re.sub(ternary_sub, g3))\n\n\ndef get_function_from_rule(rule):\n    rule = ternary_re.sub(ternary_sub, rule.strip())\n    rule = and_re.sub(' and ', rule)\n    rule = or_re.sub(' or ', rule)\n    return eval('lambda n: ' + rule, {'__builtins__': {}})\n\n\ndef get_text(context, loc, s, *a, **kw):\n    escape = context['escape']\n    msg = loc.catalog.get(s)\n    if msg:\n        s = msg.string or s\n    if a or kw:\n        if isinstance(s, bytes):\n            s = s.decode('ascii')\n        return escape(s).format(*a, **kw)\n    return escape(s)\n\n\ndef n_get_text(tell_sentry, context, loc, s, p, n, *a, **kw):\n    escape = context['escape']\n    n = n or 0\n    msg = loc.catalog.get((s, p))\n    s2 = None\n    if msg:\n        try:\n            s2 = msg.string[loc.catalog.plural_func(n)]\n        except Exception as e:\n            tell_sentry(e, context.get('request'))\n    if not s2:\n        loc = 'en'\n        s2 = s if n == 1 else p\n    kw['n'] = format_number(n, locale=loc) or n\n    if isinstance(s2, bytes):\n        s2 = s2.decode('ascii')\n    return escape(s2).format(*a, **kw)\n\n\ndef to_age(dt, loc, **kw):\n    return format_timedelta(dt - utcnow(), locale=loc, **kw)\n\n\ndef regularize_locale(loc):\n    if loc == 'no':\n\n        # There are two forms of written Norwegian, Bokm\u00e5l and Nynorsk, and\n        # while ISO 639 includes `no` as a \"macrolanguage\", the CLDR (upon\n        # which Babel, our i18n/l10n library, depends), does not include it at\n        # all. Therefore, if a client sends `no` we interpret it as `nb_NO`.\n\n        loc = 'nb_NO'\n    return loc.replace('-', '_').lower()\n\n\ndef regularize_locales(locales):\n    \"\"\"Yield locale strings in the same format as they are in LOCALES.\n    \"\"\"\n    locales = [regularize_locale(loc) for loc in locales]\n    locales_set = set(locales)\n    for loc in locales:\n        yield loc\n        parts = loc.split('_')\n        if len(parts) > 1 and parts[0] not in locales_set:\n            # Insert \"fr\" after \"fr_fr\" if it's not somewhere in the list\n            yield parts[0]\n        alias = ALIASES.get(loc)\n        if alias and alias not in locales_set:\n            # Insert \"fr_fr\" after \"fr\" if it's not somewhere in the list\n            yield alias\n    if 'en' not in locales_set and 'en_us' not in locales_set:\n        yield 'en'\n        yield 'en_us'\n\n\ndef parse_accept_lang(accept_lang):\n    languages = (lang.split(\";\", 1)[0] for lang in accept_lang.split(\",\"))\n    return regularize_locales(languages)\n\n\ndef match_lang(languages):\n    for lang in languages:\n        loc = LOCALES.get(lang)\n        if loc:\n            return loc\n    return LOCALE_EN\n\n\ndef format_currency_with_options(number, currency, locale='en', trailing_zeroes=True):\n    s = format_currency(number, currency, locale=locale)\n    if not trailing_zeroes:\n        s = s.replace(get_decimal_symbol(locale)+'00', '')\n    return s\n\n\ndef set_up_i18n(website, request):\n    accept_lang = request.headers.get(\"Accept-Language\", \"\")\n    langs = request.accept_langs = list(parse_accept_lang(accept_lang))\n    loc = match_lang(langs)\n    add_helpers_to_context(website.tell_sentry, request.context, loc, request)\n\n\ndef add_helpers_to_context(tell_sentry, context, loc, request=None):\n    context['escape'] = lambda s: s  # to be overriden by renderers\n    context['locale'] = loc\n    context['decimal_symbol'] = get_decimal_symbol(locale=loc)\n    context['_'] = lambda s, *a, **kw: get_text(context, loc, s, *a, **kw)\n    context['ngettext'] = lambda *a, **kw: n_get_text(tell_sentry, context, loc, *a, **kw)\n    context['format_number'] = lambda *a: format_number(*a, locale=loc)\n    context['format_decimal'] = lambda *a: format_decimal(*a, locale=loc)\n    context['format_currency'] = lambda *a, **kw: format_currency_with_options(*a, locale=loc, **kw)\n    context['format_percent'] = lambda *a: format_percent(*a, locale=loc)\n    context['parse_decimal'] = lambda *a: parse_decimal(*a, locale=loc)\n    def _to_age(delta, **kw):\n        try:\n            return to_age(delta, loc, **kw)\n        except:\n            return to_age(delta, 'en', **kw)\n    context['to_age'] = _to_age\n\n\ndef extract_spt(fileobj, *args, **kw):\n    pages = list(split_and_escape(fileobj.read()))\n    npages = len(pages)\n    for i, page in enumerate(pages, 1):\n        f = BytesIO(b'\\n' * page.offset + page.content)\n        content_type, renderer = parse_specline(page.header)\n        extractor = None\n        if (i == npages and not page.header) or content_type in ('text/html', 'text/plain'):\n            extractor = jinja2.ext.babel_extract\n        elif i < 3:\n            extractor = extract_python\n        if extractor:\n            for match in extractor(f, *args, **kw):\n                yield match\n", "path": "gratipay/utils/i18n.py"}], "after_files": [{"content": "# encoding: utf8\nfrom __future__ import print_function, unicode_literals\n\nfrom io import BytesIO\nimport re\nfrom unicodedata import combining, normalize\n\nfrom aspen.resources.pagination import parse_specline, split_and_escape\nfrom aspen.utils import utcnow\nfrom babel.core import LOCALE_ALIASES, Locale\nfrom babel.dates import format_timedelta\nfrom babel.messages.extract import extract_python\nfrom babel.messages.pofile import Catalog\nfrom babel.numbers import (\n    format_currency, format_decimal, format_number, format_percent,\n    get_decimal_symbol, parse_decimal\n)\nfrom collections import OrderedDict\nimport jinja2.ext\n\n\nALIASES = {k: v.lower() for k, v in LOCALE_ALIASES.items()}\nALIASES_R = {v: k for k, v in ALIASES.items()}\n\n\ndef strip_accents(s):\n    return ''.join(c for c in normalize('NFKD', s) if not combining(c))\n\n\ndef make_sorted_dict(keys, d):\n    items = ((k, d[k]) for k in keys)\n    return OrderedDict(sorted(items, key=lambda t: strip_accents(t[1])))\n\n\nCOUNTRY_CODES = \"\"\"\n    AD AE AF AG AI AL AM AO AQ AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ\n    BL BM BN BO BQ BR BS BT BV BW BY BZ CA CC CD CF CG CH CI CK CL CM CN CO CR\n    CU CV CW CX CY CZ DE DJ DK DM DO DZ EC EE EG EH ER ES ET FI FJ FK FM FO FR\n    GA GB GD GE GF GG GH GI GL GM GN GP GQ GR GS GT GU GW GY HK HM HN HR HT HU\n    ID IE IL IM IN IO IQ IR IS IT JE JM JO JP KE KG KH KI KM KN KP KR KW KY KZ\n    LA LB LC LI LK LR LS LT LU LV LY MA MC MD ME MF MG MH MK ML MM MN MO MP MQ\n    MR MS MT MU MV MW MX MY MZ NA NC NE NF NG NI NL NO NP NR NU NZ OM PA PE PF\n    PG PH PK PL PM PN PR PS PT PW PY QA RE RO RS RU RW SA SB SC SD SE SG SH SI\n    SJ SK SL SM SN SO SR SS ST SV SX SY SZ TC TD TF TG TH TJ TK TL TM TN TO TR\n    TT TV TW TZ UA UG UM US UY UZ VA VC VE VG VI VN VU WF WS YE YT ZA ZM ZW\n\"\"\".split()\n\nCOUNTRIES = make_sorted_dict(COUNTRY_CODES, Locale('en').territories)\n\nLANGUAGE_CODES_2 = \"\"\"\n    aa af ak am ar as az be bg bm bn bo br bs ca cs cy da de dz ee el en eo es\n    et eu fa ff fi fo fr ga gd gl gu gv ha he hi hr hu hy ia id ig ii is it ja\n    ka ki kk kl km kn ko ks kw ky lg ln lo lt lu lv mg mk ml mn mr ms mt my nb\n    nd ne nl nn nr om or os pa pl ps pt rm rn ro ru rw se sg si sk sl sn so sq\n    sr ss st sv sw ta te tg th ti tn to tr ts uk ur uz ve vi vo xh yo zh zu\n\"\"\".split()\n\nLANGUAGES_2 = make_sorted_dict(LANGUAGE_CODES_2, Locale('en').languages)\n\nLOCALES = {}\nLOCALE_EN = LOCALES['en'] = Locale('en')\nLOCALE_EN.catalog = Catalog('en')\nLOCALE_EN.catalog.plural_func = lambda n: n != 1\nLOCALE_EN.countries = COUNTRIES\nLOCALE_EN.languages_2 = LANGUAGES_2\n\n\nSEARCH_CONFS = dict((\n    ('da', 'danish'),\n    ('de', 'german'),\n    ('en', 'english'),\n    ('es', 'spanish'),\n    ('fi', 'finnish'),\n    ('fr', 'french'),\n    ('hu', 'hungarian'),\n    ('it', 'italian'),\n    ('nb', 'norwegian'),\n    ('nl', 'dutch'),\n    ('nn', 'norwegian'),\n    ('pt', 'portuguese'),\n    ('ro', 'romanian'),\n    ('ru', 'russian'),\n    ('sv', 'swedish'),\n    ('tr', 'turkish'),\n))\n\n\nternary_re = re.compile(r'^\\(? *(.+?) *\\? *(.+?) *: *(.+?) *\\)?$')\nand_re = re.compile(r' *&& *')\nor_re = re.compile(r' *\\|\\| *')\n\n\ndef ternary_sub(m):\n    g1, g2, g3 = m.groups()\n    return '%s if %s else %s' % (g2, g1, ternary_re.sub(ternary_sub, g3))\n\n\ndef get_function_from_rule(rule):\n    rule = ternary_re.sub(ternary_sub, rule.strip())\n    rule = and_re.sub(' and ', rule)\n    rule = or_re.sub(' or ', rule)\n    return eval('lambda n: ' + rule, {'__builtins__': {}})\n\n\ndef get_text(context, loc, s, *a, **kw):\n    escape = context['escape']\n    msg = loc.catalog.get(s)\n    if msg:\n        s = msg.string or s\n    if a or kw:\n        if isinstance(s, bytes):\n            s = s.decode('ascii')\n        return escape(s).format(*a, **kw)\n    return escape(s)\n\n\ndef n_get_text(tell_sentry, context, loc, s, p, n, *a, **kw):\n    escape = context['escape']\n    n = n or 0\n    msg = loc.catalog.get((s, p))\n    s2 = None\n    if msg:\n        try:\n            s2 = msg.string[loc.catalog.plural_func(n)]\n        except Exception as e:\n            tell_sentry(e, context.get('request'))\n    if not s2:\n        loc = 'en'\n        s2 = s if n == 1 else p\n    kw['n'] = format_number(n, locale=loc) or n\n    if isinstance(s2, bytes):\n        s2 = s2.decode('ascii')\n    return escape(s2).format(*a, **kw)\n\n\ndef to_age(dt, loc, **kw):\n    return format_timedelta(dt - utcnow(), locale=loc, **kw)\n\n\ndef regularize_locale(loc):\n    if loc == 'no':\n\n        # There are two forms of written Norwegian, Bokm\u00e5l and Nynorsk, and\n        # while ISO 639 includes `no` as a \"macrolanguage\", the CLDR (upon\n        # which Babel, our i18n/l10n library, depends), does not include it at\n        # all. Therefore, if a client sends `no` we interpret it as `nb_NO`.\n\n        loc = 'nb_NO'\n    return loc.replace('-', '_').lower()\n\n\ndef regularize_locales(locales):\n    \"\"\"Yield locale strings in the same format as they are in LOCALES.\n    \"\"\"\n    locales = [regularize_locale(loc) for loc in locales]\n    locales_set = set(locales)\n    for loc in locales:\n        yield loc\n        parts = loc.split('_')\n        if len(parts) > 1 and parts[0] not in locales_set:\n            # Insert \"fr\" after \"fr_fr\" if it's not somewhere in the list\n            yield parts[0]\n        alias = ALIASES.get(loc)\n        if alias and alias not in locales_set:\n            # Insert \"fr_fr\" after \"fr\" if it's not somewhere in the list\n            yield alias\n    if 'en' not in locales_set and 'en_us' not in locales_set:\n        yield 'en'\n        yield 'en_us'\n\n\ndef parse_accept_lang(accept_lang):\n    languages = (lang.split(\";\", 1)[0] for lang in accept_lang.split(\",\"))\n    return regularize_locales(languages)\n\n\ndef match_lang(languages):\n    for lang in languages:\n        loc = LOCALES.get(lang)\n        if loc:\n            return loc\n    return LOCALE_EN\n\n\ndef format_currency_with_options(number, currency, format=None, locale='en', trailing_zeroes=True):\n    s = format_currency(number, currency, format, locale=locale)\n    if not trailing_zeroes:\n        s = s.replace(get_decimal_symbol(locale)+'00', '')\n    return s\n\n\ndef set_up_i18n(website, request):\n    accept_lang = request.headers.get(\"Accept-Language\", \"\")\n    langs = request.accept_langs = list(parse_accept_lang(accept_lang))\n    loc = match_lang(langs)\n    add_helpers_to_context(website.tell_sentry, request.context, loc, request)\n\n\ndef add_helpers_to_context(tell_sentry, context, loc, request=None):\n    context['escape'] = lambda s: s  # to be overriden by renderers\n    context['locale'] = loc\n    context['decimal_symbol'] = get_decimal_symbol(locale=loc)\n    context['_'] = lambda s, *a, **kw: get_text(context, loc, s, *a, **kw)\n    context['ngettext'] = lambda *a, **kw: n_get_text(tell_sentry, context, loc, *a, **kw)\n    context['format_number'] = lambda *a: format_number(*a, locale=loc)\n    context['format_decimal'] = lambda *a: format_decimal(*a, locale=loc)\n    context['format_currency'] = lambda *a, **kw: format_currency_with_options(*a, locale=loc, **kw)\n    context['format_percent'] = lambda *a: format_percent(*a, locale=loc)\n    context['parse_decimal'] = lambda *a: parse_decimal(*a, locale=loc)\n    def _to_age(delta, **kw):\n        try:\n            return to_age(delta, loc, **kw)\n        except:\n            return to_age(delta, 'en', **kw)\n    context['to_age'] = _to_age\n\n\ndef extract_spt(fileobj, *args, **kw):\n    pages = list(split_and_escape(fileobj.read()))\n    npages = len(pages)\n    for i, page in enumerate(pages, 1):\n        f = BytesIO(b'\\n' * page.offset + page.content)\n        content_type, renderer = parse_specline(page.header)\n        extractor = None\n        if (i == npages and not page.header) or content_type in ('text/html', 'text/plain'):\n            extractor = jinja2.ext.babel_extract\n        elif i < 3:\n            extractor = extract_python\n        if extractor:\n            for match in extractor(f, *args, **kw):\n                yield match\n", "path": "gratipay/utils/i18n.py"}]}