How to change system locale on RHEL7?

Solution Verified - Updated -

Environment

  • Red Hat Enterprise Linux (RHEL) 7

Issue

  • How do I change the system-wide locale (or user-specific) for a local login?
  • How do I change the locale for a ssh login?
  • How do I prevent a ssh client's locale from affecting an ssh session?
  • I don't see a "file.encoding" or "sun.jnu.encoding" environmental variable set at the OS level. Can these variables be set at the OS level ? Are there any known issues with RHEL 7.3 and Java 1.8.0_25 ?

Resolution

This section details the procedures for changing the system locale for local logins and ssh logins:

1) How to configure the system locale and user locale for a local login.
2) How to configure the user locale for a ssh login.
3) How to confirm that the changes in the previous steps were successful.

Configuring locales that are set at login requires some knowledge of different configuration files. What changes you will need to make depend upon your business requirements and what you want to achieve as the end result. Red Hat recommends that you should be able to first clearly define what the end result you want to achieve is. After writing that down you should not make any configuration changes until after you have read and understood this solution article.

How to configure a system wide or a user specific locale for local access.

  • Technical background
    When an interactive shell is opened, scripts under /etc/profile.d/ directory are executed. The script /etc/profile.d/lang.sh can set LANG and other locale variables, as shown below:

    # cat /etc/profile.d/lang.sh 
    # /etc/profile.d/lang.sh - set i18n stuff
    
    sourced=0
    
    if [ -n "$LANG" ]; then
        saved_lang="$LANG"
        [ -f "$HOME/.i18n" ] && . "$HOME/.i18n" && sourced=1
        LANG="$saved_lang"
        unset saved_lang
    else
        for langfile in /etc/locale.conf "$HOME/.i18n" ; do
            [ -f $langfile ] && . $langfile && sourced=1
        done
    fi
    

If LANG is set, a copy of the variable is saved and the user's .i18n file in its home directory is sourced. However, note that LANG is set back to the saved value. That is, if LANG is already set, you cannot change the value of LANG from a .i18n file in your home directory. You can however set LC_ALL instead, since the value of LC_ALL takes precedence over the LANG environment variable (see http://pubs.opengroup.org/onlinepubs/7908799/xbd/envvar.html). Other LC_* environment variables also take precedence over LANG, but LC_ALL takes precedence over all other LC_* environment variables.

If the value of LANG is not set or is a NULL value, then both /etc/locale.conf and .i18n from the user's home directory (in that order) are sourced if they exist. This means that the users .i18n file, if it exists, can override the value set in the system wide configuration file /etc/locale.conf.

  • To set the locale at a system wide level, the file /etc/locale.conf need to be modified.
  • To set the locale for a specific user, the file $HOME/.i18n need to be modified.

NOTE: These configurations are enabled at the next login and if LANG is already set, before /etc/profile.d/lang.sh is executed, it cannot be modified with standard RHEL login scripts. Understanding this is important for non-local (ssh) access to a system discussed in the next section.

How to configure the locale for a ssh session.

  • Technical background
    By default, RHEL 7 systems accept locale environment variables from ssh clients. The following locale environment variables will (if passed by the ssh client) be set in the environment before any login scripts are ran:

    # Accept locale-related environment variables
    AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
    AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
    AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
    

    The above output is from sshd_config. If LANG is one of the environment variables passed, it will not be changed during the login process. See "How to configure a system wide or a user specific locale for local access." for an explanation of why.
    For example, when logging directly into a RHEL 7 server, e.g. at the console, if the value of LANG is set as follows (this is an example value, your system may be different):

    $ env |grep -e LANG -e LC
    LANG=en_US.UTF-8
    

    And then you change the value of LANG (it MUST be exported) to a different locale, and then use an ssh client to connect back to the same system:

    $ export LANG=ja_JP.UTF-8
    $ ssh localhost
    user@localhost's password:
    ...
    $ echo $LANG
    ja_JP.UTF-8
    

    The value of LANG is preserved from the client ssh session and not set according to the user's .i18n file or /etc/locale.conf (en_US.UTF-8 in the example). This is the expected behavior.

  • If you are not seeing this default behavior and need to use the locale from the ssh client you need to:

    1. Confirm that LANG is present in the AcceptEnv of the servers sshd_config file.
      NOTE: If you modify anything in sshd_config, the sshd service must be restarted to enable the change.

      Default configurations are:

      # Accept locale-related environment variables
      AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
      AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
      AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
      
    2. Export the LANG environment variable on the client side before running ssh.

      export LANG=ja_JP.UTF-8
      
    3. Connect to the server using ssh from the client server.
      NOTE: This assumes that you have not modified any scripts which is ran at login to change any locale environment variables.
  • If you wish to force a specific initial locale for ssh sessions on the server, you need to change your configuration using one of the following ways:

    1. Remove LANG and/or other locale variables from AcceptEnv option in sshd_config on the server, to prevent sshd from setting the LANG variable from ssh client (LANG is used here but it applies to all locale environment variables).
    2. Write a new script in /etc/profile.d/ that forces the user to use different locale environment variables. Because of the way /etc/profile finds scripts in /etc/profile.d, your script MUST be alphabetically lower in order than lang.sh - if you were to call it unset_lang.sh it would be executed AFTER lang.sh.
      NOTE: If you choose to modify /etc/profile.d/lang.sh that file is not a configuration file: when an rpm is installed that provides /etc/profile.d/lang.sh, it will overwrite your changes. You should avoid modifying /etc/profile.d/lang.sh.
      IMPORTANT: If you chose to add a script into /etc/profile.d, just in case, you should do it on one of the following ways to aid in debugging it:

      1. Have an active root session to the system (preferably on the console) just in case there are any issues caused by the changes, e.g. you cannot login the system. This will allow you to remove the new script.
      2. Test the changes in a test environment before making them to a production system.
        NOTE: /etc/profile sources scripts in /etc/profile.d - Never use exit in a script located in /etc/profile.d. Doing so, it will cause the script that is sourcing it (/etc/profile) to exit.

How to check locale changes.

  1. Log out of the current session - the locale is set when you login so any change happens at the next login.
  2. Verify any changes made using the locale command:

    # locale
    

    or run

    env |grep -e LANG -e LC_
    
  3. If the locale isn't what you now expect it to be, you should verify that the steps above have been followed. This discussion assumes that no changes have been made to files such as a user's .bash_profile, .bash_login, .profile.bashrc, etc to change locale environment variables.

Further information

  • There is no need to reboot the server. "Logging out and backing in" will allow you to see the locale change.
  • For information regarding previous RHEL versions, refer to How to change the system locale in RHEL?.
  • When connecting to a server using a terminal emulator (such as putty) the terminal emulator can define environment variables to pass to a server when opening an ssh session. Doing so allows someone to override the locale for their login session. If you are accessing a system directly via a program like putty (or using some other terminal emulator) and environment variables are being provided by the terminal emulator please refer to the documentation for the terminal emulator for information about how to change or remove environment variables.

Root Cause

  • Multiple configuration files and the method of access to a system influence the locale for a user.
  • The global locale configuration file is changed from previous RHEL versions (/etc/sysconfig/i18n) to /etc/locale.conf in RHEL7.
  • ssh sessions, by default, accept locale environment variables from the client (where the ssh command was ran), this can override what the server may want to set.

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.

2 Comments

Better choice for ssh is /etc/profile.d/lang.sh, not /etc/profile

Thanks a lot for the suggestion, Alberto. This is now part of the current version.