Coding for translation
Introduction
LedgerSMB has support to be translated. This generally has very little impact on code, but there are a few things to know to help translators get their job done.
LedgerSMB uses the Maketext Perl module for translation of strings. The strings are being searched for by a few helpers in the directory utils/devel/ -- the main driver is the 'rebuild_pot.sh' script. We use these scripts as workaround for various problems with the standard tools xgettext and xgettext.pl.
These files are being scanned for translations:
- *.pl, *.pm: in bin/ and LedgerSMB/
- *.html, *.tex, *.csv: in UI/ and templates/
- sql/Pg-database.sql
If you introduce translations in files with other extensions, please add them to the list in utils/devel/rebuild_pot.sh!
Coding impact
The little impact on coding there is:
- String litterals should be submitted for translation using the $locale->text() function
- The first string of the text() function must be a string litteral
- The string litteral argument of text() may not use variable interpolation
The last point is especially important. Instead of using:
print $locale->text("Current version: $version") . "\n";
Use:
print $locale->text("Current version: [_1]", $version) . "\n";
- If you want to translate a string in a variable that you know has been marked for translation elsewhere, use:
$locale->maketext($msg);
DOs
- Mark your strings for translation
- Mark entire sentences or paragraphs for translation when possible (and strive for it)
DON'Ts
- Don't use string composition and interpolation; this makes correct translation impossible
- Older code uses string composition and marks the "known" compositions for translation in comments; Don't do that in new code
Locale::Maketext vs Locale::TextDomain
The project uses Locale::Maketext for its translations. It's been argued that people should stop using Locale::Maketext in favor of using Locale::TextDomain. While it's true that Locale::TextDomain is clearly a superior tool for translating software in the sense that it supports many language constructs not supported by Locale::Maketext, LedgerSMB can't switch frameworks for one very important reason:
Locale::Maketext allows an application to load and use multiple languages at the same time (something Locale::TextDomain doesn't) through an object-oriented interface.
LedgerSMB needs this functionality to serve multiple users with different language preferences from the same server process. More importantly, a single user may require multiple languages to be used when e.g. a user with language preference "Italian" requests to print a balance sheet in French.