__init__.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. """Server functions for loading translations
  2. """
  3. from collections import defaultdict
  4. import errno
  5. import io
  6. import json
  7. from os.path import dirname, join as pjoin
  8. import re
  9. I18N_DIR = dirname(__file__)
  10. # Cache structure:
  11. # {'nbjs': { # Domain
  12. # 'zh-CN': { # Language code
  13. # <english string>: <translated string>
  14. # ...
  15. # }
  16. # }}
  17. TRANSLATIONS_CACHE = {'nbjs': {}}
  18. _accept_lang_re = re.compile(r'''
  19. (?P<lang>[a-zA-Z]{1,8}(-[a-zA-Z]{1,8})?)
  20. (\s*;\s*q\s*=\s*
  21. (?P<qvalue>[01](.\d+)?)
  22. )?''', re.VERBOSE)
  23. def parse_accept_lang_header(accept_lang):
  24. """Parses the 'Accept-Language' HTTP header.
  25. Returns a list of language codes in *ascending* order of preference
  26. (with the most preferred language last).
  27. """
  28. by_q = defaultdict(list)
  29. for part in accept_lang.split(','):
  30. m = _accept_lang_re.match(part.strip())
  31. if not m:
  32. continue
  33. lang, qvalue = m.group('lang', 'qvalue')
  34. # Browser header format is zh-CN, gettext uses zh_CN
  35. lang = lang.replace('-', '_')
  36. if qvalue is None:
  37. qvalue = 1.
  38. else:
  39. qvalue = float(qvalue)
  40. if qvalue == 0:
  41. continue # 0 means not accepted
  42. by_q[qvalue].append(lang)
  43. res = []
  44. for qvalue, langs in sorted(by_q.items()):
  45. res.extend(sorted(langs))
  46. return res
  47. def load(language, domain='nbjs'):
  48. """Load translations from an nbjs.json file"""
  49. try:
  50. f = io.open(pjoin(I18N_DIR, language, 'LC_MESSAGES', 'nbjs.json'),
  51. encoding='utf-8')
  52. except IOError as e:
  53. if e.errno != errno.ENOENT:
  54. raise
  55. return {}
  56. with f:
  57. data = json.load(f)
  58. return data["locale_data"][domain]
  59. def cached_load(language, domain='nbjs'):
  60. """Load translations for one language, using in-memory cache if available"""
  61. domain_cache = TRANSLATIONS_CACHE[domain]
  62. try:
  63. return domain_cache[language]
  64. except KeyError:
  65. data = load(language, domain)
  66. domain_cache[language] = data
  67. return data
  68. def combine_translations(accept_language, domain='nbjs'):
  69. """Combine translations for multiple accepted languages.
  70. Returns data re-packaged in jed1.x format.
  71. """
  72. lang_codes = parse_accept_lang_header(accept_language)
  73. combined = {}
  74. for language in lang_codes:
  75. if language == 'en':
  76. # en is default, all translations are in frontend.
  77. combined.clear()
  78. else:
  79. combined.update(cached_load(language, domain))
  80. combined[''] = {"domain":"nbjs"}
  81. return {
  82. "domain": domain,
  83. "locale_data": {
  84. domain: combined
  85. }
  86. }