Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make MO file compilation optional, issue #155 #166

Merged
merged 1 commit into from
Mar 22, 2016
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
2 changes: 1 addition & 1 deletion docs/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Rosetta can be configured via the following parameters, to be defined in your pr
* ``ROSETTA_CACHE_NAME``: When using ``rosetta.storage.CacheRosettaStorage``, you can store the Rosetta data in a specific cache. This is particularly useful when your ``default`` cache is a ``django.core.cache.backends.dummy.DummyCache`` (which happens on pre-production environments). If unset, it will default to ``rosetta`` if a cache with this name exists, or ``default`` if not.
* ``ROSETTA_POFILENAMES``: Defines which po file names are exposed in the web interface. Defaults to ``('django.po', 'djangojs.po')``
* ``ROSETTA_EXCLUDED_PATHS``: Exclude paths defined in this list from being searched (usually ends with "locale"). Defaults to ``()``

* ``ROSETTA_AUTO_COMPILE``: Determines whether the MO file is automatically compiled when the PO file is saved. Defaults to ``True``.

Storages
--------
Expand Down
3 changes: 3 additions & 0 deletions rosetta/conf/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,6 @@
# 'translators` group, create individual per-language groups, e.g.
# 'translators-de', 'translators-fr', ...
ROSETTA_LANGUAGE_GROUPS = getattr(settings, 'ROSETTA_LANGUAGE_GROUPS', False)

# Determines whether the MO file is automatically compiled when the PO file is saved.
AUTO_COMPILE = getattr(settings, 'ROSETTA_AUTO_COMPILE', True)
80 changes: 80 additions & 0 deletions rosetta/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import six
import django
import vcr
import hashlib


class RosettaTestCase(TestCase):
Expand Down Expand Up @@ -58,6 +59,7 @@ def setUp(self):
self.__require_auth = rosetta_settings.ROSETTA_REQUIRES_AUTH
self.__google_translate = rosetta_settings.GOOGLE_TRANSLATE
self.__enable_translation = rosetta_settings.ENABLE_TRANSLATION_SUGGESTIONS
self.__auto_compile = rosetta_settings.AUTO_COMPILE

shutil.copy(self.dest_file, self.dest_file + '.orig')

Expand All @@ -68,6 +70,7 @@ def tearDown(self):
rosetta_settings.ROSETTA_REQUIRES_AUTH = self.__require_auth
rosetta_settings.GOOGLE_TRANSLATE = self.__google_translate
rosetta_settings.ENABLE_TRANSLATION_SUGGESTIONS = self.__enable_translation
rosetta_settings.AUTO_COMPILE = self.__auto_compile
shutil.move(self.dest_file + '.orig', self.dest_file)

def test_1_ListLoading(self):
Expand Down Expand Up @@ -726,6 +729,83 @@ def test_38_issue_161_more_weird_locales(self):
r = self.client.get(reverse('rosetta-pick-file'))
self.assertTrue(os.path.normpath('locale/zh_Hans/LC_MESSAGES/django.po') in str(r.content))

def test_40_issue_155_auto_compile(self):

def file_hash(file_string):
if six.PY3:
with open(file_string, encoding="latin-1") as file:
file_content = file.read().encode('utf-8')
else:
with open(file_string) as file:
file_content = file.read()
return hashlib.md5(file_content).hexdigest()

def message_hashes():
r = self.client.get(reverse('rosetta-home'))
return dict([(m.msgid, 'm_' + m.md5hash) for m in r.context['rosetta_messages']])

po_file = self.dest_file
mo_file = self.dest_file[:-3] + '.mo'

# Load the template file
self.client.get(reverse('rosetta-pick-file') + '?filter=third-party')
self.client.get(reverse('rosetta-language-selection', args=('xx', 0), kwargs=dict()))

# MO file will be compiled by default.
# Get PO and MO files into an initial reference state (MO will be created or updated)
msg_hashes = message_hashes()
self.client.post(reverse('rosetta-home'), {
msg_hashes['String 1']: "Translation 1", '_next': '_next'})
po_file_hash_before, mo_file_hash_before = file_hash(po_file), file_hash(mo_file)

# Make a change to the translations
msg_hashes = message_hashes()
self.client.post(reverse('rosetta-home'), {
msg_hashes['String 1']: "Translation 2", '_next': '_next'})

# Get the new hashes of the PO and MO file contents
po_file_hash_after, mo_file_hash_after = file_hash(po_file), file_hash(mo_file)

# Both the PO and MO should have changed
self.assertNotEqual(po_file_hash_before, po_file_hash_after)
self.assertNotEqual(mo_file_hash_before, mo_file_hash_after)

# Disable auto-compilation of the MO when the PO is saved
rosetta_settings.AUTO_COMPILE = False

# Make a change to the translations
po_file_hash_before, mo_file_hash_before = po_file_hash_after, mo_file_hash_after
msg_hashes = message_hashes()
self.client.post(reverse('rosetta-home'), {
msg_hashes['String 1']: "Translation 3", '_next': '_next'})
po_file_hash_after, mo_file_hash_after = file_hash(po_file), file_hash(mo_file)

# Only the PO should have changed, the MO should be unchanged
self.assertNotEqual(po_file_hash_before, po_file_hash_after)
self.assertEqual(mo_file_hash_before, mo_file_hash_after)

# Verify that translating another string also leaves the MO unchanged
po_file_hash_before, mo_file_hash_before = po_file_hash_after, mo_file_hash_after
msg_hashes = message_hashes()
self.client.post(reverse('rosetta-home'), {
msg_hashes['String 2']: "Translation 4", '_next': '_next'})
po_file_hash_after, mo_file_hash_after = file_hash(po_file), file_hash(mo_file)

self.assertNotEqual(po_file_hash_before, po_file_hash_after)
self.assertEqual(mo_file_hash_before, mo_file_hash_after)

# Double check that switching back to auto compilation updates the MO
rosetta_settings.AUTO_COMPILE = True

po_file_hash_before, mo_file_hash_before = po_file_hash_after, mo_file_hash_after
msg_hashes = message_hashes()
self.client.post(reverse('rosetta-home'), {
msg_hashes['String 2']: "Translation 5", '_next': '_next'})
po_file_hash_after, mo_file_hash_after = file_hash(po_file), file_hash(mo_file)

self.assertNotEqual(po_file_hash_before, po_file_hash_after)
self.assertNotEqual(mo_file_hash_before, mo_file_hash_after)


# Stubbed access control function
def no_access(user):
Expand Down
6 changes: 4 additions & 2 deletions rosetta/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,10 @@ def _request_request(key, default=None):
try:
rosetta_i18n_pofile.save()
po_filepath, ext = os.path.splitext(rosetta_i18n_fn)
save_as_mo_filepath = po_filepath + '.mo'
rosetta_i18n_pofile.save_as_mofile(save_as_mo_filepath)

if rosetta_settings.AUTO_COMPILE:
save_as_mo_filepath = po_filepath + '.mo'
rosetta_i18n_pofile.save_as_mofile(save_as_mo_filepath)

post_save.send(sender=None, language_code=rosetta_i18n_lang_code, request=request)
# Try auto-reloading via the WSGI daemon mode reload mechanism
Expand Down