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 <car...@pina.cat>
> 
>         * 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 <em...@address>, 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 <em...@address>\n"
> +"Language-Team: LANGUAGE <l...@li.org>\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 @@
>  exec_pref...@exec_prefix@
>  libd...@libdir@
>  . ${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 @@
>  exec_pref...@exec_prefix@
>  libd...@libdir@
>  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/>.
> +
> +pref...@prefix@
> +exec_pref...@exec_prefix@
> +libd...@libdir@
> +
> +textdomaind...@prefix@/share/locale
> +TEXTDOMAIN=grub
> +. gettext.sh
> 
> Property changes on: util/grub-gettext_lib.in
> ___________________________________________________________________
> Added: svn:mergeinfo
> 

> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> 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 <em...@address>, 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 <em...@address>\n"
+"Language-Team: LANGUAGE <l...@li.org>\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 @@
 exec_pref...@exec_prefix@
 libd...@libdir@
 . ${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 @@
 exec_pref...@exec_prefix@
 libd...@libdir@
 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/>.
+
+pref...@prefix@
+exec_pref...@exec_prefix@
+libd...@libdir@
+
+textdomaind...@prefix@/share/locale
+TEXTDOMAIN=grub
+. gettext.sh

Property changes on: util/grub-gettext_lib.in
___________________________________________________________________
Added: svn:mergeinfo

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

Reply via email to