Merge branch 'master' into po
[ikiwiki.git] / doc / plugins / contrib / po.mdwn
1 I've been working on a plugin called "po", that adds support for multi-lingual wikis,
2 translated with gettext, using [po4a](http://po4a.alioth.debian.org/).
3
4 More information:
5
6 * It can be found in my "po" branch:
7   `git clone git://gaffer.ptitcanardnoir.org/ikiwiki.git`
8 * It is self-contained, *i.e.* it does not modify ikiwiki core at all.
9 * It is documented (including TODO and plans for next work steps) in
10   `doc/plugins/po.mdwn`, which can be found in the same branch.
11 * No public demo site is available so far, I'm working on this.
12
13 My plan is to get this plugin clean enough to be included in ikiwiki.
14
15 The current version is a proof-of-concept, mature enough for me to dare submitting it here,
16 but I'm prepared to hear various helpful remarks, and to rewrite parts of it as needed.
17
18 Any thoughts on this?
19
20 > Well, I think it's pretty stunning what you've done here. Seems very
21 > complete and well thought out. I have not read the code in great detail
22 > yet.
23
24 > Just using po files is an approach I've never seen tried with a wiki. I
25 > suspect it will work better for some wikis than others. For wikis that
26 > just want translations that match the master language as closely as
27 > possible and don't wander off and diverge, it seems perfect. (But what happens
28 > if someone edits the Discussion page of a translated page?)
29
30 > Please keep me posted, when you get closer to having all issues solved
31 > and ready for merging I can do a review and hopefully help with the
32 > security items you listed. --[[Joey]]
33
34 >> Thanks a lot for your quick review, it's reassuring to hear such nice words
35 >> from you. I did not want to design and write a full translation system, when
36 >> tools such as gettext/po4a already have all the needed functionality, for cases
37 >> where the master/slave languages paradigm fits.
38 >> Integrating these tools into ikiwiki plugin system was a pleasure.
39 >>
40 >> I'll tell you when I'm ready for merging, but in the meantime,
41 >> I'd like you to review the changes I did to the core (3 added hooks).
42 >> Can you please do this? If not, I'll go on and hope I'm not going to far in
43 >> the wrong direction.
44 >>
45 >>> Sure.. I'm not completly happy with any of the hooks since they're very
46 >>> special purpose, and also since `run_hooks` is not the best interface
47 >>> for a hook that modifies a variable, where only the last hook run will
48 >>> actually do anything. It might be better to just wrap
49 >>> `targetpage`, `bestlink`, and `beautify_urlpath`. But, I noticed
50 >>> the other day that such wrappers around exported functions are only visible by
51 >>> plugins loaded after the plugin that defines them.
52 >>> 
53 >>> Update: Take a look at the new "Function overriding" section of
54 >>> [[plugins/write]]. I think you can just inject wrappers about a few ikiwiki
55 >>> functions, rather than adding hooks. The `inject` function is pretty
56 >>> insane^Wlow level, but seems to work great. --[[Joey]]
57 >>>
58 >>>> Thanks a lot, it seems to be a nice interface for what I was trying to achieve.
59 >>>> I may be forced to wait two long weeks before I have a chance to confirm
60 >>>> this. Stay tuned. --[[intrigeri]]
61 >>>>
62 >>>>> I've updated the plugin to use `inject`. It is now fully self-contained,
63 >>>>> and does not modify the core anymore. --[[intrigeri]]
64 >>
65 >> The Discussion pages issue is something I am not sure about yet. But I will
66 >> probably decide that "slave" pages, being only translations, don't deserve
67 >> a discussion page: the discussion should happen in the language in which the
68 >> pages are written for real, which is the "master" one. --[[intrigeri]]
69 >> 
70 >> I think that's a good decision, you don't want to translate discussion,
71 >> and if the discussion page turns out multilingual, well, se la vi. ;-)
72 >> 
73 >> Relatedly, what happens if a translated page has a broken link, and you
74 >> click on it to edit it? Seems you'd first have to create a master page
75 >> and could only then translate it, right? I wonder if this will be clear
76 >> though to the user.
77 >>
78 >>> Right: a broken link points to the URL that allows to create
79 >>> a page that can either be a new master page or a non-translatable
80 >>> page, depending on `po_translatable_pages` value. The best
81 >>> solution I can thing of is to use [[plugins/edittemplate]] to
82 >>> insert something like "Warning: this is a master page, that must
83 >>> be written in $MASTER_LANGUAGE" into newly created master pages,
84 >>> and maybe another warning message on newly created
85 >>> non-translatable pages. It seems quite doable to me, but in order
86 >>> to avoid breaking existing functionality, it implies to hack a bit
87 >>> [[plugins/edittemplate]] so that multiple templates can be
88 >>> inserted at page creation time. [[--intrigeri]]
89 >>>
90 >>>> I implemented such a warning using the formbuilder_setup hook.
91 >>>> --[[intrigeri]]
92 >>
93 >> And also, is there any way to start a translation of a page into a new
94 >> lanauge using the web interface?
95 >>
96 >>> When a new language is added to `po_slave_languages`, a rebuild is
97 >>> triggered, and all missing PO files are created and checked into
98 >>> VCS. An unpriviledged wiki user can not add a new language to
99 >>> `po_slave_languages`, though. One could think of adding the needed
100 >>> interface to translate a page into a yet-unsupported slave
101 >>> language, and this would automagically add this new language to
102 >>> `po_slave_languages`. It would probably be useful in some
103 >>> usecases, but I'm not comfortable with letting unpriviledged wiki
104 >>> users change the wiki configuration as a side effect of their
105 >>> actions; if this were to be implemented, special care would be
106 >>> needed. [[--intrigeri]]
107 >>>
108 >>>> Actually I meant into any of the currently supported languages.
109 >>>> I guess that if the template modification is made, it will list those
110 >>>> languages on the page, and if a translation to a language is missing,
111 >>>> the link will allow creating it?
112 >>>>
113 >>>>> Any translation page always exist for every supported slave
114 >>>>> language, even if no string at all have been translated yet.
115 >>>>> This implies the po plugin is especially friendly to people who
116 >>>>> prefer reading in their native language if available, but don't
117 >>>>> mind reading in English else.
118 >>>>>
119 >>>>> While I'm at it, there is a remaining issue that needs to be
120 >>>>> sorted out: how painful it could be for non-English speakers
121 >>>>> (assuming the master language is English) to be perfectly able
122 >>>>> to navigate between translation pages supposed to be written in
123 >>>>> their own language, when their translation level is most
124 >>>>> often low.
125 >>>>>
126 >>>>> (It is currently easy to display this status on the translation
127 >>>>> page itself, but then it's too late, and how frustrating to load
128 >>>>> a page just to realize it's actually not translated enough for
129 >>>>> you. The "other languages" loop also allows displaying this
130 >>>>> information, but it is generally not the primary
131 >>>>> navigation tool.)
132 >>>>>
133 >>>>> IMHO, this is actually a social problem (i.e. it's no use adding
134 >>>>> a language to the supported slave ones if you don't have the
135 >>>>> manpower to actually do the translations), that can't be fully
136 >>>>> solved by technical solutions, but I can think of some hacks
137 >>>>> that would limit the negative impact: a given translation's
138 >>>>> status (currently = percent translated) could be displayed next
139 >>>>> to the link that leads to it; a color code could as well be used
140 >>>>> ("just" a matter of adding a CSS id or class to the links,
141 >>>>> depending on this variable). As there is already work to be done
142 >>>>> to have the links text generation more customizable through
143 >>>>> plugins, I could do both at the same time if we consider this
144 >>>>> matter to be important enough. --[[intrigeri]]
145 >>>>>
146 >>>>>> The translation status in links is now implemented in my
147 >>>>>> `po`branch. It requires my `meta` branch changes to
148 >>>>>> work, though. I consider the latter to be mature enough to
149 >>>>>> be merged. --[[intrigeri]]
150
151 >> FWIW, I'm tracking your po branch in ikiwiki master git in the po
152 >> branch. One thing I'd like to try in there is setting up a translated
153 >> basewiki, which seems like it should be pretty easy to do, and would be
154 >> a great demo! --[[Joey]]
155 >>
156 >>> I have a complete translation of basewiki into danish, and am working with
157 >>> others on preparing one in german.  For a complete translated user
158 >>> experience, however, you will also need templates translated (there are a few
159 >>> translatable strings there too).  My not-yet-merged po4a Markdown improvements
160 >>> (see [bug#530574](http://bugs.debian.org/530574)) correctly handles multiple
161 >>> files in a single PO which might be relevant for template translation handling.
162 >>> --[[JonasSmedegaard]]
163 >>
164 >>> I've merged your changes into my own branch, and made great
165 >>> progress on the various todo items. Please note my repository
166 >>> location has changed a few days ago, my user page was updated
167 >>> accordingly, but I forgot to update this page at the same time.
168 >>> Hoping it's not too complicated to relocated an existing remote...
169 >>> (never done that, I'm a Git beginner as well as a Perl
170 >>> newbie) --[[intrigeri]]
171 >>>>
172 >>>> Just a matter of editing .git/config, thanks for the heads up.
173 >>>>>
174 >>>>> Joey, please have a look at my branch, your help would be really
175 >>>>> welcome for the security research, as I'm almost done with what
176 >>>>> I am able to do myself in this area. --[[intrigeri]]
177 >>>>>>
178 >>>>>> I came up with a patch for the WrapI18N issue --[[Joey]]
179
180 I've set this plugin development aside for a while. I will be back and
181 finish it at some point in the first quarter of 2009. --[[intrigeri]]
182
183 > Abstract: Joey, please have a look at my po and meta branches.
184
185 > Detailed progress report:
186
187 > * it seems the po branch in your repository has not been tracking my
188 >   own po branch for two months. any config issue?
189 > * all the plugin's todo items have been completed, robustness tests
190 >   done
191 > * I've finished the detailed security audit, and the fix for po4a
192 >   bugs has entered upstream CVS last week
193 > * I've merged your new `checkcontent` hook with the `cansave` hook
194 >   I previously introduced in my own branch; blogspam plugin updated
195 >   accordingly
196 > * the rename hook changes we discussed elsewhere are also part of my
197 >   branch
198 > * I've introduced two new hooks (`canremove` and `canrename`), not
199 >   a big deal; IMHO, they extend quite logically the plugin interface
200 > * as highlighted on [[bugs/pagetitle_function_does_not_respect_meta_titles]],
201 >   my `meta` branch contains a new feature that is really useful in a
202 >   translatable wiki
203
204 > As a conclusion, I'm feeling that my branches are ready to be
205 > merged; only thing missing, I guess, are a bit of discussion and
206 > subsequent adjustments.
207
208 > --[[intrigeri]]
209
210 > I've looked it over and updated my branch with some (untested)
211 > changes.
212
213 >> I've merged your changes into my branch. Only one was buggy.
214
215 > Sorry, I'd forgotten about your cansave hook.. sorry for the duplicate
216 > work there.
217
218 > Reviewing the changes, mostly outside of `po.pm`, I have
219 > the following issues.
220 >  
221 > * renamepage to renamelink change would break the ikiwiki
222 >   3.x API, which I've promised not to do, so needs to be avoided
223 >   somehow. (Sorry, I guess I dropped the ball on not getting this
224 >   API change in before cutting 3.0..)
225 >> 
226 >> Fixed, see [[todo/need_global_renamepage_hook]].
227 >>
228 > * I don't understand the parentlinks code change and need to figure it
229 >   out. Can you explain what is going on there?
230 >> 
231 >> I'm calling `bestlink` there so that po's injected `bestlink` is
232 >> run. This way, the parent links of a page link to the parent page
233 >> version in the proper language, depending on the
234 >> `po_link_to=current` and `po_link_to=negotiated` settings.
235 >> Moreover, when using my meta branch enhancements plus meta title to
236 >> make pages titles translatable, this small patch is needed to get
237 >> the translated titles into parentlinks.
238 >> 
239 > * canrename's mix of positional and named parameters is way too
240 >   ugly to get into an ikiwiki API. Use named parameters
241 >   entirely. Also probably should just use named parameters
242 >   for canremove.
243 > * `skeleton.pm.example`'s canrename needs fixing to use either
244 >   the current or my suggested parameters.
245 >> 
246 >> Done.
247 >> 
248 > * I don't like the exporting of `%backlinks` and `$backlinks_calculated`
249 >   (the latter is exported but not used).
250 >> 
251 >> The commit message for 85f865b5d98e0122934d11e3f3eb6703e4f4c620
252 >> contains the rationale for this change. I guess I don't understand
253 >> the subtleties of `our` use, and perldoc does not help me a lot.
254 >> IIRC, I actually did not use `our` to "export" these variables, but
255 >> rather to have them shared between `Render.pm` uses.
256 >>
257 >>> My wording was unclear, I meant exposing. --[[Joey]]
258 >>>  
259 >>>> I guess I still don't know Perl's `our` enough to understand clearly.
260 >>>> No matter whether these variables are declared with `my` or `our`,
261 >>>> any plugin can `use IkiWiki::Render` and then access
262 >>>> `$IkiWiki::backlinks`, as already does e.g. the pagestat plugin.
263 >>>> So I guess your problem is not with letting plugins use these
264 >>>> variables, but with them being visible for every piece of
265 >>>> (possibly external) code called from `Render.pm`. Am I right?
266 >>>> If I understand clearly, using a brace block to lexically enclose
267 >>>> these two `our` declarations, alongside with the `calculate_backlinks`
268 >>>> and `backlinks` subs definitions, would be a proper solution, wouldn't
269 >>>> it? --[[intrigeri]]
270 >>>>
271 >>>>> No, %backlinks and the backlinks() function are not the same thing.
272 >>>>> The variable is lexically scoped; only accessible from inside
273 >>>>> `Render.pm` --[[Joey]] 
274 >>>> 
275 > * What is this `IkiWiki::nicepagetitle` and why are you
276 >   injecting it into that namespace when only your module uses it?
277 >   Actually, I can't even find a caller of it in your module.
278 >> 
279 >> I guess you should have a look to my `meta` branch and to
280 >> [[bugs/pagetitle_function_does_not_respect_meta_titles]] in order
281 >> to understand this :)
282 >>
283 >>> It would probably be good if I could merge this branch without 
284 >>> having to worry about also immediatly merging that one. --[[Joey]] 
285 >>> 
286 >>>> I removed all dependencies on my `meta` branch from the `po` one.
287 >>>> This implied removing the `po_translation_status_in_links` and
288 >>>> `po_strictly_refresh_backlinks` features, and every link text is now
289 >>>> displayed in the master language. I believe the removed features really
290 >>>> enhance user experience of a translatable wiki, that's why I was
291 >>>> initially supposing the `meta` branch would be merged first.
292 >>>> IMHO, we'll need to come back to this quite soon after `po` is merged.
293 >>>> --[[intrigeri]]
294 >>>>
295 >>>> Maybe you should keep those features in a meta-po branch?
296 >>>> I did a cursory review of your meta last night, have some issues with it, 
297 >>>> but this page isn't the place for a detailed review. --[[Joey]] 
298 >>>>
299 >>>>> Done. --[[intrigeri]]
300 >>> 
301 > * I'm very fearful of the `add_depends` in `postscan`. 
302 >   Does this make every page depend on every page that links
303 >   to it? Won't this absurdly bloat the dependency pagespecs
304 >   and slow everything down? And since nicepagetitle is given
305 >   as the reason for doing it, and nicepagetitle isn't used,
306 >   why do it?
307 >> 
308 >> As explained in the 85f865b5d98e0122934d11e3f3eb6703e4f4c620 log:
309 >> this feature hits performance a bit. Its cost was quite small in my
310 >> real-world use-cases (a few percents bigger refresh time), but
311 >> could be bigger in worst cases. When using the po plugin with my
312 >> meta branch changes (i.e. the `nicepagetitle` thing), and having
313 >> enabled the option to display translation status in links, this
314 >> maintains the translation status up-to-date in backlinks. Same when
315 >> using meta title to make the pages titles translatable. It does
316 >> help having a nice and consistent translated wiki, but as it can
317 >> also involve problems, I just turned it into an option.
318 >> 
319 >>> This has been completely removed for now due to the removal of
320 >>> the dependency on my `meta` branch. --[[intrigeri]]
321 >> 
322 > * The po4a Suggests should be versioned to the first version
323 >   that can be used safely, and that version documented in 
324 >   `plugins/po.mdwn`.
325 >>
326 >> Done.
327 >> 
328 >> --[[intrigeri]]
329
330 > --[[Joey]] 
331
332 I reverted the `%backlinks` and `$backlinks_calculated` exposing.
333 The issue they were solving probably will arise again when I'll work
334 on my meta branch again (i.e. when the simplified po one is merged),
335 but the po thing is supposed to work without these ugly `our`.
336 Seems like it was the last unaddressed item from Joey's review, so I'm
337 daring a timid "please pull"... or rather, please review again :)
338 --[[intrigeri]]
339
340 > Ok, I've reviewed and merged into my own po branch. It's looking very
341 > mergeable.
342
343 > * Is it worth trying to fix compatability with `indexpages`?
344 >> 
345 >> Supporting `usedirs` being enabled or disabled was already quite
346 >> hard IIRC, so supporting all four combinations of `usedirs` and
347 >> `indexpages` settings will probably be painful. I propose we forget
348 >> about it until someone reports he/she badly needs it, and then
349 >> we'll see what can be done.
350 >> 
351 > * Would it make sense to go ahead and modify `page.tmpl` to use
352 >   OTHERLANGUAGES and PERCENTTRANSLATED, instead of documenting how to modify it?
353 >> 
354 >> Done in my branch.
355 >> 
356 > * Would it be better to disable po support for pages that use unsupported
357 >   or poorly-supported markup languages?
358
359 >> I prefer keeping it enabled, as:
360 >> 
361 >> * most wiki markups "almost work"
362 >> * when someone needs one of these to be fully supported, it's not
363 >>   that hard to add dedicated support for it to po4a; if it were
364 >>   disabled, I fear the ones who could do this would maybe think
365 >>   it's blandly impossible and give up.
366 >> 
367  
368 > * What's the reasoning behind checking that the link plugin
369 >   is enabled? AFAICS, the same code in the scan hook should
370 >   also work when other link plugins like camelcase are used.
371 >> 
372 >> That's right, fixed.
373 >> 
374 > * In `pagetemplate` there is a comment that claims the code
375 >   relies on `genpage`, but I don't see how it does; it seems
376 >   to always add a discussion link?
377 >> 
378 >> It relies on IkiWiki::Render's `genpage` as this function sets the
379 >> `discussionlink` template param iff it considers a discussion link
380 >> should appear on the current page. That's why I'm testing
381 >> `$template->param('discussionlink')`.
382 >> 
383 >>> Maybe I was really wondering why it says it could lead to a broken
384 >>> link if the cgiurl is disabled. I think I see why now: Discussionlink
385 >>> will be set to a link to an existing disucssion page, even if cgi is
386 >>> disabled -- but there's no guarantee of a translated discussion page
387 >>> existing in that case. *However*, htmllink actually checks
388 >>> for this case, and will avoid generating a broken link so AFAICS, the
389 >>> comment is actually innacurate.. what will really happen in this case
390 >>> is discussionlink will be set to a non-link translation of
391 >>> "discussion". Also, I consider `$config{cgi}` and `%links` (etc)
392 >>> documented parts of the plugin interface, which won't change; po could
393 >>> rely on them to avoid this minor problem. --[[Joey]] 
394 >>>> 
395 >>>> Done in my branch. --[[intrigeri]]
396 >>>> 
397 >
398 > * Is there any real reason not to allow removing a translation?
399 >   I'm imagining a spammy translation, which an admin might not
400 >   be able to fix, but could remove.
401 >> 
402 >> On the other hand, allowing one to "remove" a translation would
403 >> probably lead to misunderstandings, as such a "removed" translation
404 >> page would appear back as soon as it is "removed" (with no strings
405 >> translated, though). I think an admin would be in a position to
406 >> delete the spammy `.po` file by hand using whatever VCS is in use.
407 >> Not that I'd really care, but I am slightly in favour of the way
408 >> it currently works.
409 >>
410 >>> That would definitly be confusing. It sounds to me like if we end up
411 >>> needing to allow web-based deletion of spammy translations, it will
412 >>> need improvements to the deletion UI to de-confuse that. It's fine to
413 >>> put that off until needed --[[Joey]] 
414 >> 
415 > * Re the meta title escaping issue worked around by `change`. 
416 >   I suppose this does not only affect meta, but other things
417 >   at scan time too. Also, handling it only on rebuild feels
418 >   suspicious -- a refresh could involve changes to multiple
419 >   pages and trigger the same problem, I think. Also, exposing
420 >   this rebuild to the user seems really ugly, not confidence inducing.
421 >   
422 >   So I wonder if there's a better way. Such as making po, at scan time,
423 >   re-run the scan hooks, passing them modified content (either converted
424 >   from po to mdwn or with the escaped stuff cheaply de-escaped). (Of
425 >   course the scan hook would need to avoid calling itself!)
426
427 >   (This doesn't need to block the merge, but I hope it can be addressed
428 >   eventually..)
429 >  
430 > --[[Joey]] 
431 >> 
432 >> I'll think about it soon.
433 >> 
434 >> --[[intrigeri]]
435 >>
436 >>> Did you get a chance to? --[[Joey]] 
437
438  * As discussed at [[todo/l10n]] the templates needs to be translatable too.  They
439    should be treated properly by po4a using the markdown option - at least with my
440    later patches in [bug#530574](http://bugs.debian.org/530574)) applied.
441
442  * It seems to me that the po plugin (and possibly other parts of ikiwiki) wrongly
443    uses gettext.  As I understand it, gettext (as used currently in ikiwiki) always
444    lookup a single language, That might make sense for a single-language site, but
445    multilingual sites should emit all strings targeted at the web output in each own
446    language.
447
448    So generally the system language (used for e.g. compile warnings) should be separated
449    from both master language and slave languages.
450
451    Preferrably the gettext subroutine could be extended to pass locale as optional
452    secondary parameter overriding the default locale (for messages like "N/A" as
453    percentage in po plugin).  Alternatively (with above mentioned template support)
454    all such strings could be externalized as templates that can then be localized.