Hello,

On Jun/17/2009, Vladimir 'phcoder' Serbinenko wrote:
> Hello
> 
> 
> > Comments for next steps to commit the patch are welcomed.
> 
> Quick look revealed that you haven't taken into account my comments exposed
> here:  http://lists.gnu.org/archive/html/grub-devel/2009-04/msg00181.html

I will copy-paste your comments and my reply with the attached patch.
I will comment only the concerns about things that are not about the
building system (this will come in another mail)

http://lists.gnu.org/archive/html/grub-devel/2009-04/msg00181.html

(double quote is me, single quote is vladimir)

> >         -Copy ca.mo to /usr/share/locale/ca/LC_MESSAGES/grub.mo 
> 
> Languages files should go to a subdir of $PREFIX. E.g. to
> $PREFIX/langs/$LANG.mo linux directories may be inaccessible 

Now the gettext module will search in $prefix/locale/lang.mo, where lang
is the variable that the user will setup in grub.cfg (e.g. ca for
catalan) and $prefix is usually /boot/grub

> > -I have seen that Grub2 is not printing correctly the accents,
> > could be a problem in gettext or in some other layer
> 
> Did you load unifont as your font? Are you in gfxterm mode? Plain pc
> console can't output unicode characters because it uses fixed-width
> 8-bit font. Perhaps loading the characters most useful for current
> languages to the upper 128 characters would be an option. OR we can just
> tell everyone to use gfxterm 

It's working fine, it was a problem generating the .mo file (I didnt'
setup the correct charset)

> > Index: gettext/gettext.c
> > ===================================================================
> > --- gettext/gettext.c   (revision 0)
> > +++ gettext/gettext.c   (revision 0)
> > +static int
> > +grub_gettext_get_info (int offset)
> > +{
> > +  int buf;

> Use grub_uint32_t here. Also be aware of endianness. It should be

Done!

> >grub_gettext_translation_number is a bit a misnomer because this name
> > would suggest transforming translation into number 

change from grub_gettext_translation_number (int i) to
grub_gettext_translation_from_position (int position) 
Don't confuse the string in position "N" with the position (in bytes) of
the string inside the file (called internal_position). I'm still not
happy with the names...

> > +  position=offsettranslation+i*8;
> Please respect GCS. This should be position = offsettranslation + i *
> 8; 

Done!

> > +  ret = grub_malloc(grub_strlen(orig) + 1);
> > +  grub_strcpy(ret,orig);
> > +  return ret;
> This would fail if the string isn't present at all in .mo 

I think that it's fine. If the string is in the .mo file, it will return
before:
      else if (grub_strcmp (current_string, orig) == 0)
        {
          grub_free(current_string);
          return grub_gettext_gettranslation_from_position (current);
        }

If we don't find the string, it will return the string that we wanted to
translate (orig is the original string).
So if grub tries to translate something that it's not in the .mo file we
will return the same string.

> >         + if (magic != 0x950412de) 
> A define instead of hardcoded number is suggested 

Done!

> >         + locale_prefix = grub_env_get ("locale_prefix"); 
> You need to treat the case when no locale_prefix is defined. I suggest
> to put a default $prefix/locale 

Done!

> >         +  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?  */

> I suggest
> grub_sprintf (mo_file, "%s/%s.mo", locale_prefix, lang);
> because .mo need to reside together with grub so all LC_MESSAGE is just
> unnecessary

Your way is easier. Previous way was talked with Robert, but then it
still needed some work in grub.cfg to detect the directory and in my
opinion is quite clear to have all grub stuff all together.

I send attached the patch. I will comment things that executes outside
grub environment (so, during the installation) in some other mail.

Thanks for all feedback and sorry to take so long to answer :-)

-- 
Carles Pina i Estany
        http://pinux.info
Index: conf/common.rmk
===================================================================
--- conf/common.rmk	(revision 2343)
+++ conf/common.rmk	(working copy)
@@ -154,6 +154,12 @@
 lib_SCRIPTS += 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 $@
@@ -354,7 +360,7 @@
 	terminfo.mod test.mod blocklist.mod hexdump.mod		\
 	read.mod sleep.mod loadenv.mod crc.mod parttool.mod	\
 	pcpart.mod memrw.mod normal.mod sh.mod lua.mod	\
-	gptsync.mod true.mod probe.mod
+	gptsync.mod true.mod probe.mod gettext.mod
 
 # For gptsync.mod.
 gptsync_mod_SOURCES = commands/gptsync.c
@@ -586,6 +592,11 @@
 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)
+
 # Misc.
 pkglib_MODULES += xnu_uuid.mod
 
Index: kern/misc.c
===================================================================
--- kern/misc.c	(revision 2343)
+++ 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)
 {
@@ -1080,6 +1082,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,25 @@
+#: 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:143
+#, sh-format
+msgid "${OS}, linux ${version} (recovery mode)"
+msgstr "${OS}, linux ${version} (mode recuperació)"
+
+#, sh-format
+msgid "hello"
+msgstr "hola"
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 2343)
+++ include/grub/misc.h	(working copy)
@@ -1,7 +1,7 @@
 /* misc.h - prototypes for misc functions */
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2002,2003,2005,2006,2007,2008,2009,2008  Free Software Foundation, Inc.
+ *  Copyright (C) 2002,2003,2005,2006,2007,2008,2009,2008,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
@@ -32,6 +32,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);
@@ -97,6 +99,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,285 @@
+/* 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
+
+#define MO_MAGIC_NUMBER 0x950412de
+
+static grub_uint32_t
+grub_gettext_get_info (int offset)
+{
+  grub_uint32_t value;
+
+  grub_file_seek (fd_mo, offset);
+  grub_file_read (fd_mo, (char*) &value, 4);
+  value = grub_cpu_to_le32 (value);
+  return value;
+}
+
+static void
+grub_gettext_getstring_from_offset (grub_uint32_t offset, grub_uint32_t length, char *translation)
+{
+  grub_file_seek (fd_mo, offset);
+  grub_file_read (fd_mo, translation, length);
+  translation[length] = '\0';
+}
+
+static char*
+grub_gettext_gettranslation_from_position (int position)
+{
+  int offsettranslation;
+  int internal_position;
+  grub_uint32_t length, offset;
+  char *translation;
+
+  offsettranslation = grub_gettext_get_info (GETTEXT_OFFSET_TRANSLATION);
+
+  internal_position = offsettranslation + position * 8;
+
+  grub_file_seek (fd_mo, internal_position);
+  grub_file_read (fd_mo, (char*) &length, 4);
+  length = grub_cpu_to_le32 (length);
+  
+  grub_file_seek (fd_mo, internal_position + 4),
+  grub_file_read (fd_mo, (char*) &offset, 4);
+  offset = grub_cpu_to_le32 (offset);
+
+  translation = grub_malloc(length + 1);
+  grub_gettext_getstring_from_offset (offset, length, translation);
+
+  return translation;
+}
+
+static char*
+grub_gettext_getstring_from_position (int position)
+{
+  int internal_position;
+  int length, offset;
+  char *original;
+
+  /* Get position for string i.  */
+  internal_position = grub_gettext_offsetoriginal + (position * 8);
+
+  /* Get the length of the string i.  */
+  grub_file_seek (fd_mo, internal_position);
+  grub_file_read (fd_mo, (char *) &length, 4);
+
+  /* Get the offset of the string i.  */
+  grub_file_seek (fd_mo, internal_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_from_position (current);
+
+      /* Search by bisection.  */
+      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_from_position (current);
+        }
+    current = (max+min)/2;
+    }
+
+  ret = grub_malloc(grub_strlen(orig) + 1);
+  grub_strcpy(ret,orig);
+  return ret;
+}
+
+/* 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 != MO_MAGIC_NUMBER)
+    {
+      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 *grub_prefix;
+
+  grub_prefix = grub_env_get ("prefix");
+  
+  fd_mo = 0;
+      
+  // mo_file e.g.: /boot/grub/locale/ca.mo
+
+  mo_file = grub_malloc (grub_strlen (grub_prefix) + sizeof ("/locale/") + grub_strlen (lang) + sizeof(".mo"));
+ 
+  // Warning: if changing some paths in the below line, change the grub_malloc
+  // contents below
+ 
+  grub_sprintf (mo_file, "%s/locale/%s.mo", grub_prefix, lang);
+  grub_dprintf(" -------------- %s ",mo_file);
+
+  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_text.c
===================================================================
--- normal/menu_text.c	(revision 2343)
+++ normal/menu_text.c	(working copy)
@@ -93,8 +93,8 @@
     }
   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 ("\
       Press enter to boot the selected OS, \'e\' to edit the\n\
Index: util/grub.d/10_linux.in
===================================================================
--- util/grub.d/10_linux.in	(revision 2343)
+++ util/grub.d/10_linux.in	(working copy)
@@ -141,10 +141,10 @@
     linux_root_device_thisversion=${GRUB_DEVICE}
   fi
 
-  linux_entry "${OS}, Linux ${version}" \
-      "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
-  linux_entry "${OS}, Linux ${version} (recovery mode)" \
-      "single ${GRUB_CMDLINE_LINUX}"
+  linux_entry $eval_gettext ("${OS}, Linux ${version}" \
+      "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}")
+  linux_entry $eval_gettext ("${OS}, Linux ${version} (recovery mode)" \
+      "single ${GRUB_CMDLINE_LINUX}")
 
   list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '`
 done
Index: util/grub.d/00_header.in
===================================================================
--- util/grub.d/00_header.in	(revision 2343)
+++ 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 -a -d /usr/share/locale; then
+  # Make the locales accesible
+  prepare_grub_to_access_device `${grub_probe} --target=device ${locale_prefix}`
+  lang=`get_locale_lang`
+  grub_locale_prefix=`make_system_path_relative_to_its_root ${locale_prefix}`
+  cat << EOF
+# Gettext variables and module
+set locale_prefix=${grub_locale_prefix}
+set lang=${lang}
+insmod gettext 
+EOF
+else
+  echo "gettext module is not available"
+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

Index: util/grub-mkconfig_lib.in
===================================================================
--- util/grub-mkconfig_lib.in	(revision 2343)
+++ 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
+}
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to