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 (/* <i>возникла ошибка</i> */) { /* ВЕРНО */
/* Использовать несколько строк для упрощения перевода. */
if (input_type == INPUT_FILE)
fprintf(stderr, _("%s: cannot read file: %s\n"),
argv[0], strerror(errno));
else
fprintf(stderr, _("%s: cannot read pipe: %s\n"),
argv[0], strerror(errno));
Это лучше, чем
if (/* <i>возникла ошибка</i> */) { /* НЕВЕРНО */
fprintf(stderr, _("%s: cannot read %s: %s\n"), argv[0],
input_type == INPUT_FILE ? _("file") : _("pipe"),
strerror(errno));
}
Как только что показано, хорошей мыслью является включение комментария, сообщающего о намеренном использовании нескольких строк, чтобы упростить перевод сообщений.
13.3.8. Создание переводов
После интернационализации программы необходимо подготовить переводы. Это осуществляется с помощью нескольких инструментов уровня оболочки. Мы начнем с интернационализированной версии
ch06-echodate.c
из раздела 6.1.4 «Преобразование разложенного времени в
time_t
»:
/* ch13-echodate.c --- демонстрация переводов */
#include <stdio.h>
#include <time.h>
#include <locale.h>
#define ENABLE_NLS 1
#include "gettext.h"
#define _(msgid) gettext(msgid)
#define N_(msgid) msgid
int main (void) {
struct tm tm;
time_t then;
setlocale(LC_ALL, "");
bindtextdomain("echodate", ".");
textdomain("echodate");
printf("%s", _("Enter a Date/time as YYYY/MM/DD HH:MM:SS : "));
scanf("%d/%d/%d %d:%d:%d",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
&tm.tm_hour, &tm.tm_min, &tm.tm_sec);
/* Проверка ошибок для краткости опущена. */
tm.tm_year -= 1900;
tm.tm_mon -= 1;
tm.tm_isdst = -1; /* О летнем времени ничего не известно */
then = mktime(&tm);
printf(_("Got: %s"), ctime(&then));
exit(0);
}
Мы намеренно использовали
"gettext.h"
, а не
<gettext.h>
. Если наше приложение поставляется с отдельной копией библиотеки
gettext
, тогда
"gettext.h"
найдет ее, избежав использования системной копии. С другой стороны, если имеется лишь системная копия, она будет найдена, если локальной копии нет. Общеизвестно, что ситуация усложнена фактом наличия на системах Solaris библиотеки
gettext
, которая не имеет всех возможностей версии GNU.