LINUX.ORG.RU

[gettext] «вкомпилированные» mo-файлы?

 


0

0

С внедрением glade'овских UI в бинарник более-менее разобрался. Теперь такой вопрос: как то же самое сделать с mo-файлами?

Допустим, что я не хочу заморачиваться с выбором локальной или глобальной директории локализации, а хочу, чтобы после make мой бинарник сразу запускался, без «распихивания» mo-файлов.

Возможно ли это?

P.S. На данный момент пользуюсь проверенной временем системой «локализации»: создаю заголовочный файл lang.h с содержимым вроде

#define		_LANG(_var, _ru, _en)	char _var##ru[] = _ru;\
					char _var##en[] = _en;\
					char *_var[2] = {_var##ru,  _var##en};
#define		_L(x)	(x[Lang])

_LANG(_s_Name_, "Ваши Ф.И.О.", "Your name");
_LANG(_s_Stop_n_write_, "Остановить запись и сохранить файл", "Stop writing and save file");
...
в исходники включаю его, а вместо текста пишу _L(_s_Name_), к примеру. Язык устанавливается из анализа переменной LANG.

Но этот способ неудобен тем, что приходится вручную контролировать все эти переменные.

Как бы это поудобнее автоматизировать?

☆☆☆☆☆
Ответ на: комментарий от rymis

Спасибо. Но, что-то не нравится мне вот это:

char * po2c_gettext(char * msgid)
{
        struct _po2c_msg * m;
        int b, t, n, c;

        /* if no language is set or msgid is empty, return msgid as is */
        if(_po2c_lang == NULL || *msgid == '\0')
                return(msgid);

        /* binary-search for the msgid */
        b=0; t=_po2c_lang_size - 1;

        while(t >= b)
        {
                n=(b + t) / 2;
                m=&_po2c_lang[n];

                c=strcmp(msgid, _po2c_msgids[m->msgid]);

                if(c == 0)
                        return(m->msgstr);
                else
                if(c < 0)
                        t=n - 1;
                else
                        b=n + 1;
        }

        return(msgid);
}
Неужели gettext тоже для каждого сообщения ищет аналог в другом языке? Это же тормоза, особенно, если переводного материала очень много...

Наверное, проще самому скриптик сделать, который будет преобразовывать строки вида _(«some text») в _L(_some_text_) и заполнять соответствующие _LANG-строки, исходя из содержимого po-файлов...

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от fat_angel

Зойчем это делать?!

Хочется вменяемой локализации, не зависящей от расположения каких-то «левых» файлов :)

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Это же тормоза, особенно, если переводного материала очень много...

Ты собрался в цикле триллион раз выводить локализованное сообщение?

baverman ★★★
()
Ответ на: комментарий от baverman

Нет, но я думал, что gettext по-другому работает, а не просто тупо перебирает варианты (я с такого «самопального» варианта локализации и начал, но остановился на массивах и условных переменных). Просто не понимаю, зачем задействовать излишние вычислительные ресурсы?

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Нет, но я думал, что gettext по-другому работает

Очень странный вывод. Почему он должен работать также как и po2c? Может там хеши?

И, ИМХО, бинарный поиск на таких объемах тоже достаточно быстр.

baverman ★★★
()
Ответ на: комментарий от Eddy_Em

gettext делает так же. Сколько у вас сообщений? 1024 - дают не более 10 сравнений, которые происходят не так уж и часто.

rymis ★★
()
Ответ на: комментарий от rymis

1024 - дают не более 10 сравнений, которые происходят не так уж и часто.

Это при условии предварительного индексирования.

Eddy_Em ☆☆☆☆☆
() автор топика

Ладно, черт с ним, gettext'ом, буду продолжать использовать свой метод локализации. Но такой вопрос: как локализовать надписи из glade'овских файлов?

Или ну его нафиг, этот glade, и стоит всякие менюшки и т.п. создавать через GtkItemFactory (про который почему-то пишут, что он deprecated, хотя отлично работает) и т.д.?

Eddy_Em ☆☆☆☆☆
() автор топика

GtkItemFactory заменяю на GtkUIManager, glade, скорее всего, посылается подальше, локализация - своя:

#ifdef LANG_INI
#define		_LANG(_var, _ru, _en)	gchar _var##ru[] = _ru;\
					gchar _var##en[] = _en;\
					gchar *_var[2] = {_var##ru,  _var##en};
#else
#define		_LANG(_var, _ru, _en) extern gchar *_var[2];
#endif
// для окон
#define		_L(x)	(x[Lang])
// для вывода в консоль
#define		_LC(x)	g_locale_from_utf8(x[Lang], -1, NULL, NULL, NULL)
_LANG(_s_Save, "Сохранить файл", "Save file");
// и т.д.
...
if(strstr(sys_lang, "ru")) Lang = 0;
else Lang = 1;
...
// инициализация GtkActionEntry и т.п.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

> Ладно, черт с ним, gettext'ом, буду продолжать использовать свой метод локализации.

вот ведь нечего делать

пользоваться надо универсальными средствами, а велосипеды изобретать, когда уже припрет

dt1 ★★
()
Ответ на: комментарий от dt1

пользоваться надо универсальными средствами, а велосипеды изобретать, когда уже припрет

Когда универсального средства нет - приходится изобретать велосипеды. А gettext универсальным средством не является, т.к. не позволяет получать независимые от всяких «левых» файлов бинарники.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Gettext таки является универсальным средством. А идея о том, что файлы из Вашего же проекта являются «левыми» - это жесть, мягко говоря.

Если Вам совсем заняться нечем - создайте скрипт, который распаковывает все нужное из себя куда-нибудь в подкаталог /tmp и оттуда запускает бинарник.

svu ★★★★★
()
Ответ на: комментарий от svu

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

svu ★★★★★
()
Ответ на: комментарий от svu

ИМХО, «правильный» gettext вел бы себя так:

  1. собрать все содержимое конструкций _(«текст») в отдельный файл
  2. после перевода файла - вырезать из исходников все _(«текст») и заменить их строковыми массивами с индексами, равными значению некоей переменной
  3. все переводные конструкции оформить в виде отдельного заголовочного файла с инициализацией всех используемых строковых массивов
  4. в момент запуска программы значение этой «некоей» переменной берется из значения текущего языка, соответственно автоматически все сообщения выводятся на нужном языке, безо всякого геморроя и ненужных файлов
Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от svu

Почему? Элементарно добавляем по еще одному строковому полю для нового языка, а в main делаем проверку на этот язык с установлением соответствующего значения переменной Lang. По-моему, это намного удобнее, чем уйма отдельных файлов для каждого языка.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

>1. собрать все содержимое конструкций _(«текст») в отдельный файл
Это называется pot file

2. после перевода файла - вырезать из исходников все _(«текст») и заменить их строковыми массивами с индексами, равными значению некоей переменной

Это не важно, это мелочи. Да, если переводы держать в отдельных файлах (как в случае геттекста) это очень хреновая практика, ибо не позволяет работать, когда все файлы переводов стерты.

3. все переводные конструкции оформить в виде отдельного заголовочного файла с инициализацией всех используемых строковых массивов

Бинарник вырастет до охренительных размеров, при этом 99% статических данных будут никому не нужны. И придется придумывать хитрые механизмы как их выкусывать (для тех, кому переводы не нужны). Я уж не говорю о невозможности обновлять переводы без обновления кода.

4. в момент запуска программы значение этой «некоей» переменной берется из значения текущего языка, соответственно автоматически все сообщения выводятся на нужном языке, безо всякого геморроя и ненужных файлов

Оно почти так, но не это суть.

Вы не понимаете главного - сама по себе задача «одно приложение = один файл» является маразматичной и бессмысленной, не имеющей НИКАКОЙ практической пользы, но приводящей к куче геморроя. Посмотрите хотя бы на макос - даже они перестали использовать один многофорковый файл и перешли на нормальные каталоги для приложений (другое дело, что для пользователя это выглядит как «одна иконка в файндере, которую можно перетащить»).
Нормальное приложение с собой тащит еще и всякие интерфейсные файлы (иконки, картинки, описания диалогов), конфиг файл и пр. и пр. И все это спокойно менеджится. Бессмысленная постановка задачи - и потом внезапное удивление, что никто не собирается решать ее.

svu ★★★★★
()
Ответ на: комментарий от Eddy_Em

Вы никогда не работала переводчиком, видимо.

Нафига переводчику с русского видеть перед собой строки на 101 другом языке? Ему гораздо удобнее редактировать po file только с русскими строками?

Я уж не говорю о том, что добавление языка потребует нового бинарника.

svu ★★★★★
()
Ответ на: комментарий от svu

Бинарник вырастет до охренительных размеров, при этом 99% статических данных будут никому не нужны. И придется придумывать хитрые механизмы как их выкусывать (для тех, кому переводы не нужны). Я уж не говорю о невозможности обновлять переводы без обновления кода.

Я не пишу проекты, которые понадобятся кому-то, кроме меня и пары-тройки коллег. И, естественно, кроме русского и английского никаких других языков не будет.

Вот поэтому мне и не нужен gettext! Я понимаю его преимущества при написании многоязычных приложений, но в случае двух языков - зачем?

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от svu

Нормальное приложение с собой тащит еще и всякие интерфейсные файлы (иконки, картинки, описания диалогов)

Все они прекрасно вкомпилируются в бинарник.

конфиг файл

Ну, без этого - да, никуда. Но это лишь один бинарный файл в пользовательской директории, и удаление его никакого влияния на работу приложения не окажет (кроме дефолтных настроек).

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

gettext сделан, чтобы быть как можно более универсальным

твой вариант:

1) не поддерживает динамический перевод, когда строки не жестко заданы в определенном месте программе, а откуда-то берутся

2) не годится для каких-нибудь скриптовых языков

3) добавляет лишние проблемы с переводом существительных в единственном/множественном числе

может он и хорош в определенном случае, но очевидно, что «правильный» gettext таким быть не может

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

dt1 ★★
()
Ответ на: комментарий от Eddy_Em

> Я не пишу проекты, которые понадобятся кому-то, кроме меня и пары-тройки коллег.
Даже в маленьком проекте, как океан в капле воды, отражаются вкусы и уровень его авторов.
Не приучайте себя халтурить. Особенно глупо выглядит, если усилия на халтуру оказываются больше, чем на правильную организацию процесса Впрочем, стратегически оно почти всегда бывает так, но не сразу - но в случае Вашего велосипеда почти сразу.

никаких других языков не будет.

А завтра Ваш проект захотят мощно пофинансировать китайцы...

но в случае двух языков - зачем?

См. выше про каплю воды. Просто потому что это стандартное, отлаженное решение.

svu ★★★★★
()
Ответ на: комментарий от Eddy_Em

> Я понимаю его преимущества при написании многоязычных приложений, но в случае двух языков - зачем?

а я вот не понимаю, какие же у него недостатки :)

dt1 ★★
()
Ответ на: комментарий от dt1

1) не поддерживает динамический перевод, когда строки не жестко заданы в определенном месте программе, а откуда-то берутся

gettext тоже произвольный текст не поддерживает, только фиксированный набор

2) не годится для каких-нибудь скриптовых языков

А они мне и не нужны. Хотя, на баше тоже можно такой «финт» сделать.

3) добавляет лишние проблемы с переводом существительных в единственном/множественном числе

Это да. Но с такими словами обычно используются всякие алгоритмы определения правильной формы, так что, в этом случае тоже можно вывернуться :)

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

Я не программист. Об оптимизации сейчас тоже особо не забочусь - мне бы файлов поменьше... Хотя, уменьшение времени выполнения тоже не повредит, особенно, если программа будет запускаться на каком-нибудь стареньком промышленном PI.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

> Все они прекрасно вкомпилируются в бинарник.
Как это вкомпилировать png-шную иконку, всякие xml описания интерфейсов и пр. И - главное - НАФИГА???? Еще раз - постановка задачи бессмысленная. Ни одного реального ответа ЗАЧЕМ дано не было. Ответ «хочу один файл» не может считаться за primary requirement, нужно объяснить - почему так критичен один файл (при том что весь мир спокойно работает на уровне packages)

svu ★★★★★
()
Ответ на: комментарий от Eddy_Em

> Я не программист.
Может, тогда и не надо...? «Беда, коль сапоги начнет тачать пирожник»

мне бы файлов поменьше

В 100500 раз - бессмысленная задача.

svu ★★★★★
()
Ответ на: комментарий от svu

никаких других языков не будет.

А завтра Ваш проект захотят мощно пофинансировать китайцы...

Не захотят. Это уж точно :) Программка жестко привязана к параметрам единственной в мире железяки, к тому же недвижимой :)

2 языка мне хотелось использовать для того, что не факт, что на рабочем компьютере будет установлена какая-нибудь локаль, кроме «C».

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

И еще. Подумайте о том, что однажды Вам может стать стыдно за этот код.

svu ★★★★★
()
Ответ на: комментарий от svu

Может, тогда и не надо...? «Беда, коль сапоги начнет тачать пирожник»

Надо :) Есть задача. Есть данные. Необходимо эти данные обработать и получить результат. Обработка данных несложная, но данных очень много - руками перебирать эти гигабайты фитсов не хочется...

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от svu

Наверное, вы правы. Пока не буду заморачиваться. Потом - подумаю.

Кстати, мой «велосипедный» метод выбора языка прекрасно и довольно быстро работает в веб-приложениях. И, что немаловажно для CGI-файлов, не надо засорять апачевские директории всяким мусором :)

Eddy_Em ☆☆☆☆☆
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.