375 строки
13 KiB
Python
375 строки
13 KiB
Python
# -*- coding: utf-8 -*-
|
|
from django.conf import settings
|
|
from django import test
|
|
from django.utils import translation
|
|
from django.utils.functional import lazy
|
|
|
|
import jinja2
|
|
from nose.tools import eq_
|
|
from test_utils import ExtraAppTestCase, trans_eq
|
|
|
|
from testapp.models import TranslatedModel, UntranslatedModel, FancyModel
|
|
from translations.models import (Translation, PurifiedTranslation,
|
|
TranslationSequence)
|
|
from translations import widgets
|
|
from translations.query import order_by_translation
|
|
|
|
|
|
def ids(qs):
|
|
return [o.id for o in qs]
|
|
|
|
|
|
class TranslationFixturelessTestCase(test.TestCase):
|
|
"We want to be able to rollback stuff."
|
|
|
|
def test_whitespace(self):
|
|
t = Translation(localized_string=' khaaaaaan! ', id=999)
|
|
t.save()
|
|
eq_('khaaaaaan!', t.localized_string)
|
|
|
|
|
|
class TranslationSequenceTestCase(test.TestCase):
|
|
"""
|
|
Make sure automatic translation sequence generation works
|
|
as expected.
|
|
"""
|
|
|
|
def test_empty_translations_seq(self):
|
|
"""Make sure we can handle an empty translation sequence table."""
|
|
TranslationSequence.objects.all().delete()
|
|
newtrans = Translation.new('abc', 'en-us')
|
|
newtrans.save()
|
|
assert newtrans.id > 0, (
|
|
'Empty translation table should still generate an ID.')
|
|
|
|
def test_single_translation_sequence(self):
|
|
"""Make sure we only ever have one translation sequence."""
|
|
TranslationSequence.objects.all().delete()
|
|
eq_(TranslationSequence.objects.count(), 0)
|
|
for i in range(5):
|
|
newtrans = Translation.new(str(i), 'en-us')
|
|
newtrans.save()
|
|
eq_(TranslationSequence.objects.count(), 1)
|
|
|
|
def test_translation_sequence_increases(self):
|
|
"""Make sure translation sequence increases monotonically."""
|
|
newtrans1 = Translation.new('abc', 'en-us')
|
|
newtrans1.save()
|
|
newtrans2 = Translation.new('def', 'de')
|
|
newtrans2.save()
|
|
assert newtrans2.pk > newtrans1.pk, (
|
|
'Translation sequence needs to keep increasing.')
|
|
|
|
|
|
class TranslationTestCase(ExtraAppTestCase):
|
|
fixtures = ['testapp/test_models.json']
|
|
extra_apps = ['translations.tests.testapp']
|
|
|
|
def setUp(self):
|
|
super(TranslationTestCase, self).setUp()
|
|
self.redirect_url = settings.REDIRECT_URL
|
|
self.redirect_secret_key = settings.REDIRECT_SECRET_KEY
|
|
settings.REDIRECT_URL = None
|
|
settings.REDIRECT_SECRET_KEY = 'sekrit'
|
|
translation.activate('en-US')
|
|
|
|
def tearDown(self):
|
|
super(TranslationTestCase, self).tearDown()
|
|
settings.REDIRECT_URL = self.redirect_url
|
|
settings.REDIRECT_SECRET_KEY = self.redirect_secret_key
|
|
|
|
def test_fetch_translations(self):
|
|
"""Basic check of fetching translations in the current locale."""
|
|
o = TranslatedModel.objects.get(id=1)
|
|
trans_eq(o.name, 'some name', 'en-US')
|
|
trans_eq(o.description, 'some description', 'en-US')
|
|
|
|
def test_fetch_no_translations(self):
|
|
"""Make sure models with no translations aren't harmed."""
|
|
o = UntranslatedModel.objects.get(id=1)
|
|
eq_(o.number, 17)
|
|
|
|
def test_fetch_translation_de_locale(self):
|
|
"""Check that locale fallbacks work."""
|
|
try:
|
|
translation.activate('de')
|
|
o = TranslatedModel.objects.get(id=1)
|
|
trans_eq(o.name, 'German!! (unst unst)', 'de')
|
|
trans_eq(o.description, 'some description', 'en-US')
|
|
finally:
|
|
translation.deactivate()
|
|
|
|
def test_create_translation(self):
|
|
o = TranslatedModel.objects.create(name='english name')
|
|
get_model = lambda: TranslatedModel.objects.get(id=o.id)
|
|
trans_eq(o.name, 'english name', 'en-US')
|
|
eq_(o.description, None)
|
|
|
|
# Make sure the translation id is stored on the model, not the autoid.
|
|
eq_(o.name.id, o.name_id)
|
|
|
|
# Check that a different locale creates a new row with the same id.
|
|
translation.activate('de')
|
|
german = get_model()
|
|
trans_eq(o.name, 'english name', 'en-US')
|
|
|
|
german.name = u'Gemütlichkeit name'
|
|
german.description = u'clöüserw description'
|
|
german.save()
|
|
|
|
trans_eq(german.name, u'Gemütlichkeit name', 'de')
|
|
trans_eq(german.description, u'clöüserw description', 'de')
|
|
|
|
# ids should be the same, autoids are different.
|
|
eq_(o.name.id, german.name.id)
|
|
assert o.name.autoid != german.name.autoid
|
|
|
|
# Check that de finds the right translation.
|
|
fresh_german = get_model()
|
|
trans_eq(fresh_german.name, u'Gemütlichkeit name', 'de')
|
|
trans_eq(fresh_german.description, u'clöüserw description', 'de')
|
|
|
|
# Check that en-US has the right translations.
|
|
translation.deactivate()
|
|
english = get_model()
|
|
trans_eq(english.name, 'english name', 'en-US')
|
|
english.debug = True
|
|
eq_(english.description, None)
|
|
|
|
english.description = 'english description'
|
|
english.save()
|
|
|
|
fresh_english = get_model()
|
|
trans_eq(fresh_english.description, 'english description', 'en-US')
|
|
eq_(fresh_english.description.id, fresh_german.description.id)
|
|
|
|
def test_update_translation(self):
|
|
o = TranslatedModel.objects.get(id=1)
|
|
translation_id = o.name.autoid
|
|
|
|
o.name = 'new name'
|
|
o.save()
|
|
|
|
o = TranslatedModel.objects.get(id=1)
|
|
trans_eq(o.name, 'new name', 'en-US')
|
|
# Make sure it was an update, not an insert.
|
|
eq_(o.name.autoid, translation_id)
|
|
|
|
def test_create_with_dict(self):
|
|
# Set translations with a dict.
|
|
strings = {'en-US': 'right language', 'de': 'wrong language'}
|
|
o = TranslatedModel.objects.create(name=strings)
|
|
|
|
# Make sure we get the English text since we're in en-US.
|
|
trans_eq(o.name, 'right language', 'en-US')
|
|
|
|
# Check that de was set.
|
|
translation.activate('de')
|
|
o = TranslatedModel.objects.get(id=o.id)
|
|
trans_eq(o.name, 'wrong language', 'de')
|
|
|
|
# We're in de scope, so we should see the de text.
|
|
de = TranslatedModel.objects.create(name=strings)
|
|
trans_eq(o.name, 'wrong language', 'de')
|
|
|
|
# Make sure en-US was still set.
|
|
translation.deactivate()
|
|
o = TranslatedModel.objects.get(id=de.id)
|
|
trans_eq(o.name, 'right language', 'en-US')
|
|
|
|
def test_update_with_dict(self):
|
|
# There's existing en-US and de strings.
|
|
strings = {'de': None, 'fr': 'oui'}
|
|
get_model = lambda: TranslatedModel.objects.get(id=1)
|
|
|
|
# Don't try checking that the model's name value is en-US. It will be
|
|
# one of the other locales, but we don't know which one. You just set
|
|
# the name to a dict, deal with it.
|
|
m = get_model()
|
|
m.name = strings
|
|
m.save()
|
|
|
|
# en-US was not touched.
|
|
trans_eq(get_model().name, 'some name', 'en-US')
|
|
|
|
# de was updated to NULL, so it falls back to en-US.
|
|
translation.activate('de')
|
|
trans_eq(get_model().name, 'some name', 'en-US')
|
|
|
|
# fr was added.
|
|
translation.activate('fr')
|
|
trans_eq(get_model().name, 'oui', 'fr')
|
|
|
|
def test_dict_bad_locale(self):
|
|
m = TranslatedModel.objects.get(id=1)
|
|
m.name = {'de': 'oof', 'xxx': 'bam', 'es-ES': 'si'}
|
|
m.save()
|
|
|
|
ts = Translation.objects.filter(id=m.name_id)
|
|
eq_(sorted(ts.values_list('locale', flat=True)),
|
|
['de', 'en-US', 'es-ES'])
|
|
|
|
def test_sorting(self):
|
|
"""Test translation comparisons in Python code."""
|
|
b = Translation.new('bbbb', 'de')
|
|
a = Translation.new('aaaa', 'de')
|
|
c = Translation.new('cccc', 'de')
|
|
eq_(sorted([c, a, b]), [a, b, c])
|
|
|
|
def test_sorting_en(self):
|
|
q = TranslatedModel.objects.all()
|
|
expected = [4, 1, 3]
|
|
|
|
eq_(ids(order_by_translation(q, 'name')), expected)
|
|
eq_(ids(order_by_translation(q, '-name')), list(reversed(expected)))
|
|
|
|
def test_sorting_mixed(self):
|
|
translation.activate('de')
|
|
q = TranslatedModel.objects.all()
|
|
expected = [1, 4, 3]
|
|
|
|
eq_(ids(order_by_translation(q, 'name')), expected)
|
|
eq_(ids(order_by_translation(q, '-name')), list(reversed(expected)))
|
|
|
|
def test_sorting_by_field(self):
|
|
field = TranslatedModel._meta.get_field('default_locale')
|
|
TranslatedModel.get_fallback = classmethod(lambda cls: field)
|
|
|
|
translation.activate('de')
|
|
q = TranslatedModel.objects.all()
|
|
expected = [3, 1, 4]
|
|
|
|
eq_(ids(order_by_translation(q, 'name')), expected)
|
|
eq_(ids(order_by_translation(q, '-name')), list(reversed(expected)))
|
|
|
|
del TranslatedModel.get_fallback
|
|
|
|
def test_new_purified_field(self):
|
|
# This is not a full test of the html sanitizing. We expect the
|
|
# underlying bleach library to have full tests.
|
|
s = '<a id=xx href="http://xxx.com">yay</a> <i>http://yyy.com</i>'
|
|
m = FancyModel.objects.create(purified=s)
|
|
eq_(m.purified.localized_string_clean,
|
|
'<a href="http://xxx.com" rel="nofollow">yay</a> '
|
|
'<i><a href="http://yyy.com" rel="nofollow">'
|
|
'http://yyy.com</a></i>')
|
|
eq_(m.purified.localized_string, s)
|
|
|
|
def test_new_linkified_field(self):
|
|
s = '<a id=xx href="http://xxx.com">yay</a> <i>http://yyy.com</i>'
|
|
m = FancyModel.objects.create(linkified=s)
|
|
eq_(m.linkified.localized_string_clean,
|
|
'<a href="http://xxx.com" rel="nofollow">yay</a> '
|
|
'<i><a href="http://yyy.com" rel="nofollow">'
|
|
'http://yyy.com</a></i>')
|
|
eq_(m.linkified.localized_string, s)
|
|
|
|
def test_update_purified_field(self):
|
|
m = FancyModel.objects.get(id=1)
|
|
s = '<a id=xx href="http://xxx.com">yay</a> <i>http://yyy.com</i>'
|
|
m.purified = s
|
|
m.save()
|
|
eq_(m.purified.localized_string_clean,
|
|
'<a href="http://xxx.com" rel="nofollow">yay</a> '
|
|
'<i><a href="http://yyy.com" rel="nofollow">'
|
|
'http://yyy.com</a></i>')
|
|
eq_(m.purified.localized_string, s)
|
|
|
|
def test_update_linkified_field(self):
|
|
m = FancyModel.objects.get(id=1)
|
|
s = '<a id=xx href="http://xxx.com">yay</a> <i>http://yyy.com</i>'
|
|
m.linkified = s
|
|
m.save()
|
|
eq_(m.linkified.localized_string_clean,
|
|
'<a href="http://xxx.com" rel="nofollow">yay</a> '
|
|
'<i><a href="http://yyy.com" rel="nofollow">'
|
|
'http://yyy.com</a></i>')
|
|
eq_(m.linkified.localized_string, s)
|
|
|
|
def test_purified_field_str(self):
|
|
m = FancyModel.objects.get(id=1)
|
|
eq_(u'%s' % m.purified,
|
|
'<i>x</i> '
|
|
'<a href="http://yyy.com" rel="nofollow">http://yyy.com</a>')
|
|
|
|
def test_linkified_field_str(self):
|
|
m = FancyModel.objects.get(id=1)
|
|
eq_(u'%s' % m.linkified,
|
|
'<i>x</i> '
|
|
'<a href="http://yyy.com" rel="nofollow">http://yyy.com</a>')
|
|
|
|
def test_purifed_linkified_fields_in_template(self):
|
|
m = FancyModel.objects.get(id=1)
|
|
env = jinja2.Environment()
|
|
t = env.from_string('{{ m.purified }}=={{ m.linkified }}')
|
|
s = t.render(m=m)
|
|
eq_(s, u'%s==%s' % (m.purified.localized_string_clean,
|
|
m.linkified.localized_string_clean))
|
|
|
|
def test_outgoing_url(self):
|
|
"""
|
|
Make sure linkified field is properly bounced off our outgoing URL
|
|
redirector.
|
|
"""
|
|
settings.REDIRECT_URL = 'http://example.com/'
|
|
|
|
s = 'I like http://example.org/awesomepage.html .'
|
|
m = FancyModel.objects.create(linkified=s)
|
|
eq_(m.linkified.localized_string_clean,
|
|
'I like <a href="http://example.com/'
|
|
'45cfcbcc274c1b6a4bbff81584f3463dd5a08221/http%3A//example.org/'
|
|
'awesomepage.html" rel="nofollow">http://example.org/awesomepage'
|
|
'.html</a> .')
|
|
eq_(m.linkified.localized_string, s)
|
|
|
|
def test_require_locale(self):
|
|
obj = TranslatedModel.objects.get(id=1)
|
|
eq_(unicode(obj.no_locale), 'blammo')
|
|
eq_(obj.no_locale.locale, 'en-US')
|
|
|
|
# Switch the translation to a locale we wouldn't pick up by default.
|
|
obj.no_locale.locale = 'fr'
|
|
obj.no_locale.save()
|
|
|
|
obj = TranslatedModel.objects.get(id=1)
|
|
eq_(unicode(obj.no_locale), 'blammo')
|
|
eq_(obj.no_locale.locale, 'fr')
|
|
|
|
|
|
def test_translation_bool():
|
|
t = lambda s: Translation(localized_string=s)
|
|
|
|
assert bool(t('text')) is True
|
|
assert bool(t(' ')) is False
|
|
assert bool(t('')) is False
|
|
assert bool(t(None)) is False
|
|
|
|
|
|
def test_translation_unicode():
|
|
t = lambda s: Translation(localized_string=s)
|
|
|
|
eq_(unicode(t('hello')), 'hello')
|
|
eq_(unicode(t(None)), '')
|
|
|
|
|
|
def test_widget_value_from_datadict():
|
|
data = {'f_en-US': 'woo', 'f_de': 'herr', 'f_fr_delete': ''}
|
|
actual = widgets.TransMulti().value_from_datadict(data, [], 'f')
|
|
expected = {'en-US': 'woo', 'de': 'herr', 'fr': None}
|
|
eq_(actual, expected)
|
|
|
|
|
|
def test_purified_translation_html():
|
|
"""__html__() should return a string."""
|
|
s = u'<b>heyhey</b>'
|
|
x = PurifiedTranslation(localized_string=s)
|
|
assert isinstance(x.__html__(), unicode)
|
|
eq_(x.__html__(), s)
|
|
|
|
|
|
def test_comparison_with_lazy():
|
|
x = Translation(localized_string='xxx')
|
|
lazy_u = lazy(lambda x: x, unicode)
|
|
x == lazy_u('xxx')
|
|
lazy_u('xxx') == x
|