2009-12-11 00:21:51 +03:00
|
|
|
from django.db import models, connection
|
2010-11-16 01:28:29 +03:00
|
|
|
from django.utils import encoding
|
2009-12-11 00:21:51 +03:00
|
|
|
|
2011-03-08 04:55:16 +03:00
|
|
|
import bleach
|
2010-02-23 03:34:56 +03:00
|
|
|
|
2011-01-11 02:33:34 +03:00
|
|
|
import amo.models
|
2010-03-16 18:30:15 +03:00
|
|
|
from amo import urlresolvers
|
2010-03-05 03:39:56 +03:00
|
|
|
from . import utils
|
|
|
|
|
2010-02-23 03:34:56 +03:00
|
|
|
|
2011-01-11 02:33:34 +03:00
|
|
|
class Translation(amo.models.ModelBase):
|
2009-12-11 00:21:51 +03:00
|
|
|
"""
|
|
|
|
Translation model.
|
|
|
|
|
|
|
|
Use :class:`translations.fields.TranslatedField` instead of a plain foreign
|
|
|
|
key to this model.
|
|
|
|
"""
|
|
|
|
|
|
|
|
autoid = models.AutoField(primary_key=True)
|
2009-12-17 07:21:25 +03:00
|
|
|
id = models.IntegerField()
|
2009-12-11 00:21:51 +03:00
|
|
|
locale = models.CharField(max_length=10)
|
2010-01-20 05:58:47 +03:00
|
|
|
localized_string = models.TextField(null=True)
|
2010-02-23 03:34:56 +03:00
|
|
|
localized_string_clean = models.TextField(null=True)
|
2009-12-11 00:21:51 +03:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
db_table = 'translations'
|
2009-12-17 02:28:19 +03:00
|
|
|
unique_together = ('id', 'locale')
|
2009-12-11 00:21:51 +03:00
|
|
|
|
|
|
|
def __unicode__(self):
|
2011-02-14 22:17:17 +03:00
|
|
|
return self.localized_string and unicode(self.localized_string) or ''
|
2009-12-11 00:21:51 +03:00
|
|
|
|
2009-12-17 23:03:26 +03:00
|
|
|
def __nonzero__(self):
|
|
|
|
# __nonzero__ is called to evaluate an object in a boolean context. We
|
|
|
|
# want Translations to be falsy if their string is empty.
|
2010-02-26 19:34:12 +03:00
|
|
|
return (bool(self.localized_string) and
|
|
|
|
bool(self.localized_string.strip()))
|
2009-12-17 23:03:26 +03:00
|
|
|
|
2010-12-03 01:28:25 +03:00
|
|
|
def __eq__(self, other):
|
|
|
|
# Django implements an __eq__ that only checks pks. We need to check
|
|
|
|
# the strings if we're dealing with existing vs. unsaved Translations.
|
|
|
|
return self.__cmp__(other) == 0
|
|
|
|
|
2010-01-28 05:19:59 +03:00
|
|
|
def __cmp__(self, other):
|
2010-03-04 21:40:35 +03:00
|
|
|
if hasattr(other, 'localized_string'):
|
2010-01-30 06:30:10 +03:00
|
|
|
return cmp(self.localized_string, other.localized_string)
|
2010-03-04 21:40:35 +03:00
|
|
|
else:
|
|
|
|
return cmp(self.localized_string, other)
|
2010-01-28 05:19:59 +03:00
|
|
|
|
2010-05-20 22:18:31 +04:00
|
|
|
def clean(self):
|
|
|
|
if self.localized_string:
|
|
|
|
self.localized_string = self.localized_string.strip()
|
|
|
|
|
|
|
|
def save(self, **kwargs):
|
|
|
|
self.clean()
|
|
|
|
return super(Translation, self).save(**kwargs)
|
|
|
|
|
2009-12-23 06:58:00 +03:00
|
|
|
@property
|
|
|
|
def cache_key(self):
|
|
|
|
return self._cache_key(self.id)
|
|
|
|
|
2010-11-16 01:28:29 +03:00
|
|
|
@classmethod
|
|
|
|
def _cache_key(cls, pk):
|
|
|
|
# Hard-coding the class name here so that subclasses don't try to cache
|
|
|
|
# themselves under something like "o:translations.purifiedtranslation".
|
|
|
|
key_parts = ('o', 'translations.translation', pk)
|
|
|
|
return ':'.join(map(encoding.smart_unicode, key_parts))
|
|
|
|
|
2009-12-11 00:21:51 +03:00
|
|
|
@classmethod
|
|
|
|
def new(cls, string, locale, id=None):
|
2009-12-15 22:35:59 +03:00
|
|
|
"""
|
|
|
|
Jumps through all the right hoops to create a new translation.
|
2009-12-11 00:21:51 +03:00
|
|
|
|
2009-12-15 22:35:59 +03:00
|
|
|
If ``id`` is not given a new id will be created using
|
|
|
|
``translations_seq``. Otherwise, the id will be used to add strings to
|
|
|
|
an existing translation.
|
|
|
|
"""
|
2009-12-11 00:21:51 +03:00
|
|
|
if id is None:
|
|
|
|
# Get a sequence key for the new translation.
|
|
|
|
cursor = connection.cursor()
|
|
|
|
cursor.execute("""UPDATE translations_seq
|
|
|
|
SET id=LAST_INSERT_ID(id + 1)""")
|
2010-03-01 21:58:31 +03:00
|
|
|
|
|
|
|
# The sequence table should never be empty. But alas, if it is,
|
|
|
|
# let's fix it.
|
|
|
|
if not cursor.rowcount > 0:
|
|
|
|
cursor.execute("""INSERT INTO translations_seq (id)
|
|
|
|
VALUES(LAST_INSERT_ID(id + 1))""")
|
|
|
|
|
2009-12-11 00:21:51 +03:00
|
|
|
cursor.execute('SELECT LAST_INSERT_ID() FROM translations_seq')
|
|
|
|
id = cursor.fetchone()[0]
|
|
|
|
|
2010-01-21 11:19:22 +03:00
|
|
|
# Update if one exists, otherwise create a new one.
|
|
|
|
q = {'id': id, 'locale': locale}
|
|
|
|
try:
|
2010-02-23 03:34:56 +03:00
|
|
|
trans = cls.objects.get(**q)
|
2010-01-21 11:19:22 +03:00
|
|
|
trans.localized_string = string
|
2010-02-23 03:34:56 +03:00
|
|
|
except cls.DoesNotExist:
|
2010-12-27 19:06:38 +03:00
|
|
|
trans = cls(localized_string=string, **q)
|
2010-01-21 11:19:22 +03:00
|
|
|
|
|
|
|
return trans
|
2009-12-11 00:21:51 +03:00
|
|
|
|
|
|
|
|
2010-02-23 03:34:56 +03:00
|
|
|
class PurifiedTranslation(Translation):
|
|
|
|
"""Run the string through bleach to get a safe, linkified version."""
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
proxy = True
|
|
|
|
|
|
|
|
def __unicode__(self):
|
|
|
|
if not self.localized_string_clean:
|
|
|
|
self.clean()
|
|
|
|
return unicode(self.localized_string_clean)
|
|
|
|
|
|
|
|
def __html__(self):
|
2010-02-24 04:22:29 +03:00
|
|
|
return unicode(self)
|
2010-02-23 03:34:56 +03:00
|
|
|
|
|
|
|
def clean(self):
|
2011-07-26 23:28:31 +04:00
|
|
|
from amo.utils import clean_nl
|
2010-05-20 22:18:31 +04:00
|
|
|
super(PurifiedTranslation, self).clean()
|
2011-03-08 04:55:16 +03:00
|
|
|
cleaned = bleach.clean(self.localized_string)
|
|
|
|
linkified = bleach.linkify(cleaned, nofollow=True,
|
|
|
|
filter_url=urlresolvers.get_outgoing_url)
|
2011-04-12 02:51:11 +04:00
|
|
|
self.localized_string_clean = clean_nl(linkified).strip()
|
2010-02-23 03:34:56 +03:00
|
|
|
|
2010-03-05 03:39:56 +03:00
|
|
|
def __truncate__(self, length, killwords, end):
|
2010-06-17 21:23:57 +04:00
|
|
|
return utils.truncate(unicode(self), length, killwords, end)
|
2010-03-05 03:39:56 +03:00
|
|
|
|
2010-02-23 03:34:56 +03:00
|
|
|
|
|
|
|
class LinkifiedTranslation(PurifiedTranslation):
|
|
|
|
"""Run the string through bleach to get a linkified version."""
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
proxy = True
|
|
|
|
|
|
|
|
def clean(self):
|
2011-03-08 04:55:16 +03:00
|
|
|
linkified = bleach.linkify(self.localized_string,
|
|
|
|
filter_url=urlresolvers.get_outgoing_url)
|
2010-02-23 03:34:56 +03:00
|
|
|
clean = bleach.clean(linkified, tags=['a'],
|
|
|
|
attributes={'a': ['href', 'rel']})
|
|
|
|
self.localized_string_clean = clean
|
|
|
|
|
|
|
|
|
2009-12-11 00:21:51 +03:00
|
|
|
class TranslationSequence(models.Model):
|
|
|
|
"""
|
|
|
|
The translations_seq table, so syncdb will create it during testing.
|
|
|
|
"""
|
|
|
|
id = models.IntegerField(primary_key=True)
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
db_table = 'translations_seq'
|
2010-10-07 02:37:25 +04:00
|
|
|
|
|
|
|
|
|
|
|
def delete_translation(obj, fieldname):
|
|
|
|
field = obj._meta.get_field(fieldname)
|
|
|
|
trans = getattr(obj, field.name)
|
2010-11-16 01:28:29 +03:00
|
|
|
obj.update(**{field.name: None})
|
2011-01-12 02:24:30 +03:00
|
|
|
if trans:
|
|
|
|
Translation.objects.filter(id=trans.id).delete()
|