- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Linux программирование в примерах - Арнольд Роббинс
Шрифт:
Интервал:
Закладка:
animal = _("cat");
} else if (...) {
...
} else {
...
}
printf(_("the %s %s looks at you enquiringly.n"), animal_color, color);
Здесь форматирующая строка, animal_color и animal неудачно включены в вызов gettext(). Однако, после перевода утверждение будет неверным, поскольку порядок аргументов не может быть изменен во время исполнения.
Чтобы обойти это, версия семейства printf() POSIX (но не ISO С) допускает использовать в описателе формата указатель положения. Он принимает форму десятичного числа, за которым следует символ $, сразу после начального символа %. Например printf("%2$s, %1sn", "world", "hello");
Указатель положения обозначает аргумент из списка, который следует использовать, отсчет начинается с 1 и не включает саму форматирующую строку. Этот пример выводит знаменитое сообщение 'hello, world' в правильном порядке.
GLIBC и Solaris реализуют эту возможность. Поскольку это часть POSIX, если printf() вашего поставщика Unix не реализует ее, она вскоре должна появиться.
За указателем положения могут следовать любые обычные флаги printf(), указатели ширины полей и точности. Вот правила для использования указателей положения:
• Форма с указателем положения не может смешиваться с формой без нее. Другими словами, или каждый указатель формата включает указатель положения, или ни один его не включает. Конечно, %% может использоваться всегда.
• Если в форматирующей строке используется N-й аргумент, в этой строке должны использоваться также все аргументы до N. Соответственно, следующее неверно printf("%3$s %1$sn", "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. Тестирование переводов в персональном каталоге
Коллекция сообщений в программе называется списком сообщений (message catalog). Этот термин применяется также к каждому из переводов сообщений на другой язык. Когда программа установлена, каждый перевод также устанавливается в стандартное место, где gettext() может во время исполнения найти нужный перевод.
Может оказаться полезным разместить переводы не в стандартном, а в другом каталоге, особенно для тестирования программы. Особенно на больших системах, у обычного пользователя может не быть необходимых разрешений для установки файлов в системные каталоги. Функция bindtextdomain() дает gettext() альтернативное место для поиска переводов:
#include <libintl.h> /* GLIBC */
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 %dn", также как отладочные сообщения.
7. В нужных местах используйте ngettext() (или ее варианты) для значений, которые могут быть 1 или больше 1.
8. Упростите жизнь для своих переводчиков, используя строки с полными предложениями вместо замены слов с помощью %s и ?:. Например:
if (/* возникла ошибка */) { /* ВЕРНО */
/* Использовать несколько строк для упрощения перевода. */
if (input_type == INPUT_FILE)
fprintf(stderr, _("%s: cannot read file: %sn"),
argv[0], strerror(errno));
else
fprintf(stderr, _("%s: cannot read pipe: %sn"),
argv[0], strerror(errno));
Это лучше, чем
if (/* возникла ошибка */) { /* НЕВЕРНО */
fprintf(stderr, _("%s: cannot read %s: %sn"), 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.
Переходя к созданию переводов, первым шагом является извлечение переводимых строк. Это осуществляется программой xgettext:
$ xgettext --keyword=_ --keyword=N_
> --default-domain=echodate ch13-echodate.с
Опции --keyword сообщает xgettext, что нужно искать макросы _() и N_(). Программа уже знает, как извлекать строки из gettext() и ее вариантов, а также из gettext_noop().
Вывод xgettext называется переносимым объектным файлом. Имя файла по умолчанию messages.ро, что соответствует текстовому домену по умолчанию "messages". Опция --default-domain обозначает текстовый домен для использования в имени выходного файла. В данном случае, файл назван echodate.ро. Вот его содержание:
# SOME DESCRIPTIVE TITLE. /* Шаблон, нужно отредактировать */
# Copyright (С) YEAR THE PACKAGE'S COPYRIGHT HOLDER

