Fix #12442: Add ability to request any translation of a string (#12443)

This commit is contained in:
Paul McLanahan 2022-12-07 13:55:38 -05:00 коммит произвёл GitHub
Родитель 0e1b8fbe96
Коммит 9e8b38e414
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 59 добавлений и 7 удалений

Просмотреть файл

@ -183,6 +183,13 @@ You could use that in a template like this:
For our purposes these are mostly useful for things that can change, but which shouldn't involve For our purposes these are mostly useful for things that can change, but which shouldn't involve
retranslation of a string (e.g. URLs or email addresses). retranslation of a string (e.g. URLs or email addresses).
You may also request any other translation of the string (or the original English string of course) regardless of the current locale.
.. code-block:: jinja
<h2>{{ ftl('welcome', locale='en', user='Dude') }}<h2>
This helper is available in Jinja templates and Python code in views. For use in a view you should This helper is available in Jinja templates and Python code in views. For use in a view you should
always call it in the view itself: always call it in the view itself:

Просмотреть файл

@ -46,6 +46,8 @@ def render_to_string(template_name, context=None, request=None, using=None, ftl_
context["fluent_l10n"] = fluent_l10n([locale, "en"], ftl_files) context["fluent_l10n"] = fluent_l10n([locale, "en"], ftl_files)
else: else:
context["fluent_l10n"] = fluent_l10n([locale, "en"], settings.FLUENT_DEFAULT_FILES) context["fluent_l10n"] = fluent_l10n([locale, "en"], settings.FLUENT_DEFAULT_FILES)
context["fluent_files"] = ftl_files or settings.FLUENT_DEFAULT_FILES
return loader.render_to_string(template_name, context, request, using) return loader.render_to_string(template_name, context, request, using)
@ -128,8 +130,7 @@ def render(request, template, context=None, ftl_files=None, activation_files=Non
else: else:
context["fluent_l10n"] = fluent_l10n([locale, "en"], settings.FLUENT_DEFAULT_FILES) context["fluent_l10n"] = fluent_l10n([locale, "en"], settings.FLUENT_DEFAULT_FILES)
# Every template gets its own .lang file, so figure out what it is context["fluent_files"] = ftl_files or settings.FLUENT_DEFAULT_FILES
# and pass it in the context
context["template"] = template context["template"] = template
context["template_source_url"] = template_source_url(template) context["template_source_url"] = template_source_url(template)

Просмотреть файл

@ -145,7 +145,10 @@ def l10nize(f):
# can not use += here because that mutates the original list # can not use += here because that mutates the original list
ftl_files = ftl_files + settings.FLUENT_DEFAULT_FILES ftl_files = ftl_files + settings.FLUENT_DEFAULT_FILES
locale = kwargs.get("locale") or translation.get_language(True) locale = kwargs.get("locale") or translation.get_language(True)
l10n = fluent_l10n([locale, "en"], ftl_files) locales = [locale]
if locale != "en":
locales.append("en")
l10n = fluent_l10n(locales, ftl_files)
return f(l10n, *args, **kwargs) return f(l10n, *args, **kwargs)
return inner return inner

Просмотреть файл

@ -11,12 +11,13 @@ from lib.l10n_utils import fluent
@library.global_function @library.global_function
@jinja2.pass_context @jinja2.pass_context
def ftl(ctx, message_id, fallback=None, **kwargs): def ftl(ctx, message_id, fallback=None, locale=None, **kwargs):
"""Return the translated string. """Return the translated string.
:param ctx: the context from the template (automatically included) :param ctx: the context from the template (automatically included)
:param str message_id: the ID of the message :param str message_id: the ID of the message
:param str fallback: the ID of a message to use if message_id is not translated :param str fallback: the ID of a message to use if message_id is not translated
:param str locale: If set the string returned will be from the given locale instead of the current one
:param kwargs: the other kwargs are passed to the translation as variables :param kwargs: the other kwargs are passed to the translation as variables
:return: the translated string marked as safe :return: the translated string marked as safe
@ -24,7 +25,11 @@ def ftl(ctx, message_id, fallback=None, **kwargs):
<p>{{ ftl('greeting', name='The Dude') }} <p>{{ ftl('greeting', name='The Dude') }}
""" """
return Markup(fluent.translate(ctx["fluent_l10n"], message_id, fallback, **kwargs)) if locale:
return Markup(fluent.ftl(message_id, fallback, locale=locale, ftl_files=ctx["fluent_files"], **kwargs))
l10n = ctx["fluent_l10n"]
return Markup(fluent.translate(l10n, message_id, fallback, **kwargs))
@library.global_function @library.global_function

Просмотреть файл

@ -0,0 +1,7 @@
{#
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
#}
{{ ftl("fluent-title") }}:{{ ftl("fluent-title", locale="en") }}

Просмотреть файл

@ -0,0 +1,7 @@
{#
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
#}
{{ ftl("fluent-title") }}:{{ ftl("fluent-title", locale="fr") }}

Просмотреть файл

@ -131,6 +131,8 @@ class TestFluentViewTranslationUtils(TestCase):
def test_ftl_view_util(self): def test_ftl_view_util(self):
assert fluent.ftl("fluent-title", locale="de", ftl_files="mozorg/fluent") == "Title in German" assert fluent.ftl("fluent-title", locale="de", ftl_files="mozorg/fluent") == "Title in German"
assert fluent.ftl("fluent-title", locale="fr", ftl_files="mozorg/fluent") == "Title in French"
assert fluent.ftl("fluent-title", locale="en", ftl_files="mozorg/fluent") == "This is a test of the new Fluent L10n system"
def test_ftl_view_util_no_mutate_list(self): def test_ftl_view_util_no_mutate_list(self):
"""Should not mutate the ftl_files list""" """Should not mutate the ftl_files list"""

Просмотреть файл

@ -6,16 +6,17 @@ from pathlib import Path
from unittest.mock import ANY, patch from unittest.mock import ANY, patch
from django.template import TemplateDoesNotExist from django.template import TemplateDoesNotExist
from django.test import RequestFactory from django.test import RequestFactory, override_settings
from django_jinja.backend import Jinja2 from django_jinja.backend import Jinja2
from bedrock.mozorg.tests import TestCase from bedrock.mozorg.tests import TestCase
from lib.l10n_utils import render from lib.l10n_utils import render, render_to_string
ROOT_PATH = Path(__file__).with_name("test_files") ROOT_PATH = Path(__file__).with_name("test_files")
ROOT = str(ROOT_PATH) ROOT = str(ROOT_PATH)
TEMPLATE_DIRS = [str(ROOT_PATH.joinpath("templates"))] TEMPLATE_DIRS = [str(ROOT_PATH.joinpath("templates"))]
L10N_PATH = ROOT_PATH.joinpath("l10n")
jinja_env = Jinja2.get_default().env jinja_env = Jinja2.get_default().env
@ -27,6 +28,25 @@ class TestNoLocale(TestCase):
render(request, "500.html") render(request, "500.html")
@override_settings(FLUENT_PATHS=[L10N_PATH])
@patch.object(jinja_env.loader, "searchpath", TEMPLATE_DIRS)
class TestFtlTemplateHelper(TestCase):
def setUp(self):
self.rf = RequestFactory()
def test_english_locale(self):
req = self.rf.get("/en-US/")
req.locale = "de"
result = render_to_string("test-en-title.html", request=req, ftl_files="mozorg/fluent")
assert result.strip() == "Title in German:This is a test of the new Fluent L10n system"
def test_french_locale(self):
req = self.rf.get("/en-US/")
req.locale = "en-US"
result = render_to_string("test-fr-title.html", request=req, ftl_files="mozorg/fluent")
assert result.strip() == "This is a test of the new Fluent L10n system:Title in French"
@patch.object(jinja_env.loader, "searchpath", TEMPLATE_DIRS) @patch.object(jinja_env.loader, "searchpath", TEMPLATE_DIRS)
@patch("lib.l10n_utils.django_render") @patch("lib.l10n_utils.django_render")
class TestLocaleTemplates(TestCase): class TestLocaleTemplates(TestCase):