From e6a35444dcda724cdca968a5c2f1f1df44ce51d7 Mon Sep 17 00:00:00 2001 From: Sven Eberth Date: Thu, 23 Jan 2025 12:16:43 +0100 Subject: [PATCH] fix: determine a better path for a new `TranslateSkel` (#1367) The problem was on the one hand that the path was first determined in `__str__`, which means that it is not the position where the translate object was created, but where it is converted to a string (this can also be in the renderer). I have therefore moved this to `__init__`. Furthermore, the stack loaded in `walk_stack()` skipped too many frames (we actually need the first frame directly), so this couldn't work either -- except for Jinja. Now we load the stack explicitly from the top. --- src/viur/core/i18n.py | 59 ++++++++++++++------------- src/viur/core/render/html/env/viur.py | 2 +- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/viur/core/i18n.py b/src/viur/core/i18n.py index 6a0cd936a..730166916 100644 --- a/src/viur/core/i18n.py +++ b/src/viur/core/i18n.py @@ -74,12 +74,14 @@ on your own. Just use the TranslateSkel). """ # FIXME: grammar, rst syntax import datetime -import jinja2.ext as jinja2 import logging +import sys import traceback import typing as t from pathlib import Path +import jinja2.ext as jinja2 + from viur.core import current, db, languages, tasks from viur.core.config import conf @@ -157,6 +159,8 @@ class translate: "translationCache", "force_lang", "public", + "filename", + "lineno", ) def __init__( @@ -166,6 +170,7 @@ def __init__( hint: str = None, force_lang: str = None, public: bool = False, + caller_is_jinja: bool = False, ): """ :param key: The unique key defining this text fragment. @@ -178,59 +183,57 @@ def __init__( target language. :param force_lang: Use this language instead the one of the request. :param public: Flag for public translations, which can be obtained via /json/_translate/get_public. + :param caller_is_jinja: Is the call caused by our jinja method? """ super().__init__() if not isinstance(key, str): logging.warning(f"Got non-string (type {type(key)}) as {key=}!", exc_info=True) + if force_lang is not None and force_lang not in conf.i18n.available_dialects: + raise ValueError(f"The language {force_lang=} is not available") + key = str(key) # ensure key is a str self.key = key.lower() self.defaultText = defaultText or key self.hint = hint - self.translationCache = None - if force_lang is not None and force_lang not in conf.i18n.available_dialects: - raise ValueError(f"The language {force_lang=} is not available") - self.force_lang = force_lang self.public = public + self.filename, self.lineno = None, None + + if self.key not in systemTranslations and conf.i18n.add_missing_translations: + # This translation seems to be new and should be added + for frame, line in traceback.walk_stack(sys._getframe(0).f_back): + if self.filename is None: + # Use the first frame as fallback. + # In case of calling this class directly, + # this is anyway the caller we're looking for. + self.filename = frame.f_code.co_filename + self.lineno = frame.f_lineno + if not caller_is_jinja: + break + if caller_is_jinja and not frame.f_code.co_filename.endswith(".py"): + # Look for the latest html, macro (not py) where the + # translate method has been used, that's our caller + self.filename = frame.f_code.co_filename + self.lineno = line + break def __repr__(self) -> str: return f"" - def __str__(self) -> str: if self.translationCache is None: global systemTranslations - from viur.core.render.html.env.viur import translate as jinja_translate - if self.key not in systemTranslations and conf.i18n.add_missing_translations: # This translation seems to be new and should be added - filename = lineno = None - is_jinja = False - for frame, line in traceback.walk_stack(None): - if filename is None: - # Use the first frame as fallback. - # In case of calling this class directly, - # this is anyway the caller we're looking for. - filename = frame.f_code.co_filename - lineno = frame.f_lineno - if frame.f_code == jinja_translate.__code__: - # The call was caused by our jinja method - is_jinja = True - if is_jinja and not frame.f_code.co_filename.endswith(".py"): - # Look for the latest html, macro (not py) where the - # translate method has been used, that's our caller - filename = frame.f_code.co_filename - lineno = line - break add_missing_translation( key=self.key, hint=self.hint, default_text=self.defaultText, - filename=filename, - lineno=lineno, + filename=self.filename, + lineno=self.lineno, public=self.public, ) diff --git a/src/viur/core/render/html/env/viur.py b/src/viur/core/render/html/env/viur.py index 9206e53ab..50e8b04f0 100644 --- a/src/viur/core/render/html/env/viur.py +++ b/src/viur/core/render/html/env/viur.py @@ -34,7 +34,7 @@ def translate( See also :class:`core.i18n.TranslationExtension`. """ - return translate_class(key, default_text, hint, force_lang)(**kwargs) + return translate_class(key, default_text, hint, force_lang, caller_is_jinja=True)(**kwargs) @jinjaGlobalFunction