Adds gettext support in Grub. Building system needs to be improved and maybe userland utilites improved.

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
This commit is contained in:
Carles Pina i Estany 2009-11-13 20:39:33 +00:00
parent 2e035eb9ba
commit 203ffbfa31
9 changed files with 368 additions and 8 deletions

View 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

285
gettext/gettext.c Normal file
View File

@ -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;
}

View 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

View 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)

View 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\

23
util/grub-gettext_lib.in Normal file
View File

@ -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

View 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
}

View 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=

View 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' ' '`