Алексей Барабанов
Принято считать, что в Linux уже давно нет проблем с кириллизацией
чего-либо. Эта ОС вслед за другими полным ходом движется в юникодный рай, где,
как обещают, вавилонский кризис никому не грозит. Но на практике ситуация еще
весьма далека от идеальной.
Тема кириллизации или «русификации», как иногда выражаются, с некоторых
пор исчезла с первых позиций рейтингов интереса со стороны неофитов Linux. В
нашей стране уже давно не внедряются новые кодировки. И хотя по их числу мы не
превосходим народности с иероглифическими методами написания, но в европейском
регионе явно ходим в рекордсменах. И вот теперь, когда, казалось бы, уже нет
проблем, чтобы предложить пользователям Linux все разнообразие проверенных
наработок и материалов по кириллизации, многие дистрибуторы начинают экономить,
можно сказать, на самом святом. Им кажется, что надо уже сейчас заставить всех
пользователей работать в универсальной кодировке UTF8 (алгоритм 8го
представления символов UNICODE) и в локалях, сделанных на ее основе. Увы,
в данном вопросе именно пользователи попадают между молотом и наковальней,
между стремлением разработчиков дистрибутивов к псевдопрогрессу и
консервативностью рынка прикладного программного обеспечения. Обсудим данный
вопрос подробно на примере дистрибутива SuSE Linux 10.0
и в сравнении на примере ряда других ведущих дистрибуций.
Терминология
и проблематика
Необходимость адаптации программного обеспечения к требованиям интерфейсного
окружения обуславливается тем, что существует изначальная проблема определения
кодировки символьных данных. Например, в UNIX-подобных системах файлы
представляются последовательностью байт. Таким образом, все входные потоки
данных, которые, по сути, есть файлы, тоже являются последовательностью индифферентных
байтовых кодов. Как же программа априори «поймет», что за данные ей передаются?
Есть два способа: по содержимому самого потока
данных, так называемый «in-band», и на основании внешнего предписания, или «out-band».
Первый способ зависит от формата, второй –
диктует формат. Изначально использовался только второй способ. Например,
в первых персональных компьютерах исключалось применение символьных данных
в кодировках, отличных от кодовой страницы 437 (IBM Codepage 437).
Использование данной кодовой таблицы было закреплено аппаратно, то есть
внешним путем. С распространением компьютерной технологии в регионах,
где приняты иные требования на представление символьных данных, была
определена процедура так называемой локализации, или модификации
программного обеспечения для использования региональных стандартов. Но данный
путь оказался слишком трудозатратным. И тогда было произведено
функциональное выделение всех национально-зависимых программных компонентов
так, чтобы можно было настраивать требуемую локализацию динамически.
Естественно, данная процедура всецело определялась платформой. Так, в
частности, на обсуждаемой платформе GNU/Linux локализация управляется единым
образом на основе так называемых «локалей» (locale) с помощью системной
библиотеки glibc.
Второй способ, «in-band», подразумевает, что,
получив некоторые символьные данные, программа самостоятельно сумеет определить
их кодировку, пользуясь лишь информацией из входного потока. Например,
кодировка может указываться в самом файле или в начале потока данных. Такой
способ принят во многих внутренних форматах, поддерживаемых текстовыми
редакторами, в формате HTML для этого используются специальные тэги, а в
протоколе HTTP специальные опции и так далее. Но, несомненно, самым
универсальным является способ использования кодировки такого размера
(разрядности), чтобы она смогла содержать в себе все возможные символьные
комбинации. Так возникла идея кодировки UNICODE (Unicode standard ISO 10646,
или Universal Character Set, или UCS) и её более компактной версии UTF-8
[1]. Казалось бы, проблема решена, да не тут-то было! Универсальная кодировка
не отправила использование локалей в прошлое, а лишь добавила проблем,
поскольку увеличила их число!
Локали в Linux
Итак, в программном окружении определяется понятие локали как совокупности
данных об используемых языковых и национальных особенностях среды исполнения.
Именно пользуясь параметрами локали, программа «понимает» правильным образом
символьные входные данные и выводит свои отчеты в правильных кодировках. Здесь,
в самом определении, заложена некая условность, приводящая к неверному
пониманию сущности происходящего. Бытует мнение, что из привязки локали к
процессу следует легкость манипулирования её настройкой. Мол, если локаль
передается процессу из окружения, то ничего нет проще, как установить
любую локаль прямо перед запуском. Например, в Linux используются для этого
переменные окружения LC_* и LANG. Эти переменные формируются в процессе
отработки профиля пользователя и далее передаются всем порожденным процессам.
Вот как все просто! Если в системе в базе локализации присутствует нужная локаль,
то, указав ее в окружении, мы можем заставить работать с нею любой
процесс. Увы, нет! Это со всех сторон наивный взгляд. Чтобы понять
свойства локали, давайте взглянем на процесс ее образования (см. врезку «Локали
и их образование»).
Кодировка, включенная в локаль, является тем
самым ключевым параметром, позволяющим методом «outband» указать на способ
расшифровки символов. То есть программа еще и различает все входные данные
с использованием кодировки локали и, кроме того, в той же кодировке
выводит все сообщения. Ну, положим, если для вывода используются объекты
среды, которые наследуют локаль программы, то еще можно надеяться, что при
некоторых условиях они будут адекватно воспринимать и отображать кодировку
данной локали. Но в отношении входных данных это не всегда верно. Точнее,
в отношении входных данных не работает обратная логика. Если локаль
процесса, использующего входные данные, не совпадает с локалью процесса,
их породившего, то, скорее всего, ничего хорошего не выйдет.
Самый простой пример такой ситуации, когда
программа использует ранее накопленные данные, где тип используемой кодировки
определяет информацию – это имена файлов, индексы в структурах БД, базы
служебных сообщений, сохраненные из Интернета документы. Вы наблюдали на
экранах компьютеров «кракозябры» в сообщениях программ, которые в 90% случаев
работали вполне адекватно? Вам приходилось вместо имен файлов видеть всякую «бнопню»?
Это именно те случаи, когда программа воспользовалась строковой
константой, подготовленной в другой локали, или пыталась прочесть символьные
данные, созданные с использованием иной локали. Даже точно «угадав» локаль
исходных данных, то есть, казалось бы, сводя проблему к тривиальной
перекодировке, не всегда удается достичь успеха. Пример тому – данные,
упорядоченные или проиндексированные, в соответствии с алфавитным порядком
для некоторой локали. Здесь перекодировка не даст успеха, а сортировка
будет уже не только трудоемкой, но и даже невозможной, если используются
разделяемые данные, что характерно для совместной сетевой работы.
Ну хорошо, локаль – это типичное указание «out-band»
кодировки. Примение UTF-8 должно, по идее, избавить от дополнительного
указания на локаль, так как эта кодировка допускает определение локализации на
основании самих данных. Но, увы, лишь в теории. Локаль, безусловно, указывает
на единственную используемую в ней кодировку, а вот кодировка может
использоваться в разных локалях. И чем универсальнее эта кодировка, тем больше
выбор возможных локалей. То есть в случае абсолютного универсального идеала
кодирования информации UTF-8 мы вообще лишились возможности по характеру данных
сделать заключение о том, в какой локали эта информация представлена!
Вот и получается, что кажущаяся легкость
манипулирования локалью на самом деле не соответствует действительности. Таким
образом, локаль, кроме национальной базы стандартов, включает в себя тип
кодировки внешней среды, который от процесса не зависит, да и локаль не определяет!
И, значит, для того чтобы обрабатывать широкий спектр входных данных, надо
иметь в системном окружении весь необходимый перечень локалей для возможных
кодировок, и все сопутствующие данные для построения правильной среды
исполнения программы.
Вот о сопутствующих данных далее и поговорим,
но сначала проверим, какие локали нам предлагаются в SuSE Linux.
Локали в SuSE Linux 10.0
Выполним установку системы по умолчанию, лишь указав, что принимается
русский язык, и в результате получим следующую настройку локализации:
>
locale
LANG=ru_RU.UTF-8
LC_CTYPE="ru_RU.UTF-8"
LC_NUMERIC="ru_RU.UTF-8"
LC_TIME="ru_RU.UTF-8"
LC_COLLATE="ru_RU.UTF-8"
LC_MONETARY="ru_RU.UTF-8"
LC_MESSAGES="ru_RU.UTF-8"
LC_PAPER="ru_RU.UTF-8"
LC_NAME="ru_RU.UTF-8"
LC_ADDRESS="ru_RU.UTF-8"
LC_TELEPHONE="ru_RU.UTF-8"
LC_MEASUREMENT="ru_RU.UTF-8"
LC_IDENTIFICATION="ru_RU.UTF-8"
LC_ALL=
Как можно убедиться, предлагается работать в локали
ru_RU в многобайтной кодировке UTF-8. При этом в системе определены следующие
варианты настройки:
> locale
ru_RU
ru_RU.koi8r
ru_RU.utf8
Здесь уже должно быть понятно, что представления об используемых
в нашей стране локалях у разработчиков SuSE Linux далеки от реальности. В
качестве эталонного примем мнение авторов документа [2], прошедшего проверку
опытом. Кстати, из указанного источника можно почерпнуть дополнительный
комментарий, который по причине форматных ограничений не вошел в настоящий
текст.
Поправим в немецком дистрибутиве SuSE Linux
состав локалей, которые необходимы для работы российского пользователя,
следующим скриптом, запускаемым от root:
#!/bin/sh
LOCALE=/usr/lib/locale
LP=ru_RU
LD=$(which localedef)
[ "1$LD"
== "1" ] && { echo localedef not found ; exit -1 ; }
LD="$LD -c -i
$LP"
[ "1$(locale
-a | grep ^$LP | grep utf8)" == "1" ] && $LD -f UTF-8
$LP.UTF-8
[ "1$(locale
-a | grep ^$LP | grep UTF-8)" == "1" ] && ln -sf
$LOCALE/$LP.utf8 $LOCALE/$LP.UTF-8
[ "1$(locale
-a | grep ^$LP | grep koi8r)" == "1" ] && $LD -f KOI8-R
$LP.KOI8-R
[ "1$(locale
-a | grep ^$LP | grep KOI8-R)" == "1" ] && ln -sf
$LOCALE/$LP.koi8r $LOCALE/$LP.KOI8-R
[ "1$(locale
-a | grep ^$LP | grep cp1251)" == "1" ] && $LD -f CP1251
$LP.CP1251
[ "1$(locale
-a | grep ^$LP | grep CP1251)" == "1" ] && ln -sf
$LOCALE/$LP.cp1251 $LOCALE/$LP.CP1251
[ "1$(locale
-a | grep ^$LP | grep iso88595)" == "1" ] && $LD -f
ISO-8859-5 $LP.ISO-8859-5
[ "1$(locale
-a | grep ^$LP | grep ISO-8859-5)" == "1" ] && ln -sf
$LOCALE/$LP.iso88595 $LOCALE/$LP.ISO-8859-5
[ "1$(locale
-a | grep ^$LP | grep cp866)" == "1" ] && $LD -f IBM866
$LP.CP866
[ "1$(locale
-a | grep ^$LP | grep CP866)" == "1" ] && ln -sf
$LOCALE/$LP.cp866 $LOCALE/$LP.CP866
[ "1$(locale
-a | grep ^$LP | grep maccyrillic)" == "1" ] && $LD -f
MAC-CYRILLIC $LP.MAC-CYRILLIC
[ "1$(locale
-a | grep ^$LP | grep MAC-CYRILLIC)" == "1" ] && ln -sf
$LOCALE/$LP.maccyrillic $LOCALE/$LP.MAC-CYRILLIC
И тут же проверим результат:
>
locale -a | grep ^ru_RU
ru_RU
ru_RU.cp1251
ru_RU.CP1251
ru_RU.cp866
ru_RU.CP866
ru_RU.iso88595
ru_RU.ISO-8859-5
ru_RU.koi8r
ru_RU.KOI8-R
ru_RU.maccyrillic
ru_RU.MAC-CYRILLIC
ru_RU.utf8
ru_RU.UTF-8
Полученные локали позволят работать с кириллицей
в соответствии с национальным стандартом ru_RU, используя кодировки UTF-8,
KOI8-R, CP1251, ISO-8859-5, CP866 и MAC-CYRILLIC.
Некоторого пояснения требует сосуществование
полного и сокращенного (в оригинале mangled – «порубленного») наименования
локали, например, ru_RU.KOI8-R и ru_RU.koi8r. В принципе достаточно лишь сокращенного.
Полное имя локали, указанное в переменных окружения, будет преобразовано к сокращенному
в процессе работы. Но, учитывая мнение [1] и тот факт, что в отечественных
дистрибутивах, например в ALT Linux (до версии 3.0), принято использование
полного наименования локали даже в директории размещения (/usr/lib/locale),
вероятно в расчете на независимость и оригинальность российских
программистов, создадим символьные ссылки с полными именами на директории с
базами локалей, которые были построены localedef.
Как видите, в недрах SuSE Linux заложен большой
потенциал – расширение базы локализаций произошло без загрузки каких-либо
дополнительных файлов кроме дистрибутивных.
В работающей системе SuSE Linux локаль
устанавливается единым образом на основании переменной RC_LANG, размещенной в
файле /etc/sysconfig/language. Ранее, сразу после присвоения данной переменной
нужного значения, например того же ru_RU.UTF-8, следовало выполнить:
# SuSEconfig -module profiles»
для модификации служебных файлов профилей,
формирующих окружение командной оболочки. Но теперь в этом нет необходимости,
так как профили формируются универсальными скриптами /etc/profile.d/*.sh, среди
которых lang.sh непосредственно читает /etc/sysconfig/language и все
настраивает интерактивно, то есть в процессе запуска командной оболочки, и
потом передается всем порожденным процессам. Таким образом, после модификации
переменной RC_LANG достаточно перегрузить пользовательскую сессию или запустить
дополнительную через «su -», чтобы начать работу в новой локали.
В других дистрибутивах возможен иной подход к
формированию значений переменных окружения, указывающих на используемую локаль.
Для того чтобы определить последовательность настройки, можно произвести
контекстный поиск строки LANG в скриптах и конфигурационных файлах,
расположенных в /etc.
Различные подходы к кириллизации
Вернемся к той мысли, что кроме нужной локали процесса надо обеспечить
соответствующее преобразование входных и выходных данных. То есть правильную
кодировку, как это упрощенно воспринимается. И здесь нам придется
проанализировать, какие методы кириллизации, то есть адаптации интерфейсов
для использования кириллицы, существуют.
Так как речь идет об интерфейсах, то настройки
нужного преобразования кодов можно разделить на два вида: кириллизация консоли
и кириллизация графической среды. Обсудим подробно консольный режим работы, как
базовый по отношению ко всему остальному, поскольку именно этот режим
поддерживается в ядре, а все остальные подсистемы, и X Window в том числе,
работают лишь в качестве приложений.
В современных дистрибутивах Linux присутствуют
два пакета интернационализации, с помощью которых настраивается кириллическая
консоль. Хронологически первым является пакет kbd [3], и более поздним,
порожденным как ветвь от kdb, – console-tools [4]. Долгое время ожидалось,
что console-tools, содержащий множество утилит для манипуляции шрифтами и кодировками,
вытеснит «простенький» kbd. Это мнение, подогреваемое русскоязычными соразработчитками
console-tools (см. страницу credits на [4]) и отечественными дистрибуторами, в
частности ALT Linux, «просочилось» в многочисленные руководства и учебники,
например [5]. Поторопились...
По данным поисковой системы [6], пакет console-tools
используется в дистрибутивах: Mandrake, Mandriva, Conectiva, ALT Linux, RedHat
6 и 7, Turbolinux, Trustix, Engarde. С первыми четырьмя все ясно, так как они
явно исторически тяготеют друг к другу. А вот RedHat из перечисленных версий
отметим особо!
По сведениям с того же сайта, пакет kbd
применяется в дистрибутивах SuSE, Fedora, RedHat 5 и 8, WhiteBox, CentOS,
ASP Linux, PLD, Aurox, StartCom, Arklinux, Openwall и все таже Conectiva.
Со второго по пятый в списке представлены явные «редхатоиды» и их клоны. Очень
интересно обсудить «пируэт», который совершили разработчики RedHat, перейдя на console-tools
в релизах 6 и 7 и вернувшись потом снова к kbd в релизе 8. Нет, они не
перегрелись в солярии. Можно предположить, что в связи с ожидаемым
и скорым, как думают латентные эсперантисты, переходом в универсальную
кодировку unicode (а как известно, в 8 версии RedHat Linux произошел
переход на utf 8) преимущества пакета console-tools, ориентированного
в основном на изощренные манипуляции с кодировками, теряют актуальность, а
вот средства управления виртуальными консолями в kbd, напротив, становятся
незаменимыми. Что и послужило основанием возврата к использованию kbd.
Принимая все перечисленное во внимание и учитывая,
что в SuSE Linux всегда применялся и применяется сейчас пакет kbd, далее будем
обсуждать именно его.
Ввод символов с консоли Linux
Консольный (иногда его называют «терминальным») драйвер состоит из двух
частей. Первая отвечает за ввод с клавиатуры, а вторая за вывод на экран. То
есть делится на части в соответствии с функциональным разделением самой
консоли на клавиатуру и экран. Клавиатура может быть как физическим, локальным
устройством, так и удаленным виртуальным. То же самое верно и в отношении
экрана. Если он локальный, то соответствует экрану консоли, подключенной к
компьютеру, а если виртуальный, то в последовательности преобразования может
участвовать и консольный драйвер удаленной системы. Поэтому для ясности будем
учитывать только локальные устройства.
Сначала разберемся, как происходит преобразование
вводимых данных. Воспользуемся схемой, представленной на рис. 1.

Рисунок 1. Ввод данных с
клавиатуры
Изображенная там последовательность
преобразования будет иметь место в том случае, когда клавиатурный драйвер
включен в режим XLATE и настроен в локали ru_RU.KOI8-R. На рисунке видно, что
ключевую роль в установлении соответствия некоторой клавиши и того кода,
который будет получать процесс, играет специальная таблица, называемая
раскладкой. В этой таблице происходит не только назначение определенного
символа каждой клавише, но и производится выбор кодировки. Иначе говоря, чтобы
после нажатия клавиши «А» получить символ «А» в кодировке KOI8-R, надо
использовать раскладку или таблицу, у которой в строке, соответствующей
клавиатурному коду клавиши с изображением «А», и в колонке
для нужного кириллического регистра клавиатуры содержится код 0xE1. Если
бы требовалось получать символы в кодировке CP1251, то там должен содержаться код
0xC0. Чувствуете разницу? Не важно, что программа ожидает получать символы в
соответствии с локалью. Если нужная таблица преобразований не будет загружена с
помощью утилиты loadkeys в клавиатурный драйвер, то, как бы не менялась локаль,
успешной работы не получится.
Второй режим работы драйвера клавиатуры, который
актуален для текстового режима, это UNICODE. Как следует из названия, в этом
режиме драйвер формирует на выходе коды в соответствии с UTF-8. В этом
режиме все равно используется таблица преобразования, но на выходе драйвера
создаются не однобайтные посылки, а строки переменной длинны. В SuSE Linux
параметры, управляющие работой утилиты loadkeys, настраивающей клавиатуру,
содержатся в /etc/sysconfig/keyboard. В отличие от изображенного
на рис. 1 раскладка для режима по умолчанию указана как:
# grep ^KEYTABLE
/etc/sysconfig/keyboard
KEYTABLE="ru1.map.gz"
Значит, используется кириллическое подмножество
UTF8 (предположительно) с переключением регистров через <RightAlt> + <Shift>.
Но вот проблема: кириллица вроде бы вводится, а при выводе на экран вместо
знаков этого древнего алфавита отображаются лишь пустые знако-места. Заглянув в
исходный текст ru1.map.gz определяем, что там производится отображение не в
UTF-8, а в KOI8-R. И это недоразумение, кстати сказать, сопровождает уже
несколько версий SuSE Linux подряд. Замена раскладки на ru-utf.map.gz
исправляет ошибку разработчиков дистрибутива.
Здесь отметим, что перенастройка режима ввода с
консоли производится системным скриптом /etc/init.d/kbd независимо от настроек локали.
Вывод символов в консоль Linux
Теперь обсудим, как производится вывод символьной информации с помощью
драйвера экрана. Для этого воспользуемся схемой, представленной на рис. 2.

Рисунок 2. Вывод данных на
экран монитора
На рисунке изображена последовательность
преобразования в случае использования кодировки KOI8-R. Настраиваемыми
параметрами являются таблица ACM (Application Character Map), предназначенная
для перекодировки во внутреннее представление драйвера, таблица SFM (Screen Font
Map), предназначенная для получения индекса глифа в экранном шрифтовом наборе,
и собственно растровый шрифт. Два последних элемента тесно связаны и очень
часто объединяются в единый файл. Файлы экранных шрифтов с именами,
использующими суффиксы psfu должны содержать после растрового шрифта
соответствующую таблицу перекодировки SFM. Специальная управляющая подстрока
CONSOLE_MAGIC используется для активации настроенного преобразования.
Подробности можно узнать в [5]. В общем все достаточно тривиально.
Как уже было сказано, по умолчанию SuSE Linux
настраивается для использования UTF-8. Тогда все системные переменные, которые используются
для настройки способа вывода принимают значения:
# grep ^CONSOLE_
/etc/sysconfig/console
CONSOLE_FONT="Cyr_a8x16.psfu"
CONSOLE_UNICODEMAP=""
CONSOLE_SCREENMAP="trivial"
CONSOLE_MAGIC="(K"
CONSOLE_ENCODING="UTF-8"
И здесь также отметим, что настройка вывода в
консоль призводится системным скриптом /etc/init.d/kbd независимо от настроек локали.
И лишь воля администратора, редактирующего соответствующий управляющий файл /etc/sysconfig/console,
должна обеспечить согласование кодировок.
Настройка консоли SuSE Linux
В отличие от ранее созданных локалей для
обеспечения соотвествующей настройки придется подгрузить в систему
дополнительные файлы. В дистрибутивной поставке отсутствует ACM для
MAC-CYRILLIC и некоторые клавиатурные раскладки. Используемые для настройки
разных режимов параметры перечислены в таблице 1. Недостающие отмечены
отсутствием фоновой тонировки. Эти файлы, как и все приведенные или упомянутые
здесь скрипты, можно найти в архиве [7].
Таблица 1. Параметры
настройки кодовых преобразований и локалей
|
Локаль
|
Charmap
|
Screenmap
|
Keytable
|
Encoding
|
Источник
|
|
ru_RU.UTF-8
|
UTF-8
|
trivial
|
ru-utf.map
|
UTF-8
|
Unicode Org
|
|
ru_RU.KOI8-R
|
KOI8-R
|
koi8-r_to_uni
|
ru-ms.map
|
KOI8-R
|
RFC 1489
|
|
ru_RU.CP1251
|
CP1251
|
cp1251_to_uni
|
ru_win.map
|
CP1251
|
MS Cyrillic
|
|
ru_RU.ISO-8859-5
|
ISO-8859-5
|
8859-5_to_uni
|
ru_ms-iso-8859-5.map
|
ISO-8859-5
|
SUN Cyrillic
|
|
ru_RU.CP866
|
IBM866
|
cp866_to_uni
|
ru_ms-ibm866.map
|
IBM866
|
IBM Cyrillic
|
|
ru_RU.MAC-CYRILLIC
|
MAC-CYRILLIC
|
mac-cyrillic_to_uni
|
ru_ms-mac-cyrillic.map
|
MAC-CYRILLIC
|
Apple Cyrillic
|
Вот как должен выглядеть скрипт для переключения локали
и консоли в режим работы с кодировкой CP1251, выполненный в точном соответствии
с таблицей 1:
# cat console2cp1251
#!/bin/sh
PREF=/etc/sysconfig
[ "1$UID" !=
"10" ] && { echo "you must be root!" ; exit ; }
# Console
perl -i -p -e 's/^CONSOLE_FONT=.*/CONSOLE_FONT=Cyr_a8x16.psfu/g'
$PREF/console
perl -i -p -e 's/^CONSOLE_SCREENMAP=.*/CONSOLE_SCREENMAP=cp1251_to_uni/g'
$PREF/console
perl -i -p -e 's/^CONSOLE_ENCODING=.*/CONSOLE_ENCODING=CP1251/g'
$PREF/console
# Keyboard
perl -i -p -e 's/^KEYTABLE=.*/KEYTABLE=ru_win.map.gz/g'
$PREF/keyboard
# Language
perl -i -p -e 's/^RC_LANG=.*/RC_LANG=ru_RU.CP1251/g'
$PREF/language
rckbd restart
exit
Аналогичным образом строятся скрипты для
переключения в другие локали (см. [7]). Результат перевода консоли в режим
ru_RU.CP866 изображен на рис. 3.
Характерной особенностью является отсутствие
прописной буквы «Ы» (на рисунке 3 в строке приглашения консоли), которая
совпадает по коду со служебным символом управления кодовыми таблицами SCI
(0x9B). Но в остальном все прекрасно работает.

Рисунок 3. Консоль в режиме
ru_RU.CP866
Итак, потенциально возможно настроить консольный
драйвер и окружение пользователя для работы в любой из перечисленных локалей.
Так почему же все настойчиво предлагают работать в ru_RU.UTF-8 и так
пренебрежительно относятся ко всем остальным локалям?
Использование локали
приложениями
Безусловно, это самый важный вопрос. При его исследовании можно встретить
как приятные открытия, так и озадачивающие. Тема эта неисчерпаема, как и сам набор
возможных приложений. Для нас здесь принципиальным является тот факт, что
корректное использование локалей всецело на совести разработчиков программного
обеспечения. Более того, приложение может «уметь» использовать локали, но не
поддерживать часть из них.
Например, X Window в используемом большинством
дистрибутивов Linux варианте Xorg является, по сути, обычным приложением.
Переведем SuSE Linux в локаль ru_RU.CP1251 и затем внутри работающего X Window
переключимся в CP866 и запустим новую сессию konsole. Результат
на рис. 4.

Рисунок 4. Запуск konsole в
CP866
Получаем сразу две проблемы: во-первых, сообщение
«QT: Locales not supported on X server» и, во-вторых, внутри созданного окна не
наблюдается кириллицы в CP866. Первая из-за того, что нужная локаль не
создана в /usr/lib/X11/locale, а вторая из-за того, что теперь надо для данного
экземпляра konsole указать кодировку вручную. Вспоминаем о том, что оптимисты
считают локаль свойством процесса и ... недоумеваем! Вероятно, оптимисты не
входят в число авторов этих программ.
Проявляем настойчивость и получаем уже несколько
иной результат на рис. 5.

Рисунок 5. Konsole в CP866 с
кодировкой, указанной вручную
Обратите внимание: появилась кириллица в ответе date,
корректно представлена псевдографика mc, и, самое главное, нет проблем с
прописной «Ы», так как клавиатура работает в «сыром» (raw в оригинале),
прозрачном режиме, и текстовая консоль не участвует в процессе вывода.
Только не получится повторить то же самое в локали ru_RU.MACCYRILLIC, так как в
konsole эту кодировку нельзя указать принудительно – ее просто нет. Приятно то,
что варианты 14 из таблицы 1 работают в SuSE Linux в режиме X Window, как
говорится, «из коробки».
Еще более интересные метаморфозы претерпевает локаль
в режиме удаленной работы. Например, с помощью ssh. Если из локальной сессии,
работающей в локали ru_RU.KOI8-R, подключиться к удаленному компьютеру,
настроенному для работы в другой локали, то получим следующее:
alekseybb@wsalekseybb:~>
locale
LANG=ru_RU.KOI8-R
LC_CTYPE="ru_RU.KOI8-R"
LC_NUMERIC="ru_RU.KOI8-R"
LC_TIME="ru_RU.KOI8-R"
LC_COLLATE="ru_RU.KOI8-R"
LC_MONETARY="ru_RU.KOI8-R"
LC_MESSAGES="ru_RU.KOI8-R"
LC_PAPER="ru_RU.KOI8-R"
LC_NAME="ru_RU.KOI8-R"
LC_ADDRESS="ru_RU.KOI8-R"
LC_TELEPHONE="ru_RU.KOI8-R"
LC_MEASUREMENT="ru_RU.KOI8-R"
LC_IDENTIFICATION="ru_RU.KOI8-R"
LC_ALL=
alekseybb@wsalekseybb:~>
ssh alekseybb@192.168.0.184
Password:
Last login: Thu
Mar 9 22:03:31 2006
Have a lot of fun...
alekseybb@wsvm02:~>
locale
LANG=ru_RU.KOI8-R
LC_CTYPE="ru_RU.KOI8-R"
LC_NUMERIC="ru_RU.KOI8-R"
LC_TIME="ru_RU.KOI8-R"
LC_COLLATE="ru_RU.KOI8-R"
LC_MONETARY="ru_RU.KOI8-R"
LC_MESSAGES="ru_RU.KOI8-R"
LC_PAPER="ru_RU.KOI8-R"
LC_NAME="ru_RU.KOI8-R"
LC_ADDRESS="ru_RU.KOI8-R"
LC_TELEPHONE="ru_RU.KOI8-R"
LC_MEASUREMENT="ru_RU.KOI8-R"
LC_IDENTIFICATION="ru_RU.KOI8-R"
LC_ALL=
alekseybb@wsvm02:~>
grep ^RC_LANG /etc/sysconfig/language
RC_LANG=ru_RU.MAC-CYRILLIC
Как видно из протокола сеанса, командная оболочка
запустилась в локали клиента. Произошло это благодаря тому, что в параметрах
сервера ssh указано экспортировать переменные среды клиента:
wsvm02:~
# grep ^AcceptEnv /etc/ssh/sshd_config
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
А в параметрах клиента, аналогично, передавать
переменные среды на удаленную сторону:
wsalekseybb:~ #
grep ^SendEnv /etc/ssh/ssh_config
SendEnv LANG
LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
SendEnv
LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
SendEnv
LC_IDENTIFICATION LC_ALL
Но если попытаться подключиться к компьютеру
в локали ru_RU.MAC-CYRILLIC с помощью PyTTY из-под MS Windows, то
ничего хорошего не получится, так как там нет возможности ни передать переменные
программной среды, ни прямо указать перекодировку с MAC-CYRILLIC.
Надо заметить, что в приложениях, не
поддерживающих POSIX-локали, бывают вообще странные ситуации, вроде той, что
сообщает wine при запуске некоторых абстрактно написанных программ:
fixme: msvcrt:MSVCRT_setlocale
: Codepage only locale not implemented
Дословно: локаль, определяемая только кодовой
таблицей, не реализована. В свете того, что по кодировке символьного потока
вообще нельзя установить тип локали, приведенное выше сообщение можно понимать,
как своего рода юмор.
Подведем итоги
В общем случае не представляется сложным настроить рабочую станцию GNU/Linux
в любой из желаемых локалей. Как было продемонстрировано на примере SuSE Linux
10.0, который не является кириллически толерантным, что указано в
предупреждении инсталлятора, даже такой дистрибутив поддается настройке.
Казалось бы, отечественные дистрибутивы должны все описанное в статье иметь как
встроенный сервис. Но этого не наблюдается. На Руси с древности повелось так,
что народ учили грамоте то всякие «пришлые греки», то «ушлые варяги».
Складывающаяся вокруг компьютерных кодировок ситуация следует исторической
традиции. Очередные заморские гуру, в который раз предлагают отказаться от
всего, что было ранее проверено и внедрено, и принять от них новую
чудодейственную «пилюлю». Ожидаемо, после того как четыре зарубежные компании
создали четыре взаимоисключающие способа кодирования кириллической информации,
полностью игнорируя ту, что была создана независимыми отечественными разработчиками,
в среде пользователей должен сформироваться иммунитет к языковым авантюрам.
Тем более что, как продемонстрировано выше, единого подхода к работе с локалями
не наблюдается вовсе, то есть появление новой локали закономерно приведет
к новым хлопотам и проблемам с программами. Но лишь один из ведущих
российских разработчиков – ASPLinux – признает сложившуюся ситуацию и
предлагает набор локалей и кодировок на выбор (все из перечисленного,
кроме экзотической кодировки Mac и устаревшей cp866, в версии 10 ASPLinux).
А вот дистрибуция ALT Linux, копируя западный подход, с версии 3.0
полностью переходит в ru_RU.UTF-8. Причем рекомендации по «откату»
на привычную KOI8R выкладываются в Сеть синхронно с появлением этой
искусственно созданной «проблемы» [8]. Вероятно, тщательная кириллизация Linux
не только стала казаться неактуальной для некоторых пользователей, но даже
и не считается обязательным качеством национальной продукции у некоторых
разработчиков.
Построим сравнительную таблицу дистрибутивов,
не претендуя на полноту обзора. Рассмотрим как декларированные свойства,
так и латентные, подобные тем, что позволили столь эффективно произвести
многие этапы кириллизации SuSE Linux. Выберем для сравнения парочку ведущих
дистрибутивов зарубежного производства и уже упомянутых лидеров отечественного
рынка. Зарубежные в полном формате, а отечественные в однодисковых вариантах,
для того чтобы уровнять шансы. Сравнивать будем наличие системных локалей, локалей
X Window, предложения установщика (в таблице колонки, озаглавленные «Уст.»)
и число шрифтов выбранной кодировки для X Window (например для UTF-8:
«xlsfonts | grep iso10646 | wc -l»; считая, что в них уже содержатся глифы для
кириллицы, что в общем случае не всегда выполняется). Полученные результаты
сведём в таблицу 2.
Таблица 2. Уровень исходной кириллизации
дистрибутивов
|
Дистрибутивы
|
SuSE Linux 10.0
|
RHEL 4 AS
|
ASP Linux 10 OEM
|
ALT Linux Compact 3.0.4
|
|
Критерии
|
glibc
|
Xorg
|
Уст.
|
fonts
|
glibc
|
Xorg
|
Уст.
|
fonts
|
glibc
|
Xorg
|
Уст.
|
fonts
|
glibc
|
Xorg
|
Уст.
|
fonts
|
|
Локали
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
13
|
14
|
15
|
16
|
|
UTF-8
|
Да
|
Да
|
Да
|
512
|
Да
|
Да
|
Да
|
465
|
Да
|
Да
|
Да
|
723
|
Да
|
Да
|
Да
|
59
|
|