core.i18n ========= .. py:module:: core.i18n .. autoapi-nested-parse:: This module provides translation, also known as internationalization -- short: i18n. Project translations must be stored in the datastore. There are only some static translation tables in the viur-core to have some basic ones. The viur-core's own "translation" module (routed as _translation) provides an API to manage these translations, for example in the vi-admin. How to use translations? First, make sure that the languages are configured: .. code-block:: python from viur.core.config import conf # These are the main languages (for which translated values exist) # that should be available for the project. conf.i18n.available_languages = = ["en", "de", "fr"] # These are some aliases for languages that should use the translated # values of a particular main language, but don't have their own values. conf.i18n.language_alias_map = { "at": "de", # Austria uses German "ch": "de", # Switzerland uses German "be": "fr", # Belgian uses France "us": "en", # US uses English } Now translations can be used 1. In python .. code-block:: python from viur.core.i18n import translate # Just the translation key, the minimal case print(translate("translation-key")) # also provide a default value to use if there's no value in the datastore # set and a hint to provide some context. print(translate("translation-key", "the default value", "a hint")) # Use string interpolation with variables print(translate("hello", "Hello {{name}}!", "greeting a user")(name=current.user.get()["firstname"])) 2. In jinja .. code-block:: jinja {# Use the ViUR translation extension, it can be compiled with the template, caches the translation values and is therefore efficient #} {% do translate "hello", "Hello {{name}}!", "greet a user", name="ViUR" %} {# But in some cases the key or interpolation variables are dynamic and not available during template compilation. For this you can use the translate function: #} {{ translate("hello", "Hello {{name}}!", "greet a user", name=skel["firstname"]) }} How to add translations There are two ways to add translations: 1. Manually With the vi-admin. Entries can be added manually by creating a new skeleton and filling in of the key and values. 2. Automatically The add_missing_translations option must be enabled for this. .. code-block:: python from viur.core.config import conf conf.i18n.add_missing_translations = True If a translation is now printed and the key is unknown (because someone has just added the related print code), an entry is added in the datastore kind. In addition, the default text and the hint are filled in and the filename and the line from the call from the code are set in the skeleton. This is the recommended way, as ViUR collects all the information you need and you only have to enter the translated values. (3. own way Of course you can create skeletons / entries in the datastore in your project on your own. Just use the TranslateSkel). Attributes ---------- .. autoapisummary:: core.i18n.systemTranslations core.i18n.KINDNAME core.i18n.localizedDateTime core.i18n.localizedDate core.i18n.localizedTime core.i18n.localizedAbbrevDayNames core.i18n.localizedDayNames core.i18n.localizedAbbrevMonthNames core.i18n.localizedMonthNames Classes ------- .. autoapisummary:: core.i18n.AddMissing core.i18n.LanguageWrapper core.i18n.translate core.i18n.TranslationExtension Functions --------- .. autoapisummary:: core.i18n.initializeTranslations core.i18n.add_missing_translation core.i18n.migrate_translation core.i18n.localizedStrfTime Module Contents --------------- .. py:data:: systemTranslations Memory storage for translation methods .. py:data:: KINDNAME :value: 'viur-translations' Kindname for the translations .. py:class:: AddMissing Bases: :py:obj:`enum.IntEnum` An indicator flag for the `add_missing` parameter of the `translate` to make this decision final and ignore the `conf.i18n.add_missing_translations` configuration. Initialize self. See help(type(self)) for accurate signature. .. py:attribute:: NEVER This translation will never be added, regardless of any config. It's like a final `False`. .. py:attribute:: ALWAYS This translation will be always be added, regardless of any config. It's like a final `True`. .. py:class:: LanguageWrapper(languages) Bases: :py:obj:`dict` Wrapper-class for a multi-language value. It's a dictionary, allowing accessing each stored language, but can also be used as a string, in which case it tries to guess the correct language. Used by the HTML renderer to provide multi-lang bones values for templates. :param languages: Languages which are set in the bone. .. py:attribute:: languages .. py:method:: __str__() Return str(self). .. py:method:: __bool__() .. py:method:: resolve() Causes this wrapper to evaluate to the best language available for the current request. :returns: An item stored inside this instance or the empty string. .. py:class:: translate(key, defaultText = None, hint = None, force_lang = None, public = False, add_missing = False, default_variables = None, caller_is_jinja = False) Translate class which chooses the correct translation according to the request language This class is the replacement for the old translate() function provided by ViUR2. This classes __init__ takes the unique translation key (a string usually something like "user.auth_user_password.loginfailed" which uniquely defines this text fragment), a default text that will be used if no translation for this key has been added yet (in the projects default language) and a hint (an optional text that can convey context information for the persons translating these texts - they are not shown to the end-user). This class will resolve its translations upfront, so the actual resolving (by casting this class to string) is fast. This resolves most translation issues with bones, which can now take an instance of this class as it's description/hints. :param key: The unique key defining this text fragment. Usually it's a path/filename and a unique descriptor in that file :param defaultText: The text to use if no translation has been added yet. While optional, it's recommended to set this, as the key is used instead if neither are available. :param hint: A text only shown to the person translating this text, as the key/defaultText may have different meanings in the 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 default_variables: Default values for variable substitution. :param caller_is_jinja: Is the call caused by our jinja method? .. py:attribute:: __slots__ :value: ('add_missing', 'default_variables', 'defaultText', 'filename', 'force_lang', 'hint', 'key',... .. py:attribute:: key :value: '' .. py:attribute:: defaultText :value: '' .. py:attribute:: hint :value: None .. py:attribute:: translationCache :value: None .. py:attribute:: force_lang :value: None .. py:attribute:: public :value: False .. py:attribute:: add_missing :value: False .. py:attribute:: default_variables .. py:method:: __repr__() .. py:method:: __str__() .. py:method:: translate(**kwargs) Substitute the given kwargs in the translated or default text. .. py:method:: __call__(**kwargs) Just an alias for translate .. py:method:: substitute_vars(value, **kwargs) :staticmethod: Substitute vars in a translation Variables has to start with two braces (`{{`), followed by the variable name and end with two braces (`}}`). Values can be anything, they are cast to string anyway. "Hello {{name}}!" becomes with name="Bob": "Hello Bob!" .. py:method:: merge_alias(translations) :staticmethod: Make sure each aliased language has a value If an aliased language does not have a value in the translation dict, the value of the main language is copied. .. py:class:: TranslationExtension(environment) Bases: :py:obj:`jinja2.ext.Extension` Default translation extension for jinja2 render. Use like {% translate "translationKey", "defaultText", "translationHint", replaceValue1="replacedText1" %} All except translationKey is optional. translationKey is the same Key supplied to _() before. defaultText will be printed if no translation is available. translationHint is an optional hint for anyone adding a now translation how/where that translation is used. `force_lang` can be used as a keyword argument (the only allowed way) to force the use of a specific language, not the language of the request. .. py:attribute:: tags .. py:method:: parse(parser) If any of the :attr:`tags` matched this method is called with the parser as first argument. The token the parser stream is pointing at is the name token that matched. This method has to return one or a list of multiple nodes. .. py:method:: _translate(key, default_text, hint, kwargs, translations, caller) Perform the actual translation during render .. py:function:: initializeTranslations() Fetches all translations from the datastore and populates the *systemTranslations* dictionary of this module. Currently, the translate-class will resolve using that dictionary; but as we expect projects to grow and accumulate translations that are no longer/not yet used, we plan to made the translation-class fetch it's translations directly from the datastore, so we don't have to allocate memory for unused translations. .. py:function:: add_missing_translation(key, hint = None, default_text = None, filename = None, lineno = None, variables = None, public = False) Add missing translations to datastore .. py:function:: migrate_translation(key) Migrate entities, if required. With viur-core 3.6 translations are now managed as Skeletons and require some changes, which are performed in this method. .. py:data:: localizedDateTime .. py:data:: localizedDate .. py:data:: localizedTime .. py:data:: localizedAbbrevDayNames .. py:data:: localizedDayNames .. py:data:: localizedAbbrevMonthNames .. py:data:: localizedMonthNames .. py:function:: localizedStrfTime(datetimeObj, format) Provides correct localized names for directives like %a which don't get translated on GAE properly as we can't set the locale (for each request). This currently replaces %a, %A, %b, %B, %c, %x and %X. :param datetimeObj: Datetime-instance to call strftime on :param format: String containing the Format to apply. :returns: Date and time formatted according to format with correct localization