Какие компоненты используют переменные локали? - PullRequest
0 голосов
/ 30 мая 2018

Я прочитал, что с каждым процессом связан набор переменных локали.Например, это переменные локали, связанные с процессом bash в моей системе:

$ locale
LANG="en_GB.UTF-8"
LC_COLLATE="en_GB.UTF-8"
LC_CTYPE="en_GB.UTF-8"
LC_MESSAGES="en_GB.UTF-8"
LC_MONETARY="en_GB.UTF-8"
LC_NUMERIC="en_GB.UTF-8"
LC_TIME="en_GB.UTF-8"
LC_ALL=

Я хочу знать, кто на самом деле использует эти переменные локали.

Выполняют стандартные функции Си(например: fwrite()) и системные вызовы Linux их используют?Различается ли поведение некоторых стандартных функций C или некоторых системных вызовов Linux в зависимости от значения некоторой переменной локали?

Или только эти программы могут использовать эти переменные локали?Например, я могу написать программу, которая будет отображать сообщения пользователю на другом языке в зависимости от значения переменной LANG locale.

Ответы [ 3 ]

0 голосов
/ 30 мая 2018

Я читал, что с каждым процессом связан набор переменных локали.

Это не совсем так, или, по крайней мере, он сильно упрощен.

Многие стандартные библиотечные функции (и нестандартные библиотечные функции) изменяют свое поведение, основываясь на наборе конфигураций локали, которые поддерживаются в некотором скрытом глобальном объекте в реализации стандартной библиотеки.(В некоторых реализациях библиотеки конфигурация локали поддерживается для каждого потока, а не глобально, используя локальные статические переменные потока.) Это может показаться связанным с процессом, поскольку обычно у каждого процесса есть один экземпляр времени выполнения стандартной библиотеки,но важно понимать, что, несмотря на внешний вид, поддержка локали является частью библиотеки, а не ядра ОС.(Конечно, ничто в любом стандарте не определяет, где находятся границы ядра, и даже то, каким может быть ядро. Вы можете запустить свою программу «на пустом месте» или у вас может быть ОС, которая считает полезным реализовать стандартную библиотеку в рамках системных вызовов.Я говорю здесь об общих случаях.)

Базовая конфигурация локали определяется стандартом C в разделе 7.11 (стандарта C11), который определяет два интерфейса:

  • setlocale, который изменяет конфигурацию локали библиотеки, и

  • localeconv, которая запрашивает часть конфигурации локали, позволяя пользовательскому коду соответствоватьк соглашениям о числовом форматировании локали (включая денежное форматирование).

Конфигурация локали разделена на несколько более или менее независимых компонентов, называемых «категориями».(Стандартная библиотека C ++ называет эти «грани», что также является часто используемым словом.) Существует пять категорий, определенных стандартом C, и еще одна, определенная Posix, но категории являются открытыми;отдельные реализации стандартной библиотеки могут свободно добавлять дополнительные категории.Например, стандартная библиотека C Gnu, используемая в большинстве систем Linux, в настоящее время имеет в общей сложности 12 категорий.(Текущий список см. man 7 locale в вашей системе.)

Стандартные категории:

  • LC_CTYPE: классификация символов и преобразование регистра.
  • LC_COLLATE: порядок сопоставления.
  • LC_MONETARY: денежное форматирование.
  • LC_NUMERIC: числовое, неденежное форматирование.
  • LC_TIME: дата и времяформаты.

и расширение Posix:

  • LC_MESSAGES: форматы информационных и диагностических сообщений и интерактивных ответов.

Кроме localeconv, который предоставляет доступ только к определенным конфигурациям из категорий LC_NUMERIC и LC_MONETARY, нет способа запросить какую-либо конкретную конфигурацию.

Также, нет никакого стандартного способа установить единую конфигурацию.Все, что вы можете сделать, это использовать setlocale для настройки всей категории, используя зависящее от библиотеки и нестандартизированное имя локали (которое является просто символьной строкой).Точнее, стандартизированы два имени локали:

  • Стандарт C определяет имя локали C.

  • Posix определяет имя локали POSIX.Однако Posix указывает, что соответствующий языковой стандарт должен совпадать с языковым стандартом C.

Подробности именования языковых стандартов (или должны быть) подробно описаны в документации localeдля среды, в которой вы работаете, но обычно программа с поддержкой локали никогда не вызовет setlocale со строковой константой, отличной от стандартных имен, или пустой строкой.(Я вернусь к этому через минуту.)

Интерфейс setlocale позволяет программе устанавливать отдельную категорию языковых стандартов или присваивать всем категориям языковых стандартов одно и то же имя языкового стандарта.Он также возвращает строку, которую можно использовать для возврата к ранее настроенной категории языкового стандарта (или полной конфигурации).

Имена категорий, показанные в списке категорий выше, являются макросами, определенными в <locale.h>.Дополнительный макрос LC_ALL также определяется этим заголовочным файлом: LC_ALL.Один из этих макросов должен использоваться в качестве первого аргумента для setlocale.

Стандарты C и Posix требуют, чтобы исходный языковой стандарт при запуске программы был языковым стандартом C.Многие аспекты локали C стандартизированы (и несколько больше аспектов локали Posix стандартизированы).Эта стандартизация позволяет программисту предсказать, как будут работать числовые преобразования, например.

Но часто программист захочет взаимодействовать с пользователем программы с собственными настройками языка этого пользователя.Очевидно, что нежелательно, чтобы каждая отдельная программа имела свой собственный уникальный механизм определения предпочтений языкового стандарта пользователя, поэтому стандартная библиотека предоставляет механизм для установки языкового стандарта (или отдельных категорий языковых стандартов) в соответствии с тем, на что настроен языковой стандарт по умолчанию:setlocale с пустой строкой ("") в качестве имени локали.Стандарт C не определяет какой-либо конкретный механизм для настройки этой информации;он просто предполагает, что он существует.

(Примечание: вызов setlocale с пустой строкой в ​​качестве имени локали не такой же, как вызов setlocale с NULL в качестве имени локали. NULL говорит setlocale не изменять настройку локали, но она все равно возвращает строку, связанную с текущей локалью. Это устраняет необходимость в интерфейсе getlocale.)

Posix действительно указываетмеханизм настройки пользовательских настроек, и он также настаивает на том, чтобы (большинство) стандартизированных утилит командной строки работали в локали по умолчанию.Этот механизм использует переменные среды, имена которых соответствуют макросам категории setlocale.

В реализации Posix, когда программа вызывает setlocale(LC_X, "");, библиотека переходит к проверке текущей среды:

  1. Сначала он ищет переменную окружения LC_ALL.Если он определен и имеет непустое значение, он используется для определения языкового стандарта.

  2. В противном случае, если первый аргумент setlocale не был LC_ALL, он ищетпеременная окружения, имя которой совпадает с этим аргументом.Если он определен и имеет непустое значение, он используется для определения языкового стандарта.

  3. В противном случае, если переменная среды LANG определена и имеет непустое значение, он используется (некоторым образом, зависящим от реализации) для создания имени локали.(LANG должен указывать на язык пользователя, который является важной частью их языковых настроек.)

  4. Наконец, используется некоторое общесистемное значение по умолчанию.

Переменные среды обычно инициализируются программой login (или эквивалентом GUI) на основе файлов конфигурации системы.(Точный механизм варьируется от распределения к распределению, и документацию часто трудно найти.)

Как уже упоминалось, Posix требует, чтобы почти все стандартные утилиты оболочки выполняли эквивалент setlocale(LC_ALL, ""); для работы внастроенный язык пользователя.Страница руководства каждой утилиты (или другая документация) должна указывать, делает ли она это или нет, но разумно предположить, что она делает, если нет какой-либо информации об обратном.

Кроме того, многие (но не все) стандартные библиотекиСтроковые функции ориентированы на локали.Интерфейсы библиотеки, которые определенно не учитывают языковые стандарты, включают isdigit и isxdigit, которые всегда отвечают на основе языкового стандарта C, и strcmp, который сравнивает строки так же, как memcmp, используяЗначение char (интерпретируется как unsigned int) для определения порядка сортировки.(strcoll учитывает локаль, если вы хотите сделать сравнение согласно LC_COLLATE.) А кодировки символов, используемые для широких и многобайтовых символов, управляются (каким-то неуказанным образом) категорией LC_CTYPE.

0 голосов
/ 30 мая 2018

Многие программы устанавливают языковой стандарт и используют его хотя бы для интернационализации.Некоторые конкретные примеры:

LANG="en_GB.UTF-8"

Это локаль для любой категории, которую вы специально не указали для чего-то другого.Это позволяет системе добавлять новые переменные локали обратно совместимым способом.

LC_COLLATE="en_GB.UTF-8"

Выбирает порядок сортировки языка, который используется в строках.Например, Ch считается буквой на испанском языке и следует после Cz .Одна функция библиотеки C, которая использует это strcoll(), и команды POSIX, которые включают ls (при сортировке файлов по имени) и sort.

LC_CTYPE="en_GB.UTF-8"

Это определяет текущую кодировку символов.В C11 вы можете установить это, а затем использовать ввод и вывод широких символов, например wprintf().Библиотека будет прозрачно преобразовывать между широкими символами и набором символов, используемым внешним миром.Это все еще не совсем работает в Windows, если только вы не совершите дополнительную магию, но в других местах UTF-8 стал стандартом.Все большее число программ, таких как clang (начиная с версии 7), больше не поддерживают ничего, кроме UTF-8.

LC_MESSAGES="en_GB.UTF-8"

Это определяет, в каком языке и наборе символов вы видите локализованные сообщения. В C наВ Unix / Linux они обычно загружаются из файла .po библиотекой gettext.

LC_MONETARY="en_GB.UTF-8"

Это влияет на то, как strfmon() форматирует денежные суммы.

LC_NUMERIC="en_GB.UTF-8"

Определяет форматирование чисел , которые не являются денежными суммами.

LC_TIME="en_GB.UTF-8"

Это влияет на форматирование времени.Попробуйте LC_TIME=fr_FR.UTF-8 date в оболочке, чтобы увидеть пример.(Или используйте locale -a | grep UTF, чтобы выбрать подходящую экзотическую локаль.) Также хорошо проверьте, правильно ли работают ваш часовой пояс и ntpd.

LC_ALL=

Используйте вместо этого LANG.Он устанавливает каждую категорию локали одновременно, но переопределяет значения во всех других переменных локали.Он существует для обратной совместимости.

Например, я использую LANG=en_US.utf8 на своем компьютере с Linux, но я переопределяю LC_TIME=en_GB.utf8, чтобы получить 24-часовое время на английском языке.Это было бы невозможно сделать, если было установлено LC_ALL.

LANG также позволяет вашим значениям по умолчанию переноситься на любую другую информацию о локали, поддерживаемую вашей системой, такую ​​как LC_ADDRESS, LC_IDENTIFICATION, LC_RESPONSE, LC_MEASUREMENT и LC_TELEPHONE.

0 голосов
/ 30 мая 2018

По умолчанию стандартные библиотечные функции C используют локаль "C" .Вы можете переключить его на пользовательский языковой стандарт, чтобы включить специфичный для языкового стандарта:

  • Обработка символов
  • Сортировка
  • Форматирование даты / времени
  • Числовое редактирование
  • Денежное форматирование
  • Сообщения

POSIX setlocale Документация содержит неполный список зависящих от локали функций, на которые она влияет:

1023, iswlower, iswprint, iswpunct, iswspace, iswupper, iswxdigit, isxdigit, localeconv, mblen, mbstowcs, mbtowc, newlocale, nl_langinfo, perror, psiginfo, setlocale, strcoll, strror, strror, strfr, towlower, towupper, uselocale, wcscoll, wcstod, wcstombs, wcsxfrm, wctomb

Например:

printf("%'d\n", 1000000000);
printf("Setting LC_ALL to %s\n", getenv("LANG"));
setlocale(LC_ALL, ""); // Set user-preferred locale.
printf("%'d\n", 1000000000);

Выходы:

1000000000
Setting LC_ALL to en_US.UTF-8
1,000,000,000
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...