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:
parent
2e035eb9ba
commit
203ffbfa31
9 changed files with 368 additions and 8 deletions
|
@ -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
285
gettext/gettext.c
Normal 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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
23
util/grub-gettext_lib.in
Normal 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
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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' ' '`
|
||||
|
|
Loading…
Reference in a new issue