Generate Linux Locales Safely with locale-gen

locale-gen turns a supported locale entry into something locale -a can actually see. You will select the locale data your Debian or Ubuntu system needs, generate it, and confirm the result; a fresh Ubuntu box rarely has anything but the defaults compiled. Allow about ten minutes, including a quick check of a program that uses the locale.

This guide describes the installed locales package version 2.39-0ubuntu8.9. Its manual page documents --keep-existing, while the installed script also accepts --purge, --archive, --no-archive, --aliases and --lang. The examples use the documented file format and the behaviour of the installed script; do not assume another distribution or package release has the same option set.

1. Check the current state

Start with read-only checks. None of these need sudo:

$ command -v locale-gen
/usr/sbin/locale-gen
$ dpkg-query -W -f='${Package} ${Version}\n' locales
locales 2.39-0ubuntu8.9
$ locale -a
C
C.utf8
POSIX
en_US.utf8

Your list will differ. The locale -a output is the useful baseline: it shows compiled locales, not every locale that could be generated. If the command is missing, install the locales package through your normal package-management process rather than copying a script from another host.

Checkpoint: record the locale names you already have. You will compare them with the list after generation.

2. Choose an entry from the supported list

/etc/locale.gen holds whitespace-separated pairs of locale name and character set. A line beginning with # is a comment and is not generated. The installed file points to the supported list at /usr/share/i18n/SUPPORTED:

$ grep '^en_GB' /usr/share/i18n/SUPPORTED
en_GB ISO-8859-1
en_GB.UTF-8 UTF-8
en_GB.ISO-8859-15 ISO-8859-15

3. Enable one locale in /etc/locale.gen

Warning: the next action changes system configuration. Save a backup first, and edit as root:

$ sudo cp --preserve=mode,ownership,timestamps /etc/locale.gen /etc/locale.gen.bak
$ sudoedit /etc/locale.gen

Find the exact supported line, remove its leading # and any following space, then save. For the example above, the resulting line should read:

en_GB.UTF-8 UTF-8

Keep unrelated selections as they are. A common distraction is to set LANG=en_GB.UTF-8 in a shell and expect that to compile the locale; it will not. Environment variables choose a locale for a process, they do not create locale data. Only the file plus locale-gen perform the generation. Check the edit before running it:

$ grep -E '^[[:space:]]*[^#[:space:]]+[[:space:]]+[^#[:space:]]+' /etc/locale.gen | grep '^en_GB.UTF-8 UTF-8$'
en_GB.UTF-8 UTF-8

4. Generate the selected locales

Run the generator with elevated privileges:

$ sudo locale-gen
Generating locales (this might take a while)...
  en_GB.UTF-8... done
Generation complete.

The exact progress lines depend on the selections in your file. The command reads /etc/locale.gen and invokes localedef for each active entry, then writes compiled data under /usr/lib/locale, so it can affect every user and every process using the system locale store.

On this installed script, an ordinary run removes existing generated locale data before rebuilding it. Preserving the file alone is not the same as preserving compiled output. If you need to add a locale while keeping existing valid data, use the documented option:

$ sudo locale-gen --keep-existing

This is still a system-wide write. It is not a substitute for checking the requested entry is valid, and it can skip a locale the script already considers usable.

5. Verify the generated locale

Ask locale -a for the canonical name. Locale names are case-sensitive enough that you should copy the result rather than trust memory:

$ locale -a | grep -E '^en_GB([.]utf8|[.]UTF-8)$'
en_GB.utf8

The spelling in locale -a may be normalised, so en_GB.utf8 is a valid confirmation of the en_GB.UTF-8 UTF-8 source entry. Test a process without touching your login configuration:

$ LC_ALL=en_GB.UTF-8 locale charmap
UTF-8
$ LC_ALL=en_GB.UTF-8 locale date_fmt
%a %d %b %Y %T %Z

These checks apply the locale only to each command. They do not edit /etc/default/locale, your shell startup files or another user's environment.

6. Diagnose failures and undo the edit

If generation reports an invalid locale or character set, compare the line with /usr/share/i18n/SUPPORTED. Check both columns, spelling and punctuation; a commented line is also easy to miss in a long file.

To undo only your configuration edit, restore the backup and do not run the generator until you have reviewed it:

$ sudo cp --preserve=mode,ownership,timestamps /etc/locale.gen.bak /etc/locale.gen
$ grep '^en_GB.UTF-8 UTF-8$' /etc/locale.gen || echo 'en_GB selection is no longer enabled'

Restoring the file does not remove already-compiled locale data. If you deliberately ran a rebuild and need the previous compiled set back, there is no general undo command in locale-gen: re-enable the intended entries and run the generator again. Do not delete arbitrary directories under /usr/lib/locale, since that can break programs currently starting with those locales.

For a more detailed error, inspect the individual localedef diagnostics and confirm the source locale and character map exist. Do not silence errors with a guessed locale name. A successful command plus a matching locale -a entry are the completion checks that matter.

Done means