Локализация и интернационализация [107.3]

Рейтинг: 57.8% · 13 голосов
Полный курс LPIC-1 (экзамены 101-500 и 102-500): архитектура, загрузка, пакеты, команды и текст, ФС и права, шелл-скрипты, пользователи, сервисы, сеть, безопасность. Debian и RHEL.
Ответить
Аватара пользователя
Sergey_Sysadmin
Сообщения: 134
Зарегистрирован: 11 май 2026, 05:31

Локализация и интернационализация [107.3]

Сообщение Sergey_Sysadmin »

Оглавление курса (41)
  1. Введение в LPIC-1 и как устроен путь администратора
  2. Железо, устройства и модули ядра [101.1]
  3. Загрузка системы: от BIOS до systemd [101.2]
  4. systemd, цели и уровни выполнения [101.3]
  5. План разметки диска и swap [102.1]
  6. Загрузчик GRUB 2 [102.2]
  7. Разделяемые библиотеки [102.3]
  8. Управление пакетами в Debian: dpkg и apt [102.4]
  9. Управление пакетами RPM, DNF и Zypper [102.5]
  10. Linux как гость виртуализации [102.6]
  11. Командная строка Bash [103.1]
  12. Обработка текста фильтрами [103.2]
  13. Базовое управление файлами [103.3]
  14. Потоки, конвейеры и перенаправление [103.4]
  15. Процессы: создание, мониторинг, сигналы [103.5]
  16. Приоритеты выполнения процессов [103.6]
  17. Регулярные выражения [103.7]
  18. Редактор vi и vim [103.8]
  19. Разделы и создание файловых систем [104.1]
  20. Целостность и обслуживание ФС [104.2]
  21. Монтирование файловых систем [104.3]
  22. Урок 21. Права доступа и владение: rwx, chmod, umask и специальные биты
  23. Жёсткие и символические ссылки
  24. FHS и поиск файлов в системе [104.7]
  25. Окружение и кастомизация оболочки [105.1]
  26. Урок 25. Написание простых bash-скриптов [105.2]
  27. Графика, рабочие столы и доступность
  28. Учётные записи пользователей и групп
  29. Автоматизация задач: cron, at, таймеры [107.2]
  30. Локализация и интернационализация [107.3] (вы здесь)
  31. Системное время и синхронизация [108.1]
  32. Системное логирование [108.2]
  33. Основы почтового агента (MTA) [108.3]
  34. Печать и CUPS [108.4]
  35. Основы интернет-протоколов [109.1]
  36. Постоянная конфигурация сети [109.2]
  37. Диагностика сети [109.3]
  38. DNS на стороне клиента [109.4]
  39. Задачи администрирования безопасности [110.1]
  40. Настройка безопасности хоста [110.2]
  41. Шифрование данных: SSH и GnuPG [110.3]
Урок 29. Локализация и интернационализация [107.3]

Машина без правильной локали и часового пояса - источник тихих, противных багов: логи с временем "не от мира сего", команда sort выдаёт неожиданный порядок, скрипт падает на дробном числе, а в имени файла вместо кириллицы видны кракозябры. В этом уроке разбираемся, как Linux хранит время и язык окружения, чем locale отличается от часового пояса, как чинить кодировки утилитой iconv и почему один и тот же скрипт ведёт себя по-разному в зависимости от переменной LC_ALL.

Изображение

Как это работает

Сначала про время. Системные часы (RTC и программный таймер ядра) лучше всего держать в UTC - это абсолютная шкала без переходов на летнее время. Локальное время вычисляется на лету из UTC плюс правило часового пояса. Эти правила (когда смещение, когда переходы, исторические сдвиги) лежат в базе tzdata в каталоге /usr/share/zoneinfo - по одному скомпилированному бинарному файлу на зону, например /usr/share/zoneinfo/Europe/Moscow. Файл /etc/localtime - это символьная ссылка или копия нужного файла зоны, именно его читают библиотечные функции при форматировании времени.

База tzdata живёт своей жизнью: правительства меняют пояса и отменяют переход на летнее время, поэтому пакет с зонами регулярно обновляется (релизы вида 2026a, 2026b). Держать его свежим - часть гигиены сервера, иначе после очередной реформы машина покажет неверное локальное время.

Теперь про язык. Локаль - это набор правил "как в данной культуре принято" писать числа, деньги, даты, как сравнивать строки и на каком языке выводить сообщения. Задаётся переменными окружения. LANG - общий рубильник для всех категорий. Категории LC_* перекрывают LANG по частям: LC_COLLATE отвечает за сортировку, LC_CTYPE за классификацию символов и кодировку, LC_NUMERIC за десятичный разделитель, LC_TIME за формат даты, LC_MESSAGES за язык сообщений программ. Переменная LC_ALL - аварийный перекрыватель: если она задана, она бьёт и LANG, и все LC_*. Поэтому в скриптах для предсказуемости часто пишут LC_ALL=C.

Имя локали имеет вид язык_СТРАНА.кодировка, например ru_RU.UTF-8. Особые имена: C (он же POSIX) - минимальная локаль, байтовая сортировка, английские сообщения; C.UTF-8 - то же, но с поддержкой UTF-8 как кодировки. В 2026 рабочая кодировка везде UTF-8, старые однобайтовые (KOI8-R, ISO-8859, CP1251) встречаются только в легаси-данных. UTF-8 хорош тем, что ASCII в нём занимает один байт и совместим, а остальные символы - от двух до четырёх байт.

Важно: locale - это про интерпретацию байтов, а не про их изменение. Если файл реально записан в CP1251, локаль UTF-8 его не "переведёт" - её надо перекодировать утилитой iconv.

Команды и примеры

Часовой пояс через systemd - одинаково на всех современных дистрибутивах:

Код: Выделить всё

timedatectl                      # текущее время, зона, статус NTP
timedatectl list-timezones       # список всех зон
timedatectl set-timezone Europe/Moscow
timedatectl set-ntp true         # включить синхронизацию времени
timedatectl set-timezone сам пересоздаёт ссылку /etc/localtime. Интерактивный помощник, который по континенту и стране подберёт имя зоны - tzselect (он только печатает имя, ничего не меняет). Проверить вручную:

Код: Выделить всё

ls -l /etc/localtime
# /etc/localtime -> ../usr/share/zoneinfo/Europe/Moscow
date                             # время в локальной зоне
date -u                          # то же в UTC
Посмотреть и перечислить локали:

Код: Выделить всё

locale                           # текущие значения всех категорий
locale -a                        # какие локали собраны в системе
locale -a | grep -i ru          # есть ли русская
Сгенерировать недостающую локаль. Debian/Ubuntu - правим список и запускаем генератор:

Код: Выделить всё

# вписать ru_RU.UTF-8 в /etc/locale.gen (или dpkg-reconfigure locales)
sudo sed -i 's/^# *ru_RU.UTF-8/ru_RU.UTF-8/' /etc/locale.gen
sudo locale-gen
sudo update-locale LANG=ru_RU.UTF-8
RHEL/Fedora - локали ставятся пакетами langpacks, отдельного locale-gen нет:

Код: Выделить всё

sudo dnf install glibc-langpack-ru
localectl set-locale LANG=ru_RU.UTF-8
Постоянная локаль на уровне системы хранится в /etc/locale.conf (читается systemd), управляется localectl. Для одной сессии достаточно export. Временно для одной команды:

Код: Выделить всё

LC_ALL=C sort names.txt          # детерминированная байтовая сортировка
LANG=ru_RU.UTF-8 date            # дата по-русски
Конвертация кодировок. iconv читает поток, перекодирует из одной кодировки в другую:

Код: Выделить всё

iconv -f CP1251 -t UTF-8 old.txt -o new.txt
iconv -l                         # список поддерживаемых кодировок
iconv -f UTF-8 -t UTF-8//IGNORE bad.txt -o clean.txt   # выкинуть битые байты
Суффикс //TRANSLIT пытается заменить непредставимый символ похожим, //IGNORE - просто выбрасывает. Узнать кодировку файла поможет file -i (или утилита enca для текста).

Влияние локали наглядно на сортировке. В локали C сортировка идёт по кодам байтов: все заглавные буквы раньше строчных. В ru_RU.UTF-8 действуют человеческие правила, регистр и порядок букв учитываются культурно:

Код: Выделить всё

printf 'b\nA\na\nB\n' | LC_ALL=C sort        # A B a b
printf 'b\nA\na\nB\n' | LC_ALL=ru_RU.UTF-8 sort  # a A b B
Частые грабли
  • LC_ALL задана где-то в профиле и молча перекрывает всё - LANG менять бесполезно, пока не снимете LC_ALL. Проверяйте командой locale на пустые и неожиданные значения.
  • Скрипт работает у вас и падает на сервере из-за LC_NUMERIC: десятичный разделитель в ru_RU - запятая, и awk или printf неверно парсят "3.14". В скриптах фиксируйте LC_ALL=C.
  • Имя зоны чувствительно к регистру и формату: Europe/Moscow, а не europe/moscow или MSK. Аббревиатуры вроде EST в качестве зоны - ловушка, они не учитывают переход на летнее время.
  • Файл в CP1251 открыт как UTF-8 - видны кракозябры. Локаль не перекодирует содержимое, нужен iconv. И наоборот, дважды перекодированный UTF-8 уже не починить вслепую.
  • Поставили langpack или сгенерировали локаль, но не перелогинились - переменные окружения подхватываются только в новой сессии.
  • Часы в UTC, но date показывает не то: дело не в часах, а в /etc/localtime или в устаревшем tzdata после реформы пояса. Обновите пакет с зонами.
  • LANGUAGE (с приоритетом списков языков для сообщений gettext) путают с LANG - это разные переменные, LANGUAGE влияет только на язык переводов.
Мини-лаба
  • Выполните timedatectl и запомните текущую зону. Переключитесь командой timedatectl set-timezone на Asia/Tokyo и сравните вывод date и date -u.
  • Верните свою зону через tzselect (получите имя) и timedatectl set-timezone. Проверьте ссылку ls -l /etc/localtime.
  • Командой locale -a убедитесь, есть ли ru_RU.UTF-8. Если нет - сгенерируйте её способом для вашего дистрибутива (locale-gen или dnf install glibc-langpack-ru).
  • Создайте файл со строками b, A, a, B и отсортируйте его дважды: LC_ALL=C sort и LC_ALL=ru_RU.UTF-8 sort. Объясните разницу.
  • Сделайте текстовый файл с кириллицей, перекодируйте его в CP1251 утилитой iconv, затем обратно в UTF-8. Проверьте file -i на каждом шаге.
  • Задайте LC_NUMERIC=ru_RU.UTF-8 и выполните printf "%.2f\n" 3,14 и затем то же с LC_ALL=C для значения 3.14 - сравните поведение.
Контрольные вопросы
  • Чем отличается /etc/localtime от каталога /usr/share/zoneinfo и что на что ссылается?
  • Какая переменная имеет наивысший приоритет: LANG, LC_TIME или LC_ALL, и почему её используют в скриптах?
  • За какую категорию локали отвечает LC_COLLATE и как локаль C меняет результат sort?
  • Какой командой systemd сменить часовой пояс и что при этом происходит с /etc/localtime?
  • Почему открытие файла в кодировке CP1251 под локалью UTF-8 даёт кракозябры и какой утилитой это лечится?
  • Чем имя локали C.UTF-8 отличается от ru_RU.UTF-8 по части сортировки и сообщений?
👍2 ❤️4 🔥2 😄 🤔2
Аватара пользователя
Pourle
Сообщения: 1
Зарегистрирован: 14 май 2026, 12:44

Re: Локализация и интернационализация [107.3]

Сообщение Pourle »

А зачем вообще держать часы в UTC, если сервер всю жизнь стоит в одном городе? У нас RTC в локальном времени, и пока ничего не сломалось.
👍2 ❤️ 🔥 😄 🤔1
Аватара пользователя
pasha2003
Сообщения: 1
Зарегистрирован: 28 май 2026, 16:26

Re: Локализация и интернационализация [107.3]

Сообщение pasha2003 »

Поймал ровно ту граблю с LC_NUMERIC: bash-скрипт со сборкой метрик на проде давал кривые числа, потому что awk парсил 1,5 как 1. LC_ALL=C в шапке скрипта - и отпустило.
👍 ❤️1 🔥 😄 🤔2
Ответить
← Предыдущая глава
Автоматизация задач: cron, at, таймеры [107.2]
Следующая глава →
Системное время и синхронизация [108.1]

Все главы курса «LPIC-1: администратор Linux (101 + 102)»

Поделиться темой: ✈ Telegram VK
  • Похожие темы

Вернуться в «LPIC-1: администратор Linux»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость