summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2019-11-15 20:49:27 +0100
committerÉtienne Loks <etienne.loks@iggdrasil.net>2019-11-15 20:51:05 +0100
commitda44f143199b3adeb61c1ecd0c9f1e60a5604b23 (patch)
tree7b615b92d6e3161473184f7f55450148e6e5df99
parentc826f855e52b96398a990fdf9d51e38c8156f6c9 (diff)
downloadIshtar-da44f143199b3adeb61c1ecd0c9f1e60a5604b23.tar.bz2
Ishtar-da44f143199b3adeb61c1ecd0c9f1e60a5604b23.zip
Overload translation in database
-rw-r--r--archaeological_operations/migrations/0071_auto_20191115_1650.py20
-rw-r--r--example_project/local_settings.py.sample3
-rw-r--r--example_project/settings.py6
-rw-r--r--ishtar_common/apps.py5
-rw-r--r--ishtar_common/models.py5
-rw-r--r--ishtar_common/utils.py11
-rw-r--r--overload_translation/__init__.py1
-rw-r--r--overload_translation/admin.py13
-rw-r--r--overload_translation/migrations/0001_initial.py34
-rw-r--r--overload_translation/migrations/__init__.py0
-rw-r--r--overload_translation/models.py17
-rw-r--r--overload_translation/utils.py80
12 files changed, 192 insertions, 3 deletions
diff --git a/archaeological_operations/migrations/0071_auto_20191115_1650.py b/archaeological_operations/migrations/0071_auto_20191115_1650.py
new file mode 100644
index 000000000..992142752
--- /dev/null
+++ b/archaeological_operations/migrations/0071_auto_20191115_1650.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.18 on 2019-11-15 16:50
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('archaeological_operations', '0070_auto_20190923_1408'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='culturalattributiontype',
+ name='order',
+ field=models.IntegerField(default=10, verbose_name='Order'),
+ ),
+ ]
diff --git a/example_project/local_settings.py.sample b/example_project/local_settings.py.sample
index f49963c84..555adb711 100644
--- a/example_project/local_settings.py.sample
+++ b/example_project/local_settings.py.sample
@@ -51,3 +51,6 @@ SRID = 27572
ENCODING = '' # specific encoding for CSV export - default to utf-8
SURFACE_UNIT = 'square-metre'
SURFACE_UNIT_LABEL = u'm²'
+
+# translation overload can consume resources for a low profile machine
+# USE_TRANSLATION_OVERLOAD = True
diff --git a/example_project/settings.py b/example_project/settings.py
index 65ca93395..b858c5907 100644
--- a/example_project/settings.py
+++ b/example_project/settings.py
@@ -170,6 +170,9 @@ INSTALLED_APPS = [
# 'debug_toolbar',
]
+USE_TRANSLATION_OVERLOAD = True
+TRANSLATION_OVERLOAD_DEBUG = False
+
MAIN_APP = ""
LOGFILE = ''
@@ -294,6 +297,9 @@ except ImportError as e:
except ImportError as e:
print('Unable to load local_settings.py:', e)
+if USE_TRANSLATION_OVERLOAD:
+ INSTALLED_APPS.insert(0, 'overload_translation')
+
if "SECRET_KEY" not in globals(): # explicit import from the root for celery
current_path = os.path.abspath(__file__)
current_dir_path = os.path.dirname(current_path).split(os.sep)[-1]
diff --git a/ishtar_common/apps.py b/ishtar_common/apps.py
index 56768bc51..41dce9300 100644
--- a/ishtar_common/apps.py
+++ b/ishtar_common/apps.py
@@ -15,6 +15,11 @@ class IshtarAdminSite(AdminSite):
admin_site = IshtarAdminSite(name='ishtaradmin')
+class TranslationOverloadConfig(AppConfig):
+ name = "overload_translation"
+ verbose_name = _("Translation - Overload")
+
+
class ArchaeologicalContextRecordConfig(AppConfig):
name = 'archaeological_context_records'
verbose_name = _("Ishtar - Context record")
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index f6ed81f9c..e7f0e9262 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -68,8 +68,9 @@ from django.db.utils import DatabaseError
from django.template.defaultfilters import slugify
from django.utils.functional import lazy
from django.utils.safestring import SafeText, mark_safe
-from django.utils.translation import ugettext_lazy as _, ugettext, \
- pgettext_lazy, activate, deactivate
+from django.utils.translation import activate, deactivate
+from ishtar_common.utils import ugettext_lazy as _, ugettext, \
+ pgettext_lazy
from ishtar_common.utils_secretary import IshtarSecretaryRenderer
from simple_history.models import HistoricalRecords as BaseHistoricalRecords
from unidecode import unidecode
diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py
index d446a381a..d828e79cd 100644
--- a/ishtar_common/utils.py
+++ b/ishtar_common/utils.py
@@ -55,10 +55,19 @@ from django.db import models
from django.http import HttpResponseRedirect
from django.utils.datastructures import MultiValueDict as BaseMultiValueDict
from django.utils.safestring import mark_safe
-from django.utils.translation import ugettext_lazy as _, ugettext
from django.template.defaultfilters import slugify
+if settings.USE_TRANSLATION_OVERLOAD:
+ from overload_translation.utils import ugettext_lazy, ugettext, \
+ pgettext_lazy, pgettext
+else:
+ from django.utils.translation import ugettext_lazy, ugettext, \
+ pgettext_lazy, pgettext
+
+_ = ugettext_lazy
+
+
def dict_to_tuple(dct):
values = []
for k, v in dct.items():
diff --git a/overload_translation/__init__.py b/overload_translation/__init__.py
new file mode 100644
index 000000000..e9e41546e
--- /dev/null
+++ b/overload_translation/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'ishtar_common.apps.TranslationOverloadConfig'
diff --git a/overload_translation/admin.py b/overload_translation/admin.py
new file mode 100644
index 000000000..85f7543cd
--- /dev/null
+++ b/overload_translation/admin.py
@@ -0,0 +1,13 @@
+from django.contrib import admin
+
+from overload_translation import models
+from ishtar_common.apps import admin_site
+
+
+class TranslationOverloadAdmin(admin.ModelAdmin):
+ list_display = ("message", "context", "lang", "translation")
+ list_filter = ("lang",)
+ search_fields = ("message", "context")
+
+
+admin_site.register(models.TranslationOverload, TranslationOverloadAdmin)
diff --git a/overload_translation/migrations/0001_initial.py b/overload_translation/migrations/0001_initial.py
new file mode 100644
index 000000000..33e2732ad
--- /dev/null
+++ b/overload_translation/migrations/0001_initial.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.18 on 2019-11-15 17:48
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='TranslationOverload',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('message', models.TextField(verbose_name='String')),
+ ('context', models.CharField(blank=True, default='', max_length=256, verbose_name='Translation context')),
+ ('translation', models.TextField(verbose_name='Translation')),
+ ('lang', models.CharField(choices=[('fr', 'Français'), ('en', 'English')], max_length=4, verbose_name='Language')),
+ ],
+ options={
+ 'verbose_name_plural': 'Translations overload',
+ 'verbose_name': 'Translation overload',
+ },
+ ),
+ migrations.AlterUniqueTogether(
+ name='translationoverload',
+ unique_together=set([('message', 'lang', 'context')]),
+ ),
+ ]
diff --git a/overload_translation/migrations/__init__.py b/overload_translation/migrations/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/overload_translation/migrations/__init__.py
diff --git a/overload_translation/models.py b/overload_translation/models.py
new file mode 100644
index 000000000..723c22836
--- /dev/null
+++ b/overload_translation/models.py
@@ -0,0 +1,17 @@
+from django.conf import settings
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+
+class TranslationOverload(models.Model):
+ message = models.TextField(_("String"))
+ context = models.CharField(_("Translation context"), max_length=256,
+ default="", blank=True)
+ translation = models.TextField(_("Translation"))
+ lang = models.CharField(_("Language"), choices=settings.LANGUAGES,
+ max_length=4)
+
+ class Meta:
+ verbose_name = _("Translation overload")
+ verbose_name_plural = _("Translations overload")
+ unique_together = ("message", "lang", "context")
diff --git a/overload_translation/utils.py b/overload_translation/utils.py
new file mode 100644
index 000000000..1b7c04cdd
--- /dev/null
+++ b/overload_translation/utils.py
@@ -0,0 +1,80 @@
+from django.conf import settings
+from django.core.cache import cache
+from django.db.utils import DatabaseError
+from django.utils.functional import lazy
+from django.utils.translation import ugettext as _, pgettext as _p, get_language
+
+import hashlib
+
+from overload_translation import models
+
+
+NO_VALUE = "<<no-value>>"
+
+
+def simple_trans(message, context):
+ if context:
+ s = _p(context, message)
+ else:
+ s = _(message)
+ if not settings.TRANSLATION_OVERLOAD_DEBUG:
+ return s
+ s += " - message:\"{}\"".format(
+ message.replace("{", "OPEN-BRACES").replace("}", "CLOSE-BRACES"))
+ if context:
+ s += " - context:\"{}\"".format(context)
+ return s
+
+
+def ugettext(message, context=""):
+ has_translation_key = "{}-has-dynamic-translation".format(
+ settings.PROJECT_SLUG)
+ has_translations = cache.get(has_translation_key)
+ if has_translations is False:
+ return simple_trans(message, context)
+ elif has_translations is None:
+ if models.TranslationOverload.objects.count():
+ cache.set(has_translation_key, True, settings.CACHE_TIMEOUT)
+ else:
+ cache.set(has_translation_key, False, settings.CACHE_TIMEOUT)
+ return simple_trans(message, context)
+ current_language = get_language()
+ if not current_language:
+ return simple_trans(message, context)
+ current_context = current_language
+ if context:
+ current_context += "-" + context
+ key = "{}-translation-{}-{}".format(settings.PROJECT_SLUG,
+ current_context, message)
+
+ m = hashlib.md5()
+ m.update(key.encode('utf-8'))
+ key = m.hexdigest()
+ value = cache.get(key)
+ if value == NO_VALUE:
+ return simple_trans(message, context)
+ elif value:
+ return value
+ try:
+ q = models.TranslationOverload.objects.filter(
+ lang=current_language, message=message, context=context)
+ nb = q.count()
+ except DatabaseError:
+ cache.set(key, NO_VALUE, settings.CACHE_TIMEOUT)
+ return simple_trans(message, context)
+ if not nb:
+ cache.set(key, NO_VALUE, settings.CACHE_TIMEOUT)
+ return simple_trans(message, context)
+ value = q.values_list("translation", flat=True).all()[0]
+ cache.set(key, value, settings.CACHE_TIMEOUT)
+ return value
+
+
+ugettext_lazy = lazy(ugettext, str)
+
+
+def pgettext(context, message):
+ return ugettext(message, context=context)
+
+
+pgettext_lazy = lazy(pgettext, str) \ No newline at end of file