wrc: Load translations from mo files instead of po.

This commit is contained in:
Alexandre Julliard 2011-10-22 18:21:04 +02:00
parent 4215722988
commit f4ec097c9b
7 changed files with 140 additions and 57 deletions

View File

@ -17,7 +17,7 @@ INCLUDES = -I$(srcdir) -I. -I$(top_srcdir)/include -I$(top_builddir)/include
ALLCFLAGS = $(INCLUDES) $(DEFS) $(DLLFLAGS) $(EXTRACFLAGS) $(CPPFLAGS) $(CFLAGS) $(MODCFLAGS) ALLCFLAGS = $(INCLUDES) $(DEFS) $(DLLFLAGS) $(EXTRACFLAGS) $(CPPFLAGS) $(CFLAGS) $(MODCFLAGS)
ALLLINTFLAGS = $(INCLUDES) $(DEFS) $(LINTFLAGS) ALLLINTFLAGS = $(INCLUDES) $(DEFS) $(LINTFLAGS)
IDLFLAGS = $(INCLUDES) $(DEFS) $(EXTRAIDLFLAGS) IDLFLAGS = $(INCLUDES) $(DEFS) $(EXTRAIDLFLAGS)
RCFLAGS = --nostdinc --po-dir=$(top_srcdir)/po $(TARGETFLAGS) $(INCLUDES) $(DEFS) $(EXTRARCFLAGS) RCFLAGS = --nostdinc $(PORCFLAGS) $(TARGETFLAGS) $(INCLUDES) $(DEFS) $(EXTRARCFLAGS)
IDL_GEN_C_SRCS = $(IDL_C_SRCS:.idl=_c.c) $(IDL_I_SRCS:.idl=_i.c) \ IDL_GEN_C_SRCS = $(IDL_C_SRCS:.idl=_c.c) $(IDL_I_SRCS:.idl=_i.c) \
$(IDL_P_SRCS:.idl=_p.c) $(IDL_S_SRCS:.idl=_s.c) $(IDL_P_SRCS:.idl=_p.c) $(IDL_S_SRCS:.idl=_s.c)
@ -189,9 +189,9 @@ rsrc.pot: $(WRC)
msg.pot: $(WMC) msg.pot: $(WMC)
$(LDPATH) $(WMC) -O pot -o $@ $(MC_SRCS) $(LDPATH) $(WMC) -O pot -o $@ $(MC_SRCS)
$(MC_SRCS:.mc=.res): $(WMC) $(ALL_PO_FILES) $(MC_SRCS:.mc=.res): $(WMC) $(ALL_MO_FILES)
$(RC_SRCS:.rc=.res): $(WRC) $(RC_SRCS:.rc=.res): $(WRC)
$(PO_SRCS:.rc=.res): $(ALL_PO_FILES) $(PO_SRCS:.rc=.res): $(ALL_MO_FILES)
# Misc. rules # Misc. rules

View File

@ -53,8 +53,8 @@ ICOTOOL = @ICOTOOL@
MSGFMT = @MSGFMT@ MSGFMT = @MSGFMT@
CROSSTARGET = @CROSSTARGET@ CROSSTARGET = @CROSSTARGET@
LINGUAS = @LINGUAS@ LINGUAS = @LINGUAS@
ALL_PO_FILES = $(LINGUAS:%=@top_srcdir@/po/%.po)
ALL_MO_FILES = $(LINGUAS:%=@top_builddir@/po/%.mo) ALL_MO_FILES = $(LINGUAS:%=@top_builddir@/po/%.mo)
PORCFLAGS = @PORCFLAGS@
CROSSAR = $(CROSSTARGET)-ar CROSSAR = $(CROSSTARGET)-ar
CROSSRANLIB = $(CROSSTARGET)-ranlib CROSSRANLIB = $(CROSSTARGET)-ranlib
MKINSTALLDIRS = $(top_srcdir)/tools/mkinstalldirs -m 755 MKINSTALLDIRS = $(top_srcdir)/tools/mkinstalldirs -m 755

7
configure vendored
View File

@ -604,6 +604,7 @@ ac_includes_default="\
ac_subst_vars='LTLIBOBJS ac_subst_vars='LTLIBOBJS
LIBOBJS LIBOBJS
PORCFLAGS
LINGUAS LINGUAS
ALL_TEST_RESOURCES ALL_TEST_RESOURCES
LDAPLIBS LDAPLIBS
@ -15432,7 +15433,7 @@ then
@echo timestamp > \$@ @echo timestamp > \$@
ALL_POT_FILES =$ALL_POT_FILES ALL_POT_FILES =$ALL_POT_FILES
\$(ALL_PO_FILES): \$(srcdir)/po/wine.pot \$(LINGUAS:%=$srcdir/po/%.po): \$(srcdir)/po/wine.pot
msgmerge -q \$@ \$(srcdir)/po/wine.pot | msgattrib --no-obsolete -o \$@.new && mv \$@.new \$@ msgmerge -q \$@ \$(srcdir)/po/wine.pot | msgattrib --no-obsolete -o \$@.new && mv \$@.new \$@
\$(srcdir)/po/wine.pot: \$(ALL_POT_FILES) \$(srcdir)/po/wine.pot: \$(ALL_POT_FILES)
msgcat -o \$@ \$(ALL_POT_FILES)" msgcat -o \$@ \$(ALL_POT_FILES)"
@ -15440,7 +15441,11 @@ fi
if test "$MSGFMT" != false if test "$MSGFMT" != false
then then
PORCFLAGS="--po-dir=\$(top_builddir)/po"
wine_fn_append_rule ALL_MAKEFILE_DEPENDS "__builddeps__: \$(ALL_MO_FILES)" wine_fn_append_rule ALL_MAKEFILE_DEPENDS "__builddeps__: \$(ALL_MO_FILES)"
else
LINGUAS=
fi fi
if test "x$enable_tools" != xno if test "x$enable_tools" != xno

View File

@ -3066,7 +3066,7 @@ then
@echo timestamp > \$[@] @echo timestamp > \$[@]
ALL_POT_FILES =$ALL_POT_FILES ALL_POT_FILES =$ALL_POT_FILES
\$(ALL_PO_FILES): \$(srcdir)/po/wine.pot \$(LINGUAS:%=$srcdir/po/%.po): \$(srcdir)/po/wine.pot
msgmerge -q \$[@] \$(srcdir)/po/wine.pot | msgattrib --no-obsolete -o \$[@].new && mv \$[@].new \$[@] msgmerge -q \$[@] \$(srcdir)/po/wine.pot | msgattrib --no-obsolete -o \$[@].new && mv \$[@].new \$[@]
\$(srcdir)/po/wine.pot: \$(ALL_POT_FILES) \$(srcdir)/po/wine.pot: \$(ALL_POT_FILES)
msgcat -o \$[@] \$(ALL_POT_FILES)]) msgcat -o \$[@] \$(ALL_POT_FILES)])
@ -3074,7 +3074,10 @@ fi
if test "$MSGFMT" != false if test "$MSGFMT" != false
then then
AC_SUBST([PORCFLAGS],["--po-dir=\$(top_builddir)/po"])
WINE_APPEND_RULE([ALL_MAKEFILE_DEPENDS],[__builddeps__: \$(ALL_MO_FILES)]) WINE_APPEND_RULE([ALL_MAKEFILE_DEPENDS],[__builddeps__: \$(ALL_MO_FILES)])
else
LINGUAS=
fi fi
if test "x$enable_tools" != xno if test "x$enable_tools" != xno

View File

@ -19,6 +19,7 @@
*/ */
#include "config.h" #include "config.h"
#include "wine/port.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -43,6 +44,16 @@
static resource_t *new_top, *new_tail; static resource_t *new_top, *new_tail;
struct mo_file
{
unsigned int magic;
unsigned int revision;
unsigned int count;
unsigned int msgid_off;
unsigned int msgstr_off;
/* ... rest of file data here */
};
static int is_english( const language_t *lan ) static int is_english( const language_t *lan )
{ {
return lan->id == LANG_ENGLISH && lan->sub == SUBLANG_DEFAULT; return lan->id == LANG_ENGLISH && lan->sub == SUBLANG_DEFAULT;
@ -393,20 +404,6 @@ static const struct
#ifndef HAVE_LIBGETTEXTPO #ifndef HAVE_LIBGETTEXTPO
static const char *get_msgstr( const char *msgid, const char *context, int *found )
{
if (context) (*found)++;
return msgid;
}
static void load_po_file( const char *name )
{
}
static void free_po_file(void)
{
}
void write_pot_file( const char *outname ) void write_pot_file( const char *outname )
{ {
error( "PO files not supported in this wrc build\n" ); error( "PO files not supported in this wrc build\n" );
@ -419,8 +416,6 @@ void write_po_files( const char *outname )
#else /* HAVE_LIBGETTEXTPO */ #else /* HAVE_LIBGETTEXTPO */
static po_file_t po_file;
static void po_xerror( int severity, po_message_t message, static void po_xerror( int severity, po_message_t message,
const char *filename, size_t lineno, size_t column, const char *filename, size_t lineno, size_t column,
int multiline_p, const char *message_text ) int multiline_p, const char *message_text )
@ -473,35 +468,6 @@ static po_message_t find_message( po_file_t po, const char *msgid, const char *m
return msg; return msg;
} }
static const char *get_msgstr( const char *msgid, const char *context, int *found )
{
const char *ret = msgid;
po_message_t msg;
po_message_iterator_t iterator;
msg = find_message( po_file, msgid, context, &iterator );
if (msg && !po_message_is_fuzzy( msg ))
{
ret = po_message_msgstr( msg );
if (!ret[0]) ret = msgid; /* ignore empty strings */
else (*found)++;
}
po_message_iterator_free( iterator );
return ret;
}
static void load_po_file( const char *name )
{
if (!(po_file = po_file_read( name, &po_xerror_handler )))
error( "cannot load po file '%s'\n", name );
}
static void free_po_file(void)
{
po_file_free( po_file );
po_file = NULL;
}
static void add_po_string( po_file_t po, const string_t *msgid, const string_t *msgstr, static void add_po_string( po_file_t po, const string_t *msgid, const string_t *msgstr,
const language_t *lang ) const language_t *lang )
{ {
@ -820,6 +786,108 @@ void write_po_files( const char *outname )
#endif /* HAVE_LIBGETTEXTPO */ #endif /* HAVE_LIBGETTEXTPO */
static struct mo_file *mo_file;
static void byteswap( unsigned int *data, unsigned int count )
{
unsigned int i;
for (i = 0; i < count; i++)
data[i] = data[i] >> 24 | (data[i] >> 8 & 0xff00) | (data[i] << 8 & 0xff0000) | data[i] << 24;
}
static void load_mo_file( const char *name )
{
struct stat st;
int res, fd;
fd = open( name, O_RDONLY | O_BINARY );
if (fd == -1) fatal_perror( "Failed to open %s", name );
fstat( fd, &st );
mo_file = xmalloc( st.st_size );
res = read( fd, mo_file, st.st_size );
if (res == -1) fatal_perror( "Failed to read %s", name );
else if (res != st.st_size) error( "Failed to read %s\n", name );
close( fd );
/* sanity checks */
if (st.st_size < sizeof(*mo_file))
error( "%s is not a valid .mo file\n", name );
if (mo_file->magic == 0xde120495)
byteswap( &mo_file->revision, 4 );
else if (mo_file->magic != 0x950412de)
error( "%s is not a valid .mo file\n", name );
if ((mo_file->revision >> 16) > 1)
error( "%s: unsupported file version %x\n", name, mo_file->revision );
if (mo_file->msgid_off >= st.st_size ||
mo_file->msgstr_off >= st.st_size ||
st.st_size < sizeof(*mo_file) + 2 * 8 * mo_file->count)
error( "%s: corrupted file\n", name );
if (mo_file->magic == 0xde120495)
{
byteswap( (unsigned int *)((char *)mo_file + mo_file->msgid_off), 2 * mo_file->count );
byteswap( (unsigned int *)((char *)mo_file + mo_file->msgstr_off), 2 * mo_file->count );
}
}
static void free_mo_file(void)
{
free( mo_file );
mo_file = NULL;
}
static inline const char *get_mo_msgid( int index )
{
const char *base = (const char *)mo_file;
const unsigned int *offsets = (const unsigned int *)(base + mo_file->msgid_off);
return base + offsets[2 * index + 1];
}
static inline const char *get_mo_msgstr( int index )
{
const char *base = (const char *)mo_file;
const unsigned int *offsets = (const unsigned int *)(base + mo_file->msgstr_off);
return base + offsets[2 * index + 1];
}
static const char *get_msgstr( const char *msgid, const char *context, int *found )
{
int pos, res, min, max;
const char *ret = msgid;
char *id = NULL;
if (!mo_file) /* strings containing a context still need to be transformed */
{
if (context) (*found)++;
return ret;
}
if (context) id = strmake( "%s%c%s", context, 4, msgid );
min = 0;
max = mo_file->count - 1;
while (min <= max)
{
pos = (min + max) / 2;
res = strcmp( get_mo_msgid(pos), msgid );
if (!res)
{
const char *str = get_mo_msgstr( pos );
if (str[0]) /* ignore empty strings */
{
ret = str;
(*found)++;
}
break;
}
if (res > 0) max = pos - 1;
else min = pos + 1;
}
free( id );
return ret;
}
static string_t *translate_string( string_t *str, int *found ) static string_t *translate_string( string_t *str, int *found )
{ {
string_t *new; string_t *new;
@ -988,6 +1056,12 @@ void add_translations( const char *po_dir )
for (res = resource_top; res; res = res->next) if (is_english( res->lan )) break; for (res = resource_top; res; res = res->next) if (is_english( res->lan )) break;
if (!res) return; if (!res) return;
if (!po_dir) /* run through the translation process to remove msg contexts */
{
translate_resources( new_language( LANG_ENGLISH, SUBLANG_DEFAULT ));
goto done;
}
new_top = new_tail = NULL; new_top = new_tail = NULL;
name = strmake( "%s/LINGUAS", po_dir ); name = strmake( "%s/LINGUAS", po_dir );
@ -1008,15 +1082,16 @@ void add_translations( const char *po_dir )
if (i == sizeof(languages)/sizeof(languages[0])) if (i == sizeof(languages)/sizeof(languages[0]))
error( "unknown language '%s'\n", tok ); error( "unknown language '%s'\n", tok );
name = strmake( "%s/%s.po", po_dir, tok ); name = strmake( "%s/%s.mo", po_dir, tok );
load_po_file( name ); load_mo_file( name );
translate_resources( new_language(languages[i].id, languages[i].sub) ); translate_resources( new_language(languages[i].id, languages[i].sub) );
free_po_file(); free_mo_file();
free( name ); free( name );
} }
} }
fclose( f ); fclose( f );
done:
/* prepend the translated resources to the global list */ /* prepend the translated resources to the global list */
if (new_tail) if (new_tail)
{ {

View File

@ -562,7 +562,7 @@ int main(int argc,char *argv[])
output_name = NULL; output_name = NULL;
exit(0); exit(0);
} }
if (po_dir) add_translations( po_dir ); add_translations( po_dir );
/* Convert the internal lists to binary data */ /* Convert the internal lists to binary data */
resources2res(resource_top); resources2res(resource_top);

View File

@ -108,9 +108,9 @@ Enable pedantic warnings. Notably redefinition of #define statements can
be discovered with this option. be discovered with this option.
.TP .TP
.I \fB\-\-po-dir=\fIdir\fR .I \fB\-\-po-dir=\fIdir\fR
Enable the generation of resource translations based on po files Enable the generation of resource translations based on mo files
loaded from the specified directory. That directory must follow the loaded from the specified directory. That directory must follow the
gettext convention, in particular in must contain one .po file for gettext convention, in particular in must contain one .mo file for
each language, and a LINGUAS file listing the available languages. each language, and a LINGUAS file listing the available languages.
.TP .TP
.I \fB\-r\fR .I \fB\-r\fR