bug-gettext
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [bug-gettext] RFC: move LANGUAGE check out of gettext()


From: Daiki Ueno
Subject: Re: [bug-gettext] RFC: move LANGUAGE check out of gettext()
Date: Wed, 11 May 2016 17:43:21 +0900
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.1.50 (gnu/linux)

Hi Bruno,

Thank you very much for the detailed explanation.

Bruno Haible <address@hidden> writes:

> Why is this being reported for the LANGUAGE environment variable but not
> for the LANG and LC_ALL environment variables? Because for LANG and LC_*
> we have an architecture composed of three functionalities:
>
>   (A) environment variables: getenv(), setenv()
>
>   (B) locales: setlocale(), newlocale(), uselocale().
>
>   (C) gettext() and friends.
>
> (A) is the bottom-most layer. But it has the limitation that multi-threaded
> programs must not call setenv().
>
> (B) is a layer that fetches the initial values from (A), and that allows
> mutators (setlocale(), uselocale()) in multi-threaded programs.
> So that multi-threaded applications can modify the program's locale after
> startup, there is the setlocale() function.
> So that multi-threaded programs can have a locale per thread, there is a
> uselocale() function.
>
> (C) is an application layer that happens to be in Glibc for convenience
> reasons. It is based on the layer (B).
>
>
> Back to the LANGUAGE environment variable. The problem is that here we
> have the layers (A) and (C), but (B) is missing. The solution ought to
> be to introduce a layer (B) for LANGUAGE. LANGUAGE is not specified by
> POSIX and does not perfectly fit into the locale system, therefore I
> believe it is best treated separately.
>
> So, what I imagine is a layer (B) with an API like this:
>
>   /* Returns the language precedence list for the program. */
>   const char *get_i18n_language (void);
>
>   /* Sets the language precedence list for the program.
>      NULL means to use the one inferred from the environment variable. */
>   void set_i18n_language (const char *);
>
> or - if you want to have a language per thread -:
>
>   /* Returns the language precedence list for the current thread. */
>   const char *get_i18n_language (void);
>
>   /* Sets the language precedence list for the program.
>      NULL means to use the one inferred from the environment variable. */
>   void set_i18n_language (const char *);
>
>   /* Sets the language precedence list for the current thread.
>      NULL means to use the one for the program or, if not set,
>      the one inferred from the environment variable. */
>   void set_thread_i18n_language (const char *);
>
> You can protect the implementation of these functions with locks
> (functions/macros gl_rwlock_*).
>
>
> With this approach,
>   - Multithread program can change the i18n language in a thread-safe
>     way, without using setenv().
>   - The setlocale() code is left alone.

The approach makes a lot of sense.  I will prepare a patch along those
lines.

>   * It modifies the code of setlocale() for a purpose that is unrelated to
>     the locale system.
>
>     The fact that glibc's locale/setlocale.c has to increment _nl_msg_cat_cntr
>     (notification from layer (B) to layer (C)) is already bad enough; it
>     exists because there is no standardized API for being notified of
>     locale changes. It forces us to override setlocale on non-glibc systems,
>     using gnulibology patterns.
>
>     But adding yet another call from layer (B) to layer (C) is even more of a
>     hack.

Yes.  The intention of this hack was to save existing programs without
modification (for the new API).  However, for the majority of programs,
it could be mitigated in a general-purpose library like GLib, by calling
set_i18n_language() during initialization of the library.

Regards,
-- 
Daiki Ueno



reply via email to

[Prev in Thread] Current Thread [Next in Thread]