| 32 | | def to_locale(language): |
|---|
| | 35 | # Format of Accept-Language header values. From RFC 2616, section 14.4 and 3.9. |
|---|
| | 36 | accept_language_re = re.compile(r''' |
|---|
| | 37 | ([A-Za-z]{1,8}(?:-[A-Za-z]{1,8})*|\*) # "en", "en-au", "x-y-z", "*" |
|---|
| | 38 | (?:;q=(0(?:\.\d{,3})?|1(?:.0{,3})?))? # Optional "q=1.00", "q=0.8" |
|---|
| | 39 | (?:\s*,\s*|$) # Multiple accepts per header. |
|---|
| | 40 | ''', re.VERBOSE) |
|---|
| | 41 | |
|---|
| | 42 | def to_locale(language, to_lower=False): |
|---|
| 304 | | accept = request.META.get('HTTP_ACCEPT_LANGUAGE', None) |
|---|
| 305 | | if accept is not None: |
|---|
| 306 | | |
|---|
| 307 | | t = _accepted.get(accept, None) |
|---|
| 308 | | if t is not None: |
|---|
| 309 | | return t |
|---|
| 310 | | |
|---|
| 311 | | def _parsed(el): |
|---|
| 312 | | p = el.find(';q=') |
|---|
| 313 | | if p >= 0: |
|---|
| 314 | | lang = el[:p].strip() |
|---|
| 315 | | order = int(float(el[p+3:].strip())*100) |
|---|
| 316 | | else: |
|---|
| 317 | | lang = el |
|---|
| 318 | | order = 100 |
|---|
| 319 | | p = lang.find('-') |
|---|
| 320 | | if p >= 0: |
|---|
| 321 | | mainlang = lang[:p] |
|---|
| 322 | | else: |
|---|
| 323 | | mainlang = lang |
|---|
| 324 | | return (lang, mainlang, order) |
|---|
| 325 | | |
|---|
| 326 | | langs = [_parsed(el) for el in accept.split(',')] |
|---|
| 327 | | langs.sort(lambda a,b: -1*cmp(a[2], b[2])) |
|---|
| 328 | | |
|---|
| 329 | | for lang, mainlang, order in langs: |
|---|
| 330 | | if lang in supported or mainlang in supported: |
|---|
| 331 | | langfile = gettext_module.find('django', globalpath, [to_locale(lang)]) |
|---|
| 332 | | if langfile: |
|---|
| 333 | | # reconstruct the actual language from the language |
|---|
| 334 | | # filename, because otherwise we might incorrectly |
|---|
| 335 | | # report de_DE if we only have de available, but |
|---|
| 336 | | # did find de_DE because of language normalization |
|---|
| 337 | | lang = langfile[len(globalpath):].split(os.path.sep)[1] |
|---|
| 338 | | _accepted[accept] = lang |
|---|
| 339 | | return lang |
|---|
| | 317 | accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '') |
|---|
| | 318 | for lang, unused in parse_accept_lang_header(accept): |
|---|
| | 319 | if lang == '*': |
|---|
| | 320 | break |
|---|
| | 321 | |
|---|
| | 322 | # We have a very restricted form for our language files (no encoding |
|---|
| | 323 | # specifier, since they all must be UTF-8 and only one possible |
|---|
| | 324 | # language each time. So we avoid the overhead of gettext.find() and |
|---|
| | 325 | # look up the MO file manually. |
|---|
| | 326 | |
|---|
| | 327 | normalized = locale.locale_alias.get(to_locale(lang, True)) |
|---|
| | 328 | if not normalized: |
|---|
| | 329 | continue |
|---|
| | 330 | |
|---|
| | 331 | # Remove the default encoding from locale_alias |
|---|
| | 332 | normalized = normalized.split('.')[0] |
|---|
| | 333 | |
|---|
| | 334 | if normalized in _accepted: |
|---|
| | 335 | # We've seen this locale before and have an MO file for it, so no |
|---|
| | 336 | # need to check again. |
|---|
| | 337 | return _accepted[normalized] |
|---|
| | 338 | |
|---|
| | 339 | for lang in (normalized, normalized.split('_')[0]): |
|---|
| | 340 | if lang not in supported: |
|---|
| | 341 | continue |
|---|
| | 342 | langfile = os.path.join(globalpath, lang, 'LC_MESSAGES', |
|---|
| | 343 | 'django.mo') |
|---|
| | 344 | if os.path.exists(langfile): |
|---|
| | 345 | _accepted[normalized] = lang |
|---|
| | 346 | return lang |
|---|
| | 467 | |
|---|
| | 468 | def parse_accept_lang_header(lang_string): |
|---|
| | 469 | """ |
|---|
| | 470 | Parses the lang_string, which is the body of an HTTP Accept-Language |
|---|
| | 471 | header, and returns a list of (lang, q-value), ordered by 'q' values. |
|---|
| | 472 | |
|---|
| | 473 | Any format errors in lang_string results in an empty list being returned. |
|---|
| | 474 | """ |
|---|
| | 475 | result = [] |
|---|
| | 476 | pieces = accept_language_re.split(lang_string) |
|---|
| | 477 | if pieces[-1]: |
|---|
| | 478 | return [] |
|---|
| | 479 | for i in range(0, len(pieces) - 1, 3): |
|---|
| | 480 | first, lang, priority = pieces[i : i + 3] |
|---|
| | 481 | if first: |
|---|
| | 482 | return [] |
|---|
| | 483 | priority = priority and float(priority) or 1.0 |
|---|
| | 484 | result.append((lang, priority)) |
|---|
| | 485 | result.sort(lambda x, y: -cmp(x[1], y[1])) |
|---|
| | 486 | return result |
|---|