diff --git a/tools/wmc/po.c b/tools/wmc/po.c index e9969ef14e1..414e4a66049 100644 --- a/tools/wmc/po.c +++ b/tools/wmc/po.c @@ -435,6 +435,143 @@ void write_pot_file( const char *outname ) 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 */ 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" ); } +void add_translations( const char *po_dir ) +{ +} + #endif diff --git a/tools/wmc/wmc.c b/tools/wmc/wmc.c index 1dde0d8f654..837cfa60321 100644 --- a/tools/wmc/wmc.c +++ b/tools/wmc/wmc.c @@ -49,6 +49,7 @@ static const char usage[] = " -i Inline messagetable(s)\n" " -o file Output to file (default is inputfile.rc)\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 Output unicode messagetable(s)\n" " -v Show supported codepages and languages\n" @@ -104,6 +105,8 @@ int rcinline = 0; */ static int dodebug = 0; +static char *po_dir; + char *output_name = NULL; /* The name given by the -o option */ char *input_name = NULL; /* The name given on the command-line */ char *header_name = NULL; /* The name given by the -H option */ @@ -173,7 +176,7 @@ int main(int argc,char *argv[]) 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) { @@ -229,6 +232,9 @@ int main(int argc,char *argv[]) lose++; } break; + case 'P': + po_dir = xstrdup( optarg ); + break; case 'u': unicodein = 1; break; @@ -319,6 +325,7 @@ int main(int argc,char *argv[]) write_bin_files(); break; case FORMAT_RES: + if (po_dir) add_translations( po_dir ); write_res_file( output_name ); break; case FORMAT_POT: diff --git a/tools/wmc/wmc.man.in b/tools/wmc/wmc.man.in index ed8b69c13e3..74542a55c40 100644 --- a/tools/wmc/wmc.man.in +++ b/tools/wmc/wmc.man.in @@ -52,6 +52,12 @@ Output to \fIfile\fR. Default is \fIinputfile.rc\fR. Set the output format. Supported formats are \fBrc\fR (the default), \fBres\fR, and \fBpot\fR. .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 Assume that the inputfile is in unicode. .TP diff --git a/tools/wmc/wmctypes.h b/tools/wmc/wmctypes.h index 483507a90e5..6c9a97c5e68 100644 --- a/tools/wmc/wmctypes.h +++ b/tools/wmc/wmctypes.h @@ -117,6 +117,7 @@ typedef struct lan_blk { struct lan_blk *next; /* Linkage for languages */ struct lan_blk *prev; 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 */ int nblk; /* Nr of blocks in array */ } lan_blk_t; diff --git a/tools/wmc/write.c b/tools/wmc/write.c index f6e6d524f57..0fc38adacbf 100644 --- a/tools/wmc/write.c +++ b/tools/wmc/write.c @@ -620,7 +620,7 @@ void write_res_file( const char *name ) put_dword( 0 ); /* DataVersion */ put_word( 0x30 ); /* Memory options */ put_word( lbp->lan ); /* Language */ - put_dword( 0 ); /* Version */ + put_dword( lbp->version ); /* Version */ put_dword( 0 ); /* Characteristics */ output_bin_data( lbp ); diff --git a/tools/wmc/write.h b/tools/wmc/write.h index 745098bb874..8451e0b7950 100644 --- a/tools/wmc/write.h +++ b/tools/wmc/write.h @@ -25,5 +25,6 @@ void write_rc_file(const char *fname); void write_bin_files(void); void write_res_file( const char *name ); void write_pot_file( const char *outname ); +void add_translations( const char *po_dir ); #endif