diff --git a/conf/common.rmk b/conf/common.rmk
index a66bd97fd..deb18372b 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -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
index 000000000..089f59db4
--- /dev/null
+++ b/gettext/gettext.c
@@ -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 .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/*
+ .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;
+}
diff --git a/include/grub/misc.h b/include/grub/misc.h
index faa2d5c42..0a3406737 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -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
diff --git a/kern/misc.c b/kern/misc.c
index cacfbc753..827f864c4 100644
--- a/kern/misc.c
+++ b/kern/misc.c
@@ -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)
diff --git a/normal/menu_text.c b/normal/menu_text.c
index e0d96c47f..e757110c0 100644
--- a/normal/menu_text.c
+++ b/normal/menu_text.c
@@ -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
index 000000000..00d1bdd98
--- /dev/null
+++ b/util/grub-gettext_lib.in
@@ -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 .
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+
+TEXTDOMAINDIR=@prefix@/share/locale
+TEXTDOMAIN=grub
+. gettext.sh
diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
index bb30cc475..47e37f265 100644
--- a/util/grub-mkconfig_lib.in
+++ b/util/grub-mkconfig_lib.in
@@ -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
+}
diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
index 9f421dc1c..fe1352883 100644
--- a/util/grub.d/00_header.in
+++ b/util/grub.d/00_header.in
@@ -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=
diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
index f17955846..9cb39e41c 100644
--- a/util/grub.d/10_linux.in
+++ b/util/grub.d/10_linux.in
@@ -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' ' '`