Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions lib/l10n_utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from django.conf import settings
from django.http import HttpResponseRedirect

from dotlang import get_lang_path
import jingo
from funfactory.urlresolvers import split_path
from jinja2.exceptions import TemplateNotFound

from dotlang import get_lang_path, lang_file_is_active


def render(request, template, context={}, **kwargs):
"""
Expand All @@ -18,17 +21,26 @@ def render(request, template, context={}, **kwargs):

if present, otherwise, it'll render the specified (en-US) template.
"""
# Every template gets its own .lang file, so figure out what it is
# and pass it in the context
context['langfile'] = get_lang_path(template)

# Look for localized template if not default lang.
if request.locale != settings.LANGUAGE_CODE:

# redirect to default lang if locale not active
if not (settings.DEV or
lang_file_is_active(context['langfile'], request.locale)):
return HttpResponseRedirect('/' + '/'.join([
settings.LANGUAGE_CODE,
split_path(request.get_full_path())[1]
]))

localized_tmpl = '%s/templates/%s' % (request.locale, template)
try:
return jingo.render(request, localized_tmpl, context, **kwargs)
except TemplateNotFound:
# If not found, just go on and try rendering the parent template.
pass

# Every template gets its own .lang file, so figure out what it is
# and pass it in the context
context['langfile'] = get_lang_path(template)

return jingo.render(request, template, context, **kwargs)
27 changes: 27 additions & 0 deletions lib/l10n_utils/dotlang.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,30 @@ def get_lang_path(path):
path = '/'.join(p)
base, ext = os.path.splitext(path)
return base


def lang_file_is_active(path, lang):
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this should get some caching or not. It should be pretty quick to check the first line of a file, but if you guys think that storing the results in memcache for a minute or so might help with load then it can be easily added.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it's worth given how easy this would be to cache, although I'm curious why you'd only cache it for a minute. How often do these files change on production? Is memcache cleared when we push?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was based on the value in our settings for DOTLANG_CACHE being 60. I think we should consider increasing that as well to at least the length of time between the cron runs.

"""
If the lang file for a locale exists and has the correct comment returns
True, and False otherwise.
:param path: the relative lang file name
:param lang: the language code
:return: bool
"""
rel_path = os.path.join('locale', lang, '%s.lang' % path)
cache_key = 'active:%s' % rel_path
is_active = cache.get(cache_key)
if is_active is None:
is_active = False
fpath = os.path.join(settings.ROOT, rel_path)
try:
with codecs.open(fpath, 'r', 'utf-8', errors='replace') as lines:
firstline = lines.readline()
if firstline.startswith('## active ##'):
is_active = True
except IOError:
pass

cache.set(cache_key, is_active, settings.DOTLANG_CACHE)

return is_active
61 changes: 59 additions & 2 deletions lib/l10n_utils/tests/test_dotlang.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,74 @@

from django.conf import settings
from django.core import mail
from django.core.urlresolvers import clear_url_caches
from django.test.client import Client

from jingo import env
from jinja2 import FileSystemLoader
from mock import patch
from nose.tools import assert_not_equal, eq_
from nose.tools import assert_not_equal, eq_, ok_
from pyquery import PyQuery as pq
from tower.management.commands.extract import extract_tower_python

from l10n_utils.dotlang import _, FORMAT_IDENTIFIER_RE, parse, translate
from l10n_utils.dotlang import (_, FORMAT_IDENTIFIER_RE, lang_file_is_active,
parse, translate)
from mozorg.tests import TestCase


ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test_files')
LANG_FILES = 'test_file'
TEMPLATE_DIRS = (os.path.join(ROOT, 'templates'),)


@patch.object(env, 'loader', FileSystemLoader(TEMPLATE_DIRS))
@patch.object(settings, 'ROOT_URLCONF', 'l10n_utils.tests.test_files.urls')
@patch.object(settings, 'ROOT', ROOT)
class TestLangFilesActivation(TestCase):
def setUp(self):
clear_url_caches()
self.client = Client()

@patch.object(settings, 'DEV', False)
def test_lang_file_is_active(self):
"""
`lang_file_is_active` should return true if lang file has the
comment, and false otherwise.
"""
ok_(lang_file_is_active('active_de_lang_file', 'de'))
ok_(not lang_file_is_active('active_de_lang_file', 'es'))
ok_(not lang_file_is_active('inactive_de_lang_file', 'de'))
ok_(not lang_file_is_active('does_not_exist', 'de'))

@patch.object(settings, 'DEV', False)
def test_active_locale_not_redirected(self):
""" Active lang file should render correctly. """
response = self.client.get('/de/active-de-lang-file/')
eq_(response.status_code, 200)
doc = pq(response.content)
eq_(doc('h1').text(), 'Die Lage von Mozilla')

@patch.object(settings, 'DEV', False)
@patch.object(settings, 'LANGUAGE_CODE', 'en-US')
def test_inactive_locale_redirected(self):
""" Inactive locale should redirect to en-US. """
response = self.client.get('/de/inactive-de-lang-file/')
eq_(response.status_code, 302)
eq_(response['location'],
'http://testserver/en-US/inactive-de-lang-file/')
response = self.client.get('/de/inactive-de-lang-file/', follow=True)
doc = pq(response.content)
eq_(doc('h1').text(), 'The State of Mozilla')

@patch.object(settings, 'DEV', True)
def test_inactive_locale_not_redirected_dev_true(self):
"""
Inactive lang file should not redirect in DEV mode.
"""
response = self.client.get('/de/inactive-de-lang-file/')
eq_(response.status_code, 200)
doc = pq(response.content)
eq_(doc('h1').text(), 'Die Lage von Mozilla')


class TestDotlang(TestCase):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## active ##

;The State of Mozilla
Die Lage von Mozilla


;Mozilla‘s vision of the Internet is a place where anyone can access information, a place where everyone can hack and tinker; one that has openness, freedom and transparency; where users have control over their personal data and where all minds have the freedom to create and to consume without walls or tight restrictions.
Mozillas Vision des Internets ist ein Ort, wo jeder auf Informationen zugreifen kann, ein Ort, wo jeder programmieren und herumspielen kann; einer, der offen, frei und transparent ist; wo Benutzer die Kontrolle über ihre persönlichen Daten haben und wo jeder Geist die Freiheit hat, zu schaffen und zu konsumieren, ohne Mauern oder enge Einschränkungen.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
;The State of Mozilla
Die Lage von Mozilla


;Mozilla‘s vision of the Internet is a place where anyone can access information, a place where everyone can hack and tinker; one that has openness, freedom and transparency; where users have control over their personal data and where all minds have the freedom to create and to consume without walls or tight restrictions.
Mozillas Vision des Internets ist ein Ort, wo jeder auf Informationen zugreifen kann, ein Ort, wo jeder programmieren und herumspielen kann; einer, der offen, frei und transparent ist; wo Benutzer die Kontrolle über ihre persönlichen Daten haben und wo jeder Geist die Freiheit hat, zu schaffen und zu konsumieren, ohne Mauern oder enge Einschränkungen.
14 changes: 14 additions & 0 deletions lib/l10n_utils/tests/test_files/templates/active_de_lang_file.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<html>
<body>
<h1>{{ _('The State of Mozilla') }}</h1>
<p>
{% trans %}
Mozilla‘s vision of the Internet is a place where anyone can
access information, a place where everyone can hack and tinker;
one that has openness, freedom and transparency; where users have
control over their personal data and where all minds have the
freedom to create and to consume without walls or tight restrictions.
{% endtrans %}
</p>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<html>
<body>
<h1>{{ _('The State of Mozilla') }}</h1>
<p>
{% trans %}
Mozilla‘s vision of the Internet is a place where anyone can
access information, a place where everyone can hack and tinker;
one that has openness, freedom and transparency; where users have
control over their personal data and where all minds have the
freedom to create and to consume without walls or tight restrictions.
{% endtrans %}
</p>
</body>
</html>
2 changes: 2 additions & 0 deletions lib/l10n_utils/tests/test_files/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@

urlpatterns = patterns('',
page('trans-block-reload-test', 'trans_block_reload_test.html'),
page('active-de-lang-file', 'active_de_lang_file.html'),
page('inactive-de-lang-file', 'inactive_de_lang_file.html'),
)
6 changes: 3 additions & 3 deletions lib/l10n_utils/tests/test_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@
TEMPLATE_DIRS = (os.path.join(ROOT, 'templates'),)


@patch.object(env, 'loader', FileSystemLoader(TEMPLATE_DIRS))
@patch.object(settings, 'ROOT_URLCONF', 'l10n_utils.tests.test_files.urls')
@patch.object(settings, 'ROOT', ROOT)
class TestTransBlocks(TestCase):
def setUp(self):
clear_url_caches()
self.client = Client()

@patch.object(env, 'loader', FileSystemLoader(TEMPLATE_DIRS))
@patch.object(settings, 'ROOT_URLCONF', 'l10n_utils.tests.test_files.urls')
@patch.object(settings, 'ROOT', ROOT)
def test_trans_block_works(self):
""" Sanity check to make sure translations work at all. """
response = self.client.get('/de/trans-block-reload-test/')
Expand Down