Skip to content

Commit

Permalink
use jinja i18n infrastructure
Browse files Browse the repository at this point in the history
To avoid duplication, this commit adds support for the jinja i18n
extension, allowing the translation of message from templates. This also
allows pybabel to extract messages with their correct source location,
something not possible before. This makes merging of new and old
messages more robust.
  • Loading branch information
humenda committed Apr 14, 2018
1 parent da12ca6 commit 5895539
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 20 deletions.
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ This plugin enables a smarter way to translate a [Lektor](http://getlektor.com)

## Principles

The idea of this plugin is to capture the **sentences** from your **content**, and populate a standard *Gettext* [PO file](https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html). Using usual tools, user can translate these files, very easily. Then the plugin will merge the translations into new [_alternative_](https://www.getlektor.com/docs/content/alts/) content files, providing a translated website.
The idea of this plugin is to capture the **sentences** or **paragraphs** from your **content** and **templates**, and populate a standard *Gettext* [PO file](https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html). Using usual tools, user can translate these files, very easily. Then the plugin will merge the translations into new [_alternative_](https://www.getlektor.com/docs/content/alts/) content files, providing a translated website.

## Configuration

### Configuration file

`configs/i18n.ini`:
#### `configs/i18n.ini`

content = en
translations = fr,es,it
Expand All @@ -24,9 +24,18 @@ Where :
* `i18npath` is the directory where translation files will be produced/stored (default is `i18n`). This directory needs to be relative to root path.
* `translate_paragraphwise` specifies whether translation strings are created per line or per paragraph. The latter is helpful for documents wrapping texts at 80 character boundaries. It is set to `False` by default.

#### `babel.cfg`

If you plan to localise your templates as well, you can use
`{{ _("some string") }}` in your templates. To make this work, pybabel should be installed (pip install pybabel; maybe pip3). A `babel.cfg` also has to exist in your project root with this content:

[jinja2: **/templates/**.html]
encoding = utf-8
extensions=jinja2.ext.autoescape,jinja2.ext.with_

### Translatable fields

In order for a field to be marked a translatable, an option has to be set in the field definition. Both blocks and flowblocks fields are subjects to translations.
In order for a field to be marked as translatable, an option has to be set in the field definition. Both blocks and flowblocks fields are subjects to translations.

in `flowblocks/*.ini` and/or `models/*.ini`, mark a field as translatable with :

Expand Down
51 changes: 34 additions & 17 deletions lektor_i18n.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,34 @@ def trans(translator, s):
def truncate(s, length=32):
return (s[:length] + '..') if len(s) > length else s

#pylint: disable=too-few-public-methods,redefined-variable-type
class TemplateTranslator():
def __init__(self, i18npath):
self.i18npath = i18npath
self.__lastlang = None
self.translator = None
self.init_translator()

def init_translator(self):
ctx = get_ctx()
if not ctx:
self.translator = gettext.GNUTranslations()
return super().__init__()
if not self.__lastlang == ctx.locale:
self.__lastlang = ctx.locale
self.translator = gettext.translation("contents",
join(self.i18npath, '_compiled'),
languages=[ctx.locale], fallback=True)

def gettext(self, x):
self.init_translator() # lagnuage could have changed
return self.translator.gettext(x)

def ngettext(self, *x):
self.init_translator()
return self.translator.ngettext(*x)


class Translations():
"""Memory of translations"""

Expand Down Expand Up @@ -195,20 +223,7 @@ class I18NPlugin(Plugin):
name = u'i18n'
description = u'Internationalisation helper'

def translate_tag(self, s, *args, **kwargs):
if not self.enabled:
return s # no operation
s = s.strip()
ctx = get_ctx()
if self.content_language==ctx.locale:
translations.add(s,'(dynamic)')
reporter.report_debug_info('added to translation memory (dynamic): ', truncate(s))
return s
else:
translator = gettext.translation("contents", join(self.i18npath,'_compiled'), languages=[ctx.locale], fallback = True)
return trans(translator, s)


# ToDo: what is this function for
def choose_language(self, l, language, fallback='en', attribute='language'):
"""Will return from list 'l' the element with attribute 'attribute' set to given 'language'.
If none is found, will try to return element with attribute 'attribute' set to given 'fallback'.
Expand Down Expand Up @@ -238,16 +253,18 @@ def on_setup_env(self):
self.trans_parwise = self.get_config().get('translate_paragraphwise',
'false') in ('true','True','1')
self.content_language=self.get_config().get('content', 'en')
self.env.jinja_env.add_extension('jinja2.ext.i18n')
self.env.jinja_env.policies['ext.i18n.trimmed'] = True # do a .strip()
self.env.jinja_env.install_gettext_translations(TemplateTranslator(self.i18npath))
# ToDo: is this stil required
try:
self.translations_languages=self.get_config().get('translations').replace(' ','').split(',')
except AttributeError:
raise RuntimeError('Please specify the "translations" configuration option in configs/i18n.ini')

if not self.content_language in self.translations_languages:
self.translations_languages.append(self.content_language)
self.env.jinja_env.filters['translate'] = self.translate_tag
self.env.jinja_env.globals['_'] = self.translate_tag
self.env.jinja_env.globals['choose_language'] = self.choose_language
#self.env.jinja_env.globals['choose_language'] = self.choose_language

def process_node(self, fields, sections, source, zone, root_path):
"""For a give node (), identify all fields to translate, and add new
Expand Down

0 comments on commit 5895539

Please sign in to comment.