Категории
Самые читаемые
PochitayKnigi » Компьютеры и Интернет » Программное обеспечение » Linux программирование в примерах - Арнольд Роббинс

Linux программирование в примерах - Арнольд Роббинс

Читать онлайн Linux программирование в примерах - Арнольд Роббинс

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 121 122 123 124 125 126 127 128 129 ... 165
Перейти на страницу:

if (nwords == l)

 printf("one word misspelledn");

else

 printf("%d words misspelledn", nwords);

Решением является параллельный набор процедур специально для форматирования множественных значений:

#include <libintl.h> /* GLIBC */

char *ngettext(const char *msgid, const char *msgid_plural,

 unsigned long int n);

char *dngettext(const char *domainname, const char *msgid,

 const char *msgid_plural, unsigned long int n);

char *dcngettext(const char *domainname, const char *nmgid,

 const char *msgid_plural, unsigned long int n,

 int category)

Помимо первоначального аргумента msgid, эти функции принимают дополнительные аргументы:

const char *msgid_plural

Строка по умолчанию для использования в качестве множественного числа. Вскоре будут примеры.

unsigned long int n

Число имеющихся элементов.

Список сообщений каждой локали указывает, как переводить множественные числа.[145] Функция ngettext() (и ее варианты) проверяет n и на основании спецификации в списке сообщений возвращает соответствующий перевод msgid. Если в списке нет перевода для msgid, или находясь в локали «С», ngettext() возвращает msgid, если 'n == 1'; в противном случае она возвращает msgid_plural. Таким образом, наш пример ошибочных слов выглядит следующим образом:

printf("%sn", ngettext("%d word misspelled", "%d words misspelled", nwords), nwords);

Обратите внимание, что nwords должен быть передан ngettext() для выбора форматирующей строки, а затем printf() для форматирования. Вдобавок, будьте осмотрительны и не используйте макрос или выражение, значение которого каждый раз изменяется, как в случае 'n++'! Такое может случиться, если вы осуществляете глобальное редактирование, добавляя вызовы ngettext() и не обращая на это внимания.

13.3.4. Упрощение использования gettext()

Вызов gettext() в исходном коде программы служит двум целям. Во-первых, он осуществляет перевод во время исполнения, что является в конце концов главным. Однако, он служит также для отметки строк, которые нужно перевести. Утилита xgettext читает исходный код программы и извлекает все оригинальные строки, которые нужно перевести. (Далее в главе мы кратко рассмотрим это.)

Рассмотрим все-таки случай, когда статические строки не используются непосредственно:

static char *copyrights[] = {

 "Copyright 2004, Jane Programmer",

 "Permission is granted ...",

 /* ... Здесь куча легальностей */

 NULL

};

void copyright(void) {

 int i;

 for (i = 0; copyrights[i] != NULL, i++)

  printf("%sn", gettext(copyrights[i]));

}

Здесь мы хотели бы иметь возможность вывести переводы строк об авторских правах, если они доступны. Однако, как извлекающее устройство xgettext предполагает найти эти строки? Мы не можем заключить их в вызовы gettext(), поскольку это не будет работать во время компиляции:

/* ПЛОХОЙ КОД: не будет компилироваться */

static char *copyrights[] = {

 gettext("Copyright 2004, Jane Programmer"),

 gettext("Permission is granted ..."),

 /* ... Здесь куча легальностей */

 NULL

};

13.3.4.1. Переносимые программы: "gettext.h"

Здесь мы предполагаем, что вы хотите написать программу, которая может использоваться вместе с библиотекой GNU gettext на любой системе Unix, а не только GNU/Linux. Следующий раздел описывает, что сделать для программ только для GNU/Linux.

Пометка строк включает два шага. Первый заключается в использовании вспомогательного заголовка gettext.h, который поставляется с дистрибутивом GNU gettext. Этот файл обрабатывает несколько проблем переносимости и компиляции, упрощая использование gettext() в ваших собственных программах:

#define ENABLELNLS 1 /* ENABLE_NLS должен быть true, чтобы gettext() работала */

#include "gettext.h" /* Вместо <libintl.h> */

Если макрос ENABLE_NLS не определен[146] или установлен в ноль, gettext.h развертывает вызовы gettext() в первый аргумент. Это делает возможным перенос кода, использующего gettext(), на системы, в которых не установлены ни GNU gettext, ни собственная их версия. Помимо прочего, этот заголовочный файл определяет следующий макрос:

/* Вызов псевдофункции, который служит в качестве маркера для

   автоматического извлечения сообщений, но не осуществляющий вызов

   gettext(). Перевод времени исполнения осуществляется в другом

   месте кода. Аргумент String должен быть символической строкой.

   Сцепленные строки и другие строковые выражения не будут работать.

   Разворачивание макроса не параметризовано, так что он подходит для

   инициализации статических переменных 'char[]' или 'const char[]'. */

#define gettext_noop(String) String

Комментарий самодостаточен. С помощью этого макроса мы можем теперь перейти ко второму шагу. Мы перепишем код следующим образом:

#define ENABLE_NLS 1

#include "gettext.h"

static char copyrights[] =

 gettext_noop("Copyright 2004, Jane Programmern"

 "Permission is granted ...n"

 /* ... Здесь куча легальностей */

 "So there.");

void copyright(void) {

 printf("%sn", gettext(copyrights));

}

Обратите внимание, что мы сделали два изменения. Во-первых, copyrights теперь является одной длинной строкой, созданной с использованием возможности конкатенации строк стандартного C. Эта простая строка затем включена в вызов gettext_noop(). Нам нужна одна строка, чтобы легальности могли быть переведены в виде одного элемента

Второе изменение заключается в непосредственном выводе перевода в виде одной строки в copyright().

К этому времени вы, возможно, думаете: «Вот здорово, набирать каждый раз 'gettext(...)' довольно неприятно». Ну, вы правы. Это не только создает лишнюю работу по набиванию, но также и затрудняет чтение исходного кода. Соответственно, когда вы используете заголовочный файл gettext.h, руководство GNU gettext рекомендует включить два других макроса с именами _() и N_() следующим образом:

#define ENABLE_NLS 1

#include "gettext.h"

#define _(msgid) gettext(msgid)

#define N_(msgid) msgid

Такой подход снижает накладные расходы по использованию gettext() всего лишь тремя дополнительными символами для переводимой строковой константы и всего лишь четырьмя символами для статических строк:

#include <stdio.h>

#define ENABLE_NLS 1

#include "gettext.h"

#define _(msgid) gettext(msgid)

#define N_(msgid) msgid

...

static char copyrights[] =

 N_("Copyright 2004, Jane Programmern"

 "Permission is granted ...n"

 /* ... Здесь куча легальностей */

 "So there.");

void copyright(void) {

 printf("%sn", gettext(copyrights));

}

int main(void) {

 setlocale(LC_ALL, ""); /* gettext.h gets <locale.h> for us too */

 printf("%sn", _("hello, world"));

 copyright();

 exit(0);

}

Эти макросы скромны, и на практике все GNU программы, использующие GNU gettext, следуют этому соглашению. Если вы собираетесь использовать GNU gettext, вам тоже нужно следовать этому соглашению.

13.3.4.2. Только GLIBC: <libintl.h>

Для программ, которые будут использоваться лишь на системах с GLIBC, использование заголовочных файлов и макросов похоже, но проще:

#include <stdio.h>

#include <libintl.h>

#define _(msgid) gettext(msgid)

#define N_(msgid) msgid

/* ... все остальное то же ... */

Как мы видели ранее, заголовочный файл <libintl.h> объявляет gettext() и другие функции. Вам все равно нужно определять _() и N_(), но не нужно беспокоиться о ENABLE_NLS или включении с исходным кодом вашей программы файла gettext.h.

13.3.5. Перестановка порядка слов с помощью printf()

Иногда при переводах порядок слов, естественный для английского языка, не подходит в других языках. Например, на английском прилагательные идут перед определяемыми существительными, а на многих других языках — после. Таким образом, следующий код представляет проблему:

char *animal_color, *animal;

if (...) {

 animal_color = _("brown");

 animal = _("cat");

} else if (...) {

 ...

} else {

 ...

}

printf(_("the %s %s looks at you enquiringly.n"), animal_color, color);

Здесь форматирующая строка, animal_color и animal неудачно включены в вызов gettext(). Однако, после перевода утверждение будет неверным, поскольку порядок аргументов не может быть изменен во время исполнения.

1 ... 121 122 123 124 125 126 127 128 129 ... 165
Перейти на страницу:
Тут вы можете бесплатно читать книгу Linux программирование в примерах - Арнольд Роббинс.
Комментарии