wmc: Add support for generating message translations based on po files.
This commit is contained in:
parent
196ffdf671
commit
72921af40b
141
tools/wmc/po.c
141
tools/wmc/po.c
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue