2009-04-30

on coders and translators

after reading gabor's latest post, i thought to myself that his proposal can also be reversed...

that is, instead of asking translators for their help (which is fine), let's also propose ourselves pro-actively as translator. i mean, we're a large international community, and we have so much to share rather than just code!

indeed, we are also a human being speaking a given language, before actually being a perl coder...

therefore, i propose myself for some french translations. if you have a project that is in need of french translation, just drop me a line. i don't promise i'll deliver a 100% perfect translation, not even do i promise to deliver it in a given timeframe. but i promise to have a look at it, and try to translate a few strings here and there. and as time goes by, i hope to go through...

so, let's create a pool of translators - who would like to follow?

notes:
  • i don't know if the need for translators is really that big, but who knows? maybe it would be the occasion to think about it for your modules, and help i18n to spread in cpan, leading to more perl usage in the end...
  • even if you're french, you can volunteer to spread the load...
  • we could even set up some kind of translation market where we could list applications needing translation, and translators ready to help. from what i've heard, it should be dead easy to set this up with a small catalyst app... (hint, hint)

2009-04-29

spell check in padre now supports multiple languages... kinda

reshaping the spellcheck plugin for padre to provide a decent interface was my first goal when i took over its maintenance. fulfilling this goal deserved to bounce plugin version to 1.0.0, but that's not the end of my plans...

therefore, i just released version 1.1.0, allowing to change the dictionary language in the preferences dialog of the plugin. you need to have the wanted dictionary installed (note that you can pick only installed dictionaries), otherwise aspell will not work correctly... of course it won't crash anything, you'll just end up with no suggestion and this sort of things.

so, why am i saying that it kinda supports multiple languages? because there is a bug in the styled text control (aka scintilla aka wx::stc) version (1.70) shipped with wxwidgets 2.8.x, which seems to confuse bytes and chars in unicode texts.

this is easily demonstrated by the following snippet:

#!/usr/bin/perl
use strict;
use warnings;
use Wx ':everything';
use Wx::STC;

my $f = Wx::Frame->new(undef,-1,"test");
my $s = Wx::BoxSizer->new(wxVERTICAL);
my $t1 = Wx::StyledTextCtrl->new($f);
my $t2 = Wx::StyledTextCtrl->new($f);
$s->Add($t1);
$s->Add($t2);
$f->SetSizer($s);

$t1->SetText("cote");
$t2->SetText("côte");
$t1->SetSelection(0,3);
$t2->SetSelection(0,3);

$f->Show;
sub Wx::App::OnInit {1}
Wx::App->new->MainLoop;


this creates a window with 2 stc, one containing ascii text, the other containing unicode text. then we try to select the first 3 characters in both stc. look how the first stc correctly selects 3 chars, while the second selects only 2 of them:


i hope this is fixed in later versions of scintilla - but even if that's the case, it needs to be integrated into wxwidgets... and current development version of wxwidgets (2.9.x) only has version 1.75 included, which is already 18 monthes old... (if anyone is interested to update stc in wxwidgets, i'm sure they will welcome your help)

so, there it is - the plugin supports non-english dictionaries... but cannot spell check non-ascii texts! that's pretty useless, isn't it? :-(

side note: this plugin version is now locale-aware, and inaugurates the era of translated plugins...

2009-04-28

plugins and translation

localizing an application is important if one wants to take over the world with it. this is why we try to localize padre (the perl ide) and translate it in as many languages as possible. (if padre isn't translated in your language, your help would be more than welcome!)

we are using the standard wx localization framework, which is similar to & compatible with gettext. then, using standard xgettext, msgmerge and msgfmt commands, the translators can do their magic and voilà! padre is translated.

this is working quite well.

but now, enter plugins. indeed, to keep padre as lean as possible, non-core features are deported in plugins. and even if padre is still a young project, there are already quite a lot of plugins for padre.

but how to translate plugins?

first (and stupid) solution would be to extract the strings to be translated and add them to padre's messages file. definitely not a good idea, since padre and the plugins do not share the same release planning, and we would end up with strings mismatch between what padre ships and what the plugin uses.

therefore, the plugin must provide its own translation. but that's a bit difficult, since they are not an application of their own: they are running inside padre, an application that already has its translated messages thank you very much.

so we need a way to have more than one strings catalog open at the same time. i had some troubles finding the correct method within wx documentation, but finally came up with:
$locale->AddCatalog($catalog);


$catalog being the catalog containing the new translated strings. and in order not to clash with main catalog (named after the locale, eg "fr-fr" for my current locale), the plugin catalog should be named $plugin-$locale.

but of course, it doesn't work as is. indeed, wx doesn't know where to find this new catalog. so we need to add a new search path to find the locales:
$locale->AddCatalogLookupPathPrefix($directory);


of course, we want padre plugins to be as easy to write as possible, so we don't want plugin authors to have to do this kind of non-sexy things.

therefore, plugin authors just need to define a plugin_locale_directory() method that will tell padre where to look for translated string catalogs. and since the plugins inherit from the base class padre::plugin, they have such a default method which points to the share directory as defined by file::sharedir. therefore, plugin authors don't even need to redefine this method if they're using the install_share instruction of module::install. (i don't like module::install, but that's not the point here)

ok, so plugin authors have one method to add. now they need to extract the strings and translate them (or ask other people to translate them). that's using standard gettext tools, so nothing really gets in the way.

and that's all. because padre handles the loading of new catalogs automatically, as long as they're named $plugin-$locale. that is, if the german translation of Padre::Plugin::SpellCheck is called SpellCheck-de.mo, then padre will find it and make sure that wx translates your plugin.

this is a good thing, because wx is a bitch to program with. that is, you can add a catalog or a catalog path, but you cannot remove them. and you don't want to load all your catalogs at once, to reduce memory load. and padre also takes care of locale switching, unloading previous locales and loading new ones. (unloading as in destroy locale object and create a new one since wx does not know how to remove a loaded locale).

therefore, even for localization, padre plugins are easy to write. why don't you join us and write your own, to have padre behave just how you expect? (using a real programming language that you know and love)

2009-04-24

cpan activity

the 2009.1 version of the mandriva linux distribution will be released rsn.

once this happens, i'll be able to update the rpm packages for which i'm responsible. indeed, to polish the release, mandriva was in version freeze for the last 45 days. that is, we contributors were not allowed to upload a new upstream version of a package - unless we can prove it's a bugfix version only.

but i digress, let's get back to this blog entry. i'm responsible for 86 packages within mandriva, most of them being perl cpan modules. and what's interesting, is that during this month & a half of forced inactivity, 19 of them have been updated. in fact, some of them have seen more than one cpan release.

19 packages updated out of 86 (20 if you count a new parrot version) during 45 days. around 25%. that's not bad. and it definitely proves that the perl community is still alive!

2009-04-23

we are iron man

beginning 2009, i started this blog to speak about perl, how nice a language it is, and how alive it remains despite what the nay-sayers write everywhere.

so when i read matt's rant, this definitely rang a bell. thus you won't be surprised that i volunteered to the iron man contest proposed by matt.

i don't know whether i'll manage to keep up with the contest. but at least i'll try - and that's the point.

WE ARE ALIVE. WE ARE LEGION. WE ARE IRON MAN.

2009-04-22

padre does spell check

padre, the perl ide, can now check a text for spelling mistakes. this is done with the padre::plugin::spellcheck plugin. new version 1.0.0 is currently propagating on cpan, and should be available soon.

so, how to use it? the first step (beside installing padre and the plugin) is to enable it. open padre, go to plugins menu, open the plugin manager, then select the spell checking plugin, and click on enable:


(you will notice the nice icon, courtesy of mark james - open-source definitely needs artists besides coders)

of course, this should be done only once. that is, if you already tried this plugin, you don't need to re-enable it. (but if you already tried the plugin, then i can imagine that you're quite familiar with padre, and that you don't need this explanation)

so, the plugin is enabled, and you can now close the plugin manager. open the file that you want to spell check, and just press f7 (which seems to be the standard shortcuts among text processors to launch spell checking). this will check your text, and if there are some mistakes, it will open the following window:



the offending text will be selected. the buttons do what one can expect.

some things to note:
  • only english is supported right now. this will change later on.
  • the add to dictionary is not yet implemented.
  • this plugin is using text::aspell (the perl bindings for aspell) underneath (yes, this means you need to have aspell installed on your machine). in the future, i plan to allow one to change the low-level options of aspell...
  • check spelling a program is not a good idea. however,since aspell supports some filtering modes, i'll investigate them.
and don't forget that you're welcome to join the padre development team! we could use more contributors...

2009-04-20

polyglot: conclusion

reminder: this article is part of a serie.

well that's it... the best things do have an end, and this polyglot exercise is no exception. i hope you learnt quite a few things during this trip in troubled programming water - and most of all, i hope you enjoyed it. i did, anyway! :-)

our polyglot program now supports the following languages:
  • perl
  • c and c++
  • pascal
  • bash (and also ksh and ksh-like shells)
  • fortran
  • befunge
  • brainfuck and ook
  • html/javascript


that's not bad. here's the compacted program:


(*foo /*bar#[^" Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. "
*1337#) 2>/dev/null;i=0; a=1; b=1;echo $a;while test $i -lt 9;do c=$((a+b));a=$b;b=$c;echo $a;i=$((i+1));done;exit; Ook. Ook.
*0) if 0; sub C () {} # Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook! Ook? Ook! Ook! Ook? Ook! Ook. Ook. */ );
#include <stdio.h> /* Ook. Ook. Ook. Ook. Ook. Ook. */
#include <stdlib.h> /* Ook. Ook. Ook. Ook. Ook. Ook. */
#define C /* Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? */
#define $ /* Ook. Ook. Ook. Ook? Ook. Ook. Ook? Ook.
C ; " Ook? Ook. Ook! Ook? Ook! Ook! Ook. Ook? Ook! Ook? Ook. Ook? Ook. Ook? Ook. Ook. Ook. Ook? Ook. Ook. Ook. Ook? Ook. Ook. */
C ; main () { /*"; { # Ook? Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook! Ook! Ook? Ook! Ook. Ook? */ int $ i, $ n1, $ n2, $ n3;
C ; $ i = 0; $ n1 = 1; $ n2 = 1; printf( "%d\n", $ n1 ); while ( $ i < 9 ) {
C ; $ n3 = $ n1 + $ n2; $ n1 = $ n2; $ n2 = $ n3; printf( "%d\n", $ n1 ); $ i++; }}
#define foo /* Ook! Ook? Ook? Ook. Ook. Ook. Ook. Ook?
C ; __END__ Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook! Ook! Ook? Ook! Ook. Ook? Ook. Ook? Ook. Ook?
*) program foo; var i, n1, n2, n3 : integer; begin i := 0; n1 := 1; n2 := 1; writeln(n1); while i < 9 do begin (* Ook! Ook?
*) n3 := n1 + n2; n1 := n2; n2 := n3; writeln(n1); i := i + 1; end; end. (* Ook? Ook. Ook? Ook. Ook? Ook. Ook. Ook. Ook. Ook?
integer i, n1, n2, n3 ; n1 = 1 ; n2 = 1 ; print '(I0)', n1 Ook. Ook? Ook. Ook? Ook! Ook! Ook? Ook! Ook? Ook.
do 10 i = 1, 9 Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
n3 = n1 + n2 ; n1 = n2 ; n2 = n3 ; print '(I0)', n1 Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
10 continue ; end ]++++++++++>[-]++++++++++>+>+<<[->[>>+>+>+<<<<-]>[<+>>>>+<<
* <-]>>>[<<<+>>>-]<>+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>>+<-]<<-<-]>>>>[<<<<+>>>>-]<<<<>[-]<[+++++++++++++++++++++++
* +++++++++++++++++++++++++.------------------------------------------------[<---------->-]]<++++++++++++++++++++++++++++++++++++++
* ++++++++++.------------------------------------------------<<<<.>>>>[-]<<<][ Ook? Ook. Ook! Ook? Ook. Ook? Ook. Ook? Ook. Ook?
* Ook. Ook. Ook? Ook. Ook? Ook. Ook! Ook? Ook. Ook? Ook. Ook. Ook. Ook? Ook! Ook? Ook! Ook! Ook? Ook! Ook? Ook. Ook? Ook. Ook! Ook!
* Ook? Ook! Ook. Ook? Ook! Ook? Ook? Ook. Ook. Ook. Ook. Ook? Ook! Ook! Ook? Ook! Ook. Ook? Ook! Ook? Ook? Ook. Ook? Ook. Ook. Ook.
* Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook.
* Ook? Ook. Ook! Ook! Ook? Ook! Ook? Ook. Ook? Ook. Ook! Ook! Ook? Ook. Ook! Ook! Ook? Ook! Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook?
* Ook! Ook? Ook? Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook. Ook. Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook? Ook! Ook! Ook? Ook! Ook? Ook.
* Ook? Ook. Ook? Ook. Ook? Ook. Ook. Ook? Ook! Ook? Ook! Ook! Ook? Ook! Ook? Ook. Ook! Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
* Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
* Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
* Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
* Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
* Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
* Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
* Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
* Ook! Ook! Ook! Ook! Ook! Ook? Ook? Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
* Ook! Ook! Ook. Ook? Ook! Ook! Ook? Ook! Ook? Ook! Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
* Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
* Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
* Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
* Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
* Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
* Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
* <html><script language="javascript">function foo_it(){var foo;var i=0;var n1=1;var n2=1;document.writeln(n1); foo // Ook! Ook!
*= 2;while(i<9){n3=n1+n2;n1=n2;n2=n3;document.write("<br>",n1);i++}}</script><body onload="foo_it()"></body></html> // Ook! Ook!
*n 1:86*+,a,86*+,a,11884pv Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! > " Ook! Ook! Ook! Ook! Ook! Ook! "
*$ +,>a,94g\84g1-:84p!#@_>:94p+:a`#v_:'0 ; Ook! Ook! Ook? Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook! Ook. ; ::
* Ook. Ook? ^ ,+*68-*+55/+55::,+*+338/+55:< Ook. Ook? Ook. Ook? Ook. Ook? Ook! Ook? Ook! Ook! Ook? Ook! Ook? Ook. */
#define fubar Ook? Ook. Ook? Ook. Ook? Ook! ]*)



that's not to say that we cannot add other languages. out of my mind, i guess one could fit cobol, postscript, and maybe ruby... (note: i don't think python can be added since pascal renders it too difficult. removing pascal would allow it - i have some working polyglot with python).

but now it's your turn to work, and continue this serie! clone the git repository, send me your patches, and i'll post them in this blog...

enjoy! :-)

2009-04-08

polyglot: html / javascript for the win!

reminder: this article is part of a serie.

still ready for more polyglot action? then let's continue. today's language is a bit special, since it's targetting the browser. we're indeed going to craft a mix of html and javascript, the goal being that firefox renders the file as the 10 first fibonacci numbers. it's not that difficult, using the onload argument of the body tag. here's the html / javascript snippet:


<html><script language="javascript">
function foo_it () {
var i = 0
var n1 = 1
var n2 = 1
document.writeln(n1)
while (i < 9) {
n3=n1+n2
n1=n2
n2=n3
document.write("<br>",n1)
i++
}
}
</script><body onload="foo_it()"></body></html>


the nice thing is that if the html is well written, everything outside the <html> tags will be ignored. so, once again, let's put this at the end of our file. but we have a problem: we cannot have * fortran comments in the middle of our javascript code! and we cannot use the /* */ comments, since we're already inside a c comment... a first solution would be to put everything on a single line - but we can do better. since * is the multiply operator in javascript, let's create a temp variable foo that will be multiplied in place with *=. and we can then insert our code (compacted on 4 lines):


[...]
* <html><script language="javascript">function foo_it () { var foo; foo
*= 2; var i=0; var n1=1; var n2=1; document.writeln(n1); foo
*= 3; while ( i<9 ) { n3=n1+n2; n1=n2; n2=n3; document.write("<br>",n1); foo
*= 4; i++ } } </script><body onload="foo_it()"></body></html>
[...]


our tests still pass, and opening this file in firefox (after renaming it to html, in order for firefox to render it as html, not as plain text) yields the famous sequence. unfortunately, this test cannot be scripted, because of javascript...

the latest version of the program can be seen here, and now supports 9 languages. on a parallel note, is it me or are those blog entries getting smaller and smaller? :-)

anyway, that was today's entry...