wmc: Add support for generating message translations based on po files.

This commit is contained in:
Alexandre Julliard 2011-01-24 20:12:54 +01:00
parent 196ffdf671
commit 72921af40b
6 changed files with 158 additions and 2 deletions

View File

@ -435,6 +435,143 @@ void write_pot_file( const char *outname )
po_file_free( po ); po_file_free( po );
} }
static lan_blk_t *new_top, *new_tail;
static lanmsg_t *translate_string( po_file_t po, lanmsg_t *str, int lang, int *found )
{
po_message_t msg;
po_message_iterator_t iterator;
lanmsg_t *new;
const char *transl;
int res;
char *buffer, *msgid, *context;
if (str->len <= 1 || !(buffer = convert_msgid_ascii( str, 0 ))) return str;
msgid = buffer;
context = get_message_context( &msgid );
msg = find_message( po, msgid, context, &iterator );
po_message_iterator_free( iterator );
if (msg && !po_message_is_fuzzy( msg ))
{
transl = po_message_msgstr( msg );
if (!transl[0]) transl = msgid; /* ignore empty strings */
else (*found)++;
}
else transl = msgid;
new = xmalloc( sizeof(*new) );
new->lan = lang;
new->cp = 0; /* FIXME */
new->file = str->file;
new->line = str->line;
new->len = wine_utf8_mbstowcs( 0, transl, strlen(transl) + 1, NULL, 0 );
new->msg = xmalloc( new->len * sizeof(WCHAR) );
res = wine_utf8_mbstowcs( MB_ERR_INVALID_CHARS, transl, strlen(transl) + 1, new->msg, new->len );
if (res == -2)
error( "Invalid utf-8 character in string '%s'\n", transl );
free( buffer );
return new;
}
static void translate_block( po_file_t po, block_t *blk, block_t *new, int lang, int *found )
{
int i;
new->idlo = blk->idlo;
new->idhi = blk->idhi;
new->size = 0;
new->msgs = xmalloc( blk->nmsg * sizeof(*new->msgs) );
new->nmsg = blk->nmsg;
for (i = 0; i < blk->nmsg; i++)
{
new->msgs[i] = translate_string( po, blk->msgs[i], lang, found );
new->size += ((2 * new->msgs[i]->len + 3) & ~3) + 4;
}
}
static void translate_messages( po_file_t po, int lang )
{
int i, found;
lan_blk_t *lbp, *new;
for (lbp = lanblockhead; lbp; lbp = lbp->next)
{
if (!is_english( lbp->lan )) continue;
found = 0;
new = xmalloc( sizeof(*new) );
/* English "translations" take precedence over the original contents */
new->version = is_english( lang ) ? 1 : -1;
new->lan = lang;
new->blks = xmalloc( lbp->nblk * sizeof(*new->blks) );
new->nblk = lbp->nblk;
for (i = 0; i < lbp->nblk; i++)
translate_block( po, &lbp->blks[i], &new->blks[i], lang, &found );
if (found)
{
if (new_tail) new_tail->next = new;
else new_top = new;
new->prev = new_tail;
new_tail = new;
}
else
{
free( new->blks );
free( new );
}
}
}
void add_translations( const char *po_dir )
{
lan_blk_t *lbp;
po_file_t po;
char buffer[256];
char *p, *tok, *name;
unsigned int i;
FILE *f;
/* first check if we have English resources to translate */
for (lbp = lanblockhead; lbp; lbp = lbp->next) if (is_english( lbp->lan )) break;
if (!lbp) return;
new_top = new_tail = NULL;
name = strmake( "%s/LINGUAS", po_dir );
if (!(f = fopen( name, "r" ))) return;
free( name );
while (fgets( buffer, sizeof(buffer), f ))
{
if ((p = strchr( buffer, '#' ))) *p = 0;
for (tok = strtok( buffer, " \t\r\n" ); tok; tok = strtok( NULL, " \t\r\n" ))
{
for (i = 0; i < sizeof(languages)/sizeof(languages[0]); i++)
if (!strcmp( tok, languages[i].name )) break;
if (i == sizeof(languages)/sizeof(languages[0]))
error( "unknown language '%s'\n", tok );
name = strmake( "%s/%s.po", po_dir, tok );
if (!(po = po_file_read( name, &po_xerror_handler )))
error( "cannot load po file for language '%s'\n", tok );
translate_messages( po, MAKELANGID(languages[i].id, languages[i].sub) );
po_file_free( po );
free( name );
}
}
fclose( f );
/* prepend the translated messages to the global list */
if (new_tail)
{
new_tail->next = lanblockhead;
lanblockhead->prev = new_tail;
lanblockhead = new_top;
}
}
#else /* HAVE_LIBGETTEXTPO */ #else /* HAVE_LIBGETTEXTPO */
void write_pot_file( const char *outname ) void write_pot_file( const char *outname )
@ -442,4 +579,8 @@ void write_pot_file( const char *outname )
error( "PO files not supported in this wmc build\n" ); error( "PO files not supported in this wmc build\n" );
} }
void add_translations( const char *po_dir )
{
}
#endif #endif

View File

@ -49,6 +49,7 @@ static const char usage[] =
" -i Inline messagetable(s)\n" " -i Inline messagetable(s)\n"
" -o file Output to file (default is inputfile.rc)\n" " -o file Output to file (default is inputfile.rc)\n"
" -O fmt Set output format (rc, res, pot)\n" " -O fmt Set output format (rc, res, pot)\n"
" -P dir Directory where to find po files\n"
" -u Inputfile is in unicode\n" " -u Inputfile is in unicode\n"
" -U Output unicode messagetable(s)\n" " -U Output unicode messagetable(s)\n"
" -v Show supported codepages and languages\n" " -v Show supported codepages and languages\n"
@ -104,6 +105,8 @@ int rcinline = 0;
*/ */
static int dodebug = 0; static int dodebug = 0;
static char *po_dir;
char *output_name = NULL; /* The name given by the -o option */ char *output_name = NULL; /* The name given by the -o option */
char *input_name = NULL; /* The name given on the command-line */ char *input_name = NULL; /* The name given on the command-line */
char *header_name = NULL; /* The name given by the -H option */ char *header_name = NULL; /* The name given by the -H option */
@ -173,7 +176,7 @@ int main(int argc,char *argv[])
strcat(cmdline, " "); strcat(cmdline, " ");
} }
while((optc = getopt(argc, argv, "B:cdDhH:io:O:p:uUvVW")) != EOF) while((optc = getopt(argc, argv, "B:cdDhH:io:O:P:uUvVW")) != EOF)
{ {
switch(optc) switch(optc)
{ {
@ -229,6 +232,9 @@ int main(int argc,char *argv[])
lose++; lose++;
} }
break; break;
case 'P':
po_dir = xstrdup( optarg );
break;
case 'u': case 'u':
unicodein = 1; unicodein = 1;
break; break;
@ -319,6 +325,7 @@ int main(int argc,char *argv[])
write_bin_files(); write_bin_files();
break; break;
case FORMAT_RES: case FORMAT_RES:
if (po_dir) add_translations( po_dir );
write_res_file( output_name ); write_res_file( output_name );
break; break;
case FORMAT_POT: case FORMAT_POT:

View File

@ -52,6 +52,12 @@ Output to \fIfile\fR. Default is \fIinputfile.rc\fR.
Set the output format. Supported formats are \fBrc\fR (the default), Set the output format. Supported formats are \fBrc\fR (the default),
\fBres\fR, and \fBpot\fR. \fBres\fR, and \fBpot\fR.
.TP .TP
.BI \-P\ directory
Enable the generation of resource translations based on po files
loaded from the specified directory. That directory must follow the
gettext convention, in particular in must contain one .po file for
each language, and a LINGUAS file listing the available languages.
.TP
.B \-u .B \-u
Assume that the inputfile is in unicode. Assume that the inputfile is in unicode.
.TP .TP

View File

@ -117,6 +117,7 @@ typedef struct lan_blk {
struct lan_blk *next; /* Linkage for languages */ struct lan_blk *next; /* Linkage for languages */
struct lan_blk *prev; struct lan_blk *prev;
int lan; /* The language of this block */ int lan; /* The language of this block */
int version; /* The resource version for auto-translated resources */
block_t *blks; /* Array of blocks for this language */ block_t *blks; /* Array of blocks for this language */
int nblk; /* Nr of blocks in array */ int nblk; /* Nr of blocks in array */
} lan_blk_t; } lan_blk_t;

View File

@ -620,7 +620,7 @@ void write_res_file( const char *name )
put_dword( 0 ); /* DataVersion */ put_dword( 0 ); /* DataVersion */
put_word( 0x30 ); /* Memory options */ put_word( 0x30 ); /* Memory options */
put_word( lbp->lan ); /* Language */ put_word( lbp->lan ); /* Language */
put_dword( 0 ); /* Version */ put_dword( lbp->version ); /* Version */
put_dword( 0 ); /* Characteristics */ put_dword( 0 ); /* Characteristics */
output_bin_data( lbp ); output_bin_data( lbp );

View File

@ -25,5 +25,6 @@ void write_rc_file(const char *fname);
void write_bin_files(void); void write_bin_files(void);
void write_res_file( const char *name ); void write_res_file( const char *name );
void write_pot_file( const char *outname ); void write_pot_file( const char *outname );
void add_translations( const char *po_dir );
#endif #endif