167 lines
5.8 KiB
Markdown
167 lines
5.8 KiB
Markdown
|
# Lektor i18n plugin
|
||
|
|
||
|
This plugin enables a smarter way to translate a [Lektor](http://getlektor.com) static website using old-good PO files. So you can use your beloved translation processes and tools.
|
||
|
|
||
|
## Principles
|
||
|
|
||
|
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`
|
||
|
|
||
|
content = en
|
||
|
translations = fr,es,it
|
||
|
i18npath = i18n
|
||
|
translate_paragraphwise = False
|
||
|
|
||
|
Where :
|
||
|
|
||
|
* `content` is the language used to write `contents.lr` files (default is `en`)
|
||
|
* `translations` is the list of target languages (you want to translate into).
|
||
|
* `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 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 :
|
||
|
|
||
|
[model]
|
||
|
name = Page
|
||
|
label = {{ this.title }}
|
||
|
|
||
|
[fields.title]
|
||
|
label = Title
|
||
|
type = string
|
||
|
translate = True
|
||
|
|
||
|
[fields.body]
|
||
|
label = Body
|
||
|
type = markdown
|
||
|
translate = True
|
||
|
|
||
|
Both `title` and `body` are now translatable. It means that during the parsing phase, all sentences from `title` or `body` fields from the `contents.lr` files with `Page` model will populate the collected PO file.
|
||
|
|
||
|
Another flowblock example:
|
||
|
|
||
|
[block]
|
||
|
name = Section Block
|
||
|
button_label = Section
|
||
|
|
||
|
[fields.title]
|
||
|
label = Title
|
||
|
type = string
|
||
|
translate = True
|
||
|
|
||
|
[fields.body]
|
||
|
label = Body
|
||
|
type = markdown
|
||
|
translate = True
|
||
|
|
||
|
[fields.image]
|
||
|
label = Image
|
||
|
type = select
|
||
|
source = record.attachments.images
|
||
|
|
||
|
[fields.image_position]
|
||
|
label = Image Position
|
||
|
type = select
|
||
|
choices = left, right
|
||
|
choice_labels = Left, Right
|
||
|
default = right
|
||
|
|
||
|
Here again, `body` and `title` will be translated. But `image` and `image_position` won't.
|
||
|
|
||
|
### Non-english content
|
||
|
|
||
|
Thanx to a limitation of msginit it's not so easy to translate a website with default language set to anything but english.
|
||
|
|
||
|
So if your default content language is not english, you will have to edit the first `contents-en.po` file and remove the translations (by hand ?)...
|
||
|
|
||
|
## Installation
|
||
|
|
||
|
### Prerequisites
|
||
|
|
||
|
#### Lektor
|
||
|
|
||
|
This plugin has been tested with `Lektor 3..0.x`.
|
||
|
|
||
|
#### GetText
|
||
|
|
||
|
Both Gettext and Pybabel are required. For a Debian/Ubuntu system, this means a simple :
|
||
|
|
||
|
sudo apt-get install gettext python3-babel
|
||
|
|
||
|
On macOS, use a decent package manager, like MacPorts or Homebrew. With Homebrew:
|
||
|
|
||
|
brew install gettext
|
||
|
|
||
|
and then pip to fetch pybabel:
|
||
|
|
||
|
pip install babel
|
||
|
|
||
|
### Installation
|
||
|
|
||
|
Very straightforward :
|
||
|
|
||
|
$ lektor plugins add lektor-i18n
|
||
|
|
||
|
Verify installation with a simple :
|
||
|
|
||
|
$ lektor plugins list
|
||
|
...
|
||
|
lektor-i18n (version 0.1)
|
||
|
...
|
||
|
|
||
|
## Usage
|
||
|
|
||
|
The translation mechanism is hooked into the build system. So translating a website just means building the website.
|
||
|
|
||
|
$ lektor build
|
||
|
|
||
|
On first call, a new `i18n` directory (can be changed in configuration file) will be created on top the lektor tree.
|
||
|
|
||
|
This directory will be populated with a single `contents.pot` file, compiling all the sentences found by the plugin. The list of fields eligible to translation is configured in the models/flows definition with `translate=True` added to each field.
|
||
|
|
||
|
For each translation language (still from the configuration file), a `content-<language>.po` file will be created/updated. These are the files that need to be translated with your prefered tool (like [POEdit](http://poedit.net) or [Transifex](http://transifex.com)).
|
||
|
|
||
|
All translation files (`contents-*.po`) are then compiled and merged with the original `contents.lr` files to produce all the `contents-<language>.lr` files in their respective directories.
|
||
|
|
||
|
Due to the way Lektor building system is designed, all these steps happen on every build. This means that sometime, after translating the `contents-*.po` files, it might be required to run the build system twice to see the translation appear in the final HTML files.
|
||
|
|
||
|
### Project file
|
||
|
|
||
|
It's still the user responsability to modify the project file in order to include the expected languages :
|
||
|
|
||
|
[alternatives.en]
|
||
|
name = English
|
||
|
primary = yes
|
||
|
locale = en_US
|
||
|
|
||
|
[alternatives.fr]
|
||
|
name = French
|
||
|
url_prefix = /fr/
|
||
|
locale = fr
|
||
|
|
||
|
See [Lektor Documentation](https://www.getlektor.com/docs/content/alts/) for more information.
|
||
|
|
||
|
## Support
|
||
|
|
||
|
This plugin is provided as-is by [NumeriCube](http://numericube.com) a human-sized Paris-based company prodiving tailored services to smart customers.
|
||
|
|
||
|
We will be happy to try to help you with this plugin if need. Just file an issue on our [GitHub account](https://gihub.com/numericube/lektor-i18n-plugin/).
|
||
|
|