The problem
osCommerce stores the static text (ie not the products description) in PHP files. The files are located in the includes/languages directory; the main file is <language>.php, page files are in subdirectory <language>/<page_name>.php.
Advantages include fast loading and the possible inclusion of logic (actually, only index.php does this).
But it also makes it more difficult for translators. Of course the translated text must respect the PHP syntax! In practice, you have to add a backslash \ before single quotes. You get lots of single quotes in French.
Another practical difficulty is that the language files are deep in the code structure. This offers one more way to non-technically oriented users to mess things up. And they would rather spend time selling stuff, not wading in PHP.
The idea
To solve both problems, we want to:
- Move the files to a safe place, and
- Change their format to something easier
...all this without developing an entire CMS.
The implementation
Moving stuff around
The first one is easy — the safe place is already available, this is where users upload their mail templates, a pages/ directory at the root of the shop. We just move the languages/ directory there. There's one thing to take care of: <language>.php includes a function to splice dates. We keep this function in <language>.php and move it up to includes/. We do have a small change to application_top:
require(DIR_WS_LANGUAGES . $language . '.php');
becomes:
require(DIR_WS_INCLUDES . $language . '.php');
Changing the format
I've used the .ini format with success. You can't do that much with it, but it's simple. Here is what we want:
define('BOX_HEADING_WHATS_NEW',
'What\'s New?');
becomes:
BOX_HEADING_WHATS_NEW = What's New?
Simple, eh?
But the parse_ini_file() will choke on lines with an equal sign (=). It reasonably expects a single one in the line. So we do our own parsing. Not too difficult, considering we only have to split the line at the first equal sign. Ah, let's also skip comments (lines starting with a #) and lines with no definition (what could we do with those?) Here's the parser:
function parse_translation
($file){ $lines =
file($file);
foreach ($lines as $line) { // Skip comments if ($line{0} ==
'#') continue;
// Skip lines with no definition (no = sign) if (!
$equal =
strpos($line,
'=')) continue;
define(trim(substr($line,
0,
$equal)),
trim(substr($line,
$equal +
1)));
}}
Add a line to application top to fecth all translations (general and page-specific):
// include the language translations
require(DIR_WS_INCLUDES . $language . '.php');
get_translation();
Converting the original language files
Finally, we just need to convert the PHP language files to our new format. Perl is perfectly suited to the task. Just run this small utility, eg convert_language_file.pl modules/*/*.php.
#!/usr/bin/perl -wuse Carp;
use Data::
Dumper;
croak
"Usage: $0 <file list>\n" unless @ARGV;
my $current =
'';
while (<>
) { # Traitement au changement de fichier if ($current ne $ARGV) { # Fermer le fichier précédent close OUT
if defined(OUT
);
$current =
$ARGV;
print "Processing " .
$current .
"\n";
# Ouvrir le fichier de sortie .ini ($output =
$current) =~
s/php/ini/;
open OUT,
">$output" or die "can't open $output for writing\n";
} ## On ne prend que les define() next unless /^ *define/;
chomp;
## Supprimer le PHP s/^ *define\
('//;
s/', *
'/ = /;
s/'\
);.*$//;
## Convertir les \' en ' s/\\
'/'/g;
print OUT
$_ .
"\n";
}
Et voilà !