set LC_* but not LC_ALL

13,126

Solution 1

There are three sets of locale settings¹:

  • LANG, the fallback setting, if you haven't specified a value for a category. It's indended for users to indicate their locale in a simple way.
  • LC_xxx for each category (xxx can be MESSAGES, TIME, etc.).
  • LC_ALL overrides all settings. It's a way for applications to override all settings in order to work in a known locale (usually C, the default locale), typically so that various commands produce output in a known format.

So you can set LANG=de_AT.UTF-8 and LC_MESSAGES=C (C is the default locale and means untranslated; en_US is usually identical to C for messages).

However, there are two categories where I don't recommend changing the default, because it breaks a lot of programs:

  • LC_COLLATE is the character collation order. It's not very useful because it only indicates how to sort characters, not how to sort strings. Tools that know how to sort strings don't use LC_COLLATE. Furthermore a lot of tools expect things like “[a-z] matches all 26 ASCII lowercase letters and no other ASCII characters”, but that's not true in most non-default locales (try echo B | LC_COLLATE=en_US grep '[a-z]').
  • LC_NUMERIC indicates how to display numbers. In particular, in many languages, it makes floating point numbers use a , rather than . as the decimal point. But most programs that parse numbers expect a . and treat a , as a field separator.

So I recommend to

  • either explicitly LC_COLLATE=C LC_NUMERIC=_C,
  • or leave LANG unset and only set a value for the useful categories (LC_MESSAGES, LC_TIME, LC_PAPER, plus LC_CTYPE (whose value may vary depending on your terminal)).

¹ Plus LANGUAGE with GNU libc. If you hadn't heard about it, you're not missing much.

Solution 2

The man page locale(7) says:

the default locale [...] is determined using the following steps:

  1. If there is a non-null environment variable LC_ALL, the value of LC_ALL is used.

  2. If an environment variable with the same name as one of the categories [LC_*] above exists and is non-null, its value is used for that category.

  3. If there is a non-null environment variable LANG, the value of LANG is used.

So, you can use LANG as a sort of low-precedence analogue of LC_ALL: set the value of LANG to de_AT and LC_MESSAGES to en_US:

$ env LC_MESSAGES=en_US.UTF-8 LANG=de_AT.UTF-8 locale | egrep '(MESSAGES|PAPER)'
LC_MESSAGES=en_US.UTF-8
LC_PAPER="de_AT.UTF-8"
Share:
13,126

Related videos on Youtube

Heinzi
Author by

Heinzi

Updated on September 18, 2022

Comments

  • Heinzi
    Heinzi over 1 year

    I'd like to have a German (Austria) locale (A4 paper size, 24 hour time, yyyy-mm-dd), but an English-language user interface (I don't like poor translations). I figured that the correct way to achieve this is to set the LC_ variables as follows in my .bashrc (please correct me if I'm wrong):

    LC_MESSAGES=en_US.UTF-8
    LC_$everythingelse=de_AT.UTF-8
    

    Is there a more elegant way to set LC_$everythingelse rather than setting every single value? Setting LC_ALL is not an option, since it takes precedence over LC_MESSAGES:

    $ export LC_ALL=de_AT.UTF_8
    $ export LC_MESSAGES=en_US.UTF_8
    $ echo $LC_MESSAGES
    en_US.UTF_8
    $ locale | grep LC_MESSAGES
    LC_MESSAGES="de_AT.UTF_8"
    

    PS: It's a shared machine and I'm not sudoer, so changing system-wide settings is not an option.

  • Heinzi
    Heinzi almost 13 years
    Thanks for the detailed answer and the explanations! I will try a localized LC_NUMERIC, though, since the numpad on German keyboards has a , in place of a . (unfortunately), so entering numbers with a dot is inconvenient (and most apps seem to work nicely with a non-standard LC_NUMERIC). I do not fully understand your LC_COLLATE example: On my system, the example you gave does not match B.
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' almost 13 years