А как Вы тогда объясните то, что все крупные продукты имеют именно локализованные версии, а не текстовые файлы с переводами?
На самом деле здесь дело в возможностях автора. Если этот самы втор один (вдвоём, втроём) работает над программой, то маловероятно, что у него есть возможность локализовать программу самому. В таком случае выбор один — не очень качественный перевод на общественных началах.
Если же автора (чаще компании-автора) есть возможность заказать перевод профессионалам, то локализованные версии — лучший выбор.
В общем, здесь как везде — либо дорого, но качественно, либо дёшево но некачественно.
LoadString, LoadIcon, LoadMenu, LoadCursor и др. используют FindResource для поиска нужного ресурса.
FindResource использует алгоритм поиска по языку с откатом на LANG_ENGLISH,SUBLANG_DEFAULT в случае
отсутствия языкового ресурса отличного от LANG_NEUTRAL и языка текущей локали.
> Например, вы имеете кнопку с надписью "Keyword" — 7 букв. > Перевод на русский язык будет выглядеть как > "Ключевое слово" — 14 букв. Ровно в два раза больше. > И как Вы думаете, влезет ли это словосочетание на кнопку, > на которой до этого располагался английский вариант? > Я думаю, что нет.
А я буду делать свою прогу на русском языке, тогда перевод на аглицкий точно влезет куда надо :)
Тем не менее признаю, что мое замечание "Можно но не нужно" не относится к монстрам, разрабатываемым на фирмах уровня Microsoft.
Тут следует отметить вот что. Описанный метод — это модификация метода локализации посредством текстового файла со строками на разных языках. В отличие от последнего он позволяет иметь не только строки на разных языках для элемента управления, но и разное расположение этих самых элементов управления для разных языков! Большое преимущество здесь состоит в том, что, во-первых, как уже отмечалось, одни и те же слова в разных языках имеют разную длину. А во-вторых, носители разных языков, из-за менталитета, воспринимают одни и те же дизайнерские решения по-разному. Например, носители языков, где пишут с права на лево, просматривают окна в порядке не лево верх -> право низ, а право верх -> лево низ. А это ведёт к иному расположению элементов управления в окне.
А что касается больших продуктов, то там выгоднее для каждого языка собирать отдельный билд.
В MSDN алгоритм поиска по языку функциями FindResource и FindResourceEx был опубликован два года назад.
Но. Во-первых, это была прямая дезинформация, во-вторых, уже год как той статьи нет. Я писал тестовую
программу для изучения этого вопроса.
>В отличие от последнего он позволяет иметь не только >строки на разных языках для элемента управления, но и >разное расположение этих самых элементов управления >для разных языков!
Да, именно это я и хотел сказать в своем предыдущем постинге, но забыл упомянуть про контролы (вспомнил только при перечитке).
Возвращаясь к приведенному мной примеру, замечу, что для того, чтобы русский вариант написания нормально влез в контрол, достаточно просто растянуть элемент управления и, если необходимо, увеличить размеры диалогового ресурса.
Создание же, изначально, программы на русском языке, а затем ее перевод на другие языки не правилен, с моей точки зрания, по двум причинам: во-первых, если Вы озадачились локаизацией приложения на другие языки, то это подразумевает, что программу будут использовать люди не умеющие читать по русски. А Вы даете гарантию, что приложение установится нормально или никто не сотрет файл с английской локализацией и не удалит Вашу программу только потому, что не сможет понять интерфейс?
Во-вторых, кто Вам сказал, что фразы на русском язык самые длинные из всех языков?
Здравствуйте, Михаил А. Русаков, Вы писали:
МАР>Замечание относится непосредственно к MFC. Итак, локализация в MFC делается еще проще: достаточно в редакторе ресурсов приложения выбрать ресурс, подлежащий локализации, кликнуть правой кнопкой мыши и выбрать пункт "Insert Copy". После этого Вас попросят указать язык, на котором будет эта копия. Далее остается только перевести скопированный ресурс — остальное MFC сделает сама.
МАР>При загрузке приложения MFC будет искать и загружать ресурсы в зависимости от текущей локали пользователя в следующей последовательности: сначала ищет ресурс с суб_языком = равном локали Windows. Если такового не находится, то она (MFC) пытается загрузить ресурс с языком = локали Windows... Затем английский, затем нейтральный... И если уж не нашлось никакого, то MFC берет ресурс с первым "попавшимся под руку" языком.
МАР>Смысл в том, что у программиста не болит голова о локализации... Знай себе, вовремя делай копии ресурсов...
МАР>Единственным недостатком предложенного мной метода является то, что MFC грузит ресурсы язык которых соответствует языку Windows, а не региональным настройкам панели управления. То есть, если Вы будете работать на английском Windows, то всегда будете наблюдать английский интерфейс, если локализация выполнена по описанному мной способу.
МАР>С другой стороны, это правильное решение: ведь если Вы работаете в ОС на каком-то языке, то это значит, что Вы можете, как минимум, читать на этом языке....
МАР>Удачи!
Помнится, что 'такой автомат' работает только под ВинНТ 4.0 а в остальных случаях надо руцями пользовать FindResourseEx...
C уважением.
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Спасибо, сэкономили кучу времени.
КД>Особенно с LoadStringLang. Её реализация в Windows действительно очень далека от идеала.
КД>Единственное, что с картинкой, показывающей заполненность групп по 16 строк. Надо было нолики подрисовать и в начале группы, чтобы не пугаться лишний раз, когда первый раз видишь это дело под отладчиком
Если хочется, чтобы выбор языка происходил на основании именно "настроек в панели управлния", т.е. locale, то можно сделать так:
BOOL CMyApp::InitInstance()
{
InitCommonControls();
HINSTANCE hRes = NULL;
LANGID li = GetUserDefaultLangID();
switch(PRIMARYLANGID (li)){
case LANG_RUSSIAN:
hRes= LoadLibrary(L"Resource_Russian.dll");
break;
case LANG_SPANISH:
hRes= LoadLibrary(L"Resource_Spanish.dll");
break;
case LANG_ITALIAN:
hRes= LoadLibrary(L"Resource_Italian.dll");
break;
case LANG_GERMAN:
hRes= LoadLibrary(L"Resource_German.dll");
break;
case LANG_FRENCH:
hRes= LoadLibrary(L"Resource_French.dll");
break;
};
if(hRes)
AfxSetResourceHandle(hRes);
CWinApp::InitInstance();
...
Соотвественно в dll-ках лежат копии ресурсов, с нужным language.
У меня в самом exe-шнике лежит английская версия, которая грузится по умолчанию, либо если не получилось загрузить нужную библиотеку.
Здравствуйте, Гулай Борис aka BoresExpress, Вы писали:
А зачем такие сложности с этими устаревшими таблицами сообщений, для которых нужно отдельно запускать mc? В MFC можно все поместить в обычные строковые ресурсы, а потом форматировать строку, содержащую всякие там %1 и %2!d! с помощью CString::FormatMessage(messageId [, parameter]...).
Здравствуйте, Михаил А. Русаков, Вы писали:
МАР>Единственным недостатком предложенного мной метода является то, что MFC грузит ресурсы язык которых соответствует языку Windows, а не региональным настройкам панели управления. То есть, если Вы будете работать на английском Windows, то всегда будете наблюдать английский интерфейс, если локализация выполнена по описанному мной способу.
Действительно всегда, или, всё же, существует способ обмануть MFC?
И если существует, еще усложню — есть ли способ менять язык во время работы программы?
Здравствуйте, e-smirnov, Вы писали:
ES>Действительно всегда, или, всё же, существует способ обмануть MFC? ES>И если существует, еще усложню — есть ли способ менять язык во время работы программы?
Я как раз на эту тему вчера статью отослал, так что если опубликуют...
Здравствуйте, Kooksha, Вы писали:
K>Для MFC версии есть проблема с диалоговым окном: DoModal не работает с CreateIndirect() Работает только с InitModalIndirect(), но этот метод не локализует ресурс. Как быть?
Очень просто. Для вашего класса диалога CMyDialog нужно вызывать пустой унаследованный конструктор CDialog(), например, вот так:
CMyDialog::CMyDialog(CWnd* pParent /*=NULL*/) : CDialog()
{
m_pParentWnd = pParent;
//{{AFX_DATA_INIT(CMyDialog)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
Ссылку на родительское окно сохраняем в конструкторе, нам она понадобится в вызове метода InitModalIndirect. Ну, а теперь переопределяем метод DoModal, например, так:
int CMyDialog::DoModal()
{
if (!InitModalIndirect((LPDLGTEMPLATE)LoadResourceLang(RT_DIALOG, this->IDD), m_pParentWnd))
return IDCANCEL;
return CDialog::DoModal();
}
где LoadResourceLang — своя функция, которая, собственно, описывает логику поиска сначала ресурсов на русском, например, а затем и на английском.
Алексей Радиванюк
Re[2]: MFC: есть проблема с диалогом (DoModal)
От:
Аноним
Дата:
09.12.04 09:10
Оценка:
Здравствуйте, Alecard, Вы писали:
A>Ссылку на родительское окно сохраняем в конструкторе, нам она понадобится в вызове метода InitModalIndirect. Ну, а теперь переопределяем метод DoModal, например, так:
A>
A>int CMyDialog::DoModal()
A>{
A> if (!InitModalIndirect((LPDLGTEMPLATE)LoadResourceLang(RT_DIALOG, this->IDD), m_pParentWnd))
A> return IDCANCEL;
A> return CDialog::DoModal();
A>}
A>
К сожалению, InitModalIndirect() отказывается создавать модальный диалог на основе указанного шаблона. Порывшись в Google, я обнаружил такое решение: подменить всю функцию DoModal(). См. http://www.developpez.net/forums/viewtopic.php?p=768010.
Единственное, что я поменял — вместо:
К сожалению, вынужден сказать, что предлагаемый подход не работает в полной мере.
Например, для немецкого языка диалоги не показывают умляуты, хотя в меню они есть.
Как это дело проверить
1. Выставляем текущую локаль — германия
2. Запускам тестовое приложение — убеждаемся, что в меню умляуты есть, в диалогах (например, в эбаут) — нет.
3. Выставляем язык для неюникодных приложений — немецкий.
4. Запускаем тестовое приложение, убеждаемся, что умляуты появились и в диалогах.
Итого — все более-менее нормально работает только при _обязательной_ настройке для неюникодных приложений. А нафига оно тогда, спрашивается, в таком виде надо... Вообще говоря, странно — в меню умляуты есть всегда, в диалоге — нет. Мысли по поводу?