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