Hello, Briefly: applied the suggested changes, and new patch attached. Don't hesitate to say anything back (I know that you don't :-) ). Later I will spend some time with it again.
Cheers, On Nov/22/2009, Robert Millan wrote: > On Sat, Nov 21, 2009 at 10:14:10PM +0000, Carles Pina i Estany wrote: > > @@ -179,7 +185,7 @@ > > 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 > > @@ -610,6 +616,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) > > I haven't switched the old declarations, but for new modules please use > something like: > > pkglib_MODULES += gettext.mod > gettext_mod_SOURCES = gettext/gettext.c > gettext_mod_CFLAGS = $(COMMON_CFLAGS) > gettext_mod_LDFLAGS = $(COMMON_LDFLAGS) Done! > this way it is easier to move declarations around, etc. > > > +static grub_file_t grub_mofile_open (const char *name); > > We usually skip declarations for static functions (when all its users are > placed after its implementation, of course). Done! > > +#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 > > These would look much prettier with some tabs ;-) Done! > > + grub_file_seek (fd_mo, offset); > > + grub_file_read (fd_mo, translation, length); > > You do a lot of grub_file_seek + grub_file_read throurough the code. Maybe > grub_file_pread() would be more appropiate? (for space saving) Done! > > + grub_free(current_string); > > + min=current; > > [...] > > + current = (max+min)/2; > > [...] > > + ret = grub_malloc(grub_strlen(orig) + 1); > > + grub_strcpy(ret,orig); > > Missing spaces (between function name and parenthesis, around '=', etc). > > I suggest you use indent(1), this will automatically adjust to our coding > style. used indent, Done! > > + /* > > + 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; > > + } > > + */ > > Uhm I wonder if we could answer this question before the code is merged; what > does everyone think about .mo.gz? > > > + locale_dir = grub_env_get ("locale_dir"); > > This needs to be checked for NULL. Why? If it's NULL it will try to open a .mo file that doesn't exist (probably) and will print the path. So the user will notice that somethiing is missing. I've added a check, grub_printf saying that the variable is not setted up and a return but not sure if this should happen. > > + // mo_file e.g.: /boot/grub/locale/ca.mo > > Please use C-style comments (/* */). Done! > > + mo_file = grub_malloc (grub_strlen (locale_dir) + sizeof ("/") + > > grub_strlen (lang) + sizeof(".mo")); > > Note that sizeof ("/") equals 2 ('/' + '\0'). changed "/" by '/', you are right. Done! > > + grub_dprintf("gettext", "Will try to open file: %s " ,mo_file); > > + > > + fd_mo = grub_mofile_open(mo_file); > > In this case I think error handling would be more useful than debug > print (i.e. if file can't be opened, rise an error). I don't remember the details, but if grub_mofile_open cannot open it it raise an error: fd_mo = grub_file_open (filename); if (!fd_mo) { grub_error (GRUB_ERR_FILE_READ_ERROR, "Cannot read %s", filename); return 0; } and the caller will not do anything if it returns 0. > > + /* Testing: > > + grub_register_command ("_", grub_cmd_translate, GRUB_COMMAND_FLAG_BOTH, > > + "_", "internalization support trans", 0); > > + */ > > We could define this interface unconditionally, but it'd be more consistent > as `gettext' command (like the one in GNU gettext package). We didn't include anything to not populate the standard shell with superflous commands. By the moment I've removed above lines, we can add it later. > > > === added file 'include/grub/i18n_grub.h' > > --- include/grub/i18n_grub.h 1970-01-01 00:00:00 +0000 > > +++ include/grub/i18n_grub.h 2009-11-19 21:32:05 +0000 > > [...] > > +#ifndef GRUB_I18N_GRUB_H > > +#define GRUB_I18N_GRUB_H 1 > > + > > +# define _(str) grub_gettext(str) > > + > > +#endif /* GRUB_I18N_GRUB_H */ > > You can use <grub/i18n.h> for this (in fact it already defines _ to a > noop stub for non-util and would just need to be modified). Changed, I didn't read it properly some days ago. So... Done! > > +const char *EXPORT_FUNC(grub_gettext_dummy) (const char *s); > > +extern const char *(*EXPORT_VAR(grub_gettext)) (const char *s);// = > > grub_gettext_dummy; > > This could be in i18n.h too (except the comment ;-)). > > Btw, is it necessary to export grub_gettext_dummy symbol? If we avoid it > it's a few less bytes in kernel :-) if it's not exported it doesn't compile: kern/misc.c:33: error: 'grub_gettext_dummy' undeclared here (not in a function) > > +# Gettext variables and module > > +cat << EOF > > +set locale_dir=${locale_dir} > > +set lang=${grub_lang} > > +insmod gettext > > +EOF > > We could avoid loading the module at all for non-utf8 capable setups (when > this happens, grub-mkconfig exports LANG=C, so this can be easily detected). Done! -- Carles Pina i Estany http://pinux.info
=== added file 'ChangeLog.gettext' --- ChangeLog.gettext 1970-01-01 00:00:00 +0000 +++ ChangeLog.gettext 2009-11-22 12:40:27 +0000 @@ -0,0 +1,18 @@ +YYYY-MM-DD Carles Pina i Estany <car...@pina.cat> + + * conf/common.rmk: Add grub-gettext_lib target and updates + lib_DATA and CLEANFILES. Adds gettext.mod SOURCES, CFLAGS, + LDFLAGS. + * gettext/gettext.c: New file. (Reads mo files). + * include/grub/file.h (grub_file_pread): New prototype. + * include/grub/i18n.h (_): New prototype. + * include/grub/misc.h (grub_gettext_dummy, grub_gettext): New + prototypes. + * kern/misc.c (grub_gettext_dummy): New function. + * menu/menu_text.c: Include <grub/i18n.h>. + * menu/menu_text.c (print_timeout): Gettexttize string. + * menu/menu_text.c (print_message): Gettexttize string. + * po/POTFILES: Add `normal/menu_text.c'. + * po/ca.po: Add new translations. + * util/grub.d/00_header.in: Define locale_dir and lang. insmod + gettext module and defines locale_dir and lang in grub.cfg. === modified file 'conf/common.rmk' --- conf/common.rmk 2009-11-18 23:05:59 +0000 +++ conf/common.rmk 2009-11-22 12:02:01 +0000 @@ -163,6 +163,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 $@ @@ -610,6 +616,12 @@ bufio_mod_CFLAGS = $(COMMON_CFLAGS) bufio_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For gettext.mod. +pkglib_MODULES += gettext.mod +gettext_mod_SOURCES = gettext/gettext.c +gettext_mod_CFLAGS = $(COMMON_CFLAGS) +gettext_mod_LDFLAGS = $(COMMON_LDFLAGS) + # Misc. pkglib_MODULES += xnu_uuid.mod === added directory 'gettext' === added file 'gettext/gettext.c' --- gettext/gettext.c 1970-01-01 00:00:00 +0000 +++ gettext/gettext.c 2009-11-22 12:44:26 +0000 @@ -0,0 +1,296 @@ +/* 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> +#include <grub/gzio.h> + +/* + .mo file information from: + http://www.gnu.org/software/autoconf/manual/gettext/MO-Files.html . +*/ + + +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_ssize_t +grub_gettext_pread (grub_file_t file, void *buf, grub_size_t len, + grub_off_t offset) +{ + if (grub_file_seek (file, offset) == (grub_off_t) - 1) + { + return -1; + } + return grub_file_read (file, buf, len); +} + +static grub_uint32_t +grub_gettext_get_info (int offset) +{ + grub_uint32_t value; + + grub_gettext_pread (fd_mo, (char *) &value, 4, offset); + + 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_gettext_pread (fd_mo, translation, length, offset); + 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_gettext_pread (fd_mo, (char *) &length, 4, internal_position); + length = grub_cpu_to_le32 (length); + + grub_gettext_pread (fd_mo, (char *) &offset, 4, internal_position + 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_gettext_pread (fd_mo, (char *) &length, 4, internal_position); + + /* Get the offset of the string i. */ + grub_gettext_pread (fd_mo, (char *) &offset, 4, internal_position + 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; + grub_file_t new_fd; + + /* Using fd_mo and not another variable because + it's needed for grub_gettext_get_info. */ + + new_fd = grub_gzfile_open (filename, 1); + grub_errno = GRUB_ERR_NONE; + + if (!new_fd) + { + grub_dprintf ("gettext: Cannot read %s", filename); + return 0; + } + + fd_mo = new_fd; + + 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; + } + + return fd_mo; +} + +static void +grub_gettext_init_ext (const char *lang) +{ + char *mo_file; + char *locale_dir; + + locale_dir = grub_env_get ("locale_dir"); + if (locale_dir == NULL) + { + grub_printf ("locale_dir variable is not setted up."); + return; + } + + fd_mo = NULL; + + /* mo_file e.g.: /boot/grub/locale/ca.mo */ + + mo_file = + grub_malloc (grub_strlen (locale_dir) + grub_strlen ("/") + + grub_strlen (lang) + grub_strlen (".mo") + 1); + + /* Warning: if changing some paths in the below line, change the grub_malloc + contents below. */ + + grub_sprintf (mo_file, "%s/%s.mo", locale_dir, lang); + + fd_mo = grub_mofile_open (mo_file); + + /* Will try adding .gz as well. */ + if (fd_mo == NULL) + { + grub_sprintf (mo_file, "%s.gz", mo_file); + fd_mo = grub_mofile_open (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); + + /* 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; +} === modified file 'include/grub/i18n.h' --- include/grub/i18n.h 2009-11-17 09:52:08 +0000 +++ include/grub/i18n.h 2009-11-21 23:52:17 +0000 @@ -24,7 +24,7 @@ # include <libintl.h> # define _(str) gettext(str) #else -# define _(str) str +# define _(str) grub_gettext(str) #endif #endif /* GRUB_I18N_H */ === modified file 'include/grub/misc.h' --- include/grub/misc.h 2009-10-28 22:55:27 +0000 +++ include/grub/misc.h 2009-11-22 12:34:50 +0000 @@ -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 @@ -191,6 +191,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); + #ifdef NEED_ENABLE_EXECUTE_STACK void EXPORT_FUNC(__enable_execute_stack) (void *addr); #endif === modified file 'kern/misc.c' --- kern/misc.c 2009-11-01 23:03:09 +0000 +++ kern/misc.c 2009-11-21 23:55:37 +0000 @@ -30,6 +30,8 @@ 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 @@ 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) === modified file 'normal/menu_text.c' --- normal/menu_text.c 2009-05-02 19:49:34 +0000 +++ normal/menu_text.c 2009-11-22 11:44:20 +0000 @@ -25,6 +25,7 @@ #include <grub/time.h> #include <grub/env.h> #include <grub/menu_viewer.h> +#include <grub/i18n.h> /* Time to delay after displaying an error message about a default/fallback entry failing to boot. */ @@ -93,8 +94,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\ @@ -266,7 +267,7 @@ { /* NOTE: Do not remove the trailing space characters. They are required to clear the line. */ - char *msg = " The highlighted entry will be booted automatically in %ds. "; + const char *msg = _(" The highlighted entry will be booted automatically in %ds. "); char *msg_end = grub_strchr (msg, '%'); grub_gotoxy (second_stage ? (msg_end - msg) : 0, GRUB_TERM_HEIGHT - 3); === modified file 'po/POTFILES' --- po/POTFILES 2009-11-18 23:20:22 +0000 +++ po/POTFILES 2009-11-22 11:45:38 +0000 @@ -10,3 +10,5 @@ util/mkisofs/rock.c util/mkisofs/tree.c util/mkisofs/write.c + +normal/menu_text.c === modified file 'po/ca.po' --- po/ca.po 2009-11-18 23:20:22 +0000 +++ po/ca.po 2009-11-22 11:47:54 +0000 @@ -6,7 +6,7 @@ msgstr "" "Project-Id-Version: GNU GRUB\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-11-19 00:16+0100\n" +"POT-Creation-Date: 2009-11-22 11:45+0000\n" "PO-Revision-Date: 2009-11-17 12:26+0100\n" "Last-Translator: Robert Millan <rmh.g...@aybabtu.com>\n" "Language-Team: None <no-team-...@li.org>\n" @@ -882,6 +882,20 @@ msgid "Path table size(bytes): %d\n" msgstr "" +#: normal/menu_text.c:97 +#, 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 a seleccionar l'entrada.\n" + +#: normal/menu_text.c:270 +#, c-format +msgid " The highlighted entry will be booted automatically in %ds. " +msgstr " L entrada seleccionada sera arrancada automaticament en %ds. " + #: util/grub.d/10_kfreebsd.in:40 msgid "%s, with kFreeBSD %s" msgstr "" === modified file 'util/grub.d/00_header.in' --- util/grub.d/00_header.in 2009-08-25 19:42:56 +0000 +++ util/grub.d/00_header.in 2009-11-21 23:53:44 +0000 @@ -22,6 +22,8 @@ exec_pref...@exec_prefix@ libd...@libdir@ grub_prefix=`echo /boot/grub | sed ${transform}` +locale_dir=`echo /boot/grub/locale | sed ${transform}` +grub_lang=`echo $LANG | cut -d _ -f 1` . ${libdir}/grub/grub-mkconfig_lib @@ -100,6 +102,15 @@ ;; esac +# Gettext variables and module +if [ "x${LANG}" != "xC" ] ; then + cat << EOF +set locale_dir=${locale_dir} +set lang=${grub_lang} +insmod gettext +EOF +fi + if [ "x${GRUB_HIDDEN_TIMEOUT}" != "x" ] ; then if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then verbose=
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel