grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: gettext patch (beta)


From: Carles Pina i Estany
Subject: Re: gettext patch (beta)
Date: Sat, 24 Jan 2009 16:09:33 +0100
User-agent: Mutt/1.5.18 (2008-05-17)

Sorry, a new mistake has been removed

If someone wants to test:
a) msgfmt po/ca.po -o /usr/share/locale/ca/LC_MESSAGES/grub.mo
b) edit /boot/grub/grub.cfg and change lang=C by lang=ca

Thanks,

On Jan/24/2009, Carles Pina i Estany wrote:
> 
> New version (same ChangeLog), fixing some warning messages, mistake in
> 00_header, etc.
> 
> On Jan/21/2009, Carles Pina i Estany wrote:
> > 
> > Hello,
> > 
> > I have been working with the gettext patch (and Robert gave me a hand,
> > thanks)
> > 
> > Take this version as a RFC and call for help (see at the bottom, it
> > includes beer invitation in Fosdem).
> > 
> > ChangeLog:
> > -------------------
> > YYYY-MM-DD  Carles Pina i Estany <address@hidden>
> > 
> >         * Makefile.in: Add uptrans target to help to update .pot file
> >         * conf/common.rmk: Add grub-gettext_lib target, dependency and
> >           SOURCES, CFLAGS, LDFLAGS
> >         * kern/misc.c: Define grub_gettext symbol and add implement
> >           grub_gettext_dummy function
> >         * po/TODO: Temporary file with instructions of what Makefile.in
> >           will do
> >         * po/ca.po: Catalan translation stub
> >         * include/grub/misc.h: Define macro _(char *s). Declare
> >           grub_gettext_dummy and grub_gettext
> >         * gettext/gettext.c: New file with gettext implementation
> >         * normal/menu.c (print_message): add _( ) to some strings
> >         * util/grub.d/10_linux.in: include grub-gettext_lib file.
> >           For the Linux menuentry, call eval_gettext
> >         * util/grub.d/00_header.in: add locale_prefix and gettext 
> >           locale detection and setting up the access to the mo directory
> >         * util/grub-mkconfig_lib.in: add get_locale_lang
> >         * util/grub-gettext_lib.in: new file
> > -------------------
> > 
> > How to test and see something:
> > -Apply the patch
> > 
> > -In po/ execute msgfmt ca.po -o ca.mo
> > 
> > -Copy ca.mo to /usr/share/locale/ca/LC_MESSAGES/grub.mo
> > 
> > -Compile and install the patched Grub
> > 
> > -Maybe the new 00_header will detect your language and add the 
> >  configuration (this has not been tested)
> > 
> > -In Grub2 console you should:
> > set lang=ca
> > set locale_prefix=/usr/share/locale
> > insmod gettext
> > (ESC)
> > 
> > Then the lines under the menu box will appear in Catalan.
> > 
> > The gettext module has a hook to the lang variable, if you change lang to 
> > a new value, it will reload the file. Ops! And I didn't do any hook for
> > locale_prefix, I will do it but by the moment you can rmmod gettext
> > and insmod again
> > 
> > CALL FOR HELP:
> > I need to write the Makefile.in (see po/TODO :-( ). I'm not used or
> > familiar to write Makefiles :-( if someone wants to help it would 
> > speed up the process quite much. It needs only to merge the files with
> > the new .pot, compile (msgfmt), and install to the correct directory.
> > 
> > I exactly know what has to do, so if someone knows about
> > installation/Makefiles and doesn't know about gettext it's not a
> > problem, contact me. Else I will try to implement soon.
> > 
> > I would even invite to a couple of beers in Fosdem if someone does
> > this part :-)
> > 
> > TODO:
> > -the Makefile.in
> > -and more testing about 00_header with gettext detection.
> > -Add _("") for mainly all strings (I would do in a separate patch)
> > -I have seen that Grub2 is not printing correctly the accents,
> > could be a problem in gettext or in some other layer
> > 
> > -- 
> > Carles Pina i Estany                GPG id: 0x17756391
> >     http://pinux.info
> 
> > Index: Makefile.in
> > ===================================================================
> > --- Makefile.in     (revision 1952)
> > +++ Makefile.in     (working copy)
> > @@ -170,6 +170,16 @@
> >  endif
> >  endif
> >  
> > +#TODO: define on the header?    
> > +SHELLSDIR = $(srcdir)/util/grub.d
> > +uptrans:
> > +   #TODO: only one xgettext for everything
> > +   xgettext -k_ -LC -o - `find "$(srcdir)/" -name '*.c'` -o po/grub.pot
> > +
> > +   #TODO: in which variable we have all shell scripts?
> > +   xgettext -k_ -Lshell -o - $(SHELLSDIR)/00_header.in 
> > $(SHELLSDIR)/10_freebsd.in $(SHELLSDIR)/10_hurd.in $(SHELLSDIR)/10_linux.in 
> > $(SHELLSDIR)/10_windows.in $(SHELLSDIR)/30_os-prober.in 
> > $(SHELLSDIR)/40_custom.in -o po/grub.pot
> > +
> > +
> >  # Used for building modules externally
> >  pkglib_BUILDDIR += build_env.mk
> >  build_env.mk: Makefile
> > Index: conf/common.rmk
> > ===================================================================
> > --- conf/common.rmk (revision 1952)
> > +++ conf/common.rmk (working copy)
> > @@ -142,6 +142,12 @@
> >  lib_DATA += update-grub_lib
> >  CLEANFILES += update-grub_lib
> >  
> > +grub-gettext_lib: util/grub-gettext_lib.in config.status
> > +   ./config.status --file=$@:$<
> > +   chmod +x $@
> > +lib_DATA += grub-gettext_lib
> > +CLEANFILES += grub-gettext_lib
> > +
> >  %: util/grub.d/%.in config.status
> >     ./config.status --file=$@:$<
> >     chmod +x $@
> > @@ -329,7 +335,7 @@
> >     cmp.mod cat.mod help.mod search.mod                                     
> > \
> >     loopback.mod fs_uuid.mod configfile.mod echo.mod        \
> >     terminfo.mod test.mod blocklist.mod hexdump.mod         \
> > -   read.mod sleep.mod loadenv.mod crc.mod
> > +   read.mod sleep.mod loadenv.mod crc.mod gettext.mod
> >  
> >  # For hello.mod.
> >  hello_mod_SOURCES = hello/hello.c
> > @@ -492,3 +498,10 @@
> >  bufio_mod_SOURCES = io/bufio.c
> >  bufio_mod_CFLAGS = $(COMMON_CFLAGS)
> >  bufio_mod_LDFLAGS = $(COMMON_LDFLAGS)
> > +
> > +# For gettext.mod.
> > +gettext_mod_SOURCES = gettext/gettext.c
> > +gettext_mod_CFLAGS = $(COMMON_CFLAGS)
> > +gettext_mod_LDFLAGS = $(COMMON_LDFLAGS)
> > +
> > +
> > Index: conf/common.mk
> > ===================================================================
> > --- conf/common.mk  (revision 1952)
> > +++ conf/common.mk  (working copy)
> > @@ -567,6 +567,12 @@
> >  lib_DATA += update-grub_lib
> >  CLEANFILES += update-grub_lib
> >  
> > +grub-gettext_lib: util/grub-gettext_lib.in config.status
> > +   ./config.status --file=$@:$<
> > +   chmod +x $@
> > +lib_DATA += grub-gettext_lib
> > +CLEANFILES += grub-gettext_lib
> > +
> >  %: util/grub.d/%.in config.status
> >     ./config.status --file=$@:$<
> >     chmod +x $@
> > @@ -2366,7 +2372,7 @@
> >     cmp.mod cat.mod help.mod search.mod                                     
> > \
> >     loopback.mod fs_uuid.mod configfile.mod echo.mod        \
> >     terminfo.mod test.mod blocklist.mod hexdump.mod         \
> > -   read.mod sleep.mod loadenv.mod crc.mod
> > +   read.mod sleep.mod loadenv.mod crc.mod gettext.mod
> >  
> >  # For hello.mod.
> >  hello_mod_SOURCES = hello/hello.c
> > @@ -4236,3 +4242,62 @@
> >  
> >  bufio_mod_CFLAGS = $(COMMON_CFLAGS)
> >  bufio_mod_LDFLAGS = $(COMMON_LDFLAGS)
> > +
> > +# For gettext.mod.
> > +gettext_mod_SOURCES = gettext/gettext.c
> > +CLEANFILES += gettext.mod mod-gettext.o mod-gettext.c pre-gettext.o 
> > gettext_mod-gettext_gettext.o und-gettext.lst
> > +ifneq ($(gettext_mod_EXPORTS),no)
> > +CLEANFILES += def-gettext.lst
> > +DEFSYMFILES += def-gettext.lst
> > +endif
> > +MOSTLYCLEANFILES += gettext_mod-gettext_gettext.d
> > +UNDSYMFILES += und-gettext.lst
> > +
> > +gettext.mod: pre-gettext.o mod-gettext.o $(TARGET_OBJ2ELF)
> > +   -rm -f $@
> > +   $(TARGET_CC) $(gettext_mod_LDFLAGS) $(TARGET_LDFLAGS) $(MODULE_LDFLAGS) 
> > -Wl,-r,-d -o $@ pre-gettext.o mod-gettext.o
> > +   if test ! -z $(TARGET_OBJ2ELF); then ./$(TARGET_OBJ2ELF) $@ || (rm -f 
> > $@; exit 1); fi
> > +   $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -K 
> > _grub_mod_init -K _grub_mod_fini -R .note -R .comment $@
> > +
> > +pre-gettext.o: $(gettext_mod_DEPENDENCIES) gettext_mod-gettext_gettext.o
> > +   -rm -f $@
> > +   $(TARGET_CC) $(gettext_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ 
> > gettext_mod-gettext_gettext.o
> > +
> > +mod-gettext.o: mod-gettext.c
> > +   $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(gettext_mod_CFLAGS) 
> > -c -o $@ $<
> > +
> > +mod-gettext.c: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh
> > +   sh $(srcdir)/genmodsrc.sh 'gettext' $< > $@ || (rm -f $@; exit 1)
> > +
> > +ifneq ($(gettext_mod_EXPORTS),no)
> > +def-gettext.lst: pre-gettext.o
> > +   $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 gettext/' > $@
> > +endif
> > +
> > +und-gettext.lst: pre-gettext.o
> > +   echo 'gettext' > $@
> > +   $(NM) -u -P -p $< | cut -f1 -d' ' >> $@
> > +
> > +gettext_mod-gettext_gettext.o: gettext/gettext.c 
> > $(gettext/gettext.c_DEPENDENCIES)
> > +   $(TARGET_CC) -Igettext -I$(srcdir)/gettext $(TARGET_CPPFLAGS)  
> > $(TARGET_CFLAGS) $(gettext_mod_CFLAGS) -MD -c -o $@ $<
> > +-include gettext_mod-gettext_gettext.d
> > +
> > +CLEANFILES += cmd-gettext_mod-gettext_gettext.lst 
> > fs-gettext_mod-gettext_gettext.lst partmap-gettext_mod-gettext_gettext.lst
> > +COMMANDFILES += cmd-gettext_mod-gettext_gettext.lst
> > +FSFILES += fs-gettext_mod-gettext_gettext.lst
> > +PARTMAPFILES += partmap-gettext_mod-gettext_gettext.lst
> > +
> > +cmd-gettext_mod-gettext_gettext.lst: gettext/gettext.c 
> > $(gettext/gettext.c_DEPENDENCIES) gencmdlist.sh
> > +   set -e;           $(TARGET_CC) -Igettext -I$(srcdir)/gettext 
> > $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(gettext_mod_CFLAGS) -E $<      | sh 
> > $(srcdir)/gencmdlist.sh gettext > $@ || (rm -f $@; exit 1)
> > +
> > +fs-gettext_mod-gettext_gettext.lst: gettext/gettext.c 
> > $(gettext/gettext.c_DEPENDENCIES) genfslist.sh
> > +   set -e;           $(TARGET_CC) -Igettext -I$(srcdir)/gettext 
> > $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(gettext_mod_CFLAGS) -E $<      | sh 
> > $(srcdir)/genfslist.sh gettext > $@ || (rm -f $@; exit 1)
> > +
> > +partmap-gettext_mod-gettext_gettext.lst: gettext/gettext.c 
> > $(gettext/gettext.c_DEPENDENCIES) genpartmaplist.sh
> > +   set -e;           $(TARGET_CC) -Igettext -I$(srcdir)/gettext 
> > $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(gettext_mod_CFLAGS) -E $<      | sh 
> > $(srcdir)/genpartmaplist.sh gettext > $@ || (rm -f $@; exit 1)
> > +
> > +
> > +gettext_mod_CFLAGS = $(COMMON_CFLAGS)
> > +gettext_mod_LDFLAGS = $(COMMON_LDFLAGS)
> > +
> > +
> > Index: kern/misc.c
> > ===================================================================
> > --- kern/misc.c     (revision 1952)
> > +++ kern/misc.c     (working copy)
> > @@ -24,6 +24,8 @@
> >  #include <grub/term.h>
> >  #include <grub/env.h>
> >  
> > +char* (*grub_gettext) (const char *s) = grub_gettext_dummy;
> > +
> >  void *
> >  grub_memmove (void *dest, const void *src, grub_size_t n)
> >  {
> > @@ -1036,6 +1038,13 @@
> >    return p - dest;
> >  }
> >  
> > +/* grub_gettext_dummy is not translating anything.  */
> > +char *
> > +grub_gettext_dummy (const char *s)
> > +{
> > +  return s;
> > +}
> > +
> >  /* Abort GRUB. This function does not return.  */
> >  void
> >  grub_abort (void)
> > Index: po/ca.po
> > ===================================================================
> > --- po/ca.po        (revision 0)
> > +++ po/ca.po        (revision 0)
> > @@ -0,0 +1,39 @@
> > +# SOME DESCRIPTIVE TITLE.
> > +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
> > +# This file is distributed under the same license as the PACKAGE package.
> > +# FIRST AUTHOR <address@hidden>, YEAR.
> > +#
> > +#, fuzzy
> > +msgid ""
> > +msgstr ""
> > +"Project-Id-Version: PACKAGE VERSION\n"
> > +"Report-Msgid-Bugs-To: \n"
> > +"POT-Creation-Date: 2009-01-21 21:14+0100\n"
> > +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
> > +"Last-Translator: FULL NAME <address@hidden>\n"
> > +"Language-Team: LANGUAGE <address@hidden>\n"
> > +"MIME-Version: 1.0\n"
> > +"Content-Type: text/plain; charset=CHARSET\n"
> > +"Content-Transfer-Encoding: 8bit\n"
> > +
> > +#: normal/menu.c:90
> > +#, c-format
> > +msgid ""
> > +"\n"
> > +"      Use the %C and %C keys to select which entry is highlighted.\n"
> > +msgstr ""
> > +"\n"
> > +"      Utilitzeu les tecles %C i %C per seleccionar l'entrada.\n"
> > +
> > +#: normal/menu.c:93
> > +msgid ""
> > +"      Press enter to boot the selected OS, 'e' to edit the\n"
> > +"      commands before booting or 'c' for a command-line."
> > +msgstr ""
> > +"      Presioneu retorn per arrancar el SO seleccionat, 'e' editar\n"
> > +"      les comandes abans d'arrancar, 'c' per línia d'ordres."
> > +
> > +#: util/grub.d/10_linux.in:148
> > +#, sh-format
> > +msgid "${OS}, linux ${version} (single-user mode)"
> > +msgstr "${OS}, linux ${version} (mode mono-usuari)"
> > Index: po/TODO
> > ===================================================================
> > --- po/TODO (revision 0)
> > +++ po/TODO (revision 0)
> > @@ -0,0 +1,5 @@
> > +Prepare a Makefile.in to:
> > +
> > +-Compile all .po to .mo (msgfmt $LANG.po -o $LANG.mo)
> > +-Copy to /usr/share/locale/$LANG/LC_MESSAGES/grub.mo (or 
> > /usr/local/share/locale/$LANG/LC_MESSAGES/..., so $prefix...)
> > +-Check that grub-gettext_lib.in is correct
> > Index: include/grub/misc.h
> > ===================================================================
> > --- include/grub/misc.h     (revision 1952)
> > +++ include/grub/misc.h     (working copy)
> > @@ -31,6 +31,8 @@
> >  /* XXX: If grub_memmove is too slow, we must implement grub_memcpy.  */
> >  #define grub_memcpy(d,s,n) grub_memmove ((d), (s), (n))
> >  
> > +#define _(s)       grub_gettext(s)
> > +
> >  void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t 
> > n);
> >  char *EXPORT_FUNC(grub_strcpy) (char *dest, const char *src);
> >  char *EXPORT_FUNC(grub_strncpy) (char *dest, const char *src, int c);
> > @@ -84,6 +86,9 @@
> >  grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n,
> >                                       grub_uint32_t d, grub_uint32_t *r);
> >  
> > +char *EXPORT_FUNC(grub_gettext_dummy) (const char *s);
> > +extern char *(*EXPORT_VAR(grub_gettext)) (const char *s);// = 
> > grub_gettext_dummy;
> > +
> >  #ifdef NEED_ENABLE_EXECUTE_STACK
> >  void EXPORT_FUNC(__enable_execute_stack) (void *addr);
> >  #endif
> > Index: gettext/gettext.c
> > ===================================================================
> > --- gettext/gettext.c       (revision 0)
> > +++ gettext/gettext.c       (revision 0)
> > @@ -0,0 +1,299 @@
> > +/* gettext.c - gettext module */
> > +/*
> > + *  GRUB  --  GRand Unified Bootloader
> > + *  Copyright (C) 2009 Free Software Foundation, Inc.
> > + *
> > + *  GRUB is free software: you can redistribute it and/or modify
> > + *  it under the terms of the GNU General Public License as published by
> > + *  the Free Software Foundation, either version 3 of the License, or
> > + *  (at your option) any later version.
> > + *
> > + *  GRUB is distributed in the hope that it will be useful,
> > + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + *  GNU General Public License for more details.
> > + *
> > + *  You should have received a copy of the GNU General Public License
> > + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> > + */
> > +
> > +#include <grub/types.h>
> > +#include <grub/misc.h>
> > +#include <grub/mm.h>
> > +#include <grub/err.h>
> > +#include <grub/dl.h>
> > +#include <grub/normal.h>
> > +#include <grub/file.h>
> > +#include <grub/kernel.h>
> > +
> > +/* 
> > +   .mo file information from: 
> > +   http://www.gnu.org/software/autoconf/manual/gettext/MO-Files.html .
> > +*/
> > +
> > +
> > +static grub_file_t grub_mofile_open (const char *name);
> > +static grub_file_t fd_mo;
> > +
> > +static int grub_gettext_offsetoriginal;
> > +static int grub_gettext_max;
> > +
> > +static char* (*grub_gettext_original) (const char *s);
> > +
> > +#define GETTEXT_MAGIC_NUMBER 0
> > +#define GETTEXT_FILE_FORMAT 4
> > +#define GETTEXT_NUMBER_OF_STRINGS 8
> > +#define GETTEXT_OFFSET_ORIGINAL 12
> > +#define GETTEXT_OFFSET_TRANSLATION 16
> > +
> > +static int
> > +grub_gettext_get_info (int offset)
> > +{
> > +  int buf;
> > +
> > +  grub_file_seek (fd_mo, offset);
> > +  grub_file_read (fd_mo, (char*) &buf, 4);
> > +  return buf;
> > +}
> > +
> > +static void
> > +grub_gettext_getstring_from_offset (int offset, int length, char 
> > *translation)
> > +{
> > +  grub_file_seek (fd_mo,offset);
> > +  grub_file_read (fd_mo,translation,length);
> > +  translation[length] = '\0';
> > +}
> > +
> > +static char*
> > +grub_gettext_gettranslation_number (int i)
> > +{
> > +  int offsettranslation;
> > +  int position;
> > +  int length, offset;
> > +  char *translation;
> > +
> > +  offsettranslation = grub_gettext_get_info (GETTEXT_OFFSET_TRANSLATION);
> > +
> > +  position=offsettranslation+i*8;
> > +
> > +  grub_file_seek (fd_mo, position);
> > +  grub_file_read (fd_mo, (char*) &length, 4);
> > +  
> > +  grub_file_seek (fd_mo, position + 4),
> > +  grub_file_read (fd_mo, (char*) &offset, 4);
> > +
> > +  translation = grub_malloc(length + 1);
> > +  grub_gettext_getstring_from_offset (offset, length, translation);
> > +
> > +  return translation;
> > +}
> > +
> > +static char*
> > +grub_gettext_getstring_num (int num)
> > +{
> > +  int position;
> > +  int length, offset;
> > +  char *original;
> > +
> > +  /* Get position for string i.  */
> > +  position = grub_gettext_offsetoriginal + (num * 8);
> > +
> > +  /* Get the length of the string i.  */
> > +  grub_file_seek (fd_mo, position);
> > +  grub_file_read (fd_mo, (char *) &length, 4);
> > +
> > +  /* Get the offset of the string i.  */
> > +  grub_file_seek (fd_mo, position + 4);
> > +  grub_file_read (fd_mo, (char *) &offset, 4);
> > +
> > +  /* Get the string i.  */
> > +  original = grub_malloc (length + 1);
> > +  grub_gettext_getstring_from_offset (offset, length, original);
> > +
> > +  return original;
> > +}
> > +
> > +static char*
> > +grub_gettext_translate (char *orig)
> > +{
> > +  char *current_string;
> > +  char *ret;
> > +
> > +  int min,max,current;
> > +
> > +  if (fd_mo == 0)
> > +    return orig;
> > +
> > +  min = 0;
> > +  max = grub_gettext_max;
> > +
> > +  current = (max + min) / 2;
> > +
> > +  while (current != min && current != max)
> > +    {
> > +      current_string = grub_gettext_getstring_num (current);
> > +      /* grub_printf("Current: %s\n",current_string);  */
> > +
> > +      /* Search by bissection.  */
> > +      if (grub_strcmp (current_string, orig) < 0)
> > +        {
> > +          grub_free(current_string);
> > +          min=current;
> > +        }
> > +      else if (grub_strcmp (current_string, orig) > 0)
> > +        {
> > +          grub_free(current_string);
> > +          max=current;
> > +        }
> > +      else if (grub_strcmp (current_string, orig) == 0)
> > +        {
> > +          grub_free(current_string);
> > +          return grub_gettext_gettranslation_number (current);
> > +        }
> > +    current = (max+min)/2;
> > +    }
> > +
> > +  ret = grub_malloc(grub_strlen(orig) + 1);
> > +  grub_strcpy(ret,orig);
> > +  return ret;
> > +}
> > +
> > +// XXX: Return a real grub_err_t or static void
> > +static grub_err_t
> > +grub_cmd_translate (struct grub_arg_list *state __attribute__ ((unused)),
> > +           int argc __attribute__ ((unused)),
> > +           char **args __attribute__ ((unused)))
> > +{
> > +  if (argc != 1)
> > +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "text to translate 
> > required");
> > +
> > +  char *translation;
> > +
> > +  translation = grub_gettext_translate(args[0]);
> > +  grub_printf("%s\n",translation);
> > +  //grub_printf("grub__: %d\n",grub__);
> > +
> > +  return 0;
> > +}
> > +
> > +/* This is similar to grub_gzfile_open. */
> > +static grub_file_t
> > +grub_mofile_open (const char *filename)
> > +{
> > +  int unsigned magic;
> > +  int version;
> > +
> > +  /* Using fd_mo and not another variable because
> > +     it's needed for grub_gettext_get_info.  */
> > +
> > +  fd_mo = grub_file_open (filename);
> > +  if (! fd_mo)
> > +    {
> > +      grub_error (GRUB_ERR_FILE_READ_ERROR, "Cannot read %s",filename);
> > +      return 0;
> > +    }
> > +
> > +  magic = grub_gettext_get_info (GETTEXT_MAGIC_NUMBER);
> > +
> > +  if (magic != 0x950412de)
> > +    {
> > +      grub_error (GRUB_ERR_BAD_FILE_TYPE, "mo: invalid mo file: %s", 
> > filename);
> > +      grub_file_close (fd_mo);
> > +      fd_mo = 0;
> > +      return 0;
> > +    }
> > +  
> > +  version = grub_gettext_get_info (GETTEXT_FILE_FORMAT);
> > +
> > +  if (version != 0)
> > +    {
> > +      grub_error (GRUB_ERR_BAD_FILE_TYPE, "mo: invalid mo version in file: 
> > %s", filename);
> > +      fd_mo = 0;
> > +      return 0;
> > +    }
> > +  
> > +  /*
> > +  Do we want .mo.gz files? Then, the code:
> > +  file = grub_gzio_open (io, 0); // 0: transparent
> > +  if (! file)
> > +    {
> > +      grub_printf("Problems opening the file\n");
> > +      grub_file_close (io);
> > +      return 0;
> > +    }
> > +  */
> > +
> > +  return fd_mo;
> > +}
> > +
> > +static void
> > +grub_gettext_init_ext (const char *lang)
> > +{
> > +  char *mo_file;
> > +  char *locale_prefix;
> > +
> > +  locale_prefix = grub_env_get ("locale_prefix");
> > +  
> > +  fd_mo = 0;
> > +      
> > +  // mo_file e.g.: /usr/share/locale/ca/LC_MESSAGES/grub.mo
> > +
> > +  mo_file = grub_malloc (grub_strlen (locale_prefix) + sizeof ("/") + 
> > grub_strlen (lang) + sizeof ("/LC_MESSAGES/grub.mo"));
> > +      
> > +  if (! mo_file)
> > +    return;
> > +
> > +  grub_sprintf (mo_file, "%s/%s/LC_MESSAGES/grub.mo", locale_prefix, lang);
> > +  /* XXX: lang is written by the user, need to sanitaze the input?  */
> > +
> > +  fd_mo = grub_mofile_open(mo_file);
> > +  grub_free (mo_file);
> > +
> > +  if (fd_mo)
> > +    {
> > +      grub_gettext_offsetoriginal = 
> > grub_gettext_get_info(GETTEXT_OFFSET_ORIGINAL);
> > +      grub_gettext_max = grub_gettext_get_info(GETTEXT_NUMBER_OF_STRINGS);
> > +
> > +      grub_gettext_original = grub_gettext;
> > +      grub_gettext = grub_gettext_translate;
> > +    }
> > +}
> > +
> > +static char*
> > +grub_gettext_env_write_lang (struct grub_env_var *var __attribute__ 
> > ((unused)),
> > +                        const char *val)
> > +{
> > +  grub_gettext_init_ext (val);
> > +
> > +  return grub_strdup (val);
> > +}
> > +
> > +GRUB_MOD_INIT(gettext)
> > +{
> > +  (void)mod;                       /* To stop warning.  */
> > + 
> > +  const char *lang;
> > +
> > +  lang = grub_env_get ("lang"); 
> > +
> > +  grub_gettext_init_ext (lang);
> > +
> > +  /* Testing:
> > +  grub_register_command ("_", grub_cmd_translate, GRUB_COMMAND_FLAG_BOTH,
> > +                    "_", "internalization support trans", 0);
> > +  */
> > +
> > +  /* Reload .mo file information if lang changes.  */
> > +  grub_register_variable_hook ("lang", NULL, grub_gettext_env_write_lang);
> > +
> > +  /* Preserve hooks after context changes.  */
> > +  grub_env_export ("lang");
> > +}
> > +
> > +GRUB_MOD_FINI(gettext)
> > +{
> > +  if (fd_mo != 0)
> > +    grub_file_close(fd_mo);
> > +
> > +  grub_gettext = grub_gettext_original;
> > +}
> > Index: normal/menu.c
> > ===================================================================
> > --- normal/menu.c   (revision 1952)
> > +++ normal/menu.c   (working copy)
> > @@ -87,17 +87,16 @@
> >      }
> >    else
> >      {
> > -      grub_printf ("\n\
> > -      Use the %C and %C keys to select which entry is highlighted.\n",
> > +      grub_printf (_("\n\
> > +      Use the %C and %C keys to select which entry is highlighted.\n"),
> >                (grub_uint32_t) GRUB_TERM_DISP_UP, (grub_uint32_t) 
> > GRUB_TERM_DISP_DOWN);
> > -      grub_printf ("\
> > +      grub_printf (_("\
> >        Press enter to boot the selected OS, \'e\' to edit the\n\
> > -      commands before booting or \'c\' for a command-line.");
> > +      commands before booting or \'c\' for a command-line."));
> >        if (nested)
> >     grub_printf ("\n\
> >        ESC to return previous menu.");
> >      }
> > -  
> >  }
> >  
> >  static grub_menu_entry_t
> > @@ -317,7 +316,7 @@
> >       They are required to clear the line.  */
> >    char *msg = "   The highlighted entry will be booted automatically in 
> > %ds.    ";
> >    char *msg_end = grub_strchr (msg, '%');
> > -  
> > +
> >    grub_gotoxy (second_stage ? (msg_end - msg) : 0, GRUB_TERM_HEIGHT - 3);
> >    grub_printf (second_stage ? msg_end : msg, timeout);
> >    grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
> > Index: util/grub.d/10_linux.in
> > ===================================================================
> > --- util/grub.d/10_linux.in (revision 1952)
> > +++ util/grub.d/10_linux.in (working copy)
> > @@ -20,6 +20,7 @@
> >  address@hidden@
> >  address@hidden@
> >  . ${libdir}/grub/grub-mkconfig_lib
> > +. ${libdir}/grub/grub-gettext_lib
> >  
> >  if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
> >    OS=GNU/Linux
> > @@ -139,7 +140,7 @@
> >  EOF
> >  
> >    cat << EOF
> > -menuentry "${OS}, linux ${version} (single-user mode)" {
> > +menuentry "$(eval_gettext '${OS}, linux ${version} (single-user mode)')" {
> >  EOF
> >    prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/"
> >    cat << EOF
> > Index: util/grub.d/00_header.in
> > ===================================================================
> > --- util/grub.d/00_header.in        (revision 1952)
> > +++ util/grub.d/00_header.in        (working copy)
> > @@ -22,6 +22,7 @@
> >  address@hidden@
> >  address@hidden@
> >  grub_prefix=`echo /boot/grub | sed ${transform}`
> > +locale_prefix="/usr/share/locale" # TODO: dynamic with exec_prefix ?
> >  
> >  . ${libdir}/grub/grub-mkconfig_lib
> >  
> > @@ -112,3 +113,17 @@
> >  EOF
> >    ;;
> >  esac
> > +
> > +if test -e ${grub_prefix}/gettext.mod ; then
> > +  # Make the locales accesible
> > +  prepare_grub_to_access_device `${grub_probe} --target=device 
> > ${locale_prefix}`
> > +  lang=`get_locale_lang`
> > +  cat << EOF
> > +if `make_system_path_relative_to_its_root ${locale_prefix}` ; then
> > +  set locale_prefix=${locale_prefix}
> > +  set lang=${lang}
> > +  insmod gettext 
> > +EOF
> > +else
> > +  echo "gettext module is not available"
> > +fi
> > Index: util/grub-mkconfig_lib.in
> > ===================================================================
> > --- util/grub-mkconfig_lib.in       (revision 1952)
> > +++ util/grub-mkconfig_lib.in       (working copy)
> > @@ -176,3 +176,14 @@
> >    fi
> >    return 0
> >  }
> > +
> > +get_locale_lang ()
> > +{
> > +  lang="`echo ${LANG} | cut -d _ -f 1`"
> > +  if [ "x${lang}" = "x" ] ; then
> > +    return 1
> > +  else
> > +    echo "${lang}"
> > +    return 0
> > +  fi
> > +}
> > Index: util/grub-gettext_lib.in
> > ===================================================================
> > --- util/grub-gettext_lib.in        (revision 0)
> > +++ util/grub-gettext_lib.in        (revision 0)
> > @@ -0,0 +1,23 @@
> > +# Configuration of grub-gettext
> > +# Copyright (C) 2009  Free Software Foundation, Inc.
> > +#
> > +# GRUB is free software: you can redistribute it and/or modify
> > +# it under the terms of the GNU General Public License as published by
> > +# the Free Software Foundation, either version 3 of the License, or
> > +# (at your option) any later version.
> > +#
> > +# GRUB is distributed in the hope that it will be useful,
> > +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > +# GNU General Public License for more details.
> > +#
> > +# You should have received a copy of the GNU General Public License
> > +# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> > +
> > address@hidden@
> > address@hidden@
> > address@hidden@
> > +
> > address@hidden@/share/locale
> > +TEXTDOMAIN=grub
> > +. gettext.sh
> > 
> > Property changes on: util/grub-gettext_lib.in
> > ___________________________________________________________________
> > Added: svn:mergeinfo
> > 
> 
> > _______________________________________________
> > Grub-devel mailing list
> > address@hidden
> > http://lists.gnu.org/mailman/listinfo/grub-devel
> 
> -- 
> Carles Pina i Estany          GPG id: 0x17756391
>       http://pinux.info

> Index: Makefile.in
> ===================================================================
> --- Makefile.in       (revision 1954)
> +++ Makefile.in       (working copy)
> @@ -112,6 +112,7 @@
>  PKGDATA = $(pkgdata_DATA) $(pkgdata_SRCDIR)
>  PROGRAMS = $(bin_UTILITIES) $(sbin_UTILITIES)
>  SCRIPTS = $(bin_SCRIPTS) $(sbin_SCRIPTS) $(grub-mkconfig_SCRIPTS)
> +GRUBD = $(srcdir)/util/grub.d
>  
>  CLEANFILES =
>  MOSTLYCLEANFILES = 
> @@ -170,6 +171,11 @@
>  endif
>  endif
>  
> +uptrans:
> +     xgettext -k_ -LC -o - `find "$(srcdir)/" -name '*.c'` -o po/grub.pot
> +     xgettext -k_ -Lshell -o - $(GRUBD)/* -j -o po/grub.pot
> +
> +
>  # Used for building modules externally
>  pkglib_BUILDDIR += build_env.mk
>  build_env.mk: Makefile
> Index: conf/common.rmk
> ===================================================================
> --- conf/common.rmk   (revision 1954)
> +++ conf/common.rmk   (working copy)
> @@ -142,6 +142,12 @@
>  lib_DATA += update-grub_lib
>  CLEANFILES += update-grub_lib
>  
> +grub-gettext_lib: util/grub-gettext_lib.in config.status
> +     ./config.status --file=$@:$<
> +     chmod +x $@
> +lib_DATA += grub-gettext_lib
> +CLEANFILES += grub-gettext_lib
> +
>  %: util/grub.d/%.in config.status
>       ./config.status --file=$@:$<
>       chmod +x $@
> @@ -329,7 +335,7 @@
>       cmp.mod cat.mod help.mod search.mod                                     
> \
>       loopback.mod fs_uuid.mod configfile.mod echo.mod        \
>       terminfo.mod test.mod blocklist.mod hexdump.mod         \
> -     read.mod sleep.mod loadenv.mod crc.mod
> +     read.mod sleep.mod loadenv.mod crc.mod gettext.mod
>  
>  # For hello.mod.
>  hello_mod_SOURCES = hello/hello.c
> @@ -492,3 +498,10 @@
>  bufio_mod_SOURCES = io/bufio.c
>  bufio_mod_CFLAGS = $(COMMON_CFLAGS)
>  bufio_mod_LDFLAGS = $(COMMON_LDFLAGS)
> +
> +# For gettext.mod.
> +gettext_mod_SOURCES = gettext/gettext.c
> +gettext_mod_CFLAGS = $(COMMON_CFLAGS)
> +gettext_mod_LDFLAGS = $(COMMON_LDFLAGS)
> +
> +
> Index: conf/common.mk
> ===================================================================
> --- conf/common.mk    (revision 1954)
> +++ conf/common.mk    (working copy)
> @@ -567,6 +567,12 @@
>  lib_DATA += update-grub_lib
>  CLEANFILES += update-grub_lib
>  
> +grub-gettext_lib: util/grub-gettext_lib.in config.status
> +     ./config.status --file=$@:$<
> +     chmod +x $@
> +lib_DATA += grub-gettext_lib
> +CLEANFILES += grub-gettext_lib
> +
>  %: util/grub.d/%.in config.status
>       ./config.status --file=$@:$<
>       chmod +x $@
> @@ -2366,7 +2372,7 @@
>       cmp.mod cat.mod help.mod search.mod                                     
> \
>       loopback.mod fs_uuid.mod configfile.mod echo.mod        \
>       terminfo.mod test.mod blocklist.mod hexdump.mod         \
> -     read.mod sleep.mod loadenv.mod crc.mod
> +     read.mod sleep.mod loadenv.mod crc.mod gettext.mod
>  
>  # For hello.mod.
>  hello_mod_SOURCES = hello/hello.c
> @@ -4236,3 +4242,62 @@
>  
>  bufio_mod_CFLAGS = $(COMMON_CFLAGS)
>  bufio_mod_LDFLAGS = $(COMMON_LDFLAGS)
> +
> +# For gettext.mod.
> +gettext_mod_SOURCES = gettext/gettext.c
> +CLEANFILES += gettext.mod mod-gettext.o mod-gettext.c pre-gettext.o 
> gettext_mod-gettext_gettext.o und-gettext.lst
> +ifneq ($(gettext_mod_EXPORTS),no)
> +CLEANFILES += def-gettext.lst
> +DEFSYMFILES += def-gettext.lst
> +endif
> +MOSTLYCLEANFILES += gettext_mod-gettext_gettext.d
> +UNDSYMFILES += und-gettext.lst
> +
> +gettext.mod: pre-gettext.o mod-gettext.o $(TARGET_OBJ2ELF)
> +     -rm -f $@
> +     $(TARGET_CC) $(gettext_mod_LDFLAGS) $(TARGET_LDFLAGS) $(MODULE_LDFLAGS) 
> -Wl,-r,-d -o $@ pre-gettext.o mod-gettext.o
> +     if test ! -z $(TARGET_OBJ2ELF); then ./$(TARGET_OBJ2ELF) $@ || (rm -f 
> $@; exit 1); fi
> +     $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -K 
> _grub_mod_init -K _grub_mod_fini -R .note -R .comment $@
> +
> +pre-gettext.o: $(gettext_mod_DEPENDENCIES) gettext_mod-gettext_gettext.o
> +     -rm -f $@
> +     $(TARGET_CC) $(gettext_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ 
> gettext_mod-gettext_gettext.o
> +
> +mod-gettext.o: mod-gettext.c
> +     $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(gettext_mod_CFLAGS) 
> -c -o $@ $<
> +
> +mod-gettext.c: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh
> +     sh $(srcdir)/genmodsrc.sh 'gettext' $< > $@ || (rm -f $@; exit 1)
> +
> +ifneq ($(gettext_mod_EXPORTS),no)
> +def-gettext.lst: pre-gettext.o
> +     $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 gettext/' > $@
> +endif
> +
> +und-gettext.lst: pre-gettext.o
> +     echo 'gettext' > $@
> +     $(NM) -u -P -p $< | cut -f1 -d' ' >> $@
> +
> +gettext_mod-gettext_gettext.o: gettext/gettext.c 
> $(gettext/gettext.c_DEPENDENCIES)
> +     $(TARGET_CC) -Igettext -I$(srcdir)/gettext $(TARGET_CPPFLAGS)  
> $(TARGET_CFLAGS) $(gettext_mod_CFLAGS) -MD -c -o $@ $<
> +-include gettext_mod-gettext_gettext.d
> +
> +CLEANFILES += cmd-gettext_mod-gettext_gettext.lst 
> fs-gettext_mod-gettext_gettext.lst partmap-gettext_mod-gettext_gettext.lst
> +COMMANDFILES += cmd-gettext_mod-gettext_gettext.lst
> +FSFILES += fs-gettext_mod-gettext_gettext.lst
> +PARTMAPFILES += partmap-gettext_mod-gettext_gettext.lst
> +
> +cmd-gettext_mod-gettext_gettext.lst: gettext/gettext.c 
> $(gettext/gettext.c_DEPENDENCIES) gencmdlist.sh
> +     set -e;           $(TARGET_CC) -Igettext -I$(srcdir)/gettext 
> $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(gettext_mod_CFLAGS) -E $<      | sh 
> $(srcdir)/gencmdlist.sh gettext > $@ || (rm -f $@; exit 1)
> +
> +fs-gettext_mod-gettext_gettext.lst: gettext/gettext.c 
> $(gettext/gettext.c_DEPENDENCIES) genfslist.sh
> +     set -e;           $(TARGET_CC) -Igettext -I$(srcdir)/gettext 
> $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(gettext_mod_CFLAGS) -E $<      | sh 
> $(srcdir)/genfslist.sh gettext > $@ || (rm -f $@; exit 1)
> +
> +partmap-gettext_mod-gettext_gettext.lst: gettext/gettext.c 
> $(gettext/gettext.c_DEPENDENCIES) genpartmaplist.sh
> +     set -e;           $(TARGET_CC) -Igettext -I$(srcdir)/gettext 
> $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(gettext_mod_CFLAGS) -E $<      | sh 
> $(srcdir)/genpartmaplist.sh gettext > $@ || (rm -f $@; exit 1)
> +
> +
> +gettext_mod_CFLAGS = $(COMMON_CFLAGS)
> +gettext_mod_LDFLAGS = $(COMMON_LDFLAGS)
> +
> +
> Index: kern/misc.c
> ===================================================================
> --- kern/misc.c       (revision 1954)
> +++ kern/misc.c       (working copy)
> @@ -24,6 +24,8 @@
>  #include <grub/term.h>
>  #include <grub/env.h>
>  
> +const char* (*grub_gettext) (const char *s) = grub_gettext_dummy;
> +
>  void *
>  grub_memmove (void *dest, const void *src, grub_size_t n)
>  {
> @@ -1044,6 +1046,13 @@
>    return p - dest;
>  }
>  
> +/* grub_gettext_dummy is not translating anything.  */
> +const char *
> +grub_gettext_dummy (const char *s)
> +{
> +  return s;
> +}
> +
>  /* Abort GRUB. This function does not return.  */
>  void
>  grub_abort (void)
> Index: po/ca.po
> ===================================================================
> --- po/ca.po  (revision 0)
> +++ po/ca.po  (revision 0)
> @@ -0,0 +1,39 @@
> +# SOME DESCRIPTIVE TITLE.
> +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
> +# This file is distributed under the same license as the PACKAGE package.
> +# FIRST AUTHOR <address@hidden>, YEAR.
> +#
> +#, fuzzy
> +msgid ""
> +msgstr ""
> +"Project-Id-Version: PACKAGE VERSION\n"
> +"Report-Msgid-Bugs-To: \n"
> +"POT-Creation-Date: 2009-01-21 21:14+0100\n"
> +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
> +"Last-Translator: FULL NAME <address@hidden>\n"
> +"Language-Team: LANGUAGE <address@hidden>\n"
> +"MIME-Version: 1.0\n"
> +"Content-Type: text/plain; charset=CHARSET\n"
> +"Content-Transfer-Encoding: 8bit\n"
> +
> +#: normal/menu.c:90
> +#, c-format
> +msgid ""
> +"\n"
> +"      Use the %C and %C keys to select which entry is highlighted.\n"
> +msgstr ""
> +"\n"
> +"      Utilitzeu les tecles %C i %C per seleccionar l'entrada.\n"
> +
> +#: normal/menu.c:93
> +msgid ""
> +"      Press enter to boot the selected OS, 'e' to edit the\n"
> +"      commands before booting or 'c' for a command-line."
> +msgstr ""
> +"      Presioneu retorn per arrancar el SO seleccionat, 'e' editar\n"
> +"      les comandes abans d'arrancar, 'c' per línia d'ordres."
> +
> +#: util/grub.d/10_linux.in:148
> +#, sh-format
> +msgid "${OS}, linux ${version} (single-user mode)"
> +msgstr "${OS}, linux ${version} (mode mono-usuari)"
> Index: po/TODO
> ===================================================================
> --- po/TODO   (revision 0)
> +++ po/TODO   (revision 0)
> @@ -0,0 +1,5 @@
> +Prepare a Makefile.in to:
> +
> +-Compile all .po to .mo (msgfmt $LANG.po -o $LANG.mo)
> +-Copy to /usr/share/locale/$LANG/LC_MESSAGES/grub.mo (or 
> /usr/local/share/locale/$LANG/LC_MESSAGES/..., so $prefix...)
> +-Check that grub-gettext_lib.in is correct
> Index: include/grub/misc.h
> ===================================================================
> --- include/grub/misc.h       (revision 1954)
> +++ include/grub/misc.h       (working copy)
> @@ -31,6 +31,8 @@
>  /* XXX: If grub_memmove is too slow, we must implement grub_memcpy.  */
>  #define grub_memcpy(d,s,n)   grub_memmove ((d), (s), (n))
>  
> +#define _(s) grub_gettext(s)
> +
>  void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t n);
>  char *EXPORT_FUNC(grub_strcpy) (char *dest, const char *src);
>  char *EXPORT_FUNC(grub_strncpy) (char *dest, const char *src, int c);
> @@ -84,6 +86,9 @@
>  grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n,
>                                         grub_uint32_t d, grub_uint32_t *r);
>  
> +const char *EXPORT_FUNC(grub_gettext_dummy) (const char *s);
> +extern const char *(*EXPORT_VAR(grub_gettext)) (const char *s);// = 
> grub_gettext_dummy;
> +
>  #ifdef NEED_ENABLE_EXECUTE_STACK
>  void EXPORT_FUNC(__enable_execute_stack) (void *addr);
>  #endif
> Index: gettext/gettext.c
> ===================================================================
> --- gettext/gettext.c (revision 0)
> +++ gettext/gettext.c (revision 0)
> @@ -0,0 +1,300 @@
> +/* gettext.c - gettext module */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2009 Free Software Foundation, Inc.
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/types.h>
> +#include <grub/misc.h>
> +#include <grub/mm.h>
> +#include <grub/err.h>
> +#include <grub/dl.h>
> +#include <grub/normal.h>
> +#include <grub/file.h>
> +#include <grub/kernel.h>
> +
> +/* 
> +   .mo file information from: 
> +   http://www.gnu.org/software/autoconf/manual/gettext/MO-Files.html .
> +*/
> +
> +
> +static grub_file_t grub_mofile_open (const char *name);
> +static grub_file_t fd_mo;
> +
> +static int grub_gettext_offsetoriginal;
> +static int grub_gettext_max;
> +
> +static const char* (*grub_gettext_original) (const char *s);
> +
> +#define GETTEXT_MAGIC_NUMBER 0
> +#define GETTEXT_FILE_FORMAT 4
> +#define GETTEXT_NUMBER_OF_STRINGS 8
> +#define GETTEXT_OFFSET_ORIGINAL 12
> +#define GETTEXT_OFFSET_TRANSLATION 16
> +
> +static int
> +grub_gettext_get_info (int offset)
> +{
> +  int buf;
> +
> +  grub_file_seek (fd_mo, offset);
> +  grub_file_read (fd_mo, (char*) &buf, 4);
> +  return buf;
> +}
> +
> +static void
> +grub_gettext_getstring_from_offset (int offset, int length, char 
> *translation)
> +{
> +  grub_file_seek (fd_mo,offset);
> +  grub_file_read (fd_mo,translation,length);
> +  translation[length] = '\0';
> +}
> +
> +static char*
> +grub_gettext_gettranslation_number (int i)
> +{
> +  int offsettranslation;
> +  int position;
> +  int length, offset;
> +  char *translation;
> +
> +  offsettranslation = grub_gettext_get_info (GETTEXT_OFFSET_TRANSLATION);
> +
> +  position=offsettranslation+i*8;
> +
> +  grub_file_seek (fd_mo, position);
> +  grub_file_read (fd_mo, (char*) &length, 4);
> +  
> +  grub_file_seek (fd_mo, position + 4),
> +  grub_file_read (fd_mo, (char*) &offset, 4);
> +
> +  translation = grub_malloc(length + 1);
> +  grub_gettext_getstring_from_offset (offset, length, translation);
> +
> +  return translation;
> +}
> +
> +static char*
> +grub_gettext_getstring_num (int num)
> +{
> +  int position;
> +  int length, offset;
> +  char *original;
> +
> +  /* Get position for string i.  */
> +  position = grub_gettext_offsetoriginal + (num * 8);
> +
> +  /* Get the length of the string i.  */
> +  grub_file_seek (fd_mo, position);
> +  grub_file_read (fd_mo, (char *) &length, 4);
> +
> +  /* Get the offset of the string i.  */
> +  grub_file_seek (fd_mo, position + 4);
> +  grub_file_read (fd_mo, (char *) &offset, 4);
> +
> +  /* Get the string i.  */
> +  original = grub_malloc (length + 1);
> +  grub_gettext_getstring_from_offset (offset, length, original);
> +
> +  return original;
> +}
> +
> +static const char*
> +grub_gettext_translate (const char *orig)
> +{
> +  char *current_string;
> +  char *ret;
> +
> +  int min,max,current;
> +
> +  if (fd_mo == 0)
> +    return orig;
> +
> +  min = 0;
> +  max = grub_gettext_max;
> +
> +  current = (max + min) / 2;
> +
> +  while (current != min && current != max)
> +    {
> +      current_string = grub_gettext_getstring_num (current);
> +      /* grub_printf("Current: %s\n",current_string);  */
> +
> +      /* Search by bissection.  */
> +      if (grub_strcmp (current_string, orig) < 0)
> +        {
> +          grub_free(current_string);
> +          min=current;
> +        }
> +      else if (grub_strcmp (current_string, orig) > 0)
> +        {
> +          grub_free(current_string);
> +          max=current;
> +        }
> +      else if (grub_strcmp (current_string, orig) == 0)
> +        {
> +          grub_free(current_string);
> +          return grub_gettext_gettranslation_number (current);
> +        }
> +    current = (max+min)/2;
> +    }
> +
> +  ret = grub_malloc(grub_strlen(orig) + 1);
> +  grub_strcpy(ret,orig);
> +  return ret;
> +}
> +
> +// XXX: Return a real grub_err_t or static void
> +/*static grub_err_t
> +grub_cmd_translate (struct grub_arg_list *state __attribute__ ((unused)),
> +             int argc __attribute__ ((unused)),
> +             char **args __attribute__ ((unused)))
> +{
> +  if (argc != 1)
> +    return grub_error (GRUB_ERR_BAD_ARGUMENT, "text to translate required");
> +
> +  char *translation;
> +
> +  translation = grub_gettext_translate(args[0]);
> +  grub_printf("%s\n",translation);
> +  //grub_printf("grub__: %d\n",grub__);
> +
> +  return 0;
> +}
> +*/
> +
> +/* This is similar to grub_gzfile_open. */
> +static grub_file_t
> +grub_mofile_open (const char *filename)
> +{
> +  int unsigned magic;
> +  int version;
> +
> +  /* Using fd_mo and not another variable because
> +     it's needed for grub_gettext_get_info.  */
> +
> +  fd_mo = grub_file_open (filename);
> +  if (! fd_mo)
> +    {
> +      grub_error (GRUB_ERR_FILE_READ_ERROR, "Cannot read %s",filename);
> +      return 0;
> +    }
> +
> +  magic = grub_gettext_get_info (GETTEXT_MAGIC_NUMBER);
> +
> +  if (magic != 0x950412de)
> +    {
> +      grub_error (GRUB_ERR_BAD_FILE_TYPE, "mo: invalid mo file: %s", 
> filename);
> +      grub_file_close (fd_mo);
> +      fd_mo = 0;
> +      return 0;
> +    }
> +  
> +  version = grub_gettext_get_info (GETTEXT_FILE_FORMAT);
> +
> +  if (version != 0)
> +    {
> +      grub_error (GRUB_ERR_BAD_FILE_TYPE, "mo: invalid mo version in file: 
> %s", filename);
> +      fd_mo = 0;
> +      return 0;
> +    }
> +  
> +  /*
> +  Do we want .mo.gz files? Then, the code:
> +  file = grub_gzio_open (io, 0); // 0: transparent
> +  if (! file)
> +    {
> +      grub_printf("Problems opening the file\n");
> +      grub_file_close (io);
> +      return 0;
> +    }
> +  */
> +
> +  return fd_mo;
> +}
> +
> +static void
> +grub_gettext_init_ext (const char *lang)
> +{
> +  char *mo_file;
> +  char *locale_prefix;
> +
> +  locale_prefix = grub_env_get ("locale_prefix");
> +  
> +  fd_mo = 0;
> +      
> +  // mo_file e.g.: /usr/share/locale/ca/LC_MESSAGES/grub.mo
> +
> +  mo_file = grub_malloc (grub_strlen (locale_prefix) + sizeof ("/") + 
> grub_strlen (lang) + sizeof ("/LC_MESSAGES/grub.mo"));
> +      
> +  if (! mo_file)
> +    return;
> +
> +  grub_sprintf (mo_file, "%s/%s/LC_MESSAGES/grub.mo", locale_prefix, lang);
> +  /* XXX: lang is written by the user, need to sanitaze the input?  */
> +
> +  fd_mo = grub_mofile_open(mo_file);
> +  grub_free (mo_file);
> +
> +  if (fd_mo)
> +    {
> +      grub_gettext_offsetoriginal = 
> grub_gettext_get_info(GETTEXT_OFFSET_ORIGINAL);
> +      grub_gettext_max = grub_gettext_get_info(GETTEXT_NUMBER_OF_STRINGS);
> +
> +      grub_gettext_original = grub_gettext;
> +      grub_gettext = grub_gettext_translate;
> +    }
> +}
> +
> +static char*
> +grub_gettext_env_write_lang (struct grub_env_var *var __attribute__ 
> ((unused)),
> +                          const char *val)
> +{
> +  grub_gettext_init_ext (val);
> +
> +  return grub_strdup (val);
> +}
> +
> +GRUB_MOD_INIT(gettext)
> +{
> +  (void)mod;                 /* To stop warning.  */
> + 
> +  const char *lang;
> +
> +  lang = grub_env_get ("lang"); 
> +
> +  grub_gettext_init_ext (lang);
> +
> +  /* Testing:
> +  grub_register_command ("_", grub_cmd_translate, GRUB_COMMAND_FLAG_BOTH,
> +                      "_", "internalization support trans", 0);
> +  */
> +
> +  /* Reload .mo file information if lang changes.  */
> +  grub_register_variable_hook ("lang", NULL, grub_gettext_env_write_lang);
> +
> +  /* Preserve hooks after context changes.  */
> +  grub_env_export ("lang");
> +}
> +
> +GRUB_MOD_FINI(gettext)
> +{
> +  if (fd_mo != 0)
> +    grub_file_close(fd_mo);
> +
> +  grub_gettext = grub_gettext_original;
> +}
> Index: normal/menu.c
> ===================================================================
> --- normal/menu.c     (revision 1954)
> +++ normal/menu.c     (working copy)
> @@ -87,12 +87,12 @@
>      }
>    else
>      {
> -      grub_printf ("\n\
> -      Use the %C and %C keys to select which entry is highlighted.\n",
> +      grub_printf (_("\n\
> +      Use the %C and %C keys to select which entry is highlighted.\n"),
>                  (grub_uint32_t) GRUB_TERM_DISP_UP, (grub_uint32_t) 
> GRUB_TERM_DISP_DOWN);
> -      grub_printf ("\
> +      grub_printf (_("\
>        Press enter to boot the selected OS, \'e\' to edit the\n\
> -      commands before booting or \'c\' for a command-line.");
> +      commands before booting or \'c\' for a command-line."));
>        if (nested)
>       grub_printf ("\n\
>        ESC to return previous menu.");
> Index: util/grub.d/10_linux.in
> ===================================================================
> --- util/grub.d/10_linux.in   (revision 1954)
> +++ util/grub.d/10_linux.in   (working copy)
> @@ -20,6 +20,7 @@
>  address@hidden@
>  address@hidden@
>  . ${libdir}/grub/grub-mkconfig_lib
> +. ${libdir}/grub/grub-gettext_lib
>  
>  if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
>    OS=GNU/Linux
> @@ -139,7 +140,7 @@
>  EOF
>  
>    cat << EOF
> -menuentry "${OS}, linux ${version} (single-user mode)" {
> +menuentry "$(eval_gettext '${OS}, linux ${version} (single-user mode)')" {
>  EOF
>    prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/"
>    cat << EOF
> Index: util/grub.d/00_header.in
> ===================================================================
> --- util/grub.d/00_header.in  (revision 1954)
> +++ util/grub.d/00_header.in  (working copy)
> @@ -22,6 +22,7 @@
>  address@hidden@
>  address@hidden@
>  grub_prefix=`echo /boot/grub | sed ${transform}`
> +locale_prefix="/usr/share/locale" # TODO: dynamic with exec_prefix ?
>  
>  . ${libdir}/grub/grub-mkconfig_lib
>  
> @@ -112,3 +113,18 @@
>  EOF
>    ;;
>  esac
> +
> +if test -e ${grub_prefix}/gettext.mod ; then
> +  # Make the locales accesible
> +  prepare_grub_to_access_device `${grub_probe} --target=device 
> ${locale_prefix}`
> +  lang=`get_locale_lang`
> +  cat << EOF
> +if `make_system_path_relative_to_its_root ${locale_prefix}` ; then
> +  set locale_prefix=${locale_prefix}
> +  set lang=${lang}
> +  insmod gettext 
> +fi
> +EOF
> +else
> +  echo "gettext module is not available"
> +fi
> Index: util/grub-mkconfig_lib.in
> ===================================================================
> --- util/grub-mkconfig_lib.in (revision 1954)
> +++ util/grub-mkconfig_lib.in (working copy)
> @@ -176,3 +176,14 @@
>    fi
>    return 0
>  }
> +
> +get_locale_lang ()
> +{
> +  lang="`echo ${LANG} | cut -d _ -f 1`"
> +  if [ "x${lang}" = "x" ] ; then
> +    return 1
> +  else
> +    echo "${lang}"
> +    return 0
> +  fi
> +}
> Index: util/grub-gettext_lib.in
> ===================================================================
> --- util/grub-gettext_lib.in  (revision 0)
> +++ util/grub-gettext_lib.in  (revision 0)
> @@ -0,0 +1,23 @@
> +# Configuration of grub-gettext
> +# Copyright (C) 2009  Free Software Foundation, Inc.
> +#
> +# GRUB is free software: you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation, either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# GRUB is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> +
> address@hidden@
> address@hidden@
> address@hidden@
> +
> address@hidden@/share/locale
> +TEXTDOMAIN=grub
> +. gettext.sh
> 
> Property changes on: util/grub-gettext_lib.in
> ___________________________________________________________________
> Added: svn:mergeinfo
> 

> _______________________________________________
> Grub-devel mailing list
> address@hidden
> http://lists.gnu.org/mailman/listinfo/grub-devel

-- 
Carles Pina i Estany            GPG id: 0x17756391
        http://pinux.info




reply via email to

[Prev in Thread] Current Thread [Next in Thread]