
1 Linux Cyrillic Москва май 2005 - март 2006 Алексей Барабанов.
Кириллизация в GNU/Linux.
Принято считать, что в Linux уже давно нет проблем с кириллизацией чего-либо. Эта ОС вслед за другими полным ходом движется в юникодный рай, где, как обещают, вавилонский кризис никому не грозит. Но на практике ситуация еще весьма далека от идеальной.
Введение.
Тема кириллизации, или руссификации, как иногда выражаются, с некоторых пор исчезла с первых позиций рейтингов интереса со стороны неофитов Linux. В нашей стране уже давно не внедряются новые кодировки. И, хотя, по их числу мы не превосходим народности с иероглифическими методами написания, но в европейском регионе явно ходим в рекордсменах. И вот теперь, когда, казалось бы, уже нет проблем, чтобы предложить пользователям Linux все разнообразие проверенных наработок и материалов по кириллизации, многие дистрибуторы начинают экономить, можно сказать, на самом святом. Им кажется, что надо уже сейчас заставить всех пользователей работать в универсальной кодировке UTF-8 (алгоритм 8-го представления символов UNICODE) и в локалях, сделанных на ее основе. Увы, в данном вопросе именно пользователи попадают между молотом и наковальней, между стремлением разработчиков дистрибутивов к псевдопрогрессу и консервативностью рынка прикладного программного обеспечения.
Обсудим данный вопрос подробно на примере дистрибутива SuSE Linux 10.0 и в сравнении на примере ряда других ведущих дистрибуций.
Терминология и проблематика.
Необходимость адаптации программного обеспечения к требованиям интерфейсного окружения обуславливается тем, что существует изначальная проблема определения кодировки символьных данных. Например, в UNIX-подобных системах файлы представляются последовательностью байт. Таким образом, все входные потоки данных, которые, по сути, есть файлы, тоже являются последовательностью индифферентных байтовых кодов. Как же программа априори поймет, что за данные ей передаются? Есть два способа: по содержимому самого потока данных, так называемый in-band, и на основании внешнего предписания, или out-band. Первый способ зависит от формата, второй - диктует формат. Изначально использовался только второй способ. Например, в первых персональных компьютерах исключалось применение символьных данных в кодировках, отличных от кодовой страницы 437 (IBM Codepage 437). Использование данной кодовой таблицы было закреплено аппаратно, то есть внешним путем. С распространением компьютерной технологии в регионах, где приняты иные требования на представление символьных данных, была определена процедура так называемой локализации, или модификации программного обеспечения для использования региональных стандартов. Но данный путь оказался слишком трудозатратным. И тогда было произведено функциональное выделение всех национально-зависимых программных компонентов так, что бы можно было настраивать требуемую локализацию динамически.
Естественно, данная процедура всецело определялась платформой. Так в частности, на обсуждаемой платформе GNU/Linux локализация управляется единым образом на основе 2 Linux Cyrillic так называемых локалей (locale) с помощью системной библиотеки glibc.
Второй способ, in-band, подразумевает, что получив некоторые символьные данные, программа самостоятельно сумеет определить их кодировку, пользуясь лишь информацией из входного потока. Например, кодировка может указываться в самом файле или в начале потока данных. Такой способ принят во многих внутренних форматах, поддерживаемых текстовыми редакторами, в формате HTML для этого используются специальные тэги, а в протоколе HTTP специальные опции, и так далее. Но, несомненно, самым универсальным является способ использования кодировки такого размера (разрядности), чтобы она смогла содержать в себе все возможные символьные комбинации. Так возникла идея кодировки UNICODE (Unicode standard ISO 10646, или Universal Character Set, или UCS) и её более компактной версии UTF-8 [1]. Казалось бы, проблема решена, да не тут то было!
Универсальная кодировка не отправила использование локалей в прошлое, а лишь добавила проблем, поскольку увеличила их число!
Локали в Linux.
Итак, в программном окружении определяется понятие локали как совокупности данных об используемых языковых и национальных особенностях среды исполнения. Именно пользуясь параметрами локали, программа понимает правильным образом символьные входные данные и выводит свои отчеты в правильных кодировках. Здесь, в самом определении, заложена некая условность, приводящая к неверному пониманию сущности происходящего. Бытует мнение, что из привязки локали к процессу следует легкость манипулирования её настройкой. Мол, если локаль передается процессу из окружения, то ничего нет проще, как установить любую локаль прямо перед запуском. Например, в Linux используются для этого переменные окружения LC_* и LANG. Эти переменные формируются в процессе отработки профиля пользователя и далее передаются всем порожденным процессам. Вот, как все просто! Если в системе в базе локализации присутствует нужная локаль, то, указав ее в окружении, мы можем заставить работать с нею любой процесс. Увы, нет! Это со всех сторон наивный взгляд. Чтобы понять свойства локали, давайте взглянем на процесс ее образования.
Как было сказано выше, в системе присутствует база локалей, расположенная в /usr/lib/locale. В SuSE Linux указанная директория принадлежит пакету glibc-locale. Именно там ищутся описания правил национальных стандартов и прочее, что необходимо для традиционного представления данных в соответствии с принятой локалью. И если там нужная локаль отсутствует, то ее можно скомпилировать с помощью утилиты localedef. Для этого следует вызвать утилиту с параметрами: файл описания стандартов локали и файл с описанием соответствия символов юникода (unicode) тем, что приняты для кодирования информации в данной локали. Например, л# localedef -i ru_RU -f CP1251 ru_RU.CP1251 создаст локаль ru_RU.CP1251. Название локали образуется по правилам [язык[_территория][.кодовая_таблица][@модификатор]]. Язык указывается двумя символами в строчном регистре, согласно международному стандарту ISO 639. Территория указывается тоже двумя символами, но уже прописными, обозначающими страну по стандарту ISO 3166. Следующая компонента привязывает к локали кодовую страницу.
Модификатор в кириллических локалях пока не применяется.
Кодировка в локали является тем самым ключевым параметром, позволяющим методом out-band указать на способ расшифровки символов. То есть программа еще и различает все входные данные с использованием кодировки локали и, кроме того, в той же кодировке 3 Linux Cyrillic выводит все сообщения. Ну, положим, если для вывода используются объекты среды, которые наследуют локаль программы, то еще можно надеяться, что при некоторых условиях они будут адекватно воспринимать и отображать кодировку данной локали. Но в отношении входных данных это не всегда верно. Точнее, в отношении входных данных не работает обратная логика. Если локаль процесса, использущего входные данные, не совпадает с локалью процесса, их породившего, то, скорее всего, ничего хорошего не выйдет.
Самый простой пример такой ситуации, когда программа использует ранее накопленные данные, где тип используемой кодировки определяет информацию - это имена файлов, индексы в структурах БД, базы служебных сообщений, сохраненные из Интернета документы. Вы наблюдали на экранах компьютеров кракозябры в сообщениях программ, которые в 90% случаев работали вполне адекватно? Вам приходилось вместо имен файлов видеть всякую бнопню? Это именно те случаи, когда программа воспользовалась строковой константой, подготовленной в другой локали, или пыталась прочесть символьные данные, созданные с использованием иной локали. Даже точно лугадав локаль исходных данных, то есть, казалось бы, сводя проблему к тривиальной перекодировке, не всегда удается достичь успеха. Пример тому - данные, упорядоченные или проиндексированные, в соответствии с алфавитным порядком для некоторой локали.
Здесь перекодировка не даст успеха, а сортировка будет уже не только трудоемкой, но и даже невозможной, если используются разделяемые данные, что характерно для совместной сетевой работы.
Ну хорошо, локаль - это типичное указание out-band кодировки. Примение UTF- должно, по идее, избавить от дополнительного указания на локаль, так как эта кодировка допускает определение локализации на основании самих данных. Но, увы, лишь в теории.
Локаль, безусловно, указывает на единственную используемую в ней кодировку, а вот кодировка может использоваться в разных локалях. И чем универсальнее эта кодировка, тем больше выбор возможных локалей. То есть, в случае абсолютного универсального идеала кодирования информации UTF-8 мы вообще лишились возможности по характеру данных сделать заключение о том, в какой локали эта информация представлена!
Вот и получается, что кажущаяся легкость манипулирования локалью на самом деле не соответствует действительности. Таким образом, локаль, кроме национальной базы стандартов, включает в себя тип кодировки внешней среды, который от процесса не зависит, да и локаль не определяет! И, значит, для того чтобы обрабатывать широкий спектр входных данных, надо иметь в системном окружении весь необходимый перечень локалей для возможных кодировок, и все сопутствующие данные для построения правильной среды исполнения программы. Вот о сопутствующих данных далее и поговорим, но сначала проверим, какие локали нам предлагаются в SuSE Linux.
Локали в SuSE Linux 10.0.
Выполним установку системы по умолчанию, лишь указав, что принимается русский язык, и в результате получим следующую настройку локализации:
> locale LANG=ru_RU.UTF- LC_CTYPE="ru_RU.UTF-8" LC_NUMERIC="ru_RU.UTF-8" LC_TIME="ru_RU.UTF-8" 4 Linux Cyrillic 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 -a | grep ^ru_RU ru_RU ru_RU.koi8r ru_RU.utf > Здесь уже должно быть понятно, что представления об используемых в нашей стране локалях у разработчиков 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- [ "1$(locale -a | grep ^$LP | grep UTF-8)" == "1" ] && \ ln -sf $LOCALE/$LP.utf8 $LOCALE/$LP.UTF- [ "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.CP [ "1$(locale -a | grep ^$LP | grep CP1251)" == "1" ] && \ ln -sf $LOCALE/$LP.cp1251 $LOCALE/$LP.CP [ "1$(locale -a | grep ^$LP | grep iso88595)" == "1" ] && \ $LD -f ISO-8859-5 $LP.ISO-8859- [ "1$(locale -a | grep ^$LP | grep ISO-8859-5)" == "1" ] && \ ln -sf $LOCALE/$LP.iso88595 $LOCALE/$LP.ISO-8859- 5 Linux Cyrillic [ "1$(locale -a | grep ^$LP | grep cp866)" == "1" ] && \ $LD -f IBM866 $LP.CP [ "1$(locale -a | grep ^$LP | grep CP866)" == "1" ] && \ ln -sf $LOCALE/$LP.cp866 $LOCALE/$LP.CP [ "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.cp ru_RU.CP ru_RU.cp ru_RU.CP ru_RU.iso ru_RU.ISO-8859- ru_RU.koi8r ru_RU.KOI8-R ru_RU.maccyrillic ru_RU.MAC-CYRILLIC ru_RU.utf ru_RU.UTF- > Полученные локали позволят работать с кириллицей в соответствии с национальным стандартом 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 и все настраивает интерактивно, то есть в процессе запуска командной оболочки, и потом передается всем порожденным процессам. Таким образом, после модификации 6 Linux Cyrillic переменной 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, далее будем обсуждать именно его.
7 Linux Cyrillic Ввод символов с консоли Linux.
Консольный (иногда его называют терминальным) драйвер состоит из двух частей.
Первая отвечает за ввод с клавиатуры, а вторая за вывод на экран. То есть делится на части в соответствии с функциональным разделением самой консоли на клавиатуру и экран.
Клавиатура может быть как физическим, локальным устройством, так и удаленным виртуальным. То же самое верно и в отношении экрана. Если он локальный, то соответствует экрану консоли, подключенной к компьютеру, а если виртуальный, то в последовательности преобразования может участвовать и консольный драйвер удаленной системы. Поэтому для ясности будем учитывать только локальные устройства.
Рисунок 1. Ввод данных с клавиатуры.
Сначала разберемся, как происходит преобразование вводимых данных. Воспользуемся схемой, представленной на рисунке 1. Изображенная там последовательность преобразования будет иметь место в том случае, когда клавиатурный драйвер включен в режим XLATE и настроен в локали ru_RU.KOI8-R. На рисунке видно, что ключевую роль в установлении соответствия некоторой клавиши и того кода, который будет получать 8 Linux Cyrillic процесс, играет специальная таблица, называемая раскладкой. В этой таблице происходит не только назначение определенного символа каждой клавише, но и производится выбор кодировки. Иначе говоря, чтобы после нажатия клавиши А получить символ А в кодировке 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" Значит, используется кириллическое подмножество UTF-8 (предположительно) с переключением регистров через RightAlt+Shift. Но вот проблема: кириллица вроде бы вводится, а при выводе на экран вместо знаков этого древнего алфавита отображаются лишь пустые знакоместа. Заглянув в исходный текст ru1.map.gz определяем, что там производится отображение не в UTF-8, а в KOI8-R. И это недоразумение, кстати сказать, сопровождает уже несколько версий SuSE Linux подряд. Замена раскладки на ru-utf.map.gz исправляет ошибку разработчиков дистрибутива.
Здесь отметим, что перенастройка режима ввода с консоли производится системным скриптом /etc/init.d/kbd независимо от настроек локали.
Вывод символов в консоль Linux.
Теперь обсудим, как производится вывод символьной информации с помощью драйвера экрана. Для этого воспользуемся схемой, представленной на рисунке 2. На рисунке изображена последовательность преобразования в случае использования кодировки KOI8 R. Настраиваемыми параметрами являются таблица ACM (Application Character Map), предназначенная для перекодировки во внутреннее представления драйвера, таблица SFM (Screen Font Map), предназначенная для получения индекса глифа в экранном шрифтовом наборе, и собственно растровый шрифт. Два последних элемента тесно связаны и очень часто объединяются в единый файл. Файлы экранных шрифтов с именами, использующими суффиксы psfu должны содержать после растрового шрифта соответствующую таблицу перекодировки SFM. Специальная управляющая подстрока CONSOLE_MAGIC используется для активации настроенного преобразования.
Подробности можно узнать в [5]. В общем, все достаточно тривиально.
9 Linux Cyrillic Рисунок 2. Вывод данных на экран монитора.
Как уже было сказано, по умолчанию 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" # 10 Linux Cyrillic И здесь также отметим, что настройка вывода в консоль призводится системным скриптом /etc/init.d/kbd независимо от настроек локали. И лишь воля администратора, редактирующего соответствующий управляющий файл /etc/sysconfig/console должна обеспечить согласование кодировок.
Настройка консоли SuSE Linux.
В отличие от ранее созданных локалей, для обеспечения соотвествующей настройки придется подгрузить в систему дополнительные файлы. В дистрибутивной поставке отсутствует ACM для MAC-CYRILLIC и некоторые клавиатурные раскладки.
Используемые для настройки разных режимов параметры перечислены в таблице 1.
Недостающие отмечены фоновой тонировкой. Эти файлы, как и все приведенные или упомянутые здесь скрипты, можно найти в архиве [7].
Локаль 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 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 1 2 3 4 5 Таблица 1. Параметры настройки кодовых преобразований и локалей.
Вот как должен выглядеть скрипт для переключения локали и консоли в режим работы с кодировкой CP1251, выполненный в точном соответствии с таблицей 1:
# cat console2cp #!/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.
11 Linux Cyrillic Рисунок 3. Консоль в режиме ru_RU.CP866.
Характерной особенностью является отсутствие прописной буквы Ы (на рисунке 3 в строке приглашения консоли), которая совпадает по коду со служебным символом управления кодовыми таблицами SCI (0x9B). Но в остальном, все прекрасно работает.
Итак, потенциально возможно настроить консольный драйвер и окружение пользователя для работы в любой из перечисленных локалей. Так почему же все настойчиво предлагают работать в ru_RU.UTF-8, и так пренебрежительно относятся ко всем остальным локалям?
Использование локали приложениями.
Безусловно, это самый важный вопрос. При его исследовании можно встретить как приятные открытия, так и озадачивающие. Тема эта неисчерпаема, как и сам набор возможных приложений. Для нас здесь принципиальным является тот факт, что корректное использование локалей всецело на совести разработчиков программного обеспечения.
Более того, приложение может луметь использовать локали, но не поддерживать часть из них.
Например, X Window, в используемом большинством дистрибутивов Linux варианте Xorg, является, по сути, обычным приложением. Переведем SuSE Linux в локаль ru_RU.CP1251 и затем внутри работающего X Window переключимся в CP866 и запустим новую сессию 12 Linux Cyrillic konsole. Результат на рисунке 4.
Рисунок 4. Запуск konsole в CP866.
Получаем сразу две проблемы: во-первых, сообщение QT: Locales not supported on X server, и во-вторых, внутри созданного окна не наблюдается кириллицы в CP866. Первая из-за того, что нужная локаль не создана в /usr/lib/X11/locale, а вторая из-за того, что теперь надо для данного экземпляра konsole указать кодировку вручную. Вспоминаем о том, что оптимисты считают локаль свойством процесса и... недоумеваем! Вероятно, оптимисты не входят в число авторов этих программ.
Проявляем настойчивость и получаем уже несколько иной результат на рисунке 5.
Обратите внимание: появилась кириллица в ответе date, корректно представлена псевдографика mc, и, самое главное, нет проблем с прописной Ы, так как клавиатура работает в сыром (raw в оригинале), прозрачном режиме, и текстовая консоль не участвует в процессе вывода. Только не получится повторить то же самое в локали ru_RU.MAC-CYRILLIC, так как в konsole эту кодировку нельзя указать принудительно - ее просто нет. Радует то, что варианты 1-4 из таблицы 1 работают в SuSE Linux в режиме X Window, как говорится, лиз коробки.
13 Linux Cyrillic Рисунок 5. Konsole в CP866 с кодировкой, указанной вручную.
Еще более интересные метаморфозы претерпевает локаль в режиме удаленной работы.
Например, с помощью 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. Password:
Last login: Thu Mar 9 22:03:31 Have a lot of fun...
alekseybb@wsvm02:~> locale 14 Linux Cyrillic 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 alekseybb@wsvm02:~> Как видно из протокола сеанса, командная оболочка запустилась в локали клиента.
Произошло это благодаря тому, что в параметрах сервера 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 wsvm02:~ # А в параметрах клиента, аналогично, передавать переменные среды на удаленную сторону:
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 wsalekseybb:~ # Но если попытаться подключиться к компьютеру в локали 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, который не является кириллически толерантным, что указано в 15 Linux Cyrillic предупреждении инсталлятора, даже такой дистрибутив поддается настройке. Казалось бы, отечественные дистрибутивы должны все описанное в статье иметь как встроенный сервис. Но этого не наблюдается. На Руси с древности повелось так, что народ учили грамоте то всякие пришлые греки, то лушлые варяги. Складывающаяся вокруг компьютерных кодировок ситуация следует исторической традиции. Очередные заморские гуру, в который раз, предлагают отказаться от всего, что было ранее проверено и внедрено, и принять от них новую чудодейственную пилюлю. Ожидаемо, после того, как четыре зарубежные компании создали четыре взаимоисключающие способа кодирования кириллической информации, полностью игнорируя ту, что была создана независимыми отечественными разработчиками, в среде пользователей должен сформироваться иммунитет к языковым авантюрам. Тем более, что, как продемонстрировано выше, единого подхода к работе с локалями не наблюдается вовсе, то есть появление новой локали закономерно приведет к новым хлопотам и проблемам с программами. Но лишь один из ведущих российских разработчиков - ASPLinux - признает сложившуюся ситуацию и предлагает набор локалей и кодировок на выбор (все из перечисленного, кроме экзотической кодировки Mac и устаревшей cp866, в версии 10 ASPLinux). А вот дистрибуция ALT Linux, копируя западный подход, с версии 3.0 полностью переходит в ru_RU.UTF-8. Причем рекомендации по лоткату на привычную KOI8-R выкладываются в Сеть синхронно с появлением этой искусственно созданной проблемы [8]. Вероятно, тщательная кириллизация Linux не только стала казаться не актуальной для некоторых пользователей, но даже и не считается обязательным качеством национальной продукции у некоторых разработчиков.
Построим сравнительную таблицу дистрибутивов, не претендуя на полноту обзора.
Рассмотрим как декларированные свойства, так и латентные, подобные тем, что позволили столь эффективно произвести многие этапы кириллизации SuSE Linux. Выберем для сравнения парочку ведущих дистрибутивов зарубежного производства и уже упомянутых лидеров отечественного рынка. Зарубежные в полном формате, а отечественные в однодисковых вариантах, для того чтобы уровнять шансы. Сравнивать будем наличие системных локалей, локалей X Window, предложения установщика (в таблице колонки, озаглавленные Уст.) и число шрифтов выбранной кодировки для X Window (например для UTF-8: xlsfonts | grep iso10646 | wc -l ;
считая что в них уже содержатся глифы для кириллицы, что в общем случае не всегда выполняется). Полученные результаты сведём в таблицу 2.
Дистрибутивы: SuSE Linux 10.0 RHEL 4 AS ASP Linux 10 OEM ALT Linux Compact 3.0. Критерии: 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 Локали UTF-8 1 Да Да Да 512 Да Да Да 465 Да Да Да 723 Да Да Да KOI8-R 2 Да Да 349 Да Да Да 228 Да Да Да 1027 Да Да CP1251 3 Да 0 Да Да 0 Да Да Да 368 Да Да ISO8859-5 4 Да 102 Да Да 52 Да Да Да 52 Да Да CP866 5 25 0 0 Да MAC-CYRILLIC 6 0 0 0 Число полных 7 1 2 4 поддержанных локалей Таблица 2.Уровень исходной кириллизации дистрибутивов.
Заметно, насколько не согласована политика внутри коллективов разработчиков. Например, 16 Linux Cyrillic в SuSE инсталлятор предлагает лишь UTF-8, тогда как внутри, еще в силу привычки, все есть для безбедной работы в KOI8-R, и это при почти полном игнорировании CP1251, от качества настройки которой в нашей стране существенно зависит интеграция с MS Windows, ну а наличие шрифтов для кодировки CP866 не объяснить никакой адекватной логикой. Точно также непонятно, зачем в ALT Linux Compact 3.0 создана локаль для X Window, соответствующая CP866, при отсутствии всего остального для этой кодировки. На этом фоне лишь ASP Linux можно считать образцом взвешенного и разумного подхода. В строке 7 указано число локалей, полностью реализованных и поддержанных сервисом.
Этот параметр является киррилическим рейтингом по факту.
Так что же произошло на самом деле? Что так неоднозначно понимается создателями продукции, наполняющей внутренний рынок дистрибутивов GNU/Linux? Что их смущает?
К уже имеющим хождение в России пяти кодировкам добавилась еще одна. И всего-то!
После пяти предыдущих надо появление очередной, шестой, встречать с уже натренированным навыком.
Успехов Вам, читатели, в настройке собственных рабочих станций, иногда вопреки загадочному желанию разработчиков, далеких от общественных интересов!
Использованные ссылки:
1.Юникод. Материалы википедии - свободной энциклопедии.
2.RU.LINUX Frequently Asked Questions. Составитель Александр Канавин. Глава 3.
Руссификация. 3.Пакет интернационализации консоли kbd. ftp://ftp.win.tue.nl/pub/home/aeb/linux local/utils/kbd/ 4.Пакет интернационализации консоли console-tools. 5.Костромин Виктор Алексеевич. Линукс для пользователя. Электронный вариант.
6.Поисковая система для rpm. 7.Архив файлов к настоящей статье. 8.Как сменить системную локаль на KOI-8 в дистрибутиве ALT Linux Compact 3.
Книги, научные публикации