| 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): |
|---|
| 316 | | accept = request.META.get('HTTP_ACCEPT_LANGUAGE', None) |
|---|
| 317 | | if accept is not None: |
|---|
| 318 | | |
|---|
| 319 | | t = _accepted.get(accept, None) |
|---|
| 320 | | if t is not None: |
|---|
| 321 | | return t |
|---|
| 322 | | |
|---|
| 323 | | def _parsed(el): |
|---|
| 324 | | p = el.find(';q=') |
|---|
| 325 | | if p >= 0: |
|---|
| 326 | | lang = el[:p].strip() |
|---|
| 327 | | order = int(float(el[p+3:].strip())*100) |
|---|
| 328 | | else: |
|---|
| 329 | | lang = el |
|---|
| 330 | | order = 100 |
|---|
| 331 | | p = lang.find('-') |
|---|
| 332 | | if p >= 0: |
|---|
| 333 | | mainlang = lang[:p] |
|---|
| 334 | | else: |
|---|
| 335 | | mainlang = lang |
|---|
| 336 | | return (lang, mainlang, order) |
|---|
| 337 | | |
|---|
| 338 | | langs = [_parsed(el) for el in accept.split(',')] |
|---|
| 339 | | langs.sort(lambda a,b: -1*cmp(a[2], b[2])) |
|---|
| 340 | | |
|---|
| 341 | | for lang, mainlang, order in langs: |
|---|
| 342 | | if lang in supported or mainlang in supported: |
|---|
| 343 | | langfile = gettext_module.find('django', globalpath, [to_locale(lang)]) |
|---|
| 344 | | if langfile: |
|---|
| 345 | | # reconstruct the actual language from the language |
|---|
| 346 | | # filename, because otherwise we might incorrectly |
|---|
| 347 | | # report de_DE if we only have de available, but |
|---|
| 348 | | # did find de_DE because of language normalization |
|---|
| 349 | | lang = langfile[len(globalpath):].split(os.path.sep)[1] |
|---|
| 350 | | _accepted[accept] = lang |
|---|
| 351 | | return lang |
|---|
| | 329 | accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '') |
|---|
| | 330 | for lang, unused in parse_accept_lang_header(accept): |
|---|
| | 331 | if lang == '*': |
|---|
| | 332 | break |
|---|
| | 333 | |
|---|
| | 334 | # We have a very restricted form for our language files (no encoding |
|---|
| | 335 | # specifier, since they all must be UTF-8 and only one possible |
|---|
| | 336 | # language each time. So we avoid the overhead of gettext.find() and |
|---|
| | 337 | # look up the MO file manually. |
|---|
| | 338 | |
|---|
| | 339 | normalized = locale.locale_alias.get(to_locale(lang, True)) |
|---|
| | 340 | if not normalized: |
|---|
| | 341 | continue |
|---|
| | 342 | |
|---|
| | 343 | # Remove the default encoding from locale_alias |
|---|
| | 344 | normalized = normalized.split('.')[0] |
|---|
| | 345 | |
|---|
| | 346 | if normalized in _accepted: |
|---|
| | 347 | # We've seen this locale before and have an MO file for it, so no |
|---|
| | 348 | # need to check again. |
|---|
| | 349 | return _accepted[normalized] |
|---|
| | 350 | |
|---|
| | 351 | for lang in (normalized, normalized.split('_')[0]): |
|---|
| | 352 | if lang not in supported: |
|---|
| | 353 | continue |
|---|
| | 354 | langfile = os.path.join(globalpath, lang, 'LC_MESSAGES', |
|---|
| | 355 | 'django.mo') |
|---|
| | 356 | if os.path.exists(langfile): |
|---|
| | 357 | _accepted[normalized] = lang |
|---|
| | 358 | return lang |
|---|
| | 504 | |
|---|
| | 505 | def parse_accept_lang_header(lang_string): |
|---|
| | 506 | """ |
|---|
| | 507 | Parses the lang_string, which is the body of an HTTP Accept-Language |
|---|
| | 508 | header, and returns a list of (lang, q-value), ordered by 'q' values. |
|---|
| | 509 | |
|---|
| | 510 | Any format errors in lang_string results in an empty list being returned. |
|---|
| | 511 | """ |
|---|
| | 512 | result = [] |
|---|
| | 513 | pieces = accept_language_re.split(lang_string) |
|---|
| | 514 | if pieces[-1]: |
|---|
| | 515 | return [] |
|---|
| | 516 | for i in range(0, len(pieces) - 1, 3): |
|---|
| | 517 | first, lang, priority = pieces[i : i + 3] |
|---|
| | 518 | if first: |
|---|
| | 519 | return [] |
|---|
| | 520 | priority = priority and float(priority) or 1.0 |
|---|
| | 521 | result.append((lang, priority)) |
|---|
| | 522 | result.sort(lambda x, y: -cmp(x[1], y[1])) |
|---|
| | 523 | return result |
|---|
| | 524 | |
|---|