Fix #5851: Support overriding or ammending list of locales (#6035)

This modifies how several parts of translation in bedrock work:

1. You can now provide a list of locales in `active_locales` in
   the template context that will be the list of available
   translations for the page.
2. You can now provide a list of locales in `add_active_locales`
   to add extra available translations for the page.
3. The `page()` and `LangFilesMixin` helpers are updated to support
   these new context items.
4. You can now create and use `en-US` locale-specific-templates.
This commit is contained in:
Paul McLanahan 2018-10-04 11:50:42 -04:00 коммит произвёл Josh Mize
Родитель ce96b4c0ec
Коммит 3bf8e8cca1
16 изменённых файлов: 232 добавлений и 138 удалений

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

@ -18,6 +18,9 @@ urlpatterns = (
page('eula/thunderbird-1.5', 'legal/eula/thunderbird-1.5-eula.html'),
page('eula/thunderbird-2', 'legal/eula/thunderbird-2-eula.html'),
page('firefox', 'legal/firefox.html'),
# The "impressum" page is intended for Germany. Redirect to German (de) if
# requested in any other locale. (Bug 1248393)
page('impressum', 'legal/impressum.html', active_locales=['de']),
url(r'^terms/mozilla/$', LegalDocView.as_view(template_name='legal/terms/mozilla.html', legal_doc_name='Websites_ToU'),
name='legal.terms.mozilla'),
@ -44,6 +47,4 @@ urlpatterns = (
name='legal.report-infringement'),
url('^fraud-report/$', views.fraud_report, name='legal.fraud-report'),
url('^impressum/$', views.impressum, name='legal.impressum'),
)

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

@ -2,8 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import re
from django.template.loader import render_to_string
from lib import l10n_utils
@ -83,13 +81,3 @@ def fraud_report(request):
submitted = request.GET.get('submitted') == 'True'
template_vars['form_submitted'] = submitted
return l10n_utils.render(request, 'legal/fraud-report.html', template_vars)
def impressum(request):
# The "impressum" page is intended for Germany. Redirect to German (de) if
# requested in any other locale. (Bug 1248393)
if request.locale != 'de':
return redirect(re.sub(r'^/%s/' % request.locale, '/de/',
reverse('legal.impressum')), permanent=True)
return l10n_utils.render(request, 'legal/impressum.html', {'localized': True})

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

@ -22,8 +22,7 @@ class TestLoadLegalDoc(TestCase):
listdir_mock.return_value = ['en-US.md']
doc = views.load_legal_doc('the_dude_is_legal', 'de')
self.assertIsNone(doc['content'])
self.assertFalse(doc['localized'])
self.assertDictEqual(doc['translations'], {'en-US': 'English (US)'})
self.assertEqual(doc['active_locales'], ['en-US'])
@patch('os.path.exists')
@patch.object(views, 'listdir')
@ -39,8 +38,7 @@ class TestLoadLegalDoc(TestCase):
md_mock.markdownFromFile.assert_called_with(
input=good_path, output=ANY, extensions=ANY)
self.assertEqual(doc['content'], "You're not wrong Walter...")
self.assertFalse(doc['localized'])
self.assertDictEqual(doc['translations'], {'de': 'Deutsch', 'en-US': 'English (US)'})
self.assertEqual(doc['active_locales'], ['de', 'en-US'])
@patch('os.path.exists')
@patch.object(views, 'listdir')
@ -56,8 +54,7 @@ class TestLoadLegalDoc(TestCase):
md_mock.markdownFromFile.assert_called_with(
input=good_path, output=ANY, extensions=ANY)
self.assertEqual(doc['content'], "You're not wrong Walter...")
self.assertTrue(doc['localized'])
self.assertDictEqual(doc['translations'], {'de': 'Deutsch', 'en-US': 'English (US)'})
self.assertEqual(doc['active_locales'], ['de', 'en-US'])
@patch('os.path.exists')
@patch.object(views, 'listdir')
@ -76,11 +73,7 @@ class TestLoadLegalDoc(TestCase):
md_mock.markdownFromFile.assert_called_with(
input=good_path, output=ANY, extensions=ANY)
self.assertEqual(doc['content'], "You're not wrong Walter...")
self.assertTrue(doc['localized'])
self.assertDictEqual(doc['translations'], {
'hi-IN': u'\u0939\u093f\u0928\u094d\u0926\u0940 (\u092d\u093e\u0930\u0924)',
'en-US': 'English (US)',
})
self.assertEqual(doc['active_locales'], ['hi-IN', 'en-US'])
@patch('os.path.exists')
@patch.object(views, 'listdir')
@ -98,11 +91,7 @@ class TestLoadLegalDoc(TestCase):
md_mock.markdownFromFile.assert_called_with(
input=good_path, output=ANY, extensions=ANY)
self.assertEqual(doc['content'], "You're not wrong Walter...")
self.assertTrue(doc['localized'])
self.assertDictEqual(doc['translations'], {
'hi-IN': u'\u0939\u093f\u0928\u094d\u0926\u0940 (\u092d\u093e\u0930\u0924)',
'en-US': 'English (US)',
})
self.assertEqual(doc['active_locales'], ['hi-IN', 'en-US'])
class TestLegalDocView(TestCase):
@ -125,8 +114,7 @@ class TestLegalDocView(TestCase):
doc_value = "Donny, you're out of your element!"
lld_mock.return_value = {
'content': doc_value,
'localized': True,
'translations': {'de': 'Deutsch', 'en-US': 'English (US)'},
'active_locales': ['de', 'en-US'],
}
good_resp = HttpResponse(doc_value)
render_mock.return_value = good_resp
@ -138,7 +126,6 @@ class TestLegalDocView(TestCase):
eq_(resp['cache-control'], 'max-age={0!s}'.format(views.CACHE_TIMEOUT))
eq_(resp.content, doc_value)
eq_(render_mock.call_args[0][2]['doc'], doc_value)
self.assertTrue(render_mock.call_args[0][2]['localized'])
lld_mock.assert_called_with('the_dude_exists', 'de')
@patch.object(views, 'load_legal_doc')
@ -148,8 +135,7 @@ class TestLegalDocView(TestCase):
doc_value = "Donny, you're out of your element!"
lld_mock.return_value = {
'content': doc_value,
'localized': True,
'translations': {'es-ES': 'Espa\u00f1ol (de Espa\u00f1a)', 'en-US': 'English (US)'},
'active_locales': ['es-ES', 'en-US'],
}
good_resp = HttpResponse(doc_value)
render_mock.return_value = good_resp
@ -168,8 +154,7 @@ class TestLegalDocView(TestCase):
doc_value = "Donny, you're out of your element!"
lld_mock.return_value = {
'content': doc_value,
'localized': True,
'translations': {'es-ES': 'Espa\u00f1ol (de Espa\u00f1a)', 'en-US': 'English (US)'},
'active_locales': ['es-ES', 'en-US'],
}
good_resp = HttpResponse(doc_value)
render_mock.return_value = good_resp

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

@ -15,7 +15,6 @@ from mdx_outline import OutlineExtension
from bedrock.settings import path as base_path
from lib import l10n_utils
from lib.l10n_utils.dotlang import get_translations_native_names
LEGAL_DOCS_PATH = base_path('vendor-local', 'src', 'legal-docs')
CACHE_TIMEOUT = getattr(settings, 'LEGAL_DOCS_CACHE_TIMEOUT', 60 * 60)
@ -47,9 +46,8 @@ def load_legal_doc(doc_name, locale):
locales = [f.replace('.md', '') for f in listdir(source_dir) if f.endswith('.md')]
# convert legal-docs locales to bedrock equivalents
locales = [LEGAL_DOCS_LOCALES_TO_BEDROCK.get(l, l) for l in locales]
# filter out non-production locales and convert to dict with names
translations = get_translations_native_names(locales)
localized = locale != settings.LANGUAGE_CODE
# filter out non-production locales
locales = [l for l in locales if l in settings.PROD_LANGUAGES]
# it's possible the legal-docs repo changed the filename to match our locale.
# this makes it work for mapped locales even if the map becomes superfluous.
@ -59,7 +57,6 @@ def load_legal_doc(doc_name, locale):
if not path.exists(source_file):
source_file = path.join(LEGAL_DOCS_PATH, doc_name, 'en-US.md')
localized = False
try:
# Parse the Markdown file
@ -69,14 +66,12 @@ def load_legal_doc(doc_name, locale):
content = output.getvalue().decode('utf8')
except IOError:
content = None
localized = False
finally:
output.close()
return {
'content': content,
'localized': localized,
'translations': translations,
'active_locales': locales,
}
@ -116,8 +111,7 @@ class LegalDocView(TemplateView):
context = super(LegalDocView, self).get_context_data(**kwargs)
context[self.legal_doc_context_name] = legal_doc['content']
context['localized'] = legal_doc['localized']
context['translations'] = legal_doc['translations']
context['active_locales'] = legal_doc['active_locales']
return context
@classmethod

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

@ -51,8 +51,14 @@ def page(name, tmpl, decorators=None, url_name=None, **kwargs):
be applied to the view.
@param url_name: The value to use as the URL name, default is to coerce
the template path into a name as described above.
@param active_locales: A list of locale codes that should be active for this page
regardless of the state of the lang files. Useful for pages with locale-
specific templates or non-English text in the template. Ignores the lang
file activation tags.
@param add_active_locales: A list of locale codes that should be active for this page
in addition to those from the lang files.
@param kwargs: Any additional arguments are passed to l10n_utils.render
after the request and the template name.
as the context.
"""
pattern = r'^%s/$' % name if name else r'^$'

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

@ -8,7 +8,8 @@ from bedrock.mozorg.tests import TestCase
@patch('bedrock.newsletter.forms.get_lang_choices',
lambda *x: [['en', 'English'], ['fr', 'French'], ['pt', 'Portuguese']])
@patch('lib.l10n_utils.template_is_active', lambda *x: True)
@patch('lib.l10n_utils.translations_for_template',
lambda *x: ['en-US', 'fr', 'pt-BR', 'af'])
class TestNewsletterFooter(TestCase):
def setUp(self):
self.view_name = 'newsletter.subscribe'

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

@ -8,11 +8,11 @@ from django.http import HttpResponse
from django.test.client import RequestFactory
import basket
from bedrock.base.urlresolvers import reverse
from mock import ANY, DEFAULT, patch
from nose.tools import eq_
from pyquery import PyQuery as pq
from bedrock.base.urlresolvers import reverse
from bedrock.mozorg.tests import TestCase
from bedrock.newsletter.tests import newsletters
from bedrock.newsletter.views import (
@ -340,7 +340,9 @@ class TestExistingNewsletterView(TestCase):
self.data['lang'] = 'en'
self.data['country'] = 'us'
url = reverse('newsletter.existing.token', args=(self.token,))
with self.activate('en-US'):
url = reverse('newsletter.existing.token', args=(self.token,))
with patch.multiple('basket',
update_user=DEFAULT,
subscribe=DEFAULT,

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

@ -139,8 +139,7 @@ def privacy(request):
template_vars = {
'doc': process_legal_doc(doc['content']),
'localized': doc['localized'],
'translations': doc['translations'],
'active_locales': doc['active_locales'],
}
return l10n_utils.render(request, 'privacy/index.html', template_vars)

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

@ -452,6 +452,12 @@ When a request is made for a particular page, bedrock's rendering function
automatically checks for a locale-specific template, and, if one exists, will
render it instead of the originally specified (locale-agnostic) template.
.. NOTE::
Creating a locale-specific template for en-US was not possible when this
feature was introduced, but it is now. So you can create your en-US-only
template and the rest of the locales will continue to use the default.
.. IMPORTANT::
Note that the presence of an L10n template (e.g.
@ -459,6 +465,57 @@ render it instead of the originally specified (locale-agnostic) template.
a locale-specific template in bedrock.
Specifying Active Locales in Views
----------------------------------
Normally we rely on activation tags in our translation files (.lang files)
to determine in which languages a page will be available. This will almost always
be what we want for a page. But sometimes we need to explicitly state the locales
available for a page. The `impressum` page for example is only available in German
and the template itself has German hard-coded into it since we don't need it to be
translated into any other languages. In cases like these we can send a list of locale
codes with the template context and it will be the final list. This can be accomplished
in a few ways depending on how the view is coded.
For a plain view function, you can simply pass a list of locale codes to `l10n_utils.render`
in the context using the name `active_locales`. This will be the full list of available
translations. Use `add_active_locales` if you want to add languages to the existing list:
.. code-block:: python
def french_and_german_only(request):
return l10n_utils.render(request, 'home.html', {'active_locales': ['de', 'fr'])
If you don't need a custom view and are just using the `page()` helper function in your `urls.py`
file, then you can similarly pass in a list:
.. code-block:: python
page('about', 'about.html', active_locales=['en-US', 'es-ES']),
Or if your view is even more fancy and you're using a Class-Based-View that inherits from `LangFilesMixin`
(which it must if you want it to be translated) then you can specify the list as part of the view Class
definition:
.. code-block:: python
class MyView(LangFilesMixin, View):
active_locales = ['zh-CN', 'hi-IN']
Or in the `urls.py` when using a CBV:
.. code-block:: python
url(r'about/$', MyView.as_view(active_locales=['de', 'fr'])),
The main thing to keep in mind is that if you specify `active_locales` that will be the full list of
localizations available for that page. If you'd like to add to the existing list of locales generated
from the lang files then you can use the `add_active_locales` name in all of the same ways as
`active_locales` above. It's a list of locale codes that will be added to the list already available.
This is useful in situations where we would have needed the l10n team to create an empty .lang file with
an active tag in it because we have a locale-specific-template with text in the language hard-coded into
the template and therefore do not otherwise need a .lang file.
Development
-----------

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

@ -13,8 +13,8 @@ from django.utils.translation.trans_real import parse_accept_lang_header
from bedrock.base.urlresolvers import split_path
from .dotlang import get_lang_path
from .gettext import template_is_active, translations_for_template
from .dotlang import get_lang_path, get_translations_native_names
from .gettext import translations_for_template
def template_source_url(template):
@ -43,7 +43,9 @@ def render(request, template, context=None, **kwargs):
if present, otherwise, it'll render the specified (en-US) template.
"""
context = {} if context is None else context
# use copy() here to avoid modifying the dict in a view that will then
# be different on the next call to the view.
context = context.copy() if context else {}
# Make sure we have a single template
if isinstance(template, list):
@ -55,55 +57,31 @@ def render(request, template, context=None, **kwargs):
context['langfile'] = get_lang_path(template)
context['template_source_url'] = template_source_url(template)
# Get the available translation list of the current page
context.setdefault('translations', {})
context['translations'].update(translations_for_template(template))
# if `locales` is given use it as the full list of active translations
if 'active_locales' in context:
translations = context['active_locales']
del context['active_locales']
else:
translations = translations_for_template(template)
# if `add_active_locales` is given then add it to the translations for the template
if 'add_active_locales' in context:
translations.extend(context['add_active_locales'])
del context['add_active_locales']
# Look for localized template if not default lang.
if hasattr(request, 'locale') and request.locale != settings.LANGUAGE_CODE:
context['translations'] = get_translations_native_names(translations)
# Look for localized template
if hasattr(request, 'locale'):
# Redirect to one of the user's accept languages or the site's default
# language (en-US) if the current locale not active
if not template_is_active(template, get_locale(request)):
# Use the default (en-US) template to render instead of redirecting
# if the template is not localized yet but the content itself is
# localized. This is useful especially for legal documents where the
# content is translated in the external legal-docs repository.
if context.get('localized', False):
return django_render(request, template, context, **kwargs)
matched = None
# Look for the user's Accept-Language HTTP header to find another
# locale we can offer
for lang in get_accept_languages(request):
if template_is_active(template, lang):
matched = lang
break
# Check for the fallback locales if the previous look-up doesn't
# work. This is useful especially in the Spanish locale where es-ES
# should be offered as the fallback of es, es-AR, es-CL and es-MX
if not matched:
for lang in get_accept_languages(request):
lang = settings.FALLBACK_LOCALES.get(lang)
if lang and template_is_active(template, lang):
matched = lang
break
# If all the attempts failed, just use en-US, the default locale of
# the site
if not matched:
matched = settings.LANGUAGE_CODE
if request.locale not in translations:
lang = get_best_translation(translations, get_accept_languages(request))
response = HttpResponseRedirect('/' + '/'.join([
matched,
lang,
split_path(request.get_full_path())[1]
]))
# Add the Vary header to avoid wrong redirects due to a cache
response['Vary'] = 'Accept-Language'
return response
# Render try #1: Look for l10n template in locale/{{ LANG }}/templates/
@ -159,8 +137,43 @@ def get_accept_languages(request):
return languages
def get_best_translation(translations, accept_languages):
# Look for the user's Accept-Language HTTP header to find another
# locale we can offer
for lang in accept_languages:
if lang in translations:
return lang
# Check for the fallback locales if the previous look-up doesn't
# work. This is useful especially in the Spanish locale where es-ES
# should be offered as the fallback of es, es-AR, es-CL and es-MX
for lang in accept_languages:
lang = settings.FALLBACK_LOCALES.get(lang)
if lang in translations:
return lang
# If all the attempts failed, just use en-US, the default locale of
# the site
if settings.LANGUAGE_CODE in translations:
return settings.LANGUAGE_CODE
# fall back to just the first locale in the list
return translations[0]
class LangFilesMixin(object):
"""Generic views mixin that uses l10n_utils to render responses."""
active_locales = None
add_active_locales = None
def get_context_data(self, **kwargs):
ctx = super(LangFilesMixin, self).get_context_data(**kwargs)
if self.active_locales:
ctx['active_locales'] = self.active_locales
if self.add_active_locales:
ctx['add_active_locales'] = self.add_active_locales
return ctx
def render_to_response(self, context, **response_kwargs):
return render(self.request, self.get_template_names(),

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

@ -287,7 +287,7 @@ def get_translations_for_langfile(langfile):
Return the list of available translations for the langfile.
:param langfile: the path to a lang file, retrieved with get_lang_path()
:return: dict, like {'en-US': 'English (US)', 'fr': 'Français'}
:return: list, like ['en-US', 'fr']
"""
cache_key = 'translations:%s' % langfile
@ -296,14 +296,13 @@ def get_translations_for_langfile(langfile):
if translations:
return translations
langs = []
translations = []
for lang in settings.PROD_LANGUAGES:
if (lang in product_details.languages and
(lang == settings.LANGUAGE_CODE or
lang_file_is_active(langfile, lang))):
langs.append(lang)
translations.append(lang)
translations = get_translations_native_names(langs)
cache.set(cache_key, translations, settings.DOTLANG_CACHE)
return translations
@ -320,6 +319,7 @@ def get_translations_native_names(locales):
translations = {}
for locale in locales:
if locale in settings.PROD_LANGUAGES:
translations[locale] = product_details.languages[locale]['native']
language = product_details.languages.get(locale)
translations[locale] = language['native'] if language else locale
return translations

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

@ -241,14 +241,14 @@ def translations_for_template(template_name):
Return the list of available translations for the template.
:param template_name: name of the template passed to render.
:return: dict, like {'en-US': 'English (US)', 'fr': 'Français'}
:return: list, like ['en-US', 'fr']
"""
lang_files = [get_lang_path(template_name)]
template = get_template(template_name)
lang_files.extend(parse_template(template.template.filename))
active_translations = {}
active_translations = []
for lf in lang_files:
active_translations.update(get_translations_for_langfile(lf))
active_translations.extend(get_translations_for_langfile(lf))
return active_translations

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

@ -21,11 +21,19 @@ jinja_env = Jinja2.get_default()
class TestRender(TestCase):
urls = 'lib.l10n_utils.tests.test_files.urls'
def _test(self, path, template, locale, accept_lang, status, destination=None):
def _test(self, path, template, locale, accept_lang, status, destination=None,
active_locales=None, add_active_locales=None):
request = RequestFactory().get(path)
request.META['HTTP_ACCEPT_LANGUAGE'] = accept_lang
request.locale = locale
response = l10n_utils.render(request, template)
ctx = {}
if active_locales:
ctx['active_locales'] = active_locales
if add_active_locales:
ctx['add_active_locales'] = add_active_locales
response = l10n_utils.render(request, template, ctx)
if status == 302:
self.assertEqual(response.status_code, 302)
@ -37,33 +45,53 @@ class TestRender(TestCase):
def test_firefox(self):
path = '/firefox/new/'
template = 'firefox/new.html'
locales = ['en-US', 'en-GB', 'fr', 'es-ES']
# Nothing to do with a valid locale
self._test(path, template, 'en-US', 'en-us,en;q=0.5',
200)
200, active_locales=locales)
# en-GB is activated on /firefox/new/
with patch.object(l10n_utils, 'template_is_active') as active_mock:
active_mock.return_value = True
self._test(path, template, 'en-GB', 'en-gb,en;q=0.5',
200)
self._test(path, template, 'en-GB', 'en-gb,en;q=0.5',
200, active_locales=locales)
active_mock.reset_mock()
active_mock.side_effect = [False, True]
# fr-FR should be treated as fr
self._test(path, template, 'fr-FR', 'fr-fr',
302, '/fr/firefox/new/')
# fr-FR should be treated as fr
self._test(path, template, 'fr-FR', 'fr-fr',
302, '/fr/firefox/new/', active_locales=locales)
active_mock.reset_mock()
active_mock.side_effect = [False, False, True]
# Should fallback to the user's second preferred language
self._test(path, template, 'zu', 'zu,fr;q=0.7,en;q=0.3',
302, '/fr/firefox/new/')
# Should fallback to the user's second preferred language
self._test(path, template, 'zu', 'zu,fr;q=0.7,en;q=0.3',
302, '/fr/firefox/new/', active_locales=locales)
active_mock.reset_mock()
active_mock.side_effect = [False, False, False, False, True]
# Should fallback to one of the site's fallback languages
self._test(path, template, 'es-CL', 'es-CL,es;q=0.7,en;q=0.3',
302, '/es-ES/firefox/new/')
# Should fallback to one of the site's fallback languages
self._test(path, template, 'es-CL', 'es-CL,es;q=0.7,en;q=0.3',
302, '/es-ES/firefox/new/', active_locales=locales)
@patch.object(l10n_utils, 'translations_for_template')
def test_add_active_locales(self, tft_mock):
path = '/firefox/new/'
template = 'firefox/new.html'
locales = ['en-US', 'en-GB']
tft_mock.return_value = ['fr', 'es-ES']
# expect same results as above, but with locales from different sources
# Nothing to do with a valid locale
self._test(path, template, 'en-US', 'en-us,en;q=0.5',
200, add_active_locales=locales)
# en-GB is activated on /firefox/new/
self._test(path, template, 'en-GB', 'en-gb,en;q=0.5',
200, add_active_locales=locales)
# fr-FR should be treated as fr
self._test(path, template, 'fr-FR', 'fr-fr',
302, '/fr/firefox/new/', add_active_locales=locales)
# Should fallback to the user's second preferred language
self._test(path, template, 'zu', 'zu,fr;q=0.7,en;q=0.3',
302, '/fr/firefox/new/', add_active_locales=locales)
# Should fallback to one of the site's fallback languages
self._test(path, template, 'es-CL', 'es-CL,es;q=0.7,en;q=0.3',
302, '/es-ES/firefox/new/', add_active_locales=locales)
class TestGetAcceptLanguages(TestCase):

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

@ -6,7 +6,6 @@
from django.conf import settings
from django.core import mail
from django.core.cache import cache
from django.core.urlresolvers import clear_url_caches
from django.http import HttpRequest
from django.test.utils import override_settings
@ -20,7 +19,7 @@ from pyquery import PyQuery as pq
from bedrock.mozorg.tests import TestCase
from lib.l10n_utils import render
from lib.l10n_utils.dotlang import (_, _lazy, FORMAT_IDENTIFIER_RE, lang_file_has_tag,
from lib.l10n_utils.dotlang import (_, _lazy, cache, FORMAT_IDENTIFIER_RE, lang_file_has_tag,
lang_file_is_active, parse, translate)
from lib.l10n_utils.extract import extract_python
@ -39,6 +38,7 @@ jinja_env = Jinja2.get_default().env
class TestLangFilesActivation(TestCase):
def setUp(self):
clear_url_caches()
cache.clear()
def test_lang_file_is_active(self):
"""

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

@ -129,7 +129,6 @@ class TestNoLocale(TestCase):
@patch.object(jinja_env.loader, 'searchpath', TEMPLATE_DIRS)
@patch('lib.l10n_utils.template_is_active', Mock(return_value=True))
@patch('lib.l10n_utils.django_render')
class TestLocaleTemplates(TestCase):
def setUp(self):
@ -137,24 +136,44 @@ class TestLocaleTemplates(TestCase):
def test_enUS_render(self, django_render):
"""
en-US requests do not look for localized templates and should render the
en-US requests without l10n or locale template should render the
originally requested template.
"""
django_render.side_effect = [TemplateDoesNotExist, TemplateDoesNotExist, True]
request = self.rf.get('/')
request.locale = 'en-US'
render(request, 'firefox/new.html', {'active_locales': ['en-US']})
django_render.assert_called_with(request, 'firefox/new.html', ANY)
def test_bedrock_enUS_render(self, django_render):
"""
en-US requests with a locale-specific template should render the
locale-specific template.
"""
django_render.side_effect = [TemplateDoesNotExist, True]
request = self.rf.get('/')
request.locale = 'en-US'
render(request, 'firefox/new.html', {'active_locales': ['en-US']})
django_render.assert_called_with(request, 'firefox/new.en-US.html', ANY)
def test_enUS_l10n_render(self, django_render):
"""
en-US requests with an l10n template should render the l10n template.
"""
request = self.rf.get('/')
request.locale = 'en-US'
render(request, 'firefox/new.html')
django_render.assert_called_with(request, 'firefox/new.html', ANY)
render(request, 'firefox/new.html', {'active_locales': ['en-US']})
django_render.assert_called_with(request, 'en-US/templates/firefox/new.html', ANY)
def test_default_render(self, django_render):
"""
Non en-US requests without l10n or locale template should render the
originally requested template.
"""
django_render.side_effect = [TemplateDoesNotExist, TemplateDoesNotExist,
True]
django_render.side_effect = [TemplateDoesNotExist, TemplateDoesNotExist, True]
request = self.rf.get('/')
request.locale = 'de'
render(request, 'firefox/new.html')
render(request, 'firefox/new.html', {'active_locales': ['de']})
django_render.assert_called_with(request, 'firefox/new.html', ANY)
def test_bedrock_locale_render(self, django_render):
@ -165,7 +184,7 @@ class TestLocaleTemplates(TestCase):
django_render.side_effect = [TemplateDoesNotExist, True]
request = self.rf.get('/')
request.locale = 'es-ES'
render(request, 'firefox/new.html')
render(request, 'firefox/new.html', {'active_locales': ['es-ES']})
django_render.assert_called_with(request, 'firefox/new.es-ES.html', ANY)
def test_l10n_render(self, django_render):
@ -175,5 +194,5 @@ class TestLocaleTemplates(TestCase):
"""
request = self.rf.get('/')
request.locale = 'es-ES'
render(request, 'firefox/new.html')
render(request, 'firefox/new.html', {'active_locales': ['es-ES']})
django_render.assert_called_with(request, 'es-ES/templates/firefox/new.html', ANY)

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

@ -900,7 +900,8 @@ URLS = flatten((
# bug 1248393
url_test('/de/about/legal/impressum/', status_code=requests.codes.ok),
url_test('/{en-US,fr,ja}/about/legal/impressum/', '/de/about/legal/impressum/'),
url_test('/{en-US,fr,ja}/about/legal/impressum/', '/de/about/legal/impressum/',
status_code=requests.codes.found),
# bug 960543
url_test('/firefox/{2,3}.0/eula/random/stuff/', '/legal/eula/firefox-{2,3}/'),