dropped support for python2 and django < 1.11

This commit is contained in:
Marco Bonetti 2020-06-07 16:43:21 +02:00
parent 6cdc390567
commit efdc0a649d
9 changed files with 331 additions and 300 deletions

2
.pep8
View file

@ -1,3 +1,3 @@
[flake8]
ignore = E501
ignore = E501,W503
exclude = south_migrations,migrations,.venv_*,docs

View file

@ -3,10 +3,6 @@ services: memcached
matrix:
include:
- python: "2.7"
env: TOX_ENV=py27-django111
- python: "3.6"
env: TOX_ENV=py36-django111
- python: "3.6"
env: TOX_ENV=py36-django20
- python: "3.6"

View file

@ -9,6 +9,8 @@ Version 0.9.5 (unreleased)
* Added Kyrgyz translation (#239,thanks @Soyuzbek)
* Ignore translator context hints checking unmatched variables (#238, #239, thanks @jeancochrane and @mondeja)
* Uncheck fuzzy on translation keyup instead of change (#235 @mondeja)
* Allow passing a function itself to the setting ROSETTA_ACCESS_CONTROL (#227, thanks @alvra)
* Dropped support for Django 1.11 and Python 2
Version 0.9.4

View file

@ -13,7 +13,7 @@ Rosetta can be configured via the following parameters, to be defined in your pr
* ``ROSETTA_REQUIRES_AUTH``: Require authentication for all Rosetta views. Defaults to ``True``.
* ``ROSETTA_POFILE_WRAP_WIDTH``: Sets the line-length of the edited PO file. Set this to ``0`` to mimic ``makemessage``'s ``--no-wrap`` option. Defaults to ``78``.
* ``ROSETTA_STORAGE_CLASS``: See the note below on Storages. Defaults to ``rosetta.storage.CacheRosettaStorage``
* ``ROSETTA_ACCESS_CONTROL_FUNCTION``: An alternative function that determines if a given user can access the translation views. This function receives a ``user`` as its argument, and returns a boolean specifying whether the passed user is allowed to use Rosetta or not.
* ``ROSETTA_ACCESS_CONTROL_FUNCTION``: An alternative function (string or a callable) that determines if a given user can access the translation views. This function receives a ``user`` as its argument, and returns a boolean specifying whether the passed user is allowed to use Rosetta or not.
* ``ROSETTA_LANGUAGE_GROUPS``: Set to ``True`` to enable language-specific groups, which can be used to give different translators access to different languages. Instead of creating a global ``translators`` group, create individual per-language groups, e.g. ``translators-de``, ``translators-fr``, and assign users to these.
* ``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')``

View file

@ -1,34 +1,27 @@
# -*- coding: utf-8 -*-
import filecmp
import hashlib
import os
import shutil
import vcr
try:
# Python 3
from urllib.parse import urlencode
except ImportError:
# Python 2
from urllib import urlencode
from urllib.parse import urlencode
from django.conf import settings
from django.dispatch import receiver
from django.core.exceptions import ImproperlyConfigured
from django.http import Http404
from django.test import TestCase, RequestFactory, override_settings
from django.test.client import Client
from django import VERSION
from django.urls import reverse, resolve
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.dispatch import receiver
from django.http import Http404
from django.test import RequestFactory, TestCase, override_settings
from django.test.client import Client
from django.urls import resolve, reverse
from django.utils.encoding import force_bytes
import six
import six
import vcr
from rosetta import views
from rosetta.signals import entry_changed, post_save
from rosetta.storage import get_storage
from rosetta import views
class RosettaTestCase(TestCase):
def __init__(self, *args, **kwargs):
super(RosettaTestCase, self).__init__(*args, **kwargs)
self.curdir = os.path.dirname(__file__)
@ -39,9 +32,15 @@ class RosettaTestCase(TestCase):
def setUp(self):
from django.contrib.auth.models import User
user = User.objects.create_superuser('test_admin', 'test@test.com', 'test_password')
user2 = User.objects.create_superuser('test_admin2', 'test@test2.com', 'test_password')
user3 = User.objects.create_superuser('test_admin3', 'test@test2.com', 'test_password')
user = User.objects.create_superuser(
'test_admin', 'test@test.com', 'test_password'
)
user2 = User.objects.create_superuser(
'test_admin2', 'test@test2.com', 'test_password'
)
user3 = User.objects.create_superuser(
'test_admin3', 'test@test2.com', 'test_password'
)
user3.is_staff = False
user3.save()
@ -84,15 +83,14 @@ class RosettaTestCase(TestCase):
def test_1_ListLoading(self):
r = self.client.get(self.third_party_file_list_url)
self.assertTrue(
os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po') in str(r.content)
os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po')
in r.content.decode()
)
@override_settings(ROSETTA_LANGUAGES=(
('xx', 'dummy language'),
))
@override_settings(ROSETTA_LANGUAGES=(('xx', 'dummy language'),))
def test_2_PickFile(self):
r = self.client.get(self.xx_form_url)
self.assertTrue('dummy language' in str(r.content))
self.assertTrue('dummy language' in r.content.decode())
def test_3_DownloadZIP(self):
kwargs = {'po_filter': 'third-party', 'lang_id': 'xx', 'idx': 0}
@ -101,9 +99,7 @@ class RosettaTestCase(TestCase):
self.assertTrue('content-type' in r._headers.keys())
self.assertTrue('application/x-zip' in r._headers.get('content-type'))
@override_settings(ROSETTA_LANGUAGES=(
('xx', 'dummy language'),
))
@override_settings(ROSETTA_LANGUAGES=(('xx', 'dummy language'),))
def test_4_DoChanges(self):
self.copy_po_file_from_template('./django.po.template')
untranslated_url = self.xx_form_url + '?msg_filter=untranslated'
@ -113,10 +109,10 @@ class RosettaTestCase(TestCase):
r = self.client.get(untranslated_url)
# make sure both strings are untranslated
self.assertTrue('dummy language' in str(r.content))
self.assertTrue('String 1' in str(r.content))
self.assertTrue('String 2' in str(r.content))
self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in str(r.content))
self.assertTrue('dummy language' in r.content.decode())
self.assertTrue('String 1' in r.content.decode())
self.assertTrue('String 2' in r.content.decode())
self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in r.content.decode())
# post a translation
data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world'}
@ -126,20 +122,18 @@ class RosettaTestCase(TestCase):
r = self.client.get(untranslated_url)
# the translated string no longer is up for translation
self.assertTrue('String 1' in str(r.content))
self.assertTrue('String 2' not in str(r.content))
self.assertTrue('String 1' in r.content.decode())
self.assertTrue('String 2' not in r.content.decode())
# display only translated strings
r = self.client.get(translated_url)
# The translation was persisted
self.assertTrue('String 1' not in str(r.content))
self.assertTrue('String 2' in str(r.content))
self.assertTrue('Hello, world' in str(r.content))
self.assertTrue('String 1' not in r.content.decode())
self.assertTrue('String 2' in r.content.decode())
self.assertTrue('Hello, world' in r.content.decode())
@override_settings(ROSETTA_LANGUAGES=(
('xx', 'dummy language'),
))
@override_settings(ROSETTA_LANGUAGES=(('xx', 'dummy language'),))
def test_5_TestIssue67(self):
# issue 67: http://code.google.com/p/django-rosetta/issues/detail?id=67
self.copy_po_file_from_template('./django.po.issue67.template')
@ -149,15 +143,15 @@ class RosettaTestCase(TestCase):
content = f_.read()
self.assertTrue('Hello, world' not in six.text_type(content))
self.assertTrue('|| n%100>=20) ? 1 : 2)' in six.text_type(content))
del(content)
del content
r = self.client.get(self.xx_form_url + '?msg_filter=untranslated')
# make sure all strings are untranslated
self.assertTrue('dummy language' in str(r.content))
self.assertTrue('String 1' in str(r.content))
self.assertTrue('String 2' in str(r.content))
self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in str(r.content))
self.assertTrue('dummy language' in r.content.decode())
self.assertTrue('String 1' in r.content.decode())
self.assertTrue('String 2' in r.content.decode())
self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in r.content.decode())
# post a translation
data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world'}
@ -169,13 +163,11 @@ class RosettaTestCase(TestCase):
self.assertTrue('Hello, world' in str(content))
self.assertTrue('|| n%100>=20) ? 1 : 2)' in str(content))
self.assertTrue('or n%100>=20) ? 1 : 2)' not in str(content))
del(content)
del content
@override_settings(ROSETTA_LANGUAGES=(
('xx', 'dummy language'),
))
@override_settings(ROSETTA_LANGUAGES=(('xx', 'dummy language'),))
def test_6_ExcludedApps(self):
with self.settings(ROSETTA_EXCLUDED_APPLICATIONS=('rosetta', )):
with self.settings(ROSETTA_EXCLUDED_APPLICATIONS=('rosetta',)):
r = self.client.get(self.third_party_file_list_url)
self.assertNotContains(r, 'rosetta/locale/xx/LC_MESSAGES/django.po')
@ -190,17 +182,15 @@ class RosettaTestCase(TestCase):
r = self.client.get(self.project_file_list_url)
self.assertNotContains(r, 'rosetta/locale/xx/LC_MESSAGES/django.po')
@override_settings(ROSETTA_LANGUAGES=(
('xx', 'dummy language'),
))
@override_settings(ROSETTA_LANGUAGES=(('xx', 'dummy language'),))
def test_8_hideObsoletes(self):
r = self.client.get(self.xx_form_url)
# not in listing
for p in range(1, 5):
r = self.client.get(self.xx_form_url + '?page=%d' % p)
self.assertTrue('dummy language' in str(r.content))
self.assertTrue('Les deux' not in str(r.content))
self.assertTrue('dummy language' in r.content.decode())
self.assertTrue('Les deux' not in r.content.decode())
r = self.client.get(self.xx_form_url + '?query=Les%20Deux')
self.assertContains(r, 'dummy language')
@ -278,7 +268,7 @@ class RosettaTestCase(TestCase):
def test_11_issue_80_tab_indexes(self):
r = self.client.get(self.xx_form_url)
self.assertTrue('tabindex="3"' in str(r.content))
self.assertTrue('tabindex="3"' in r.content.decode())
def test_12_issue_82_staff_user(self):
self.client3 = Client()
@ -297,37 +287,37 @@ class RosettaTestCase(TestCase):
self.assertTrue(r.content)
self.assertEqual(r.status_code, 200)
@override_settings(ROSETTA_LANGUAGES=(('fr', 'French'), ('xx', 'Dummy Language'),))
@override_settings(ROSETTA_LANGUAGES=(('fr', 'French'), ('xx', 'Dummy Language')))
def test_13_catalog_filters(self):
r = self.client.get(self.third_party_file_list_url)
self.assertTrue(
os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po') in str(r.content)
os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po')
in r.content.decode()
)
self.assertTrue(('contrib') not in str(r.content))
url = reverse('rosetta-file-list', kwargs={'po_filter': 'django'})
r = self.client.get(url)
self.assertTrue(
os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po') not in str(r.content)
os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po')
not in r.content.decode()
)
self.assertTrue(('contrib') in str(r.content))
r = self.client.get(self.all_file_list_url)
self.assertTrue(
os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po') in str(r.content)
os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po')
in r.content.decode()
)
self.assertTrue(('contrib') in str(r.content))
r = self.client.get(self.project_file_list_url)
self.assertTrue(
os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po') not in str(r.content)
os.path.normpath('rosetta/locale/xx/LC_MESSAGES/django.po')
not in r.content.decode()
)
self.assertTrue(('contrib') not in str(r.content))
def test_14_issue_99_context_and_comments(self):
r = self.client.get(self.xx_form_url)
self.assertTrue('This is a text of the base template' in str(r.content))
self.assertTrue('Context hint' in str(r.content))
self.assertTrue('This is a text of the base template' in r.content.decode())
self.assertTrue('Context hint' in r.content.decode())
def test_15_issue_87_entry_changed_signal(self):
self.copy_po_file_from_template('./django.po.template')
@ -338,7 +328,8 @@ class RosettaTestCase(TestCase):
self.test_old_msgstr = kwargs.get('old_msgstr')
self.test_new_msgstr = sender.msgstr
self.test_msg_id = sender.msgid
self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in str(r.content))
self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in r.content.decode())
# post a translation
data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world'}
@ -348,7 +339,7 @@ class RosettaTestCase(TestCase):
self.assertTrue(self.test_new_msgstr == 'Hello, world')
self.assertTrue(self.test_msg_id == 'String 2')
del(self.test_old_msgstr, self.test_new_msgstr, self.test_msg_id)
del (self.test_old_msgstr, self.test_new_msgstr, self.test_msg_id)
def test_16_issue_101_post_save_signal(self):
self.copy_po_file_from_template('./django.po.template')
@ -358,14 +349,14 @@ class RosettaTestCase(TestCase):
def test_receiver(sender, **kwargs):
self.test_sig_lang = kwargs.get('language_code')
self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in str(r.content))
self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in r.content.decode())
# post a translation
data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world'}
self.client.post(self.xx_form_url, data)
self.assertTrue(self.test_sig_lang == 'xx')
del(self.test_sig_lang)
del self.test_sig_lang
def test_17_issue_103_post_save_signal_has_request(self):
self.copy_po_file_from_template('./django.po.template')
@ -375,31 +366,32 @@ class RosettaTestCase(TestCase):
def test_receiver(sender, **kwargs):
self.test_16_has_request = 'request' in kwargs
self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in str(r.content))
self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in r.content.decode())
# post a translation
data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world'}
r = self.client.post(self.xx_form_url, data)
self.assertTrue(self.test_16_has_request)
del(self.test_16_has_request)
del self.test_16_has_request
def test_18_Test_Issue_gh24(self):
self.copy_po_file_from_template('./django.po.issue24gh.template')
r = self.client.get(self.xx_form_url)
self.assertTrue('m_bb9d8fe6159187b9ea494c1b313d23d4' in str(r.content))
self.assertTrue('m_bb9d8fe6159187b9ea494c1b313d23d4' in r.content.decode())
# Post a translation, it should have properly wrapped lines
data = {'m_bb9d8fe6159187b9ea494c1b313d23d4':
'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean '
'commodo ligula eget dolor. Aenean massa. Cum sociis natoque '
'penatibus et magnis dis parturient montes, nascetur ridiculus '
'mus. Donec quam felis, ultricies nec, pellentesque eu, pretium '
'quis, sem. Nulla consequat massa quis enim. Donec pede justo, '
'fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, '
'rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum '
'felis eu pede mollis pretium.'}
data = {
'm_bb9d8fe6159187b9ea494c1b313d23d4': 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean '
'commodo ligula eget dolor. Aenean massa. Cum sociis natoque '
'penatibus et magnis dis parturient montes, nascetur ridiculus '
'mus. Donec quam felis, ultricies nec, pellentesque eu, pretium '
'quis, sem. Nulla consequat massa quis enim. Donec pede justo, '
'fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, '
'rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum '
'felis eu pede mollis pretium.'
}
r = self.client.post(self.xx_form_url, data)
with open(self.dest_file, 'r') as po_file:
pofile_content = po_file.read()
@ -410,7 +402,7 @@ class RosettaTestCase(TestCase):
self.copy_po_file_from_template('./django.po.issue24gh.template')
with self.settings(ROSETTA_POFILE_WRAP_WIDTH=0):
r = self.client.get(self.xx_form_url)
self.assertTrue('m_bb9d8fe6159187b9ea494c1b313d23d4' in str(r.content))
self.assertTrue('m_bb9d8fe6159187b9ea494c1b313d23d4' in r.content.decode())
r = self.client.post(self.xx_form_url, data)
with open(self.dest_file, 'r') as po_file:
pofile_content = po_file.read()
@ -419,9 +411,9 @@ class RosettaTestCase(TestCase):
def test_19_Test_Issue_gh34(self):
self.copy_po_file_from_template('./django.po.issue34gh.template')
r = self.client.get(self.xx_form_url)
self.assertTrue('m_ff7060c1a9aae9c42af4d54ac8551f67_1' in str(r.content))
self.assertTrue('m_ff7060c1a9aae9c42af4d54ac8551f67_0' in str(r.content))
self.assertTrue('m_09f7e02f1290be211da707a266f153b3' in str(r.content))
self.assertTrue('m_ff7060c1a9aae9c42af4d54ac8551f67_1' in r.content.decode())
self.assertTrue('m_ff7060c1a9aae9c42af4d54ac8551f67_0' in r.content.decode())
self.assertTrue('m_09f7e02f1290be211da707a266f153b3' in r.content.decode())
# post a translation, it should have properly wrapped lines
data = {
@ -443,15 +435,16 @@ class RosettaTestCase(TestCase):
def test_20_Test_Issue_gh38(self):
# (Have to log in again, since our session engine changed)
self.client.login(username='test_admin', password='test_password')
self.assertTrue('django.contrib.sessions.middleware.SessionMiddleware'
in settings.MIDDLEWARE)
self.assertTrue(
'django.contrib.sessions.middleware.SessionMiddleware' in settings.MIDDLEWARE
)
# Only one backend to test: cache backend
self.copy_po_file_from_template('./django.po.issue38gh.template')
r = self.client.get(self.xx_form_url)
self.assertFalse(len(str(self.client.cookies.get('sessionid'))) > 4096)
self.assertTrue('m_9efd113f7919952523f06e0d88da9c54' in str(r.content))
self.assertTrue('m_9efd113f7919952523f06e0d88da9c54' in r.content.decode())
data = {'m_9efd113f7919952523f06e0d88da9c54': 'Testing cookie length'}
r = self.client.post(self.xx_form_url, data)
@ -460,8 +453,8 @@ class RosettaTestCase(TestCase):
self.assertTrue('Testing cookie length' in pofile_content)
r = self.client.get(self.xx_form_url + '?filter=translated')
self.assertTrue('Testing cookie length' in str(r.content))
self.assertTrue('m_9f6c442c6d579707440ba9dada0fb373' in str(r.content))
self.assertTrue('Testing cookie length' in r.content.decode())
self.assertTrue('m_9f6c442c6d579707440ba9dada0fb373' in r.content.decode())
@override_settings(ROSETTA_STORAGE_CLASS='rosetta.storage.CacheRosettaStorage')
def test_21_concurrency_of_cache_backend(self):
@ -474,7 +467,7 @@ class RosettaTestCase(TestCase):
self.client2.get(self.xx_form_url)
self.assertNotEqual(
self.client.session.get('rosetta_cache_storage_key_prefix'),
self.client2.session.get('rosetta_cache_storage_key_prefix')
self.client2.session.get('rosetta_cache_storage_key_prefix'),
)
# Clean up (restore perms)
@ -485,12 +478,10 @@ class RosettaTestCase(TestCase):
r = self.client.get(self.xx_form_url)
# We have distinct hashes, even though the msgid and msgstr are identical
self.assertTrue('m_4765f7de94996d3de5975fa797c3451f' in str(r.content))
self.assertTrue('m_08e4e11e2243d764fc45a5a4fba5d0f2' in str(r.content))
self.assertTrue('m_4765f7de94996d3de5975fa797c3451f' in r.content.decode())
self.assertTrue('m_08e4e11e2243d764fc45a5a4fba5d0f2' in r.content.decode())
@override_settings(ROSETTA_LANGUAGES=(
('xx', 'dummy language'),
))
@override_settings(ROSETTA_LANGUAGES=(('xx', 'dummy language'),))
def test_23_save_header_data(self):
from django.contrib.auth.models import User
@ -510,10 +501,10 @@ class RosettaTestCase(TestCase):
r = self.client.get(self.xx_form_url + '?filter=untranslated')
# make sure both strings are untranslated
self.assertTrue('dummy language' in str(r.content))
self.assertTrue('String 1' in str(r.content))
self.assertTrue('String 2' in str(r.content))
self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in str(r.content))
self.assertTrue('dummy language' in r.content.decode())
self.assertTrue('String 1' in r.content.decode())
self.assertTrue('String 2' in r.content.decode())
self.assertTrue('m_e48f149a8b2e8baa81b816c0edf93890' in r.content.decode())
# post a translation
data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world'}
@ -533,10 +524,10 @@ class RosettaTestCase(TestCase):
# Load the template file
r = self.client.get(self.xx_form_url)
self.assertTrue('Progress: 0%' in str(r.content))
self.assertTrue('Progress: 0%' in r.content.decode())
data = {'m_e48f149a8b2e8baa81b816c0edf93890': 'Hello, world'}
r = self.client.post(self.xx_form_url, data, follow=True)
self.assertTrue('Progress: 25%' in str(r.content))
self.assertTrue('Progress: 25%' in r.content.decode())
def test_25_replace_access_control(self):
# Test default access control allows access
@ -562,17 +553,18 @@ class RosettaTestCase(TestCase):
def test_27_extended_urlconf_language_code_loads_file(self):
url = reverse(
'rosetta-form',
kwargs={'po_filter': 'all', 'lang_id': 'fr_FR.utf8', 'idx': 0}
'rosetta-form', kwargs={'po_filter': 'all', 'lang_id': 'fr_FR.utf8', 'idx': 0}
)
r = self.client.get(url)
self.assertTrue('French (France), UTF8' in str(r.content))
self.assertTrue('m_03a603523bd75b00414a413657acdeb2' in str(r.content))
self.assertTrue('French (France), UTF8' in r.content.decode())
self.assertTrue('m_03a603523bd75b00414a413657acdeb2' in r.content.decode())
def test_28_issue_gh87(self):
"""Make sure that rosetta_i18n_catalog_filter is passed into the context."""
r = self.client.get(self.third_party_file_list_url)
self.assertContains(r, '<li class="active"><a href="/rosetta/files/third-party/">')
self.assertContains(
r, '<li class="active"><a href="/rosetta/files/third-party/">'
)
@override_settings(
SESSION_ENGINE='django.contrib.sessions.backends.signed_cookies',
@ -580,8 +572,10 @@ class RosettaTestCase(TestCase):
)
def test_29_unsupported_p3_django_16_storage(self):
if VERSION[0:2] < (2, 0):
self.assertTrue('django.contrib.sessions.middleware.SessionMiddleware'
in settings.MIDDLEWARE)
self.assertTrue(
'django.contrib.sessions.middleware.SessionMiddleware'
in settings.MIDDLEWARE
)
# Force caching to be used by making the pofile read-only
os.chmod(self.dest_file, 292) # 0444
@ -596,8 +590,7 @@ class RosettaTestCase(TestCase):
os.chmod(self.dest_file, 420) # 0644
@override_settings(
ROSETTA_POFILENAMES=('pr44.po', ),
ROSETTA_LANGUAGES=(('xx', 'dummy language'),)
ROSETTA_POFILENAMES=('pr44.po',), ROSETTA_LANGUAGES=(('xx', 'dummy language'),)
)
def test_30_pofile_names(self):
os.unlink(self.dest_file)
@ -605,15 +598,14 @@ class RosettaTestCase(TestCase):
os.path.join(self.curdir, '../locale/xx/LC_MESSAGES/pr44.po')
)
shutil.copy(
os.path.normpath(os.path.join(self.curdir, './pr44.po.template')),
destfile
os.path.normpath(os.path.join(self.curdir, './pr44.po.template')), destfile
)
r = self.client.get(self.third_party_file_list_url)
self.assertTrue('xx/LC_MESSAGES/pr44.po' in str(r.content))
self.assertTrue('xx/LC_MESSAGES/pr44.po' in r.content.decode())
r = self.client.get(self.xx_form_url)
self.assertTrue('dummy language' in str(r.content))
self.assertTrue('dummy language' in r.content.decode())
# (Clean up)
os.unlink(destfile)
@ -654,32 +646,35 @@ class RosettaTestCase(TestCase):
self.assertContains(r, 'rosetta/locale/xx/LC_MESSAGES/django.po')
@override_settings(
ROSETTA_ENABLE_REFLANG=True,
ROSETTA_LANGUAGES=(('xx', 'dummy language'),)
ROSETTA_ENABLE_REFLANG=True, ROSETTA_LANGUAGES=(('xx', 'dummy language'),)
)
def test_33_reflang(self):
self.copy_po_file_from_template('./django.po.issue60.template')
r = self.client.get(self.xx_form_url)
# Verify that there's an option to select a reflang
self.assertTrue('<option value="?ref_lang=xx">dummy language</option>' in str(r.content))
self.assertTrue(
'<option value="?ref_lang=xx">dummy language</option>' in r.content.decode()
)
r = self.client.get(self.xx_form_url + '?ref_lang=xx')
# The translated string in the test PO file ends up in the "Reference" column
self.assertTrue('<span class="message">translated-string1</span>' in str(r.content))
self.assertTrue(
'<span class="message">translated-string1</span>' in r.content.decode()
)
def test_show_occurrences(self):
r = self.client.get(self.xx_form_url)
# Verify that occurrences in view
self.assertTrue('<td class="location">' in str(r.content))
self.assertTrue('<td class="location">' in r.content.decode())
with self.settings(ROSETTA_SHOW_OCCURRENCES=False):
r = self.client.get(self.xx_form_url)
# Verify that occurrences not in view
self.assertFalse('<td class="location">' in str(r.content))
self.assertFalse('<td class="location">' in r.content.decode())
def test_34_issue_113_app_configs(self):
r = self.client.get(self.all_file_list_url)
self.assertTrue('rosetta/files/all/xx/1/">Test_App' in str(r.content))
self.assertTrue('rosetta/files/all/xx/1/">Test_App' in r.content.decode())
@override_settings(ROSETTA_STORAGE_CLASS='rosetta.storage.CacheRosettaStorage')
def test_35_issue_135_display_exception_messages(self):
@ -733,7 +728,7 @@ class RosettaTestCase(TestCase):
def test_39_invalid_get_page(self):
url = self.xx_form_url + '?filter=untranslated'
r = self.client.get(url) # Page not specified
r = self.client.get(url) # Page not specified
self.assertEqual(r.context['page'], 1)
r = self.client.get(url + '&page=') # No number given
@ -746,7 +741,6 @@ class RosettaTestCase(TestCase):
self.assertEqual(r.context['page'], 1)
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:
@ -786,32 +780,50 @@ class RosettaTestCase(TestCase):
# Disable auto-compilation of the MO when the PO is saved
with self.settings(ROSETTA_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
po_file_hash_before, mo_file_hash_before = (
po_file_hash_after,
mo_file_hash_after,
)
msg_hashes = message_hashes()
data = {msg_hashes['String 1']: "Translation 3"}
self.client.post(self.xx_form_url, data)
po_file_hash_after, mo_file_hash_after = file_hash(po_file), file_hash(mo_file)
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
po_file_hash_before, mo_file_hash_before = (
po_file_hash_after,
mo_file_hash_after,
)
msg_hashes = message_hashes()
data = {msg_hashes['String 2']: "Translation 4"}
self.client.post(self.xx_form_url, data)
po_file_hash_after, mo_file_hash_after = file_hash(po_file), file_hash(mo_file)
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)
with self.settings(ROSETTA_AUTO_COMPILE=True):
po_file_hash_before, mo_file_hash_before = po_file_hash_after, mo_file_hash_after
po_file_hash_before, mo_file_hash_before = (
po_file_hash_after,
mo_file_hash_after,
)
msg_hashes = message_hashes()
data = {msg_hashes['String 2']: "Translation 5"}
self.client.post(self.xx_form_url, data)
po_file_hash_after, mo_file_hash_after = file_hash(po_file), file_hash(mo_file)
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)
@ -842,9 +854,7 @@ class RosettaTestCase(TestCase):
request.user = self.user
kwargs = {'po_filter': 'third-party', 'lang_id': 'xx', 'idx': 0}
view = self._setup_view(
view=views.TranslationFormView(),
request=request,
**kwargs
view=views.TranslationFormView(), request=request, **kwargs
)
self.assertTrue(view.po_file_is_writable)
@ -853,9 +863,7 @@ class RosettaTestCase(TestCase):
# make the pofile read-only
os.chmod(self.dest_file, 292) # 0444
view = self._setup_view(
view=views.TranslationFormView(),
request=request,
**kwargs
view=views.TranslationFormView(), request=request, **kwargs
)
self.assertFalse(view.po_file_is_writable)
@ -873,18 +881,16 @@ class RosettaTestCase(TestCase):
request.user = self.user
kwargs = {'po_filter': 'third-party', 'lang_id': 'xx', 'idx': 0}
view = self._setup_view(
view=views.TranslationFormView(),
request=request,
**kwargs
view=views.TranslationFormView(), request=request, **kwargs
)
self.assertEqual(view.po_file_path, self.dest_file)
# But if the language isn't an option, we get a 404
with self.settings(ROSETTA_LANGUAGES=[l for l in settings.LANGUAGES if l[0] != 'xx']):
with self.settings(
ROSETTA_LANGUAGES=[l for l in settings.LANGUAGES if l[0] != 'xx']
):
view = self._setup_view(
view=views.TranslationFormView(),
request=request,
**kwargs
view=views.TranslationFormView(), request=request, **kwargs
)
with self.assertRaises(Http404):
view.po_file_path
@ -975,16 +981,26 @@ class RosettaTestCase(TestCase):
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
@vcr.use_cassette('fixtures/vcr_cassettes/test_47_azure_ajax_translation.yaml', match_on=['method', 'scheme', 'host', 'port', 'path', 'query', 'raw_body'], record_mode='new_episodes')
@vcr.use_cassette(
'fixtures/vcr_cassettes/test_47_azure_ajax_translation.yaml',
match_on=['method', 'scheme', 'host', 'port', 'path', 'query', 'raw_body'],
record_mode='new_episodes',
)
def test_47_azure_ajax_translation(self):
r = self.client.get(reverse('rosetta.translate_text') + '?from=en&to=fr&text=hello%20world')
r = self.client.get(
reverse('rosetta.translate_text') + '?from=en&to=fr&text=hello%20world'
)
self.assertContains(r, '"Salut tout le monde"')
@override_settings(ROSETTA_REQUIRES_AUTH=True)
def test_48_requires_auth_not_respected_issue_203(self):
self.client.logout()
r = self.client.get(self.all_file_list_url)
self.assertRedirects(r, '{}?next=/rosetta/files/all/'.format(settings.LOGIN_URL), fetch_redirect_response=False)
self.assertRedirects(
r,
'{}?next=/rosetta/files/all/'.format(settings.LOGIN_URL),
fetch_redirect_response=False,
)
self.assertEqual(302, r.status_code)
@override_settings(ROSETTA_REQUIRES_AUTH=False)
@ -996,22 +1012,26 @@ class RosettaTestCase(TestCase):
def test_50_custom_login_url(self):
self.client.logout()
r = self.client.get(self.all_file_list_url)
self.assertRedirects(r, '/custom-url/?next=/rosetta/files/all/', fetch_redirect_response=False)
self.assertRedirects(
r, '/custom-url/?next=/rosetta/files/all/', fetch_redirect_response=False
)
self.assertEqual(302, r.status_code)
def test_51_rosetta_languages(self):
self.assertTrue('xx' in dict(settings.LANGUAGES))
self.assertFalse('yy' in dict(settings.LANGUAGES))
with self.settings(ROSETTA_LANGUAGES=(('xx', 'foo language'), )):
with self.settings(ROSETTA_LANGUAGES=(('xx', 'foo language'),)):
r = self.client.get(self.project_file_list_url)
self.assertTrue('foo language' in str(r.content))
self.assertFalse('bar language' in str(r.content))
self.assertTrue('foo language' in r.content.decode())
self.assertFalse('bar language' in r.content.decode())
with self.settings(ROSETTA_LANGUAGES=(('xx', 'foo language'), ('yy', 'bar language'), )):
with self.settings(
ROSETTA_LANGUAGES=(('xx', 'foo language'), ('yy', 'bar language'))
):
r = self.client.get(self.project_file_list_url)
self.assertTrue('foo language' in str(r.content))
self.assertTrue('bar language' in str(r.content))
self.assertTrue('foo language' in r.content.decode())
self.assertTrue('bar language' in r.content.decode())
# Stubbed access control function

View file

@ -6,6 +6,7 @@ import re
import unicodedata
import uuid
import zipfile
from urllib.parse import urlencode
from django.conf import settings
from django.contrib import messages
@ -21,7 +22,7 @@ from django.urls import reverse
from django.utils.decorators import method_decorator
from django.utils.encoding import force_bytes
from django.utils.functional import Promise, cached_property
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.views.decorators.cache import never_cache
from django.views.generic import TemplateView, View
@ -37,14 +38,6 @@ from .signals import entry_changed, post_save
from .storage import get_storage
try:
# Python 3
from urllib.parse import urlencode
except ImportError:
# Python 2
from urllib import urlencode
def get_app_name(path):
return path.split('/locale')[0].split('/')[-1]
@ -53,12 +46,15 @@ class LoginURL(Promise):
"""
Tests friendly login URL, url is resolved at runtime.
"""
def __str__(self):
return rosetta_settings.LOGIN_URL
@method_decorator(never_cache, 'dispatch')
@method_decorator(user_passes_test(lambda user: can_translate(user), LoginURL()), 'dispatch')
@method_decorator(
user_passes_test(lambda user: can_translate(user), LoginURL()), 'dispatch'
)
class RosettaBaseMixin(object):
"""A mixin class for Rosetta's class-based views. It provides:
* security (see class decorators)
@ -91,6 +87,7 @@ class RosettaFileLevelMixin(RosettaBaseMixin):
* po_file (pofile object)
* po_file_is_writable (bool: do we have filesystem write perms to file)
"""
def _request_request(self, key, default=None):
if key in self.request.GET:
return self.request.GET.get(key)
@ -130,11 +127,12 @@ class RosettaFileLevelMixin(RosettaBaseMixin):
django_apps = self.po_filter in ('all', 'django')
project_apps = self.po_filter in ('all', 'project')
po_paths = find_pos(self.language_id,
project_apps=project_apps,
django_apps=django_apps,
third_party_apps=third_party_apps,
)
po_paths = find_pos(
self.language_id,
project_apps=project_apps,
django_apps=django_apps,
third_party_apps=third_party_apps,
)
po_paths.sort(key=get_app_name)
try:
@ -154,17 +152,18 @@ class RosettaFileLevelMixin(RosettaBaseMixin):
# If we can write changes to file, then we pull it up fresh with
# each request.
# XXX: brittle; what if this path doesn't exist? Isn't a .po file?
po_file = pofile(self.po_file_path,
wrapwidth=rosetta_settings.POFILE_WRAP_WIDTH)
po_file = pofile(
self.po_file_path, wrapwidth=rosetta_settings.POFILE_WRAP_WIDTH
)
for entry in po_file:
# Entry is an object representing a single entry in the catalog.
# We iterate through the *entire catalog*, pasting a hashed
# value of the meat of each entry on its side in an attribute
# called "md5hash".
str_to_hash = (
six.text_type(entry.msgid) +
six.text_type(entry.msgstr) +
six.text_type(entry.msgctxt or '')
six.text_type(entry.msgid)
+ six.text_type(entry.msgstr)
+ six.text_type(entry.msgctxt or '')
).encode('utf8')
entry.md5hash = hashlib.md5(str_to_hash).hexdigest()
else:
@ -178,9 +177,9 @@ class RosettaFileLevelMixin(RosettaBaseMixin):
# a hashed value of the meat of each entry on its side in
# an attribute called "md5hash".
str_to_hash = (
six.text_type(entry.msgid) +
six.text_type(entry.msgstr) +
six.text_type(entry.msgctxt or '')
six.text_type(entry.msgid)
+ six.text_type(entry.msgstr)
+ six.text_type(entry.msgctxt or '')
).encode('utf8')
entry.md5hash = hashlib.new('md5', str_to_hash).hexdigest()
storage.set(self.po_file_cache_key, po_file)
@ -206,6 +205,7 @@ class TranslationFileListView(RosettaBaseMixin, TemplateView):
"""Lists the languages, the gettext catalog files that can be translated,
and their translation progress for a filtered list of apps/projects.
"""
http_method_names = ['get']
template_name = 'rosetta/file-list.html'
@ -222,12 +222,15 @@ class TranslationFileListView(RosettaBaseMixin, TemplateView):
if not can_translate_language(self.request.user, language[0]):
continue
po_paths = find_pos(language[0],
project_apps=project_apps,
django_apps=django_apps,
third_party_apps=third_party_apps,
)
po_files = [(get_app_name(l), os.path.realpath(l), pofile(l)) for l in po_paths]
po_paths = find_pos(
language[0],
project_apps=project_apps,
django_apps=django_apps,
third_party_apps=third_party_apps,
)
po_files = [
(get_app_name(l), os.path.realpath(l), pofile(l)) for l in po_paths
]
po_files.sort(key=lambda app: app[0])
languages.append((language[0], _(language[1]), po_files))
has_pos = has_pos or bool(po_paths)
@ -255,6 +258,7 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView):
searched include: source, translated text, "occurence" file path, or
context hints.
"""
# Note: due to the unorthodox nature of the form itself, we're not using
# Django's generic FormView as our base class.
http_method_names = ['get', 'post']
@ -345,32 +349,38 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView):
file_change = True
if old_msgstr != new_msgstr or old_fuzzy != is_fuzzy:
entry_changed.send(sender=entry,
user=request.user,
old_msgstr=old_msgstr,
old_fuzzy=old_fuzzy,
pofile=self.po_file_path,
language_code=self.language_id,
)
entry_changed.send(
sender=entry,
user=request.user,
old_msgstr=old_msgstr,
old_fuzzy=old_fuzzy,
pofile=self.po_file_path,
language_code=self.language_id,
)
else:
messages.error(
self.request,
_("Some items in your last translation block couldn't "
"be saved: this usually happens when the catalog file "
"changes on disk after you last loaded it."),
_(
"Some items in your last translation block couldn't "
"be saved: this usually happens when the catalog file "
"changes on disk after you last loaded it."
),
)
if file_change and self.po_file_is_writable:
try:
self.po_file.metadata['Last-Translator'] = unicodedata.normalize(
'NFKD', u"%s %s <%s>" % (
'NFKD',
u"%s %s <%s>"
% (
getattr(self.request.user, 'first_name', 'Anonymous'),
getattr(self.request.user, 'last_name', 'User'),
getattr(self.request.user, 'email', 'anonymous@user.tld')
)
getattr(self.request.user, 'email', 'anonymous@user.tld'),
),
).encode('ascii', 'ignore')
self.po_file.metadata['X-Translated-Using'] = u"django-rosetta %s" % (
get_rosetta_version())
get_rosetta_version()
)
self.po_file.metadata['PO-Revision-Date'] = timestamp_with_timezone()
except UnicodeDecodeError:
pass
@ -382,16 +392,16 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView):
if rosetta_settings.AUTO_COMPILE:
self.po_file.save_as_mofile(po_filepath + '.mo')
post_save.send(sender=None, language_code=self.language_id,
request=self.request
)
post_save.send(
sender=None, language_code=self.language_id, request=self.request
)
# Try auto-reloading via the WSGI daemon mode reload mechanism
should_try_wsgi_reload = (
rosetta_settings.WSGI_AUTO_RELOAD and
'mod_wsgi.process_group' in self.request.environ and
self.request.environ.get('mod_wsgi.process_group', None) and
'SCRIPT_FILENAME' in self.request.environ and
int(self.request.environ.get('mod_wsgi.script_reloading', 0))
rosetta_settings.WSGI_AUTO_RELOAD
and 'mod_wsgi.process_group' in self.request.environ
and self.request.environ.get('mod_wsgi.process_group', None)
and 'SCRIPT_FILENAME' in self.request.environ
and int(self.request.environ.get('mod_wsgi.script_reloading', 0))
)
if should_try_wsgi_reload:
try:
@ -402,6 +412,7 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView):
if rosetta_settings.UWSGI_AUTO_RELOAD:
try:
import uwsgi
uwsgi.reload() # pretty easy right?
except:
pass # we may not be running under uwsgi :P
@ -433,10 +444,12 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView):
}
# Winnow down the query string args to non-blank ones
query_string_args = {k: v for k, v in query_string_args.items() if v}
return HttpResponseRedirect("{url}?{qs}".format(
url=reverse('rosetta-form', kwargs=self.kwargs),
qs=urlencode_safe(query_string_args)
))
return HttpResponseRedirect(
"{url}?{qs}".format(
url=reverse('rosetta-form', kwargs=self.kwargs),
qs=urlencode_safe(query_string_args),
)
)
def get_context_data(self, **kwargs):
context = super(TranslationFormView, self).get_context_data(**kwargs)
@ -491,8 +504,7 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView):
break
if main_language:
main_lang_po_path = self.po_file_path.replace(
'/%s/' % self.language_id,
'/%s/' % main_language_id,
'/%s/' % self.language_id, '/%s/' % main_language_id
)
# XXX: brittle; what if this path doesn't exist? Isn't a .po file?
main_lang_po = pofile(main_lang_po_path)
@ -521,29 +533,31 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView):
{k: v for k, v in query_string_args.items() if k == 'ref_lang'}
)
context.update({
'version': get_rosetta_version(),
'LANGUAGES': LANGUAGES,
'rosetta_settings': rosetta_settings,
'rosetta_i18n_lang_name': rosetta_i18n_lang_name,
'rosetta_i18n_lang_code': self.language_id,
'rosetta_i18n_lang_code_normalized': self.language_id.replace('_', '-'),
'rosetta_i18n_lang_bidi': rosetta_i18n_lang_bidi,
'rosetta_i18n_filter': self.msg_filter,
'rosetta_i18n_write': self.po_file_is_writable,
'rosetta_messages': rosetta_messages,
'page_range': needs_pagination and page_range,
'needs_pagination': needs_pagination,
'main_language': main_language,
'rosetta_i18n_app': get_app_name(self.po_file_path),
'page': page,
'query': self.query,
'pagination_query_string_base': pagination_query_string_base,
'filter_query_string_base': filter_query_string_base,
'paginator': paginator,
'rosetta_i18n_pofile': self.po_file,
'ref_lang': self.ref_lang,
})
context.update(
{
'version': get_rosetta_version(),
'LANGUAGES': LANGUAGES,
'rosetta_settings': rosetta_settings,
'rosetta_i18n_lang_name': rosetta_i18n_lang_name,
'rosetta_i18n_lang_code': self.language_id,
'rosetta_i18n_lang_code_normalized': self.language_id.replace('_', '-'),
'rosetta_i18n_lang_bidi': rosetta_i18n_lang_bidi,
'rosetta_i18n_filter': self.msg_filter,
'rosetta_i18n_write': self.po_file_is_writable,
'rosetta_messages': rosetta_messages,
'page_range': needs_pagination and page_range,
'needs_pagination': needs_pagination,
'main_language': main_language,
'rosetta_i18n_app': get_app_name(self.po_file_path),
'page': page,
'query': self.query,
'pagination_query_string_base': pagination_query_string_base,
'filter_query_string_base': filter_query_string_base,
'paginator': paginator,
'rosetta_i18n_pofile': self.po_file,
'ref_lang': self.ref_lang,
}
)
return context
@ -569,11 +583,10 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView):
ref_pofile = None
if rosetta_settings.ENABLE_REFLANG and self.ref_lang != 'msgid':
replacement = '{separator}locale{separator}{ref_lang}'.format(
separator=os.sep,
ref_lang=self.ref_lang
separator=os.sep, ref_lang=self.ref_lang
)
pattern = r'\{separator}locale\{separator}[a-z]{{2}}'.format(separator=os.sep)
ref_fn = re.sub(pattern, replacement, self.po_file_path,)
ref_fn = re.sub(pattern, replacement, self.po_file_path)
try:
ref_pofile = pofile(ref_fn)
except IOError:
@ -616,17 +629,21 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView):
rx = re.compile(re.escape(self.query), re.IGNORECASE)
def concat_entry(e):
return (six.text_type(e.msgstr) +
six.text_type(e.msgid) +
six.text_type(e.msgctxt) +
six.text_type(e.comment) +
u''.join([o[0] for o in e.occurrences]) +
six.text_type(e.msgid_plural) +
u''.join(e.msgstr_plural.values())
)
return (
six.text_type(e.msgstr)
+ six.text_type(e.msgid)
+ six.text_type(e.msgctxt)
+ six.text_type(e.comment)
+ u''.join([o[0] for o in e.occurrences])
+ six.text_type(e.msgid_plural)
+ u''.join(e.msgstr_plural.values())
)
entries = [e_ for e_ in self.po_file
if not e_.obsolete and rx.search(concat_entry(e_))]
entries = [
e_
for e_ in self.po_file
if not e_.obsolete and rx.search(concat_entry(e_))
]
else:
# Scenario #2: filtered list of messages
if self.msg_filter == 'untranslated':
@ -634,8 +651,7 @@ class TranslationFormView(RosettaFileLevelMixin, TemplateView):
elif self.msg_filter == 'translated':
entries = self.po_file.translated_entries()
elif self.msg_filter == 'fuzzy':
entries = [e_ for e_ in self.po_file.fuzzy_entries()
if not e_.obsolete]
entries = [e_ for e_ in self.po_file.fuzzy_entries() if not e_.obsolete]
else:
# ("all")
entries = [e_ for e_ in self.po_file if not e_.obsolete]
@ -647,6 +663,7 @@ class TranslationFileDownload(RosettaFileLevelMixin, View):
and compiled (.mo) files, either as they exist on disk, or, if what's on
disk is unwritable (permissions-wise), return what's in the cache.
"""
http_method_names = [u'get']
def get(self, request, *args, **kwargs):
@ -677,7 +694,6 @@ class TranslationFileDownload(RosettaFileLevelMixin, View):
@user_passes_test(lambda user: can_translate(user), LoginURL())
def translate_text(request):
def translate(text, from_language, to_language, subscription_key):
"""
This method does the heavy lifting of connecting to the translator API and fetching a response
@ -696,20 +712,20 @@ def translate_text(request):
headers = {
'Ocp-Apim-Subscription-Key': subscription_key,
'Content-type': 'application/json',
'X-ClientTraceId': str(uuid.uuid4())
'X-ClientTraceId': str(uuid.uuid4()),
}
url_parameters = {
"from": from_language,
"to": to_language
}
url_parameters = {"from": from_language, "to": to_language}
request_data = [
{"text": text}
]
request_data = [{"text": text}]
api_hostname = AZURE_TRANSLATOR_HOST + AZURE_TRANSLATOR_PATH
r = requests.post(api_hostname, headers=headers, params=url_parameters, data=json.dumps(request_data))
r = requests.post(
api_hostname,
headers=headers,
params=url_parameters,
data=json.dumps(request_data),
)
return json.loads(r.text)
language_from = request.GET.get('from', None)
@ -723,7 +739,9 @@ def translate_text(request):
AZURE_CLIENT_SECRET = getattr(settings, 'AZURE_CLIENT_SECRET', None)
try:
api_response = translate(text, language_from, language_to, AZURE_CLIENT_SECRET)
api_response = translate(
text, language_from, language_to, AZURE_CLIENT_SECRET
)
# result will be a dict if there is an error, e.g.
# {
@ -737,7 +755,9 @@ def translate_text(request):
error_message = api_error.get("message")
data = {
'success': False,
'error': "Microsoft Translation API error: Error code {}, {}".format(error_code, error_message),
'error': "Microsoft Translation API error: Error code {}, {}".format(
error_code, error_message
),
}
else:
# response body will be of the form:
@ -753,15 +773,14 @@ def translate_text(request):
translations = api_response[0].get("translations")
translated_text = translations[0].get("text")
data = {
'success': True,
'translation': translated_text
}
data = {'success': True, 'translation': translated_text}
# catch general connection exception in the requests framework
except requests.exceptions.RequestException as err:
data = {
'success': False,
'error': "Error connecting to Microsoft Translation Service: {0}".format(err),
'error': "Error connecting to Microsoft Translation Service: {0}".format(
err
),
}
return JsonResponse(data)

View file

@ -1,7 +1,8 @@
from setuptools import setup, find_packages
from setuptools.command.test import test as test_command
import sys
from setuptools import find_packages, setup
from setuptools.command.test import test as test_command
class Tox(test_command):
user_options = [('tox-args=', 'a', "Arguments to pass to tox")]
@ -19,12 +20,14 @@ class Tox(test_command):
# import here, cause outside the eggs aren't loaded
import tox
import shlex
args = self.tox_args
if args:
args = shlex.split(self.tox_args)
errno = tox.cmdline(args=args)
sys.exit(errno)
with open('README.rst') as readme:
long_description = readme.read()
@ -57,9 +60,9 @@ setup(
zip_safe=False,
install_requires=[
'six >=1.2.0',
'Django >= 1.11',
'Django >= 2.0',
'requests >= 2.1.0',
'polib >= 1.1.0'
'polib >= 1.1.0',
],
tests_require=['tox', 'vcrpy'],
cmdclass={'test': Tox},

View file

@ -1,9 +1,8 @@
# -*- coding: utf-8 -*-
# from __future__ import unicode_literals
import django
import os
import sys
import django
SITE_ID = 1
@ -15,7 +14,7 @@ DJANGO_VERSION = django.get_version()
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(PROJECT_PATH, 'rosetta.db')
'NAME': os.path.join(PROJECT_PATH, 'rosetta.db'),
}
}
@ -23,7 +22,7 @@ CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
'KEY_PREFIX': 'ROSETTA_TEST'
'KEY_PREFIX': 'ROSETTA_TEST',
}
}
@ -58,7 +57,7 @@ MIDDLEWARE = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware'
'django.contrib.messages.middleware.MessageMiddleware',
)
# Note: languages are overridden in the test runner
@ -75,15 +74,11 @@ LANGUAGES = (
SILENCED_SYSTEM_CHECKS = ["translation.E002"]
LOCALE_PATHS = [
os.path.join(PROJECT_PATH, 'locale'),
]
LOCALE_PATHS = [os.path.join(PROJECT_PATH, 'locale')]
SOUTH_TESTS_MIGRATE = False
FIXTURE_DIRS = (
os.path.join(PROJECT_PATH, 'fixtures'),
)
FIXTURE_DIRS = (os.path.join(PROJECT_PATH, 'fixtures'),)
STATIC_URL = '/static/'
ROOT_URLCONF = 'testproject.urls'
@ -102,10 +97,10 @@ TEMPLATES = [
"django.template.context_processors.media",
"django.template.context_processors.static",
"django.template.context_processors.tz",
"django.contrib.messages.context_processors.messages"
)
}
},
"django.contrib.messages.context_processors.messages",
),
},
}
]
STATIC_URL = '/static/'

View file

@ -1,7 +1,6 @@
[tox]
envlist =
flake8,
py{27,36}-django111,
py{36,37}-django{20,21},
py{36,37,38}-django{22,30},
gettext,
@ -19,16 +18,13 @@ setenv =
PYTHONDONTWRITEBYTECODE=1
deps =
django111: Django==1.11.*
django20: Django==2.0.*
django21: Django>=2.1a1,<=2.1.99
django22: Django>=2.2.8,<=2.2.99
django30: Django>=3.0,<=3.0.99
py27-django111: python-memcached
py{36,37,38}-django{111,20,21,22,30}: python3-memcached
py{36,37,38}-django{20,21,22,30}: python3-memcached
# py27-django111: pudb
requests
polib>=1.1.0
six
@ -62,9 +58,9 @@ changedir = docs
commands=
sphinx-build -W -b html . _build/html
[testenv:flake8]
basepython = python3
deps = flake8==2.4.1
commands=
flake8 {toxinidir}/rosetta