Так уж сложилось, что языком разработчиков вычислительных машин был английский язык. ;-)
По мере распространения компьютеров и (ПО) программного обеспечения для них по всему миру, постепенно стала нарастать потребность в обработке информации не только на английском, но и на других - немецком, японском, русском, e.t.c. -- национальных языках.
Потребность в такой многоязыковой поддержке ощущали как пользователи программного обеспечения - для решения своих конкретных задач, так и производители ПО - для расширения рынков сбыта.
Таким образом сложилась идея инернационализации ( internationalization, или сокращенно i18n ) программных продуктов.
Термин интернационализация ( i18n ) подразумевает под собой такой способ проектирования ( дизайн ) ПО, при котором возможность многоязыковой поддержки закладывается с самого начала.
Самым желательным вариантом реализации многоязыковой поддержки является такой, при котором нацонально-зависимая часть приложения хранится отдельно от приложений в виде набора данных : объектов локализации. При этом возможность гибкого и простого изменения языкового окружения под конкретные требования происходит без перекомпиляции этих приложений.
Таким образом, локализация ( localization, или сокращенно l10n ) - это процесс адаптации ПО под конкретные национальные требования . А технически, локализация - это изготовление отдельных объектов локализации в соответствии c требованиями конкретного языка.
POSIX locale
В стандарте POSIX (Portable Operating System) были определены средства локализации, названные locale
(к сожалению, не существует адекватного русского перевода этого термина). Locale (англ.) - местные особенности.
Locale - это такое системное средство (фича ;-) позволяющее настроить систему на работу с данными в конкретном национальном (местном) представлении. Отдаленно напоминает средство CodePage в MS-DOS или OS/2.
Средства POSIX locale охватывает немого больший круг понятий, чем просто работа с национальными символами.
Зачем ? Дело в том, что кроме собственно языка общения и алфавита, в разных странах различаются такие обычаи, как представление даты, времени, финансовых величин и т.д. Эти "культурные правила" уже закреплены традицией и национальными стандартами, иногда довольно давно, поэтому при "локализации" программных продуктов существует необходимость в настройке их еще и на эти "культурные правила". В стандарте POSIX культурные правила объединены в группы - категории локализации.
* ПРИМЕЧАНИЕ : В принципе, каких "культурных нюансов" можно найти много. См. например статью : Colors, Buttons, Words and Culture: Designing Software for the Global Community (копия здесь) или Internationalization. Но в большинстве случаев, для машинной обработки информации вполне хватает понятий POSIX locale.
Структурно, средства POSIX locale состоят из следующих компонентов :
- Набор библиотечных (libc) вызовов (locale API): setlocale(), isalpha(), toupper(), e.t.c.
- Переменные окружения, для управления средствами locale : LANG, LC_CTYPE. e.t.c.
- Утилита для получения информации о средствах locale : locale
- Исходные тексты описания locale : locale definitions, Character Set Definition File
- Утилита для изготовления (компиляции) объектов локализации : localedef
- Собственно объекты локализации (наборы данных locale) : /usr/share/locale/*
* * *
Существующая также "система управления сообщениями на национальном языке" : NLS (Native Language Support) формально не входит в POSIX locale, хотя во многом дополняет функции locale.
Также довольно тесно пересекаются с locale такие механизмы POSIX как поддержка многобайтных (multibyte) и "широких" (wide-char) символов. Эта связь не очень заметна для европейских языков, но в для поддержки алфавитов с большим числом знаков (японский ~2000, китайский ~8000, UNICODE ~25000) это становится жизненно необходимо.
* ПРИМЕЧАНИЕ : POSIX locale HЕ ИМЕЕТ накакого отношения к физическому вводу/выводу в UNIX и к проблемам работы терминала, клавиатуры и печатающих устройств с национальными символами.
Локализация от Microsoft.
Фирма Microsoft уделяет значительное внимание локализации продуктов и захвате национальных рынков программного обеспечения. Первый европейский офис был открыт в 1982 г. В мае 1983 г. была выпущена операционная система MS-DOS 2.1 с поддержкой японского языка для компьютеров IBM 5550 и NEC PC-9801.
Стоит также сказать, что ожидаемая операционная система Windows 2000 (Windows NT 5.0) будет иметь полную поддержку UNICODE, от файловой системы до шрифтов и Notepad. Кроме того, она будет содержать классическую схему локализации : будет разделен исполняемый код и национально-зависимые части. Вся информация, имеющая отношение к "национальной специфике" будет вынесена в "объекты локализации". Таким образом, национальные версии будут отличаться только небольшим числом файлов.
Наиболее полное описание модели локализации от Microsoft можно найти в книге Nadine Kano : "Developing International Software for Windows 95 and Windows NT". Эта книга есть на MSDN.
Language
Информация, полученная из "человеческого" мира и предназначенная для машинной обработки, как правило имеет специальный арибут : язык или language (lang). Причем, не только текстовая, но например audio :
Content-Description: Russian Argo audio sample :-) Content-Type: audio/basic Content-Language: ru
(RFC-1766, ISO-639)
Однако нас инересует именно текстовая информация.
Большинство языков мира имеют письменнось, а некоторые языки даже несколько (например кириллица и глаголица для славянских языков или kana и kanji в японском и т.д.). Определенная система письменности называется script. Системы письменности существуют самые разнообразные (например узелковое :-), но большинство письменностей - это изображение последовательности специальных символов (character).
* ПРИМЕЧАНИЕ : Объяснение концепции символа выходит далеко за рамки данного документа. Мы не будем вдаваться в филологические и философские подробности, а рассмотрим лишь узкий аспект -- способы представления символов (национального) языка для автоматической (машинной) обработки. Тогда термин "символ" (character) можно определить как "единицу текстовой информации" (unit of textual information), которая передается письменно и участвует в машинной обрабоке. Очень важно четко представлять себе, что речь идет об "абстрактном" символе.
Character
Каждый "абстрактный" символ имеет изображение -- glyph. Считается, что каждый символ имеет "каноническое" изображение , то есть такое, которое позволяет однозначно идентифицировать данный символ, то есть распознать и отличить его от других. Таким образом, в модели POSIX и UNICODE не уделяется никакого внимания вариантам начертания символа, то есть шрифтам (fonts) во всем их многообразии, . Поэтому все, что изображено на примере ниже, будет одним и тем же "абстрактным" символом :
ЛАТИНСКАЯ ЗАГЛАВНАЯ БУКВА А (LATIN CAPITAL LETTER A):
В стандарте UNICODE кроме определенного изображения каждому символу присвоено определенное имя :
UNICODE | Character Name | |
---|---|---|
A | U+0041 | LATIN CAPITAL LETTER A |
a |
U+0061 |
LATIN SMALL LETTER A |
Ю |
U+042E |
CYRILLIC CAPITAL LETTER YU |
1 |
U+0031 |
DIGIT ONE |
+ |
U+002B |
PLUS SIGN |
U+03A9 |
GREEK CAPITAL LETTER OMEGA | |
U+2569 |
BOX DRAWINGS DOUBLE UP AND HORIZONTAL | |
и так далее. |
В настоящее время в стандарт UNICODE, входят практчески все употребимые символы (~40.000), и им соответственно присвоены стандартные имена. Последнее значительное изменение -- введение символа валюты EURO в сентябре 1998 г.
Посмотреть набор символов UNICODE можно здесь : http://charts.unicode.org/ .
Таким образом, для нас символ (character) - это единица тектовой информации, имеющая определенное изображение и определенное имя.
Encoding.
Наиболее важным понятием при обработке символов является понятие Coded Character Set (CCS).
Давайте попробуем разобраться, что это такое.
Как мы уже ранее выяснили, существуют определенные "наборы символов" для каждого конкретного языка (алфавит). Набор таких "абстрактных" символов называется character repertoire.
Для автоматической обработки, хранения и передачи символов необходимо каждый "абстрактный" символ перевести в числовую форму для размещения в ячейках ЭВМ.
C "программистской" точки зрения это задача совершенно тривиальна. Нужно просто присвоить каждому символу (абстрактному !) определенное число, которое и хранить в памяти ЭВМ, то есть закодировать символ. Другими словами, определить схему кодирования : CES "character encoding scheme". Например, условимся, что символу 'A' - LATIN CAPITAL LETTER A соответствует число (код) 61. И наоборот, условимся , что число (integer) 61 будет означать ни что иное, как символ 'A'. Таким образом образуется пара (61, 'A') код - символ. И наоборот, символ - код. Соответствие однозначное.
Пусть у нас теперь есть набор символов : character repertoire {'A','B','C'} (это маленькое подмножество символов латинского алфавита). Продолжим кодирование. Тогда из этого множества {'A','B','C'} у нас образуется множество пар : {(61,'A'),(62,'B'),(63,'C')}.
А теперь внимание ! Вот это самое пресловутое "множество пар" имеет колоссальное значение ! Формально оно называется CCS : coded character set. Именно ему присваивается имя : ASCII, ISO_8859-5 или KOI8-R ! Перечитать еще раз !
Давайте рассмотрим подробнее. Итак :
'A' | - это абстрактный символ, "character" |
набор символов {'A','B','C'} | - "character repertoire" |
соответствие : символ 'A' <--> число 61 | - это CES "character encoding scheme", или просто encoding |
число 61 | - это "code point". |
набор чисел {61,62,63} | - это "codeset" или "code space". |
набор пар {(61,'A'),(62,'B'),(63,'C')} | - это CCS "coded character set", или сокращенно charset. |
Что собой представляет CCS ?
Фактически, CCS можно рассматривать как базу данных, в которой хранятся a)символы, b)коды и c)схема соответствия символов и кодов (CES - character encoding scheme) например в виде обычной таблицы - map (charmap). Тогда допустимы операции :
CES('A')=61 CES(61)='A'
Фактически это будет обозначать операции выборки из "базы" :
SELECT CODE FROM CCS WHERE CHAR='A' SELECT CHAR FROM CCS WHERE CODE=61
Естественно, CCS-ов существует огромное множество : ASCII, KOI8-R, ISO_8859-1 или даже UNICODE. И конечно же каждому CCS соответствует его специфицеская CES.
Как работает CCS ?
Очень просто. Пусть у нас есть поток символов ("абстрактных") : "ABBACABCC". Тогда применение CCS к этому потоку (тексту) "ABBACABCC" будет равно применению его CES к каждому символу в потоке :
CES('A') CES('B') CES('B') CES('A')...
и мы получим поток чисел (кодов) : 61 62 62 61 63 61 62 63 63.
Аналогично, применение CCS к потоку кодов даст поток "абстрактных символов".
Отсюда следует один очень простой вывод : при хранении текста (потока символов) мы должны также хранить CCS ! А вот где его хранить - это вопрос. Можно в том же потоке ( "In-band" или "MARK-UP" способ). Можно где-то снаружи потока ("Out-band" способ). Можно хранить лишь имя (ссылку на) CCS.
К сожалению, в стандартном POSIX (например на stdin/stdout) мы имеем только потоки кодов. А вся информация о CCS потеряна. Подробнее про это можно прочитать в статье о локализации POSIX.
СharSets
Давайте теперь рассмотрим собственно наборы символов (character set). Первое что мы должны сделать - это обратить внимание на терминологию. Если мы говорим о наборе "абстрактных" символов, то употребляется термин character repertoire. Если же мы говорим о наборе символов вместе с их
Transfer interrupted!
преобразования символ<-->код, то речь идет о CCS : coded character set. Именно этому набору : coded character set и присваивается имя : KOI8-R, ISO_8859-1, ASCII. Иногда термин CCS сокращают до сharset.
Так например в стандарте MIME употребляется термин сharset, хотя подразумевается конечно же CCS:
Content-Type: text/plain; charset=koi8-r
Content-Type: text/plain; charset=Windows-1251
Content-Type: text/plain; charset=ibm-866
Как определяется character repertoire для определенного charset ?
Чаще всего набор символов определяется из языка (lang) и соответствующей ему системы письменности (script). Иногда рассматривается набор символов, воспризводимый конкретной аппаратурой ( например DEC VT-100 Character Set).
Иногда конкретный набор символов является подмножеством другого, более обширного набора символов или же комбинацией нескольких наборов (или их частей). Например, широко распространенный набор символов для представления русского языка : KOI8-R, содержит в себе символы из наборов LATIN, CYRILLIC, BOX DRAWING, BLOCK ELEMENT и т.д.. А конкурирующий с ним charset - Windows-1251 содержит больше символов из набора CYRILLIC (русские, украинские, белорусские), но меньше - из BOX и BLOCK. Кроме того в KOI8-R нет например символа EURO.
Старшая половина charset (CCS) KOI8-R и code points символов.
Младшая половина совпадает с US-ASCII.
(см. также описние KOI8-R в формате POSIX.)
Существует минимальный (переносимый) (POSIX) Portable Charset - набор символов, который должны поддерживать любые информационные системы (определен в стандарте ISO 646) (он же ASCII). С другой стороны, существует также "универсальный" Universal Character Set (UCS, UNICODE) включающий в себя все возможные символы человеческих языков, технические, картографические и т.д. символы (~40.000 символов) (ISO 10646). Также, для примера, можно упомянуть один из довольно широко распространенных наборов символов : LATIN-1 (Czyborra ISO 8859-1).
Каждый charset имеет определенное имя.
Теперь насчет кодирования. Каким образом выбирается CES ?
Выполнить "кодирование" (encoding) довольно легко как для латинских так и для всех (?) индоевропейских языков (фонетическое письмо). Действительно, закодировать 26 латинских (ASCII) или 33 русских буквы не составляет труда (даже в варианте заглавных и прописных, плюс цифры, плюс знаки препинания). Количество символов (character repertoire) мало, соответственно не велико и code space и получается меньше 256 сode points, что позволяет уместить их в один байт (2^8=256 различных кодовых позиций).
Для языков, чья письменность построена по идеографическому (иероглифическому) принципу, ситуация несколько сложнее. Например в современном японском 1850 "официальных" иероглифов, тогда как в китайском их число доходит до 5000. Одного байта мало. Необходимы обширные CCS, например EUC-JP или UNICODE. Для поддержки таких языков в POSIX введены механизмы Multibyte и Wide Class chars.
В настоящее время в подавляющем большинстве charset-ов применяется 8-ми битное (байтовое) кодирование. Все настолько к этому привыкли, что charset-ы c большим количеством символов (>256) иногда называют large charset.
Проблемы могут возникнуть лишь при необходимости создания многоязычных текстов, например русско-японско-английских, или содержащих русский и иврит, e.t.c. В этом случае - практически единственное решение : UNICODE.
Также проблемы возникают в том случае, если заранее неизвестна кодировка текста (потеряна CES), так как в UNIX, да и в других OS файл не имеет никаких дополнительных атрибутов. Это также актуально для HTTP, в том случае, если кодировка (CES) файла .HTML неизвестна. Это довольно неудобно, поскольку часто единственный способ - это подбор подходящей кодировки... Вывод : указывать кодировку необходимо.
Standarts
Существует несколько стандартов описания сharset и способов их кодирования :
- RFC-1345 Character Mnemonics & Character Sets
- POSIX Character Set Definition File
- ISO 2022
- ISO 9945-2
- UNICODE (ISO10646) UCS-2, UTF-7, UTF-8
- (???)
Описание наборов символов KOI8-R, CP1251, IBM866 в формате POSIX.
Что касается имен зарегистрированных Charset-ов, то смотри здесь.
POSIX
Сначала - немного критики...
Теперь по делу.
Для установки в POSIX-системе новой locale c другим набором символов (charset) применяется утилита localedef для компиляции Файла Описания Локализации и Файла Описания Набора Символов (Character Set Description File).
$ localedef -c -i ru_RU -f KOI8-R ru_RU.KOI8-R
Для проверки установленных в POSIX-системе charset-ов применяется утилита locale :
$ locale -m $ locale charmap
Для преобразования потока символов из одного charset в другой, в стандарте POSIX существуют утилита iconv и функция iconv().
В системе Plan 9 существует утилита tcs.
Категории локализации.
Как уже было замечено, в каждой отдельной стране способ представления данных отличается. Чтобы упорядочить все эти отличия, их объединяют в группы и особым образом описывают. Такая группа признаков называется Категория Локализации :
LC_CTYPE | Определяет правила классификации и преобразования одиночных символов. Позволяет правильно определять вид символа: цифра, буква, значок, заглавная буква или прописная и т.д. Другими словами, включает правильную работу isalnum(), isalpha(), iscntrl(), isdigit(), ... и т.п. для местного алфавита. Вдобавок, включает правильный перевод строчных -- прописных букв: toupper() и tolower(). См. |
LC_COLLATE | Определяет правила сравнения и преобразования строк. Позволяет определять лексикографический порядок символов (порядок сортировки) в местном алфавите. Включает правильную работу strcoll() и strxfrm(). Оказывает непосредственное влияние на работу утилит типа sort и т.д. |
LC_TIME | Определяет правила национального представления времени и даты. Задает именование дней недели, месяцев и т.п. а также задает способ написания даты и времени. (12/24) Hепосредственно влияет на strftime() а через нее на утилиты date и т.д. |
LC_NUMERIC | Определяет правила национального представления чисел с плавающей точкой. Влияет на strtod() и форматы %f и %g printf(), scanf(). |
LC_MONETARY | Определяет правила национального представления денежных величин. (См. Currency Symbols ISO 4712) strfmon(). |
Особая категория локализации LC_ALL служит для обращения одновременно ко всем категориям, т.е. работает как '*' (wildcard).
В стандарте POSIX 1996 кроме категорий локализации стандартизированы также Ключевые Cлова (keywords), которые определяют внутреннее содержимое категорий локализации. Hапример, для категории LC_CTYPE определены ключевые слова: alpha, digit, xdigit и т.д. Для категории LC_TIME определены ключевые слова : mon, day, abmon, abday, e.t.c. (названия месяцев, название дней недели, в полной и в сокращенной форме), а также способ записи даты во внешнем представлении и т.д. Получить доступ к ключевым словам категорий локализации можно с помощью функции nl_langinfo() (не входит POSIX, но входит в XPG).
Формальное описание категорий локализации содержится в файле locale definition "описания локализации". Этот файл может быть 'откомпилирован' утилитой localedef.
Кроме перечисленных выше категорий локализации иногда также определены:
LC_RESPONSE - Hабор "стандартных" местных ответов ja, si, да, yes, e.t.c.
LC_MESSAGES - Hабор стандартных сообщений об ошибках: "File not found", "Файл не найден".
В POSIX категория LC_RESPONSE входит в LC_MESSAGES. Кроме того, значение LC_MESSAGES оказывает влияние на NLS.
Для локализации системы X Window используются ее собственные настройки locale (Xlocale), которые здесь не рассматриваются. Смотри здесь или здесь.
Как включить локализацию ?
Если на UNIX машине (с POSIX:1996) средства locale правильно установлены и программы правильно написаны, то локализация включается путем задания строки окружения LANG :
$ export LANG={язык}
Если такой строки окружения нет, то работает значение локализации по умолчанию : LANG="C" или LANG="POSIX" (что то же самое) - минимальный набор параметров, необходимый для функцонирования программ на ANSI C (ISO 9899:1990), в кодировке US-ASCII (7 bit) (Portable Character Set).
Если ваша система имеет полный набор утилит POSIX.2, то узнать установленные в системе и допустимые значения для LANG= можно командой locale :
$ locale -a
По новому стандарту (POSIX.2 приложение E (?)) значения локализации записываются в форме:
language_TERRITORY.Codeset
или формально:
language[_TERRITORY[.Codeset[@modyfier]]]
Стандарт ISO 639 описывает "language names", ISO 3166 - "territory names". Территории _SU более не существует (вернее теперь она означает Судан), однако для совместимости некоторые системы продолжают ее поддерживать как alias : ru_SU --> ru _RU.
К сожалению, стандарта на названия Codeset-ов формально нет (см. Charset и его имя), но в основном принято пользоваться названиями, зарегистрированными для MIME в IANA или в RFC-1700.
Для русского языка LANG={язык} устанавливается как правило равным LANG="ru_RU.KOI8-R" или LANG="ru_RU.ISO_8859-5" . То есть :
$ export LANG="ru_RU.KOI8-R"
Согласно стандарту допустимы также короткие именования значений locale, которые часто оформляются как aliases (псевдонимы) полного наименования. Hапример "C" --> "POSIX".
$ export LANG=ru $ export LANG=ru_RU $ export LANG=ru_RU.KOI8-R
Однако, если вы указываете короткое имя, может оказаться что Codeset вовсе не KOI8-R (см. например RedHat troubles). Лучше не пользоваться умолчаниями, а указывать точное длинное имя.
Во FreeBSD 2.x так и есть. Для Linux - зависит от дистрибутива. В коммерческих реализациях (Solaris, SCO, AIX e.t.c.) как правило используется значение LANG="ru_RU", или укороченное LANG="ru" (и как правило Codeset ISO8859-5 по умолчанию).
Hекоторые могут пожелать сделать себе локализацию в другом наборе символов : ru_RU.X-CP-866 ( ru_RU.IBM866 ), ru_RU.x-mac-cyrillic, ru_RU.ISO_8859-5 или даже ru_RU.CP1251 - на это нет никаких ограничений. :) Все эти кодировки совершенно равноправны и зарегистрированы (кроме x-mac-cyrillic) в IANA . Только не забудте, что локализация, ввод-вывод и отображение национальных символов на терминале - это совершенно разные вещи.
Для США LANG={язык} устанавливается LANG=en_US.US-ASCII (что полностью совпадает с LANG=C) или LANG=en_US.ISO646-IRV (ISO646-IRV - это тот же US-ASCII, но опубликованный ISO). А вот для Великобритании необходимо устанавливать LANG=en_GB.ISO8859-1 поскольку в наборе символов US-ASCII не содержится символа "фунт стерлингов".
Переменная окружения LANG впервые была введена в HP-UX Multi Language Subsystem и формально относится к подсистеме NLS, и поэтому имеет множество "побочных" эффектов : изменяет пути поиска и язык message-catalog-ов (NLSPATH), пути поиска и язык страничек man (MANPATH), влияет на систему X-Windows, MOTIF e.t.c.
Если система локализована не полностью и использовать полное переключение на другой язык (с помощью export LANG={язык}) нельзя, можно включить locale только для функций locale API библиотеки libc, задав значение категорий локализации. Можно также присваивать разные значения разным категориям, задавая их имена в строках окружения :
$ unset LANG
или
$ export LANG="C" $ export LC_CTYPE="ru_RU.KOI8-R" $ export LC_COLLATE="ru_RU.KOI8-R" $ export LC_TIME="C"
- (если Вас раздражают русские даты, сообщения и man-ы, но нужно обрабатывать русские буквы ;-) и т.д.
По возможности сдедует использовать как можно более полное имя для задания локализации, например :
$ export LANG="ru_RU.KOI8-R" $ export LANG="ru_RU" $ export LANG="ru"
- первый вариант наиболее предпочтителен, поскольку точно задает язык, страну и кодировку.
Не рекомендуется использовать строку окружения :
$ export LC_ALL={язык}
поскольку формально такой категории локализации нет, она "виртуальная" и обозначает "одновременно все категории" (* - wildcard). Из за этого во многих реализациях locale API возникают проблемы после вызова функции setlocale(LC_ALL,"") поскольку LC_ALL оказывается "сильнее" чем конкретная категория, например LC_TIME.
Проблемы могут возникнуть также с программами, работающими с PostScript : в категории LC_NUMERIC локализации ru_RU в соответствии со стандартом ГОСТ в качестве десятичного разделителя используется символ 'запятая' : "," в то время, как в стандарте языка PostScript : точка "." А категория LC_NUMERIC оказывает влияние на printf("%f",float); . Используйте значение C (POSIX) для LC_NUMERIC, если вы работаете с PostScript :
$ export LC_NUMERIC="POSIX"
Посмотреть текущие значения категорий локализации можно все той же утилитой locale (без параметров).
$ locale
После включения, работу средств локализации можно проверить.
* ПРИМЕЧАHИЕ: Хотя MIME и POSIX locale используют одни и те же концепции charset и codeset, взаимоотношение между MIME и locale далеко не однозначно. Так что правильная настройка locale вовсе не гарантирует правильную работу почтовой системы (в области работы с национальными символами).
* ПРИМЕЧАНИЕ: В некоторых современных системах начинает появляться локализация в UNICODE. Включается она заданием строки окружения LANG="en_US.UTF-8" для США или соответственно LANG="ru_RU.UTF-8" для России, LANG="ja_JP.UTF-8" для Японии и т.д. См: UTF-8 FAQ.
Как установить locale ?
Способ установки средств locale может довольно сильно различаться в операционных системах от разных производителей, особенно для старых реализаций POSIX до 1996 года и переходных реализациий.
Как описано тут, структурно средства POSIX locale состоят из следующих компонентов :
- Набор библиотечных (libc) вызовов (locale API): setlocale(), isalpha(), toupper(), e.t.c.
- Переменные окружения, для управления средствами locale : LANG, LC_CTYPE. e.t.c.
- Утилита для получения информации о средствах locale : locale
- Исходные тексты описания locale : locale definitions, Charfcter Set Definitions File : /usr/share/i18n/*
- Утилита для изготовления (компиляции) объектов локализации : localedef
- Собственно объекты локализации (наборы данных locale) : /usr/share/locale/*
Предположим, что библиотека libc на Вашей системе содержит все необходимые вызовы. Иначе придется поменять библиотеку (или систему). :-)
В стандарте POSIX.2 (Утилиты командной строки) определенны две утилиты - locale и localedef. Если система отвечает стандарту POSIX.2:1996, на вашей машине они имеются.
Утилита locale служит для получения различной информации о текущих значениях категорий locale, o всех установленных в системе возможных locale и о внутренних характеристиках различных категорий locale.
Имея утилиту locale можно проверить наличие необходимых "объектов локализации", а потом включить необходимое языковое окружение.
Ситуация чуть осложняется, если необходимые "объекты локализации" отсутствуют. К счастью, стандарт POSIX варианта 1996 г. сделан более переносимым, не зависящим от конкретной реализации и все действия пользователя не различаюся от системы к системе и их внутренняя реализация скрыта за утилитами POSIX.2.
Если в системе не предустановлено нужные нам "объекты локализации", они могут быть добавлены в систему с помощью утилиты localedef путем компиляции специальных (текстовых) файлов описания параметров : Файла Описания Набора Символов (Characher Set Definition File) и Файла Описания Локализации (locale definitions) . После этого они становится изветным системе и видимым по `locale -a`.
$ localedef -c -i ru_RU -f ISO_8859-5 ru_RU.ISO_8859-5 $ localedef -c -i ru_RU -f KOI8-R ru_RU.KOI8-R
Данные файлы в исходном (текстовом) виде можно получить из коллекции ftp://dkuug.dk/i18n или из комплекта исходных текстов библиотеки glibc 2.x (./localedata/*
).
Файлы Описания Локализации (locale definitions) сделаны независимыми от Charset-а, поэтому один и тот же файл ru_RU подойдет для "компиляции" locale : ru_RU.ISO-8859-5, ru_RU.KOI8-R, ru_RU.CP1251.
К сожалению, в некоторых системах (например в glibc) localedef изменяет имя Charset, поэтому после localedef каталог необходимо переименовать.
Еще один вариант - это просто скопировать недостающие файлы-"объекты локализации" в двоичном виде. Некоторые производители UNIX поставляют для своих систем продукт "Language Kit", который есть ни что иное, как комплект данных файлов. К сожалению, стандарт POSIX никак не определяет внутренний формат объектов локализации. Поэтому "Language Kit" одной системы (или даже версии) скорее всего не подойдет к другой системе.
Для расширения кругозора, можно ознакомится с примером реализации подсистемы locale в операционной системе Linux.
Как проверить, что локализация заработала ?
Если у Вас полная реализация POSIX.2 1996, то проще всего воспользоваться утилитой locale.
Применяя locale можно получить множество полезных сведений :
- какие возможные значения locale уже инсталлированы и известны системе.
$ locale -a
- каковы текущие значения отдельных категорий локализации :
$ locale
- каково внутреннее содержание какой-либо категории :
$ locale LC_CTYPE $ locale LC_TIME
e.t.c.
- каковы текущие значения ключей (keywords) в какой-либо категории локализации :
$ locale alpha $ locale toupper $ locale abmon
e.t.c.
Также можно воспользоваться такой короткой прогрммкой :
/* testlocl.c : Минимальная проверка работоспособности locale, категория LC_CTYPE, "ключевое слово" - alpha */ #include |
Для русской локализации в koi8-r согласно RFC-1489, коду 0x0f9 соответствует русская буква "Ы" :
F9 CYRILLIC CAPITAL LETTER YERI
то есть. :
$ cc -o testlocl testlocl.c $ ./testlocl LC_CTYPE = ru_RU.KOI8-R isalpha(Ы) = yes $
Правильность работы категории LC_COLLATE можно проверить даже не компилируя тестовых программок, предполагая, что утилиты tr и dd работают в соответствии с POSIX :
$ echo ы | tr '[:lower:]' '[:upper:]' Ы $ echo ы | dd conv=ucase Ы 0+1 records in 0+1 records out $
NLS. Сообщения на родном языке.
Ранее уже упоминалась возможность получения сообщений и работы с программой на родном языке. Такая возможность существует, и даннное средство называется NLS (National (или Native) Language Support).
"Национализация" в действительности включает в себя несколько аспектов :
- Перевод сообщений программы на национальный язык.
- Присвоение значения категории локализации LC_MESSAGES и/или переменной LANG.
- Перевод описания программы для man.
Чтобы организовать работу с сообщениями программы и дать возможность переводить их на другие языки, было введено такое понятие, как message catalog ( каталог сообщений ). Каталог сообщений хранится отдельно от программы. Естественно, каждая программа может ( и должна ! ) вести свой собственный каталог сообщений, а система NLS предоставляет средства для поддержки корректной работы. Большинство программ, а также системные библиотеки (libc и т.д.) используют NLS и их сообщения могу быть переключены на другой язык.
Message catalog - это фактически база данных, выборка из которой происходит по ключам :
- выбранный пользователем язык сообщений,
- имя исполняемой программы,
- конкретное сообщение в программе.
В результате, на выходе, мы получаем строку конкретного сообщения конкретной программы на нужном нам языке.
Система NLS предоставляет набор стандартных библиотечных вызовов для работы с каталогами сообщений и набор утилит для создания и поддержания этих каталогов (базы).
В настоящее время существут две основных реализации NLS :
- X/Open XPG3/XPG4 (с функцииями catopen(),catgets(),catclose() и утилитой gencat )
- SUN XView (с функциями gettext(), textdomain() ) См. статью и пример реализации GNU gettext.
В наиболее широко распространенной реализации XPG4 всем сообщениям программы присваивается определенный номер, который служит индексом для поиска текстовой строки в message catalog-е. Кроме того может существовать несколько наборов (sets) сообщений внутри одного каталога.
Для поиска самих message catalog-ов от данной программы используется переменная окружения NLSPATH .
Пример (XPG4):
Данный пример демонстрирует три этапа получения сообщения из каталога:
- Исходный текст message catalog-a
- Компиляция message catalog-а
- Использование message catalog-a
1. Исходный текст message catalog-a:
example.msg file:
$quote " $ every message catalog should have a beginning set number. $set 1 This is the set 1 of messages 1 "Hello world\n" 2 "Good Morning\n" 3 "example: 1000.220 Read permission is denied for the file %s.\n" $set 2 1 "Howdy\n" |
2. Компиляция message catalog-а :
Полученный файл обрабатывается утилитой gencat для получения файла каталога .msg .
ПРИМЕЧАНИЕ: Здесь рассматривается исходная XPG4 версия, однако входящая в состав Linux libc (libc5) Linux gencat отличается ключами командной строки и имеет дополнительные возможности (не XPG). В частности, используя символ # можно определять костанты для генерации *.h файлов. (см. tutorial ). Однако в GNU libc (libc6) все приведено в соответствие с XPG (см. glibc FAQ).
$ gencat example.cat example.msg
3. Пример использования message catalog-a :
/* X/Open XPG4 message catalog test */ #include |
Запуск:
$ cc -o example example.c $ export NLSPATH=%N <-- (не забыть поменять назад) $ ./example
Ввод/вывод в системе UNIX и локализация.
Когда-нибудь здесь будет небольшая статься о вводе/выводе в системе UNIX. :-) Пока же читатель может посмотреть кучу специальной литературы. Например :
Робачевский А.М.
"Операционная система Unix"
СПб. Издательство BHV
Санкт-Петербург, 1997
ISBN 5-7791-0057-8Andrei Robachevsky
Federal Centre RUNNet
e-mail:
phone: +7-812-2388598
fax: +7-812-2327622
http://www.runnet.ru
Здесь же кратко коснемся только проблем локализации ввода/вывода UNIX.
Итак, цитируем :
В UNIX существуют 6 типов файлов, различающихся по функциональному назначению и действиям операционной системы при выполнении тех или иных операций над файлами :
|
Продолжаем цитировать :
Из этого следует, что в общем случае не существует никакого способа узнать не только кодировку, но даже тип данных, содержащихся в файле.
В принципе, существуют два основных способа определения содержимого файла (набора/потока данных) :
- In-band - свединия о кодировке содержатся внутри файла
- Out-band - сведения о кодироке содержатся снаружи, где-то в другом месте.
Самый известный In-band способ - MIME. Здесь кодировки и вид содержимого описываются явно, в полях Content-Type: text/plain; charset=koi8-r и Content-Transfer-Encoding: base64. Концепции MIME (описание типа) используются также в HTTP (RFC-2616).
Также In-band сведения о содержимом и кодировках содержатся, например, в файлах Microsoft Word .DOC(с включенными OLE объектами), Windows .EXE и .DLL (ресурсы), e.t.c. К In-band методам можно отнести и разнообразные языки разметки (MARK-UP Languages), например тэг
Теперь об Out-band (внешних) способах. К сожалению, в UNIX поддерживается простая однопотоковая концепция организации файла. Нет никаких ресурсных вилок, как в MacOS HFS, нет Meta Info как в OS/2 HPFS. Файл - это просто набор данных, имеющий имя (ну, еще даты создания/изменения/доступа, ну еще права доступа : rwxr-xr-x ). Без всяких "расширенных атрибутов".
Проблема зашла так далеко, что в UNIX появилась специальная утилита file, которая "эвристическими методами" пытается определить тип содержимого.
Единственный более-менее распространенным способом определения типа файла является расширение, то есть несколько конечных символов в имени файла после точки : ".txt". На самом деле, никакого стандарта на "расширения" в UNIX нет, так как точка : "." является допустимым символом имени. Так что вполне могут встретится имена типа "file.doc.tar.gz", "file............txt" или ".profile".
Тем не менее, многие программы ориентируются именно на "расширения", особенно при переводе в MIME, например для простановки типа в HTTP (RFC-2616):
- apache (/usr/local/etc/http/mime.types)
- squid (sqiud-1.1.2x/include/mime.table)
- lynx (/usr/local/etc/lynx.cfg [SUFFIX])
Насколько ненадежен этот метод, можно судить например по тому, что текстовый (!) файл "ls-lR.ftp.anu.edu.au" упорно интерпретируется как "audio/basic" и некоторые программы пытаются его "сыграть" ;-))
Тем не менее, иногда этим можно пользоваться, например задавая определения типов (и многие другие атрибуты) для файлов текущего каталога, в файле ./.htaccess от apache ( модуль mod_mime ):
AddType text/plain text AddEncoding x-compress Z AddIconByType (TXT, icons/text.gif) text/plain AddIconByEncoding (COMP, icons/comp.gif) application/x-compress e.t.c. |
Ну чем не Out-band метод ? Правда доступ к файлу в таком каталоге осуществлять придется только через HTTP от apache. ;-)
Но продолжаем цитировать :
Файл в файловой системе имеет некоторое имя - последовательность символов. Когда-то считалось, что имя файла может состоять только из 7-bit ASCII символов. В случае же использования национальных символов для имени файла возникают проблемы. И в стандарте POSIX решения нет.
Существующие способы определения кодировки символов в имени файла :
- Файловая система поддерживает UNICODE, например в UTF-8 или UCS-2 :
- JOLIET
- NTFS
- EXT2FS (Linux)
- Кодировка явно указывается (не POSIX ! ) :
- При монтировании файловой системы :
- Linux mount :
$ mount -t vfat -o umask=002,noexec,gid=100,codepage=866,iocharset=koi8-r /dev/hdb1 /mnt - FreeBSD mount : /etc/fstab
/dev/sd0s1 /dos/c msdos rw,-W=koi2dos,-L=ru_RU.KOI8-R 0 0
детальное описание опций -W и -L смотрите в mount_msdos (8)
- Linux mount :
- SAMBA :
client code page = 866
character set = koi8-r
- При монтировании файловой системы :
- ??
Все операции, оперирующие с именами файлов должны быть как минимум прозрачны в отношении 8 бит.
Блочные файлы устройств позволяют организовать доступ к физическому устройству точно также, как доступ к обычному файлу. И точно также, как при работе с обычным файлом, интерпретация содержимого остается задачей программы. Никакой информации о кодировках содержимого не поддерживается.
Более неприятна ситуация с симольными (character) устройствами, где также совершенно не существует определения character set. Другими словами, стандартными средствами UNIX (POSIX) невозможно ни определить текущую, ни установить необходимую кодироку символьного устройства (например, терминала).
Стандартных средств изменения и определения кодировки нет ни для "настоящих" (подключенных через ASYNC-port) терминалов , ни для эмуляторов консоли (SCO, BSD или LINUX console), ни для окна xterm в X-Windows (работающих через псевдотерминалы /dev/pty). Понятий "кодировка" или "набор символов" нет ни в процедурах управления терминалом : termios (POSIX), ни в базах описания терминалов termcap и terminfo, ни даже в "высокоуровневых" библиотеках управления терминалом curses и ncurses. (TODO: посмотреть slang ).
Точно также, нет указателя Charset у потоков STDIN, STDOUT, STDERR.
* ПРИМЕЧАНИЕ: В настоящее время наметилось несколько путей решения этой проблемы:
-
login class расширения BSD ( не POSIX ! )
http://www.freebsd.org/handbook/handbook.html part 2.13
(или то же самое, через Linux PAM) - CHARSET-параметр протокола telnet. RFC-2066.
- Новые переменные termacp/terminfo, определяющие charset.
- "Последовательности переключения" ISO-2022 у xterm
- Реализация консоли с поддержкой UNICODE (в виде UTF-7, UTF-8). Linux UTF-8 FAQ.
FIFO или именованый канал - это файл, используемый для связи между процессами. FIFO впервые появились в System V UNIX, но большинство современных систем поддерживают этот механизм. |
Не вдаваясь в тонкости отличий System V и BSD, скажем о FIFO следующее :
- Именованный канал имеет имя. Информацию о именах смотри в пункте Каталог.
- Функционально FIFO весьма близок к Сокету.
Собственно, на имя связи и на ее содержимое распространяются те же правила, что и на имя в Каталоге.
Сокет. Сокет представляет собой двусторонний канал обмена данными между процессами и является одним из механизмов IPC (Inter-Process Communication). |
Механизм сокетов был разработан для унификации межпроцессорного взаимодействия и должен был работать независимо от :
- Реального механизма передачи информации (IP, IPX, X.25, e.t.c. )
- Формата и схемы адресации (формата адресов) объектов
- Сетевого или локального характера взаимодействия
Для описания характеристик взаимодействия было введено понятие коммуникационный домен (communication domain). Сокеты создаются в рамках определенного коммуникационного домена, и, кроме прочих характеристик, имеют соответствующее имя (связываемое с сокетом при помощи вызова bind() ).
- В коммуникационном домене AF_UNIX сокет связывается с определенным именем файла в файловой системе. Соответственно, на имя этого файла распространяются все правила именования в Каталоге.
- В коммуникационном домене AF_INET имена являются именами хостов Internet, на которые распространяются правила RFC-1035 "Domain names - concepts and facilities".
- В коммуникационном домене AF_NS (куда входят IPX/SPX) - ???.
Не вдаваясь в подробности функционирования Socket API, рассмотрим лишь отношение сокетов и методов кодирования передаваемой информации.
Сокеты (stream socket), после установления соединения предоставляют процессам чистый 8-ми битный канал обмена информацией (Out-Of-Band данные не рассматриваются). В принципе, пользователь может передавать данные в совершенно произвольном формате. Однако, существуют некоторые "устоявшиеся правила" организации протоколов обмена данными (IPC).
1. Разделять управляющую информацию и пользовательские данные. Как сказано в RFC-2277 "Srtings for humans, Protocols for computers".
2. Текстовый управляющий протокол - это "правильная вещь". (c) Eric S. Raymond, разработчик fetchmail. Для облегчения разработки и сопровождения протокола, управляющие команды и ответы сервера лучше сделать в виде текстовых строк.
3. Хорошо разработанный протокол содержит в себе созможности Handshake (или Negotiation)
- Language Negotiation, например, поля
Accept-Language:
Content-Language:- Type & Charset Negotiation, например, поля
Accept:
Accept-Charset:
Content-Type: text/plain; charset=
Content-Type: text/html; charset=- Transfer Encoding Negotiation
Accept-Encoding:
Content-Transfer-Encoding:См. например один из документов проекта Multiweb.
Кто занимается стандартизацией locale ?
Изначально стандарт на средства POSIX locale был заявлен Международной организацией по Стандартизации ISO и IEC в составе стандарта POSIX ( Portable Operating System Interface for Computer Environments ):
- POSIX.1 (ISO/IEC 9945-1:1988) - Интерфейс
- POSIX.2 (ISO/IEC 9945-2:1998) - Команды и утилиты
Позднее он был принят комитетом IEEE как IEEE Std. 1003.1-1990 а позже введен в стандарт ANSI C ( ISO 9899:1990 ).
В дальнейшем, в позднейших выпусках POSIX :
- POSIX.1 ( ISO/IEC 9945-1:1992, он же IEEE Std. 1003.1-1992)
- POSIX.2 ( ISO/IES 9945-2:1992, он же IEEE Std. 1003.2-1992)
и в выпусках 1994 и 1996 г.г. дополненных POSIX.2a, POSIX.2b, стандартный набор средств для локализации был расширен, сделан более переносимым и был более документирован.
Свой вклад в развитие localе внесla также X/Open Co Ltd. , образовав Joint Internationalization Group (JIG) и выпустив документы XPG2, XPG3, XPG4 (X/Open Portability Guide) включающие в себя также главы о локализации :
- XPG2 : X/Open Portability Guide, Volume 2, January 1987, XVS System Calls and Libraries (ISBN: 0-444-70175-3).
- XPG3 : X/Open Specification, February 1992, System Interfaces and Headers, Issue 3 (ISBN: 1-872630-37-5, C212); this specification was formerly X/Open Portability Guide, Issue 3, Volume 2, January 1989, XSI System Interface and Headers (ISBN: 0-13-685843-0, XO/XPG/89/003).
- XPG4 : X/Open CAE Specification, July 1992, System Interfaces and Headers, Issue 4 (ISBN: 1-872630-47-2, C202).
В настоящее время происходит постепенный переход на стандарт POSIX 1996 и сосуществуют самые различные реализации, включающие в себя элементы как старого POSIX 1988, так и нового POSIX 1996 в той или иной мере.
Практически все современные коммерческие реализации Unix-ов имеют полную реализацию стандартов POSIX.1 (вызовов) и POSIX.2 (утилит) версии 1996 (в отношении locale).
Из Free реализаций наиболее известны две : 4.4BSD Lite libc и GNU libc (получившая дальнейшее развитие в Linux libс) также поддерживающие POSIX 1996 .
В недалеком будущем возможно включение в стандарты локализации стандарта UNICODE (16-битныx символов) и возможности работы с ними.
В других операцонных системах, таких как Windows NT, Windows'95, OS/2 Warp, Nowell Netware и т.д. также существуют средства локализации, в общих чертах повторяющие средства локализации POSIX.
Другие стандарты ISO :
ISO 646 - 1983, ISO 7bit coded character set for information interchange. Same as 7bit ASCII.
ISO 2022 - 1986, ISO 7bit and 8bit coded character sets; Code extension techniques. Using the graphic characters and encoding later defined in is8859-1.
ISO 4873 - 1986, ISO 8bit code for information interchange; Structure and rules for implementation. Using the graphic characters and encoding later defined in is8859-1.
ISO 6429 - 1988, ISO 7bit and 8bit coded characters sets; Additional control functions for character-imaging devices.
ISO 6937/2 - coded character sets for text communication; contains part 2 on latin alphabetic and non-alphabetic graphic characters.
ISO 9036 - Arabic 7bit coded character set for information interchange.
ASMO 449 - 7bit coded Arabic character set for information interchange.
ISO/IEC 10367 - Repertoire of standardized coded graphic character sets for use in 8bit codes.
ISO/IEC 10646 - Universal Coded Character Set, same as Unicode. UCS - same as Universal Coded Character Set.
JIS x0208 - Japanese Industrial Standard codeset.
KS C5601 - Korean Standard codeset.
CNS 11643 - Chinese (ROC) codeset.
GB 2312 - Chinese (PRC) codeset.
Что значит "программа правильно написана" ?
Давайте рассмотрим теперь, как писать "правильные" с точки зрения локализации программы. Основное внимание уделим стандартам.
(Но и у стандартов есть свои проблемы. Поэтому - немного критики).
"Правильно" написанная программа с использованием POSIX locale не должна зависить от способа кодирования ("кодировки") символов. Такая программа не должна быть привязана к 7-ми битности ASCII символов, и должна пользоваться стандартными библиотечными (API) функциями locale : isalpha(), isupper(), isxxx() и tolower()/toupper() не полагаясь, что
Upper=Lower+0x20
и т.д. Конструкции, подобные этой также недопустимы :if (c >= 'A' && c <= 'Z') { ...Пользуйтесь :
if (isalpha(c) && isupper(c)) { ... или if (isascii(c) && isupper(c))Как правило, национальные алфавиты расположены начиная с кода (codepoint) 0x80, поэтому для совместимости со старыми реализациями locale можно объявить все символы как unsigned char, например ключом компилятора (для gcc -funsigned-char) или явно.
Хорошо написанная программа должна быть польностью 8-бит прозрачна. Например отметка удаленного файла в MS-DOS кодом
0x0E5
- не очень хорошее решение. Еще примеры плохих решений : знаменитая русская буква "Н" в редакторе GoldEd или русская буква "р" в Norton Commander...
Во-вторых, программа должна явно начинаться с вызова setlocale(LC_ALL,"") (такая форма вызова означает, что всем категориям локализации одновременно будет присвоено значение переменной окружения LANG). До вызова этой функции (или совсем без него) программа не обращает внимания на LANG= и фунции isalpha()... работают в локализации POSIX (С) и с набором символов ASCII. То есть, не бывает "никакой" локализации.
ПРИМЕЧАHИЕ: Во FreeBSD можно вылечить некоторые программы, в которых забыт вызов setlocale() путем задания строки окружения :
$ export ENABLE_STARTUP_LOCALE=""
тогда setlocale(LC_ALL,"") будет вызываться автоматически при старте программ (без их перекомпиляции).В Linux libc такого нет (пока?) и по умолчанию всегда включено LANG="C" или "POSIX". Однако можно пересобрать Linux libc, указав другое значение по умолчанию. Но следует отметить, что такое решение будет противоречить стандарту, по которому программа стартует в POSIX (до первого вызова setlocale()).
Для получения locale-зависимой информации следует пользоватся данными структуры lconv, которые можно получить вызовом функции localeconv() . Для получения детальной информации по категориям локализации (описанным в файле
) можно пользовться функцией nl_langinfo(). (Эта функция не входит в POSIX, но входит в XPG, и большинство систем ее имеют). Для сравнения строк символов следует пользоваться функциями strcoll() и strxfrm() вместо strcmp().
Для полной поддержки сообщений на родном языке (NLS) весь вывод сообщений пользователю должен происходить c использованием функций NLS и должен быть создан каталог сообщений (message catalog) для данной программы (и данного языка).
А в заключение, неплохо бы иметь man на разных языках. :-)
Функция setlocale() .
Основной функцией POSIX locale API является функция selocale(). Данная функция определена в #include файле locale.h как :
char *setlocale(int category, const char * locale);Существует три основных формы вызова этой функции :
- setlocale(LC_XXX,"language_TERRITORY.Codeset");
- setlocale(LC_XXX,"");
- str=setlocale(LC_XXX,NULL);
Первая форма применяется для установки конкретной категории локализации в конкретное значение.
Вторая форма применяется для установки категории локализации "по умолчанию". В этом случае значение категории локализации берется из переменных окружения.
Третья форма - это скорее форма GET - позволяет получить текущее значение категории локализации.
Локализация и POSIX.
Если мы говорим о файле, то в идеологии POSIX, файл - это просто плоская последовательность байтов. Внутреннее содержимое не стандартизовано никак. Поэтому невозможно определить, какую информацию содержит файл, а если он содержит текстовую информацию -- в какой она кодировке. То же самое можно сказать о потоках : stdin/stdout -- это потоки байтов (кодов). Кодировка (т.е. соответствие символ-код (CES)) полностью потеряна и нигде не указывается. И POSIX вовсе не гарантирует, что CES (кодировка) stdin будет совпадать с текущей локализацией, заданной через LANG=.
Точно тактая же ситуация с терминальным вводом/выводом : кодировка терминала совершенно неизвестна приложению.
К сожалению, в стандарте POSIX поддержка Charset не имеет полностью идеологически стройной и ясной концепции. Понятие Charset существует только для locale API и тех функций, которые зависят от locale.
Более того, в "чистом" POSIX вообще невозможно узнать (получить) имя Charset после вызова setlocale(). Единственный способ, узнать Charset текущей locale - это воспользоваться не-POSIX функцией XPG (но определенной в Single UNIX, SVID и Unix98) : nl_langinfo(CODESET) (определена в файле
). Тогда текущий Сharset можно получить так :
#include#include ... setlocale(LC_ALL,""); printf ("Current charset = %s\n",nl_langinfo(CODESET)); Надо ли говорить, что некоторые UNIX (например FreeBSD) не имеют этих XPG-extensions и не имеют функции nl_langinfo() как таковой вообще. (Что очень странно, поскольку в том же POSIX определена утилита locale c keyword-ом codeset которая "как-то" это имя определяет...) Например, популярная система FreeBSD до сих пор не имеет функции nl_langinfo() (как впрочем не имеет и утилиты locale, увы !).
Еще один способ определения текущего Charset-а - это разбор переменной окружения LANG= . По стандарту POSIX переменная LANG= задается в форме LANG=language_TERRITORY.Codeset. Например, переменная NLSPATH= (управляющая поведением подсистемы NLS )может иметь "подстановки" :
- %L
- The value of the LC_MESSAGES category.
- %l
- The language element from the LC_MESSAGES category.
- %t
- The territory element from the LC_MESSAGES category.
- %c
- The codeset element from the LC_MESSAGES category.
Таким образом, если задать LANG="ru_RU.KOI8-R", то мы получим :
- %L
- = "ru_RU.KOI8-R"
- %l
- = "ru"
- %t
- = "RU"
- %c
- = "KOI8-R"
Исходные тексты этих функций открыты и широко доступны.
Таким образом, установив LANG=ru_RU.KOI8-R мы получим сообщения на русском языке в кодировке KOI8-R, а установив LANG=ru_RU.ISO_8859-5 - в кодировке ISO. На некоторых системах точно так же работает переменная MANPATH=.
К сожалению, поле Charset - опционально и по стандарту можно использовать сокращенную форму : LANG=ru_RU или даже LANG=ru. (См. localedef ключ -f ). Поэтому, если ваша система это поддерживает, задавайте максимально длинное имя для LANG= , указывая Charset. (получить список можно по locale -a). К сожалению, само имя Charset-а тоже может различаться.
Довольно значительное число ошибок происходит из за того, что в языке С определен тип переменных char (хотя точнее было бы назвать его : byte). Это во-первых, жестко привязывает нас к 8-ми битным кодировкам. А во-вторых, кодировка не определена. Поэтому, если мы задаем строку (массив char), в которой употребляются символы не ASCII (с кодами >128) :
char string[]="Проверка";
-- результат совершенно непредсказуем и непереносим. Еще больше проблем вызывает идея multibyte chars.Также вызывает удивление существование (и синтаксическая корректность) типов signed / unsigned char (что такое "отрицательный" символ? Вот unsigned short int -- понятно)... Если вы планируете работу вашей программы в многоязычном окружении, неплохо бы предусмотреть атрибут Сharset у любой строки символов char *. Или полностью переходить на UNICODE (wchar_t) в качестве внутренней кодировки.
Как работает locale ? (пример Linux)
/* Несколько устаревшие сведения на 1 Dec1998*/
Для операцонной системы Linux имеют хождение одновременно множество версий Linux libc, с различной степенью поддержки locale. Hиже приведен краткий обзор версий Linux libc.
Исторически, Linux libc ведет свое происхождение от free библиотеки GNU libc (glibc), которая в своей последней стабильной версии ( GNU libc 1.0.9 ) не имела поддержки других locale кроме "C" и соответственно не имела возможности их менять. Эта библиотека дала рождение ветке Linux libc 4.x.x и 5.x.x которая постоянно совершенствовалась, переписывалась и кроме других полезных возможностей постепенно приобрела и средства locale.
... glibc1 libc-4 a.out libc libc-5 original ELF libc libc-6 GNU libc (glibc2, glibc2.1)В старой, последней a.out (не-ELF) библиотеке, Linux libc 4.7.5 была возможность переключаться на другие значения locale, но только на заданные в процессе компиляции библиотеки. Для автоматической генерции *.c файлов с описаниями параметров локализации применялись специальные утилиты (реализация Nikolay Saukh ) /* Сильно похоже на старые SCO UNIX */.
В ELF версии Linux libc 5.0.9 (получившей довольно широкое распространение в дистрибутивах Slackware 2.x, RedHat и Caldera 1.x с ядром Linux 1.2.13-ELF) появилась возможность задавать любые значения локализации.
Hо сначало надо немного обратится к реализации locale в современной библиотеке Linux libc.
Напомним, что интернационализация -- это дизайн (способ проектирования) программного обеспечения, при котором КОД не зависит от национальных особенностей. При таком подходе : локализация -- это процесс изготовления особых "объектов локализации", в которых сосредоточены языково-зависимые данные. Эти данные разбиты на функциональные группы : категории локализации.
Как мы выяснили ранее, различным категориям локализации могут быть присвоены различные значения и причем в разное время - разные. Естественно предположить, что они как-то куда-то динамически загружаются. И действительно, вызов setlocale(LC_XXXXX,"ru_SU.KOI8-R") будет пытаться открыть файл "/usr/share/locale/ru_SU.KOI8-R/LC_XXXXX" и считать его внутрь структуры в run-time части libc. Это все происходит совершенно прозрачно для пользователя.
Имя файла для считывания конструируется динамически :
/usr/share/locale/ru_RU.KOI8-R/LC_XXXXX
/usr/share/locale/ это константа, определяющая каталог в котором хранится база локализации. Различно для различных операционных систем. Для Linux смотри LFSSND (/usr/share/locale/). Для Intractive UNIX: /lib/locale/. Вообще-то IMHO должно использоваться _PATH_LOCALE из ru_RU.KOI8-R/ подкаталог в базе докализации, где "ru_RU.KOI8-R" - значение локализации. LC_XXXXX файл данных для загрузки в run-time libc для категории локализации LC_XXXXX. Этот файл называется "объект локализации". Если задана категория локализации LC_ALL, считываются все файлы из /usr/share/locale/ru_RU.KOI8-R/* и если там найдутся файлы, имена которых совпадают с именами (LC_ - locale categories) категорий локализации (LC_CTYPE, LC_COLLATE, e.t.c.) -- то они загружаются. Для остальных категорий остается значение по умолчанию : "C".
Таким образом, при правильной установке локализации, должны существовать следующие каталоги: (пример)
$ ls /usr/share/locale/*
C
POSIX
ru_RU.KOI8-R
en_DK.ISO-8859-1
...* ПРИМЕЧАHИЕ: В полном POSIX.2 точно тот же результат даст утилита locale:
$ locale -a
C
POSIX
ru_RU.KOI8-R
en_DK.ISO-8859-1
...Также должны существовать файлы ("объекты локализации") : (пример)
$ ls /usr/share/locale/ru_RU.KOI8-R/*
LC_CTYPE
LC_COLLATE
LC_MONETARY
LC_NUMERIC
LC_TIMEТеперь вопрос, откуда взять данные файлы ? ;-) См. Русификация RedHat 5.2 или POSIX locale FreeBSD 2.x или Как установить locale .
В упомянутой выше версии Linux libc 5.0.9 подсистема locale работала именно так, однако не было утилит для создания загружаемых "объектов локализации". Те утилиты, которые входили в ее состав, генерировали объекты только для 4.4 BSD lite libc (почему ?).
Рабочие утилиты localedef и locale, появились начиная с версии Linux libc 5.1.X. А начиная с 5.2.1X - в Linux libc уже есть все необходимое для работы с locale в соответствии с POSIX.2 . См. здесь.
В широко распространенных дистрибутивах RedHat Linux 4.1 и 4.2 применяется библиотека Linux libc 5.3.12 (ELF) содержащая вполне работоспособную систему locale. Однако, к сожалению, в дистрибутив RedHat не входили файлы "объекты локализации" для русского языка ru_RU.KOI8-R.
Однако GNU libc также развивалась и появилась версия GNU libc 2.0 поддерживающая locale по стандарту POSIX 1996. Она была портирована для Linux и вскоре появились дистрибутивы, использующие GNU libc 2.0.x вместо Linux libc. Например, в состав дистрибутива RedHat Linux 5.2 (Apollo) (на glibc 2.0.7) входят все необходимые утилиты и "объекты локализации" - ru_RU (в ISO8859-5) и ru_SU (KOI8-R). Хотя, без проблем там не обошлось.
В библиотеке Linux libc 5.4.x, многое взявшей от GNU libc 2.0.x реализована следующая версия кода, locale 2, и объекты локализации (файлы) от версий Linux libc 5.0.x - 5.3.Х уже не годятся. Однако, благодаря унификации POSIX 1996, эти файлы можно легко получить из текстового описания локализации и файла описания набора символов (Character Set Definition File).
В настоящее время развитие библиотеки Linux libc остановлено (на версии ~5.4.38), и общее направление развития --> слияние и переход на библиотеку glibc2. Но из за того, что существут огромное количество приложений, работающих с Linux libc, приходится иметь в системе две версии библиотеки : Linux libc, называемую libc5 (например, версии 5.3.12) и GNU libc (например, glibc версии 2.1), называемую libc6.
Лингвистика и компютеры.
- Журнал "Multilingual Communications & Technology"
http://www.multilingual.com- Журнал "Language Today"
http://www.logos.it/language_today/- Журнал "Communications of COLIPS"
http://www.comp.nus.edu.sg/~colips/commcolips/- Yamada Language Center
http://babel.uoregon.edu/- Human-Languages Page - каталог Internet ресурсов
http://www.june29.com/HLP/- Еще подборка ссылок :
http://www.acm.org/sigchi/intercultural/- Japanese Computing
http://www.vsuccess.com/japanesecomputing.html- Understanding Yiddish Information Processing
http://www.uyip.org/- Croatian language / Hrvatski jezik
http://www.hr/hrvatska/language/CroLang.html- South Asian Scripts on the Web
http://library.berkeley.edu/SSEAL/SouthAsia/Unicode.html
Локализация (l10n), интернационализация (i18n) :
- The Languages of the World by Computers and the Internet
http://www.threeweb.ad.jp/logos/- All the scripts of the World
http://idris.com/scripts/Scripts.html- Internationalization (Взгляд американских военных на проблему)
http://perch.nosc.mil:8095/Docs/UIS_Supp/I18N.html- Локализация в слайдах :
http://www.ekt.gr/~skokko/slides/- Internationalization Issue, by Michael K. Gschwind <>
http://www.vlsivie.tuwien.ac.at/mike/i18n.html- Internationalization (i18n) and Localization (l10n). Коллекция ссылок :
http://tnt.microimages.com/~dwilliss/programming/noframes/i18n.html- Internationalization concept dictionary (Cловарь по i18n)
http://www.pswtech.com/porting/i18n/- Glossary of Global Development Terms (Словарь терминов)
http://www.alteris.com/glossary.htm- Internationalization / Localization (w3c)
http://www.w3.org/International/- Borneo: Internationalization and Localization
http://www.ile.com/borneo/- Поддержка интернационализации на платформе Java.
http://www.infoart.ru:8000/it/press/cwm/31_97/java.htm
http://www.infoart.ru:8000/it/press/cwm/32_97/inter.htm
Фирмы - производители программного обеспечения.
- Netscape Internationalization Secrets (Netscape)
http://people.netscape.com/ftang/i18n.html- MSDN Going Global (Microsoft)
http://www.microsoft.com/globaldev/
http://www.microsoft.com/globaldev/archives/archives.asp- Universal Localization Program (Mozilla)
http://www.mozilla.org/docs/l10n/- JDK Internationalization Overview (Java)
http://www.javasoft.com/products/jdk/1.1/docs/guide/intl/index.html
http://www.javasoft.com/products/jdk/1.2/docs/guide/intl/index.html- The Java Toutorial. Internationalization.
http://java.sun.com/docs/books/tutorial/i18n/index.html- Inside Macintosh: Text (Apple)
http://developer.apple.com/techpubs/mac/Text/Text-2.html- Digital (Compaq?) Unix :
Writing Software for the International Market- IBM AIX :
General Programming Concepts- Hewlett Packard HP-UX Operating System
http://docs.hp.com/hpux/os/
Языки, символы, кодировки :
- Character Set Standards
http://guagua.echo.lu/oii/en/chars.html- A tutorial on character code issues
http://www.hut.fi/u/jkorpela/chars.html- Character sets (w3.org)
http://www.w3.org/International/O-charset.html- Character Set Considered Harmful
http://www.w3.org/MarkUp/html-spec/charset-harmful.html- Alphabet Soup: The Internationalization of Linux.
http://turnbull.sk.tsukuba.ac.jp/Tools/I18N/LJ-I18N.html- Code for the representation of the names of languages, ISO 639
http://www.unicode.org/unicode/onlinedat/languages.html
http://www.sil.org/sgml/iso639a.html
http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt- Country codes, ISO 3166
http://www.unicode.org/unicode/onlinedat/countries.html
http://www.ics.uci.edu/pub/ietf/http/related/iso3166.txt- IANA Registred Character Sets :
http://www.isi.edu/in-notes/iana/assignments/character-sets- ISO-8859 briefing and resources
http://ppewww.ph.gla.ac.uk/~flavell/iso8859/iso8859-pointers.html- The ISO 8859 Alphabet Soup
http://czyborra.com/charsets/iso8859.html- Cyrillic Character Sets
http://www.fingertipsoft.com/ref/cyrillic/charsets.html- The Cyrillic Charset Soup
http://czyborra.com/charsets/cyrillic.html- RFC-1489 на :
http://www.cis.ohio-state.edu/htbin/rfc/rfc1489.html
Вводит формальное определение кодировки KOI8-R ( КОИ-8 )
и нового charset для MIME :
Content-Type: text/plain; charset=KOI8-R
Content-Type: text/html; charset=KOI8-R- Великолепная страничка Ache : "Русская сетевая кодировка KOI8-R":
http://www.nagual.pp.ru/~ache/koi8.html- KOI8-U (RFC-2319) : Украинская сетевая кодировка
http://www.net.ua/KOI8-U/index.html
http://www.cis.ohio-state.edu/htbin/rfc/rfc2319.html- Japanese Character Encoding for Internet Messages (ISO-2022-JP)
http://www.cis.ohio-state.edu/htbin/rfc/rfc1468.html
http://www.cis.ohio-state.edu/htbin/rfc/rfc2237.html- GOSS: Character Sets
http://www.ewos.be/tg-cs/gtop.htm- Character Encodings Concepts (Apple)
http://adrm1.euro.apple.com/techpubs/mac/TextEncodingCMgr/TECRefBook-140.html- Multilingual Text Handling Environment *Mule*
http://www.etl.go.jp/~mule/MulePage.html- Character/Glyph Model
http://www.stonehand.com/unicode/standard/cgmodel.html- An introduction to glyphs
http://www.freetype.org/glyphs.htm- Microsoft Typography (TrueType fonts)
http://www.microsoft.com/truetype- Сайт посвященный шрифтам и типографике
http://typo.novikov.com/
UNICODE
- UNICODE
http://www.unicode.org- Unicode 2.1 Character Charts
http://charts.unicode.org- A short overview of ISO/IEC 10646 and Unicode
http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html- Unicode resources on the net.
http://www.ado.sig.or.jp/~ado/unicode/u-link-e.html- UNICODE Font
- http://www.cl.cam.ac.uk/~mgk25/ucs-fonts.html
- UniEdit UNICODE Etitor
http://www.lang.duke.edu/uniintro.htm
POSIX Locale :
- В первую очередь, конечно, необходимо читать man :) по функциям POSIX.1 :
setlocale(), isalpha()/isxxxx(), toupper() и т.д. , nl_langinfo()- Также man по утилитам POSIX.2 locale и localedef.
И конечно их исходные тексты (начиная с версии Linux libc 5.3.x или GNU libc 2.0.x).- Сведения по NLS : man catopen(),catgets(),catclose()
В исходных текстах libc, man - примеры message catalog-ов.- Также неплохо посмотреть GNU info-pages по теме libc / Locales.
HTML-версия GNU info есть например на http://www.cs.utah.edu/csinfo/texinfo/- Документы группы JTC1/SC22/WG15 - POSIX
http://anubis.dkuug.dk/JTC1/SC22/WG15/- Различные документы GNU http://www.gnu.org, в частности:
ftp://prep.ai.mit.edu/pub/gnu/ABOUT-NLS или локально : ABOUT-NLS.
Перевод: http://www.software.ru/i18n-ru/ (хост умер ?)- Страничка от - главного идеолога и разработчика средств
locale в библиотеке GNU libc и Linux libc :
http://i44s11.info.uni-karlsruhe.de/~drepper и его доклад :
http://i44www.info.uni-karlsruhe.de/~drepper/conf96/paper.html- Спецификации POSIX.1 и POSIX.2 .
(ISO/IEC 9945-2:1988, 1990, 1992, 1996 от
* ISO http://www.iso.ch и
* IEC http://www.iec.ch или, что то же самое,
IEEE Std. 1003.2-1992) и POSIX.2a, POSIX.2b .
* IEEE http://www.ieee.org
Hа http://www.posix.com утверждается, что это стоит денег, поэтому лучше всего поглядеть на
ftp://ftp.funet.fi/pub/doc/posix (там правда draft версии)
или соответственно, через WWW. Например :
ftp://ftp.funet.fi/pub/doc/posix/p1003.2/d11.2/toc - он же, через WWW виден как :
http://www.funet.fi/pub/doc/posix/p1003.2/d11.2/toc , далее :
http://www.funet.fi/pub/doc/posix/p1003.2/d11.2/2.5
http://www.funet.fi/pub/doc/posix/p1003.2/d11.2/4.34 e.t.c.- Спецификации XPG3/XPG4 от X/Open Co Ltd. (за деньги :(( ) на :
http://www.xopen.org- Коллекция locales и charmaps в исходном виде для POSIX.2 localedef
и прочие документы пограммы i18n. Ведет ее Keld Simonsen <> :
ftp://dkuug.dk/i18n/WG15-collection/
Русскиe charset ISO_8859-5, KOI8-R, CP1251, e.t.c.
Русская locale ru_RU.- World Currencies and Abbreviations. По мотивам ISO 4712 :
http://www.jhall.demon.co.uk/currency/
MIME :
- MIME FAQ из USENET группы comp.mail.mime :
ftp://rtfm.mit.edu/pub/usenet-by-group/comp.mail.mime
или то же в HTML :
http://www.cs.ruu.nl/wais/html/na-dir/mail/mime-faq/.html- MIME Overview, by Mark Grand
http://www.mindspring.com/~mgrand/mime.html- The Internet Mail Consortium [Inernationalization]
http://www.imc.org/- MIME RFC: RFC-2045..2049
http://www.oac.uci.edu/indiv/ehood/MIME/2045/rfc2045.html
http://www.oac.uci.edu/indiv/ehood/MIME/2045/rfc2046.html
http://www.oac.uci.edu/indiv/ehood/MIME/2045/rfc2047.html
http://www.oac.uci.edu/indiv/ehood/MIME/2045/rfc2048.html
http://www.oac.uci.edu/indiv/ehood/MIME/2045/rfc2049.html
Linux :
- Linux Cyrillic-HOWTO от Alexander L. Belikoff .
http://sunsite.unc.edu/LDP/HOWTO/Cyrillic-HOWTO.html
(чуть-чуть устарел)
Дает массу полезной информации по русификации дисплея и клавиатуры,
включению 8-bit в различных программах и использованию русских шрифтов.- Перевод Cyrillic-HOWTO (V3.15, 14 ноября 1997) Евгения Балдина :
http://kulichki.rambler.ru/moshkow/CYRILLIC/Cyrillic-HOWTO-russ.txt
(еще более устаревшая версия...)- Linux Ukrainian HOWTO
http://www.cinet.cn.ua/NOC/ukr/- Другие национальные Linux HOWTO :
- http://sunsite.unc.edu/LDP/HOWTO/Chinese-HOWTO.html
- http://sunsite.unc.edu/LDP/HOWTO/Danish-HOWTO.html
- http://sunsite.unc.edu/LDP/HOWTO/Finnish-HOWTO.html
- http://sunsite.unc.edu/LDP/HOWTO/German-HOWTO.html
- http://sunsite.unc.edu/LDP/HOWTO/Hebrew-HOWTO.html
- http://sunsite.unc.edu/LDP/HOWTO/Italian-HOWTO.html
- http://sunsite.unc.edu/LDP/HOWTO/Polish-HOWTO.html
- http://sunsite.unc.edu/LDP/HOWTO/Slovenian-HOWTO.html
- http://sunsite.unc.edu/LDP/HOWTO/Spanish-HOWTO.html
- http://sunsite.unc.edu/LDP/HOWTO/Thai-HOWTO.html
- Linux Locales mini-HOWTO by Peeter Joot, <>
http://www.accessv.com/~peeter/ c
http://www.accessv.com/~peeter/Locale-mini-HOWTO.html
Дает быстрый способ установки locale на машину.- Страничка Boris Tobotras <> посвященная Linux-у
http://xtalk.price.ru/linux- Страничка Dmitri Beloslioudtsev <> - автора русской NLS Linux libc
( home: http://orgland.ru/~dnb ) и его коллекция locales, charmaps и NLS :
ftp://ftp.orgland.ru/pub/unix/locale/Linux/
Ссылки на меня :-) [по результатам /var/log/httpd/referer.log]
- http://xtalk.price.ru/linux/
- http://www.chat.ru/~gene/locale.html
- http://www.delcam.ru/support/solaris/locale.html
- http://buratino.peterlink.ru/~km/links/docs.html
- http://knot.pu.ru/faq/
- http://www.tyumen.ru/~mc/linux/lil.shtml
- http://www.linux.opennet.ru/lil.shtml
- http://www.cinet.cn.ua/koi8-r/for_hackers/links.shtml
- http://multik.istu.ru/linux/rus/rus.html
- http://fos.mcs.orbita.ru/flycat/links.htm
- http://spider.macomnet.ru/~oskin/bookmarks.html
- http://www.glasnet.ru/~kazarn/rus/fonts.htm
- http://www.finec.ru/~alone/links.htm