За указателем положения могут следовать любые обычные флаги printf()
, указатели ширины полей и точности. Вот правила для использования указателей положения:
• Форма с указателем положения не может смешиваться с формой без нее. Другими словами, или каждый указатель формата включает указатель положения, или ни один его не включает. Конечно, %%
может использоваться всегда.
• Если в форматирующей строке используется printf("%3$s %1$s\n", "hello", "cruel", "world")
;
• Ссылка на определенный аргумент может быть сделана указателем положения несколько раз. Не позиционные спецификаторы формата всегда движутся через список аргументов последовательно.
Эта возможность не предназначена для непосредственного использования программистами приложений, она скорее для переводчиков. Например, перевод предыдущей форматирующей строки, "The %s %s looks at you enquiringly.\n"
, на французский мог бы быть:
"Le %2$s %1$s te regarde d'un aire interrogateur.\n"
(Даже этот перевод не совершенен: артикль «Le» имеет род. Подготовка программы к переводу трудная задача!)
13.3.6. Тестирование переводов в персональном каталоге
Коллекция сообщений в программе называется gettext()
может во время исполнения найти нужный перевод.
Может оказаться полезным разместить переводы не в стандартном, а в другом каталоге, особенно для тестирования программы. Особенно на больших системах, у обычного пользователя может не быть необходимых разрешений для установки файлов в системные каталоги. Функция bindtextdomain()
дает gettext()
альтернативное место для поиска переводов:
#include
char *bindtextdomain(const char *domainname,
const char *dirname);
Полезные каталоги включают '.
' для текущего каталога и /tmp
. Может оказаться удобным также получить каталог из переменной окружения, подобно этому:
char *td_dir;
setlocale(LC_ALL, "");
textdomain("killerapp");
if ((td_dir = getenv("KILLERAPP_TD_DIR")) != NULL)
bindtextdomain("killerapp", td_dir);
bindtextdomain()
должна быть вызвана до вызовов любой из функций из семейства gettext()
. Мы увидим пример ее использования в разделе 13.3.8 «Создание переводов»
13.3.7. Подготовка интернационализированных программ
К настоящему моменту мы рассмотрели все компоненты, из которых состоит интернационализированная программа. Данный раздел подводит итоги.
1. Включите в свое приложение заголовочный файл gettext.h
, добавьте определения для макросов _()
и N_()
в заголовочный файл, который включается во все ваши исходные файлы на С. Не забудьте определить именованную константу ENABLE_NLS
.
2. Вызовите соответствующим образом setlocale()
. Проще всего вызвать 'setlocale(LC_ALL, "")
', но иногда приложению может потребоваться быть более разборчивым в отношении используемых категорий локали.
3. Выберите для приложения текстовый домен и установите его с помощью textdomain()
.
4. При тестировании свяжите текстовый домен с определенным каталогом при помощи bindtextdomain()
.
5. Используйте соответствующим образом strfmon()
, strftime()
и флаг '
. Если нужна другая информация о локали, используйте nl_langinfo()
, особенно в сочетании с strftime()
.
6. Пометьте все строки, которые должны быть переведены, соответствующими вызовами _()
или N_()
.
Хотя некоторые не следует так помечать. Например, если вы используете getopt_long()
(см. раздел 2.1.2 «Длинные опции GNU»), вы, вероятно, не захотите, чтобы имена длинных опций были помечены для перевода. Не требуют перевода и простые форматирующие строки наподобие "%d %d\n
", также как отладочные сообщения.
7. В нужных местах используйте ngettext()
(или ее варианты) для значений, которые могут быть 1 или больше 1.
8. Упростите жизнь для своих переводчиков, используя строки с полными предложениями вместо замены слов с помощью %s
и ?:
. Например:
if (/*
/* Использовать несколько строк для упрощения перевода. */
if (input_type == INPUT_FILE)