translations.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. # -*- coding: utf-8 -*-
  2. """
  3. flaskbb.utils.translations
  4. ~~~~~~~~~~~~~~~~~~~~~~~~~~
  5. This module contains the translation Domain used by FlaskBB.
  6. :copyright: (c) 2016 by the FlaskBB Team.
  7. :license: BSD, see LICENSE for more details.
  8. """
  9. import logging
  10. import os
  11. import subprocess
  12. import babel
  13. from flask import current_app
  14. from flask_babelplus import Domain, get_locale
  15. from flask_babelplus.utils import get_state
  16. logger = logging.getLogger(__name__)
  17. class FlaskBBDomain(Domain):
  18. def __init__(self, app):
  19. self.app = app
  20. super(FlaskBBDomain, self).__init__()
  21. # Plugin translations
  22. with self.app.app_context():
  23. self.plugin_translations = \
  24. self.app.pluggy.hook.flaskbb_load_translations()
  25. def get_translations(self):
  26. """Returns the correct gettext translations that should be used for
  27. this request. This will never fail and return a dummy translation
  28. object if used outside of the request or if a translation cannot be
  29. found.
  30. """
  31. state = get_state(silent=True)
  32. if state is None:
  33. return babel.support.NullTranslations()
  34. locale = get_locale()
  35. cache = self.get_translations_cache()
  36. translations = cache.get(str(locale))
  37. # load them into the cache
  38. if translations is None:
  39. dirname = self.get_translations_path(state.app)
  40. translations = babel.support.Translations.load(
  41. dirname,
  42. locale,
  43. domain=self.domain
  44. )
  45. # now load and add the plugin translations
  46. for plugin in self.plugin_translations:
  47. logger.debug("Loading plugin translation from: "
  48. "{}".format(plugin))
  49. plugin_translation = babel.support.Translations.load(
  50. dirname=plugin,
  51. locales=locale,
  52. domain="messages"
  53. )
  54. if not type(plugin_translation) == babel.support.NullTranslations:
  55. translations.add(plugin_translation)
  56. self.cache[str(locale)] = translations
  57. return translations
  58. def update_translations(include_plugins=False):
  59. """Updates all translations.
  60. :param include_plugins: If set to `True` it will also update the
  61. translations for all plugins.
  62. """
  63. translations_folder = os.path.join(current_app.root_path, "translations")
  64. source_file = os.path.join(translations_folder, "messages.pot")
  65. subprocess.call(["pybabel", "extract", "-F", "babel.cfg",
  66. "-k", "lazy_gettext", "-o", source_file, "."])
  67. subprocess.call(["pybabel", "update", "-i", source_file,
  68. "-d", translations_folder])
  69. if include_plugins:
  70. for plugin in current_app.pluggy.list_name():
  71. update_plugin_translations(plugin)
  72. def add_translations(translation):
  73. """Adds a new language to the translations.
  74. :param translation: The short name of the translation
  75. like ``en`` or ``de_AT``.
  76. """
  77. translations_folder = os.path.join(current_app.root_path, "translations")
  78. source_file = os.path.join(translations_folder, "messages.pot")
  79. subprocess.call(["pybabel", "extract", "-F", "babel.cfg",
  80. "-k", "lazy_gettext", "-o", source_file, "."])
  81. subprocess.call(["pybabel", "init", "-i", source_file,
  82. "-d", translations_folder, "-l", translation])
  83. def compile_translations(include_plugins=False):
  84. """Compiles all translations.
  85. :param include_plugins: If set to `True` it will also compile the
  86. translations for all plugins.
  87. """
  88. translations_folder = os.path.join(current_app.root_path, "translations")
  89. subprocess.call(["pybabel", "compile", "-d", translations_folder])
  90. if include_plugins:
  91. for plugin in current_app.pluggy.list_name():
  92. compile_plugin_translations(plugin)
  93. def add_plugin_translations(plugin, translation):
  94. """Adds a new language to the plugin translations.
  95. :param plugin: The plugins identifier.
  96. :param translation: The short name of the translation
  97. like ``en`` or ``de_AT``.
  98. """
  99. plugin_folder = current_app.pluggy.get_plugin(plugin).__path__[0]
  100. translations_folder = os.path.join(plugin_folder, "translations")
  101. source_file = os.path.join(translations_folder, "messages.pot")
  102. subprocess.call(["pybabel", "extract", "-F", "babel.cfg",
  103. "-k", "lazy_gettext", "-o", source_file,
  104. plugin_folder])
  105. subprocess.call(["pybabel", "init", "-i", source_file,
  106. "-d", translations_folder, "-l", translation])
  107. def update_plugin_translations(plugin):
  108. """Updates the plugin translations.
  109. Returns ``False`` if no translations for this plugin exists.
  110. :param plugin: The plugins identifier
  111. """
  112. plugin_folder = current_app.pluggy.get_plugin(plugin).__path__[0]
  113. translations_folder = os.path.join(plugin_folder, "translations")
  114. source_file = os.path.join(translations_folder, "messages.pot")
  115. if not os.path.exists(source_file):
  116. return False
  117. subprocess.call(["pybabel", "extract", "-F", "babel.cfg",
  118. "-k", "lazy_gettext", "-o", source_file,
  119. plugin_folder])
  120. subprocess.call(["pybabel", "update", "-i", source_file,
  121. "-d", translations_folder])
  122. def compile_plugin_translations(plugin):
  123. """Compile the plugin translations.
  124. Returns ``False`` if no translations for this plugin exists.
  125. :param plugin: The plugins identifier
  126. """
  127. plugin_folder = current_app.pluggy.get_plugin(plugin).__path__[0]
  128. translations_folder = os.path.join(plugin_folder, "translations")
  129. if not os.path.exists(translations_folder):
  130. return False
  131. subprocess.call(["pybabel", "compile", "-d", translations_folder])