Coding for translation

Last modified
Sunday, November 6, 2016 - 11:23


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 '' script. We use these scripts as workaround for various problems with the standard tools xgettext and

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/!

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:


  • Mark your strings for translation
  • Mark entire sentences or paragraphs for translation when possible (and strive for it)


  • 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.