diff --git a/.gitignore b/.gitignore index b648ad00b9..eaa9e5574d 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,7 @@ docs/_build # Local static and media file storage (only when running in development mode) inventree_media inventree_static +static_i18n # Local config file config.yaml diff --git a/InvenTree/InvenTree/management/commands/prerender.py b/InvenTree/InvenTree/management/commands/prerender.py new file mode 100644 index 0000000000..b80f35d421 --- /dev/null +++ b/InvenTree/InvenTree/management/commands/prerender.py @@ -0,0 +1,63 @@ +""" +Custom management command to prerender files +""" + +import django +from django.core.management.base import BaseCommand +from django.conf import settings +from django.template.loader import render_to_string +from django.utils.module_loading import import_string +from django.http.request import HttpRequest +from django.utils.translation import override as lang_over + +import time +import os + + +def render_file(file_name, source, target, locales, ctx): + """ renders a file into all provided locales """ + for locale in locales: + target_file = os.path.join(target, locale + '.' + file_name) + with open(target_file, 'w') as localised_file: + with lang_over(locale): + renderd = render_to_string(os.path.join(source, file_name), ctx) + localised_file.write(renderd) + + +class Command(BaseCommand): + """ + django command to prerender files + """ + + def handle(self, *args, **kwargs): + # static directorys + LC_DIR = settings.LOCALE_PATHS[0] + SOURCE_DIR = settings.STATICFILES_I18_SRC + TARTGET_DIR = settings.STATICFILES_I18_TRG + + # ensure static directory exists + if not os.path.exists(TARTGET_DIR): + os.mkdir(TARTGET_DIR) + + # collect locales + locales = {} + for locale in os.listdir(LC_DIR): + path = os.path.join(LC_DIR, locale) + if os.path.exists(path) and os.path.isdir(path): + locales[locale] = locale + + # render! + request = HttpRequest() + ctx = {} + processors = tuple(import_string(path) for path in settings.STATFILES_I18_PROCESORS) + for processor in processors: + ctx.update(processor(request)) + + for file in os.listdir(SOURCE_DIR, ): + path = os.path.join(SOURCE_DIR, file) + if os.path.exists(path) and os.path.isfile(path): + print(f"render {file}") + render_file(file, SOURCE_DIR, TARTGET_DIR, locales, ctx) + else: + raise NotImplementedError('Using multi-level directories is not implemented at this point') # TODO multilevel dir if needed + print(f"rendered all files in {SOURCE_DIR}") diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index b1256dccee..c4cc8e961a 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -190,6 +190,17 @@ STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'InvenTree', 'static'), ] +# Translated Template settings +STATICFILES_I18_PREFIX = 'i18n' +STATICFILES_I18_SRC = os.path.join(BASE_DIR, 'templates', 'js') +STATICFILES_I18_TRG = STATICFILES_DIRS[0] + '_' + STATICFILES_I18_PREFIX +STATICFILES_DIRS.append(STATICFILES_I18_TRG) +STATICFILES_I18_TRG = os.path.join(STATICFILES_I18_TRG, STATICFILES_I18_PREFIX) + +STATFILES_I18_PROCESORS = [ + 'InvenTree.context.status_codes', +] + # Color Themes Directory STATIC_COLOR_THEMES_DIR = os.path.join(STATIC_ROOT, 'css', 'color-themes') diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py index cf56e01fbf..a92d95c766 100644 --- a/InvenTree/part/templatetags/inventree_extras.py +++ b/InvenTree/part/templatetags/inventree_extras.py @@ -6,6 +6,7 @@ import os from django import template from django.urls import reverse from django.utils.safestring import mark_safe +from django.templatetags.static import StaticNode from InvenTree import version, settings import InvenTree.helpers @@ -180,3 +181,31 @@ def object_link(url_name, pk, ref): ref_url = reverse(url_name, kwargs={'pk': pk}) return mark_safe('{}'.format(ref_url, ref)) + + +class I18nStaticNode(StaticNode): + """ + custom StaticNode + replaces a variable named *lng* in the path with the current language + """ + def render(self, context): + self.path.var = self.path.var.format(lng=context.request.LANGUAGE_CODE) + ret = super().render(context) + return ret + + +@register.tag('i18n_static') +def do_i18n_static(parser, token): + """ + Overrides normal static, adds language - lookup for prerenderd files #1485 + + usage (like static): + {% i18n_static path [as varname] %} + """ + bits = token.split_contents() + loc_name = settings.STATICFILES_I18_PREFIX + + # change path to called ressource + bits[1] = f"'{loc_name}/{{lng}}.{bits[1][1:-1]}'" + token.contents = ' '.join(bits) + return I18nStaticNode.handle_token(parser, token) diff --git a/InvenTree/templates/base.html b/InvenTree/templates/base.html index 8ccf691ef5..970d9f1016 100644 --- a/InvenTree/templates/base.html +++ b/InvenTree/templates/base.html @@ -143,20 +143,21 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/tasks.py b/tasks.py index 895f3183ce..d775b943a0 100644 --- a/tasks.py +++ b/tasks.py @@ -154,6 +154,7 @@ def static(c): as per Django requirements. """ + manage(c, "prerender") manage(c, "collectstatic --no-input")