| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- """Server functions for loading translations"""
- from __future__ import annotations
- import errno
- import json
- import re
- from collections import defaultdict
- from os.path import dirname
- from os.path import join as pjoin
- from typing import Any
- I18N_DIR = dirname(__file__)
- # Cache structure:
- # {'nbjs': { # Domain
- # 'zh-CN': { # Language code
- # <english string>: <translated string>
- # ...
- # }
- # }}
- TRANSLATIONS_CACHE: dict[str, Any] = {"nbjs": {}}
- _accept_lang_re = re.compile(
- r"""
- (?P<lang>[a-zA-Z]{1,8}(-[a-zA-Z]{1,8})?)
- (\s*;\s*q\s*=\s*
- (?P<qvalue>[01](.\d+)?)
- )?""",
- re.VERBOSE,
- )
- def parse_accept_lang_header(accept_lang):
- """Parses the 'Accept-Language' HTTP header.
- Returns a list of language codes in *ascending* order of preference
- (with the most preferred language last).
- """
- by_q = defaultdict(list)
- for part in accept_lang.split(","):
- m = _accept_lang_re.match(part.strip())
- if not m:
- continue
- lang, qvalue = m.group("lang", "qvalue")
- # Browser header format is zh-CN, gettext uses zh_CN
- lang = lang.replace("-", "_")
- qvalue = 1.0 if qvalue is None else float(qvalue)
- if qvalue == 0:
- continue # 0 means not accepted
- by_q[qvalue].append(lang)
- res = []
- for _, langs in sorted(by_q.items()):
- res.extend(sorted(langs))
- return res
- def load(language, domain="nbjs"):
- """Load translations from an nbjs.json file"""
- try:
- f = open(pjoin(I18N_DIR, language, "LC_MESSAGES", "nbjs.json"), encoding="utf-8") # noqa: SIM115
- except OSError as e:
- if e.errno != errno.ENOENT:
- raise
- return {}
- with f:
- data = json.load(f)
- return data["locale_data"][domain]
- def cached_load(language, domain="nbjs"):
- """Load translations for one language, using in-memory cache if available"""
- domain_cache = TRANSLATIONS_CACHE[domain]
- try:
- return domain_cache[language]
- except KeyError:
- data = load(language, domain)
- domain_cache[language] = data
- return data
- def combine_translations(accept_language, domain="nbjs"):
- """Combine translations for multiple accepted languages.
- Returns data re-packaged in jed1.x format.
- """
- lang_codes = parse_accept_lang_header(accept_language)
- combined: dict[str, Any] = {}
- for language in lang_codes:
- if language == "en":
- # en is default, all translations are in frontend.
- combined.clear()
- else:
- combined.update(cached_load(language, domain))
- combined[""] = {"domain": "nbjs"}
- return {"domain": domain, "locale_data": {domain: combined}}
|