]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Adds gettext support in Grub. Building system needs to be improved and maybe userland...
authorCarles Pina i Estany <carles@pina.cat>
Fri, 13 Nov 2009 20:39:33 +0000 (20:39 +0000)
committerCarles Pina i Estany <carles@pina.cat>
Fri, 13 Nov 2009 20:39:33 +0000 (20:39 +0000)
YYYY-MM-DD  Carles Pina i Estany <carles@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

conf/common.rmk
gettext/gettext.c [new file with mode: 0644]
include/grub/misc.h
kern/misc.c
normal/menu_text.c
util/grub-gettext_lib.in [new file with mode: 0644]
util/grub-mkconfig_lib.in
util/grub.d/00_header.in
util/grub.d/10_linux.in

index a66bd97fd35afebdf003b14ed2f376ce06b20546..deb18372bc859213f78e89ebf5bf27e912dd0b0c 100644 (file)
@@ -162,6 +162,12 @@ update-grub_lib: util/update-grub_lib.in config.status
 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 $@
@@ -178,7 +184,7 @@ grub-mkconfig_DATA += util/grub.d/README
 pkglib_MODULES += fshelp.mod fat.mod ufs1.mod ufs2.mod ext2.mod ntfs.mod \
        ntfscomp.mod minix.mod hfs.mod jfs.mod iso9660.mod xfs.mod      \
        affs.mod sfs.mod hfsplus.mod reiserfs.mod cpio.mod tar.mod      \
-       udf.mod afs.mod afs_be.mod befs.mod befs_be.mod
+       udf.mod afs.mod afs_be.mod befs.mod befs_be.mod gettext.mod
 
 # For fshelp.mod.
 fshelp_mod_SOURCES = fs/fshelp.c
@@ -609,6 +615,11 @@ 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)
+
 # Misc.
 pkglib_MODULES += xnu_uuid.mod
 
diff --git a/gettext/gettext.c b/gettext/gettext.c
new file mode 100644 (file)
index 0000000..089f59d
--- /dev/null
@@ -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 faa2d5c42ad9c1d3c7cb57979dd347793df969f7..0a3406737904cdf74398f0c52834e0c08a11c2ec 100644 (file)
@@ -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
@@ -34,6 +34,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);
@@ -191,6 +193,9 @@ grub_ssize_t EXPORT_FUNC(grub_utf8_to_ucs4) (grub_uint32_t *dest,
 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 cacfbc7532416d6e6048b75ad80ac061c128c2ba..827f864c44e9732f8646c0b21f7fecbc65881c5f 100644 (file)
@@ -30,6 +30,8 @@ grub_iswordseparator (int c)
   return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&');
 }
 
+const char* (*grub_gettext) (const char *s) = grub_gettext_dummy;
+
 void *
 grub_memmove (void *dest, const void *src, grub_size_t n)
 {
@@ -984,6 +986,13 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize,
   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 e0d96c47f452300be7e433ddb9d0c4f54e141690..e757110c0699a0b663993fba3872c6b308471c62 100644 (file)
@@ -93,8 +93,8 @@ print_message (int nested, int edit)
     }
   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\
diff --git a/util/grub-gettext_lib.in b/util/grub-gettext_lib.in
new file mode 100644 (file)
index 0000000..00d1bdd
--- /dev/null
@@ -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/>.
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+
+TEXTDOMAINDIR=@prefix@/share/locale
+TEXTDOMAIN=grub
+. gettext.sh
index bb30cc4756ccb9bc192275b5623eab3a1f8ec9a8..47e37f265009c9115549c7a20279a734cef9b8df 100644 (file)
@@ -215,3 +215,14 @@ version_find_latest ()
   done
   echo "$a"
 }
+
+get_locale_lang ()
+{
+  lang="`echo ${LANG} | cut -d _ -f 1`"
+  if [ "x${lang}" = "x" ] ; then
+    return 1
+  else
+    echo "${lang}"
+    return 0
+  fi
+}
index 9f421dc1c8f2e8c65ec6aac0ba04416f9b54083e..fe13528832531560da122a9152abae4dac570b90 100644 (file)
@@ -22,6 +22,7 @@ prefix=@prefix@
 exec_prefix=@exec_prefix@
 libdir=@libdir@
 grub_prefix=`echo /boot/grub | sed ${transform}`
+locale_prefix="/usr/share/locale" # TODO: dynamic with exec_prefix ?
 
 . ${libdir}/grub/grub-mkconfig_lib
 
@@ -100,6 +101,21 @@ 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 or /usr/share/locale is not available"
+fi
+
 if [ "x${GRUB_HIDDEN_TIMEOUT}" != "x" ] ; then
   if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then 
     verbose=
index f1795584670ca0b8274adabf3a3e6f81db18e815..9cb39e41c15d725af82b184d13d88db6fa635804 100644 (file)
@@ -95,11 +95,11 @@ while [ "x$list" != "x" ] ; do
     linux_root_device_thisversion=${GRUB_DEVICE}
   fi
 
-  linux_entry "${OS}, with Linux ${version}" \
-      "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
+  linux_entry $eval_gettext ("${OS}, with Linux ${version}" \
+      "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}")
   if [ "x${GRUB_DISABLE_LINUX_RECOVERY}" != "xtrue" ]; then
-    linux_entry "${OS}, with Linux ${version} (recovery mode)" \
-       "single ${GRUB_CMDLINE_LINUX}"
+    linux_entry $eval_gettext ("${OS}, with Linux ${version} (recovery mode)" \
+       "single ${GRUB_CMDLINE_LINUX}")
   fi
 
   list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '`