Alexandre Julliard : wmc: Add support for generating message translations based on po files.
Alexandre Julliard
julliard at winehq.org
Tue Jan 25 12:01:37 CST 2011
Module: wine
Branch: master
Commit: 72921af40b72c31f29dbc8f8b656f431e6457a4a
URL: http://source.winehq.org/git/wine.git/?a=commit;h=72921af40b72c31f29dbc8f8b656f431e6457a4a
Author: Alexandre Julliard <julliard at winehq.org>
Date: Mon Jan 24 20:12:54 2011 +0100
wmc: Add support for generating message translations based on po files.
---
tools/wmc/po.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++
tools/wmc/wmc.c | 9 +++-
tools/wmc/wmc.man.in | 6 ++
tools/wmc/wmctypes.h | 1 +
tools/wmc/write.c | 2 +-
tools/wmc/write.h | 1 +
6 files changed, 158 insertions(+), 2 deletions(-)
diff --git a/tools/wmc/po.c b/tools/wmc/po.c
index e9969ef..414e4a6 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 1dde0d8..837cfa6 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 ed8b69c..74542a5 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 483507a..6c9a97c 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 f6e6d52..0fc38ad 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 745098b..8451e0b 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
More information about the wine-cvs
mailing list