[[!template id=plugin name=po core=0 author="[[intrigeri]]"]] [[!tag type/format]] This plugin adds support for multi-lingual wikis, translated with gettext, using [po4a](http://po4a.alioth.debian.org/). It depends on the Perl `Locale::Po4a::Po` library (`apt-get install po4a`). Introduction ============ A language is chosen as the "master" one, and any other supported language is a "slave" one. A page written in the "master" language is a "master" page. It can be of any page type supported by ikiwiki, except `po`. It does not have to be named a special way: migration to this plugin does not imply any page renaming work. Example: `bla/page.mdwn` is a "master" Markdown page written in English; if `usedirs` is enabled, it is rendered as `bla/page/index.en.html`, else as `bla/page.en.html`. Any translation of a "master" page into a "slave" language is called a "slave" page; it is written in the gettext PO format. `po` is now a page type supported by ikiwiki. Example: `bla/page.fr.po` is the PO "message catalog" used to translate `bla/page.mdwn` into French; if `usedirs` is enabled, it is rendered as `bla/page/index.fr.html`, else as `bla/page.fr.html` Configuration ============= Supported languages ------------------- `po_master_language` is used to set the "master" language in `ikiwiki.setup`, such as: po_master_language => { 'code' => 'en', 'name' => 'English' } `po_slave_languages` is used to set the list of supported "slave" languages, such as: po_slave_languages => { 'fr' => 'Français', 'es' => 'Castellano', 'de' => 'Deutsch', } Decide which pages are translatable ----------------------------------- The `po_translatable_pages` setting configures what pages are translatable. It is a [[ikiwiki/PageSpec]], so you have lots of control over what kind of pages are translatable. The `.po` files are not considered as being translatable, so you don't need to worry about excluding them explicitly from this [[ikiwiki/PageSpec]]. Internal links -------------- The `po_link_to` option in `ikiwiki.setup` is used to decide how internal links should be generated, depending on web server features and site-specific preferences. ### Default linking behavior If `po_link_to` is unset, or set to `default`, ikiwiki's default linking behavior is preserved: `\[[destpage]]` links to the master language's page. ### Link to current language If `po_link_to` is set to `current`, `\[[destpage]]` links to the `destpage`'s version written in the current page's language, if available, *i.e.*: - `foo/destpage/index.LL.html` if `usedirs` is enabled - `foo/destpage.LL.html` if `usedirs` is disabled ### Link to negotiated language If `po_link_to` is set to `negotiated`, `\[[page]]` links to the negotiated preferred language, *i.e.* `foo/page/`. (In)compatibility notes: - if `usedirs` is disabled, it does not make sense to set `po_link_to` to `negotiated`; this option combination is neither implemented nor allowed. - if the web server does not support Content Negotiation, setting `po_link_to` to `negotiated` will produce a unusable website. Server support ============== Apache ------ Using Apache `mod_negotiation` makes it really easy to have Apache serve any page in the client's preferred language, if available. This is the default Debian Apache configuration. When `usedirs` is enabled, one has to set `DirectoryIndex index` for the wiki context. Setting `DefaultLanguage LL` (replace `LL` with your default MIME language code) for the wiki context can help to ensure `bla/page/index.en.html` is served as `Content-Language: LL`. lighttpd -------- lighttpd unfortunately does not support content negotiation. **FIXME**: does `mod_magnet` provide the functionality needed to emulate this? Usage ===== Templates --------- The `ISTRANSLATION` and `ISTRANSLATABLE` variables can be used to display things only on translatable or translation pages. ### Display page's versions in other languages The `OTHERLANGUAGES` loop provides ways to display other languages' versions of the same page, and the translations' status. One typically adds the following code to `templates/page.tmpl`:
The following variables are available inside the loop (for every page in): - `URL` - url to the page - `CODE` - two-letters language code - `LANGUAGE` - language name (as defined in `po_slave_languages`) - `MASTER` - is true (1) if, and only if the page is a "master" page - `PERCENT` - for "slave" pages, is set to the translation completeness, in percents ### Display the current translation status The `PERCENTTRANSLATED` variable is set to the translation completeness, expressed in percent, on "slave" pages. One can use it this way:
Additional PageSpec tests ------------------------- This plugin enhances the regular [[ikiwiki/PageSpec]] syntax with some additional tests that are documented [[here|ikiwiki/pagespec/po]]. Automatic PO file update ------------------------ Committing changes to a "master" page: 1. updates the POT file and the PO files for the supported languages; the updated PO files are then put under version control 2. triggers a refresh of the corresponding HTML slave pages Also, when the plugin has just been enabled, or when a page has just been declared as being translatable, the needed POT and PO files are created, and the PO files are checked into version control. Discussion pages ---------------- Discussion should happen in the language in which the pages are written for real, *i.e.* the "master" one. If discussion pages are enabled, "slave" pages therefore link to the "master" page's discussion page. Translating ----------- One can edit the PO files using ikiwiki's CGI (a message-by-message interface could also be implemented at some point). If [[tips/untrusted_git_push]] is setup, one can edit the PO files in one's preferred `$EDITOR`, without needing to be online. TODO ==== OTHERLANGUAGES dependencies --------------------------- Pages using `OTHERLANGUAGES` depend on any "master" and "slave" pages whose status is being displayed. It is supposed to trigger dependency loops, but no practical bugs were noticed yet. Should pages using the `OTHERLANGUAGES` template loop be declared as linking to the same page in other versions? To be rigorous, they should, but this may clutter the backlinks. Security checks --------------- - `refreshpofiles` uses `system()`, whose args have to be checked more thoroughly to prevent any security issue (command injection, etc.). > Always pass `system()` a list of parameters to avoid the shell. > I've checked in a change fixing that. --[[Joey]] - `refreshpofiles` and `refreshpot` create new files; this may need some checks, e.g. using `IkiWiki::prep_writefile()` > Yes, it would be ideal to call `prep_writefile` on each file > that they write, beforehand. This way you'd avoid symlink attacks etc to the > generated po/pot files. I haven't done it, but it seems pretty trivial. > --[[Joey]] - Can any sort of directives be put in po files that will cause mischief (ie, include other files, run commands, crash gettext, whatever). - Any security issues on running po4a on untrusted content? gettext/po4a rough corners -------------------------- - fix infinite loop when synchronizing two ikiwiki (when checkouts live in different directories): say bla.fr.po has been updated in repo2; pulling repo2 from repo1 seems to trigger a PO update, that changes bla.fr.po in repo1; then pushing repo1 to repo2 triggers a PO update, that changes bla.fr.po in repo2; etc.; fixed in `629968fc89bced6727981c0a1138072631751fee`? - new translations created in the web interface must get proper charset/encoding gettext metadata, else the next automatic PO update removes any non-ascii chars; possible solution: put such metadata into the Pot file, and let it propagate; should be fixed in `773de05a7a1ee68d2bed173367cf5e716884945a`, time will tell. Misc. improvements ------------------ ### preview preview does not work for PO files. ### automatic POT/PO update Use the `change` hook instead of `needsbuild`? ### page titles Use nice page titles from meta plugin in links, as inline already does. This is actually a duplicate for [[bugs/pagetitle_function_does_not_respect_meta_titles]], which might be fixed by something like [[todo/using_meta_titles_for_parentlinks]]. ### websetup Which configuration settings are safe enough for websetup? > I see no problems with `po_master_language` and `po_slave_languages` > (assuming websetup handles the hashes correctly). Would not hurt to check > that the values of these are legal language codes, in `checkconfig`. > `po_translatable_pages` seems entirely safe. `po_link_to` w/o usedirs > causes ikiwiki to error out. If it were changed to fall back to a safe > setting in this case rather than error, it would be safe. > --[[Joey]] ### parentlinks When the wiki home page is translatable, the parentlinks plugin sets `./index.html` as its translations' single parent link. Ideally, the home page's translations should get no parent link at all, just like the version written in the master language. ### backlinks If a given translatable `sourcepage.mdwn` links to \[[destpage]], `sourcepage.LL.po` also link to \[[destpage]], and the latter has the master page *and* all its translations listed in the backlinks. Translation quality assurance ----------------------------- Modifying a PO file via the CGI must be forbidden if the new version is not a valid PO file. As a bonus, check that it provides a more complete translation than the existing one. A new `cansave` type of hook would be needed to implement this. Note: committing to the underlying repository is a way to bypass this check.