scummvm/tools/po2c
2010-06-24 22:00:45 +00:00

261 lines
5.6 KiB
Perl
Executable File

#!/usr/bin/perl
#
# po2c - Converts .po files to C code
#
# Copyright (C) 2004 Angel Ortega <angel@triptico.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# http://www.triptico.com
#
$VERSION = "1.0.2-scummvm";
if(scalar(@ARGV) == 0)
{
print "Usage: po2c {po file[s]}\n";
exit 1;
}
%msgs = ();
%msgids = ();
# stage 1: loading
# arguments are .po files
foreach my $f (@ARGV)
{
my ($lang);
my ($langDesc);
next unless(($lang) = ($f =~ /([^\/]+)\.po$/));
if(open F, $f)
{
my ($msgid, $val, %a);
while(<F>)
{
chomp;
# ignore blank lines or comments
next if /^$/ or /^#/;
if(/^msgid\s+\"(.*)\"\s*$/)
{
# store previous msgid
if(defined($msgid))
{
$a{$msgid} = $val;
$msgids{$msgid} ++;
}
# start of msgid
$val = $1;
}
elsif(/^msgstr\s+\"(.*)\"\s*$/)
{
# store previous msgid
$msgid = $val;
# start of msgstr
$val = $1;
}
elsif(/^\"(.*)\"\s*$/)
{
# add to current value
$val .= $1;
}
}
# store previous msgid
if(defined($msgid))
{
$a{$msgid} = $val;
$msgids{$msgid} ++;
}
close F;
# add to the global message pool
$msgs{$lang} = \%a;
}
}
# stage 2: convert the data
# stores all sorted msgids into @msgids
@msgids = sort(keys(%msgids));
# travels again, storing indexes into %msgids
for(my $n = 0;$n < scalar(@msgids);$n++)
{
$msgids{$msgids[$n]} = $n;
}
# stage 3: dump as C++ code
print "// generated by po2c $VERSION - Do not modify\n\n";
# dump first the msgid array
print "static const char * const _messageIds[] = {\n";
for(my $n = 0;$n < scalar(@msgids);$n++)
{
print "\t/* $n */ \"" . $msgids[$n] . "\",\n";
}
print "\tNULL\n};\n\n";
# dump the lang structure
print "struct PoMessageEntry {\n";
print "\tint msgid;\n";
print "\tconst char *msgstr;\n";
print "};\n\n";
# dump now each language
foreach my $l (keys(%msgs))
{
print "static const PoMessageEntry _translation_${l}\[\] = {\n";
# get the translation table for the language $l
my ($m) = $msgs{$l};
# while (my ($msgstr, $msgid) = each (%$m))
foreach my $msgid (sort(keys(%$m)))
{
my ($msgstr) = "";
# make it 7-bit safe
foreach $c (split(//, $m->{$msgid})) {
if (ord($c) > 0x7f) {
$msgstr .= sprintf("\\%o", ord($c));
} else {
$msgstr .= $c;
}
}
print "\t{ " . $msgids{$msgid} . ", \"" . $msgstr . "\" },\n"
if $msgstr;
}
print "\t{ -1, NULL }\n};\n\n";
}
# finally, dump the languages
print "struct PoLangEntry {\n";
print "\tconst char *lang;\n";
print "\tconst char *charset;\n";
print "\tconst PoMessageEntry *msgs;\n";
print "};\n\n";
print "const PoLangEntry _translations[] = {\n";
foreach my $l (keys(%msgs))
{
$header = $msgs{$l}->{""};
$header =~ /charset=([^\\]+)/;
$charset = $1;
print "\t{ \"" . $l . "\", \"" . $charset . "\", _translation_${l} },\n";
}
print "\t{ NULL, NULL, NULL }\n};\n\n";
print "// code\n";
print << 'EOF';
static const PoMessageEntry *_currentTranslation = NULL;
static int _currentTranslationMessageEntryCount = 0;
static const char *_currentTranslationCharset = NULL;
void po2c_setlang(const char *lang) {
_currentTranslation = NULL;
_currentTranslationMessageEntryCount = 0;
_currentTranslationCharset = NULL;
// if lang is NULL or "", deactivate it
if (lang == NULL || *lang == '\0')
return;
// searches for a valid language array
for (int i = 0; _currentTranslation == NULL && _translations[i].lang != NULL; ++i) {
if (strcmp(lang, _translations[i].lang) == 0) {
_currentTranslation = _translations[i].msgs;
_currentTranslationCharset = _translations[i].charset;
}
}
// try partial searches
for (int i = 0; _currentTranslation == NULL && _translations[i].lang != NULL; ++i) {
if (strncmp(lang, _translations[i].lang, 2) == 0) {
_currentTranslation = _translations[i].msgs;
_currentTranslationCharset = _translations[i].charset;
}
}
// if found, count entries
if (_currentTranslation != NULL) {
for (const PoMessageEntry *m = _currentTranslation; m->msgid != -1; ++m)
++_currentTranslationMessageEntryCount;
}
}
const char *po2c_gettext(const char *msgid) {
// if no language is set or msgid is empty, return msgid as is
if (_currentTranslation == NULL || *msgid == '\0')
return msgid;
// binary-search for the msgid
int leftIndex = 0;
int rightIndex = _currentTranslationMessageEntryCount - 1;
while (rightIndex >= leftIndex) {
const int midIndex = (leftIndex + rightIndex) / 2;
const PoMessageEntry * const m = &_currentTranslation[midIndex];
const int compareResult = strcmp(msgid, _messageIds[m->msgid]);
if (compareResult == 0)
return m->msgstr;
else if (compareResult < 0)
rightIndex = midIndex - 1;
else
leftIndex = midIndex + 1;
}
return msgid;
}
const char *po2c_getcharset(void) {
if (_currentTranslationCharset)
return _currentTranslationCharset;
else
return "ASCII";
}
int po2c_getnumlangs(void) {
return ARRAYSIZE(_translations) - 1;
}
const char *po2c_getlang(const int num) {
assert(num < ARRAYSIZE(_translations));
return _translations[num].lang;
}
EOF
exit 0;