Permalink
Browse files

Fix Bug 1097785 - Legal-docs-based pages should not rely on active ta…

…gs in .lang files
  • Loading branch information...
1 parent 42c7a4b commit 095784321ba756d71157ced2cc0f8191c472ef85 @kyoshino kyoshino committed Jan 27, 2015
Showing with 78 additions and 23 deletions.
  1. +34 −9 bedrock/legal_docs/tests.py
  2. +28 −9 bedrock/legal_docs/views.py
  3. +7 −4 bedrock/privacy/views.py
  4. +9 −1 lib/l10n_utils/__init__.py
@@ -16,32 +16,44 @@
class TestLoadLegalDoc(TestCase):
- def test_legal_doc_not_found(self):
+ @patch.object(views, 'listdir')
+ def test_legal_doc_not_found(self, listdir_mock):
+ listdir_mock.return_value = ['en-US.md']
doc = views.load_legal_doc('the_dude_is_legal', 'de')
- self.assertIsNone(doc)
+ self.assertIsNone(doc['content'])
+ self.assertFalse(doc['localized'])
+ self.assertDictEqual(doc['translations'], {'en-US': 'English (US)'})
+ @patch.object(views, 'listdir')
@patch.object(views, 'StringIO')
@patch.object(views, 'md')
- def test_legal_doc_exists(self, md_mock, sio_mock):
+ def test_legal_doc_exists(self, md_mock, sio_mock, listdir_mock):
"""Should return the content of the en-US file if it exists."""
sio_mock.StringIO.return_value.getvalue.return_value = "You're not wrong Walter..."
+ listdir_mock.return_value = ['.mkdir', 'de.md', 'en-US.md']
doc = views.load_legal_doc('the_dude_exists', 'de')
good_path = join(views.LEGAL_DOCS_PATH, 'the_dude_exists', 'en-US.md')
md_mock.markdownFromFile.assert_called_with(
input=good_path, output=ANY, extensions=ANY)
- self.assertEqual(doc, "You're not wrong Walter...")
+ self.assertEqual(doc['content'], "You're not wrong Walter...")
+ self.assertTrue(doc['localized'])
+ self.assertDictEqual(doc['translations'], {'de': 'Deutsch', 'en-US': 'English (US)'})
@patch('os.path.exists')
+ @patch.object(views, 'listdir')
@patch.object(views, 'StringIO')
@patch.object(views, 'md')
- def test_localized_legal_doc_exists(self, md_mock, sio_mock, exists_mock):
+ def test_localized_legal_doc_exists(self, md_mock, sio_mock, listdir_mock, exists_mock):
sio_mock.StringIO.return_value.getvalue.return_value = "You're not wrong Walter..."
exists_mock.return_value = True
+ listdir_mock.return_value = ['.mkdir', 'de.md', 'en-US.md']
doc = views.load_legal_doc('the_dude_exists', 'de')
good_path = join(views.LEGAL_DOCS_PATH, 'the_dude_exists', 'de.md')
md_mock.markdownFromFile.assert_called_with(
input=good_path, output=ANY, extensions=ANY)
- self.assertEqual(doc, "You're not wrong Walter...")
+ self.assertEqual(doc['content'], "You're not wrong Walter...")
+ self.assertTrue(doc['localized'])
+ self.assertDictEqual(doc['translations'], {'de': 'Deutsch', 'en-US': 'English (US)'})
class TestLegalDocView(TestCase):
@@ -62,7 +74,11 @@ def test_missing_doc_is_404(self, lld_mock):
def test_good_doc_okay(self, render_mock, lld_mock):
"""Should render correct thing when all is well"""
doc_value = "Donny, you're out of your element!"
- lld_mock.return_value = doc_value
+ lld_mock.return_value = {
+ 'content': doc_value,
+ 'localized': True,
+ 'translations': {'de': 'Deutsch', 'en-US': 'English (US)'},
+ }
good_resp = HttpResponse(doc_value)
render_mock.return_value = good_resp
req = RequestFactory().get('/dude/exists/')
@@ -73,14 +89,19 @@ def test_good_doc_okay(self, render_mock, lld_mock):
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')
@patch.object(views.l10n_utils, 'render')
def test_cache_settings(self, render_mock, lld_mock):
"""Should use the cache_timeout value from view."""
doc_value = "Donny, you're out of your element!"
- lld_mock.return_value = doc_value
+ lld_mock.return_value = {
+ 'content': doc_value,
+ 'localized': True,
+ 'translations': {'es-ES': 'Espa\u00f1ol (de Espa\u00f1a)', 'en-US': 'English (US)'},
+ }
good_resp = HttpResponse(doc_value)
render_mock.return_value = good_resp
req = RequestFactory().get('/dude/exists/cached/')
@@ -96,7 +117,11 @@ def test_cache_settings(self, render_mock, lld_mock):
def test_cache_class_attrs(self, render_mock, lld_mock):
"""Should use the cache_timeout value from view class."""
doc_value = "Donny, you're out of your element!"
- lld_mock.return_value = doc_value
+ lld_mock.return_value = {
+ 'content': doc_value,
+ 'localized': True,
+ 'translations': {'es-ES': 'Espa\u00f1ol (de Espa\u00f1a)', 'en-US': 'English (US)'},
+ }
good_resp = HttpResponse(doc_value)
render_mock.return_value = good_resp
req = RequestFactory().get('/dude/exists/cached/2/')
@@ -2,7 +2,7 @@
# 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/.
-from os import path
+from os import path, listdir
import StringIO
from django.conf import settings
@@ -14,6 +14,7 @@
from bedrock.settings import path as base_path
from lib import l10n_utils
+from product_details import product_details
LEGAL_DOCS_PATH = base_path('vendor-local', 'src', 'legal-docs')
CACHE_TIMEOUT = getattr(settings, 'LEGAL_DOCS_CACHE_TIMEOUT', 60 * 60)
@@ -25,24 +26,40 @@ def load_legal_doc(doc_name, locale):
:param doc_name: name of the legal doc folder
:param locale: preferred language version of the doc
- :return: string content of the file or None
+ :return: dict containing string content of the file (or None), a boolean
+ value indicating whether the file is localized into the specified
+ locale, and a dict of all available locales for that document
"""
- source = path.join(LEGAL_DOCS_PATH, doc_name, locale + '.md')
+ source_dir = path.join(LEGAL_DOCS_PATH, doc_name)
+ source_file = path.join(source_dir, locale + '.md')
output = StringIO.StringIO()
- if not path.exists(source):
- source = path.join(LEGAL_DOCS_PATH, doc_name, 'en-US.md')
+ locales = [f.replace('.md', '') for f in listdir(source_dir) if f.endswith('.md')]
+ translations = {}
+
+ if not path.exists(source_file):
+ source_file = path.join(LEGAL_DOCS_PATH, doc_name, 'en-US.md')
try:
# Parse the Markdown file
- md.markdownFromFile(input=source, output=output,
+ md.markdownFromFile(input=source_file, output=output,
extensions=['attr_list', 'headerid', 'outline(wrapper_cls=)'])
content = output.getvalue().decode('utf8')
+ localized = locale != settings.LANGUAGE_CODE
except IOError:
- return None
+ content = None
+ localized = False
finally:
output.close()
- return content
+ for lang in locales:
+ if lang in product_details.languages:
+ translations[lang] = product_details.languages[lang]['native']
+
+ return {
+ 'content': content,
+ 'localized': localized,
+ 'translations': translations,
+ }
class LegalDocView(TemplateView):
@@ -80,7 +97,9 @@ def get_context_data(self, **kwargs):
raise Http404('Legal doc not found')
context = super(LegalDocView, self).get_context_data(**kwargs)
- context[self.legal_doc_context_name] = legal_doc
+ context[self.legal_doc_context_name] = legal_doc['content']
+ context['localized'] = legal_doc['localized']
+ context['translations'] = legal_doc['translations']
return context
@classmethod
@@ -68,7 +68,8 @@ def process_legal_doc(content):
class PrivacyDocView(LegalDocView):
def get_legal_doc(self):
doc = super(PrivacyDocView, self).get_legal_doc()
- return process_legal_doc(doc)
+ doc['content'] = process_legal_doc(doc['content'])
+ return doc
firefox_notices = PrivacyDocView.as_view(
@@ -138,13 +139,15 @@ def privacy(request):
form_submitted = form_results['form_submitted']
form_error = form_results['form_error']
+ doc = load_legal_doc('mozilla_privacy_policy', l10n_utils.get_locale(request))
+
template_vars = {
'form': form,
'form_submitted': form_submitted,
'form_error': form_error,
- 'doc': process_legal_doc(load_legal_doc('mozilla_privacy_policy',
- l10n_utils.get_locale(request))
- ),
+ 'doc': process_legal_doc(doc['content']),
+ 'localized': doc['localized'],
+ 'translations': doc['translations'],
}
return l10n_utils.render(request, 'privacy/index.html', template_vars)
@@ -41,14 +41,22 @@ def render(request, template, context=None, **kwargs):
context['langfile'] = get_lang_path(template)
# Get the available translation list of the current page
- context['translations'] = translations_for_template(template)
+ context.setdefault('translations', {})
+ context['translations'].update(translations_for_template(template))
# Look for localized template if not default lang.
if hasattr(request, 'locale') and request.locale != settings.LANGUAGE_CODE:
# 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
for lang in get_accept_languages(request):

0 comments on commit 0957843

Please sign in to comment.