Иван Синтюрин
spinoza@mail.ru
Одним из самых очевидных достоинств FAR'a является возможность его локализации. Локализация означает то, что сообщения и справка показываются на понятном для пользователя языке, и никто не запрещает ему перевести эти сообщения на любой другой язык (чем я иногда и занимался раньше). Такие же возможности предоставлены подключаемым к FAR'у внешним модулям - т.н. «плагинам». [Почти] все сообщения и вся [полностью] помощь размещаются соответственно в LNG и HLF-файлах, которые можно перевести на нужный язык (было б желание).
Урезаны в своих правах лишь плагины для плагинов, т.н. «плагины второго уровня», «подплагины», "субплагины". Плагинов, поддерживающих субплагины, правда, мало, но кто знает, что будет завтра? В чем проблема? В том, что FAR не подерживает обработку нескольких файлов типа LNG или HLF на одном языке в одном каталоге, каждому языку соответствует только пара файлов - LNG и HLF. Одно дело плагин второго уровня для multiarc'а, ему никаких сообщений выводить не нужно, другое дело плагины типа AddressBook (by Pavel Kostromitinov, рекомендую), для их субплагинов необходима возможность локализации. Как последнюю предусмотреть?
Локализация бывает 3-х видов:
Для локализации 2 и 3 вида можно использовать запись строковых сообщений в реестр [но я не люблю, когда всякая ерунда пишется в реестр, да и править эту информацию не так удобно] или в файл, а оттуда их считывать, когда потребуется.
Посидел я минут 10 и написал свою функцию, которая возвращает указатель на запрашиваемую строку в соответствии с настройками FAR'а. Она находится в файле LocMsg.cpp (см. ниже), посмотрите - все просто, «как два пальца об ...». Для 2 вида локализации Вы можете включать данный файл в свою программы директивой препроцессора include, например, так:
#include "LocMsg.cpp"
Для возможности глобальной локализации автор основного плагина должен предоставить субплагину указатель на данную функцию, т.е. включать данный код в субплагин уже не нужно. Вот содержимое моего файла LocMsg.cpp:
/*
LocMsg - Скажем локализации: «ДА!»
Author - Ivan Sintyurin. Copyright (c) 2000. All Rights Reserved.
Я буду рад, если данная функция поможет Вам писать программы с
возможностью локализации. Прошу Вас только об одном - указывайте
мой copyright (в readme, например).
Функция LocMsg возвращает указатель на строку в соответствие с
языковыми настройками FAR'а (учитывает настройки конкретных
пользователей - фича FAR 1.63).
В каталоге с плагином должен быть файл с сообщениями с именем
"ИмяПлагина.msg" Описание формата находится в файле template.msg.
Передаваемые параметры:
MsgName - название нужного сообщения
Var - если не NULL, то сюда копируется полученная строка
Должна также быть определена и заполнена глобальная структура
PluginStartupInfo Info, из нее берутся данные:
Info.RootKey - место, где хранятся данные плагинов
Info.ModuleName - полный путь к плагину
*/
char *LocMsg(char *MsgName, char *Var)
{
HKEY hKey;
DWORD Type;
static char Msg[80];
char msgfile[NM], //имя файла с данными
Lang[80]="Russian",/*Название языковой секции,
по умолчанию=Russian*/
LangKey[80]=""; //Языковые настройки FAR'а
lstrcpy(msgfile,Info.ModuleName);//Определяем имя файла
char *ptr=strrchr(msgfile,'.'); //с сообщениями.
if(ptr) lstrcpy(ptr,".msg"); //У Вас это может
else lstrcat(msgfile,".msg"); //выглядеть иначе.
lstrcat(LangKey,Info.RootKey);//Определяем:
ptr=strrchr(LangKey,'\\'); //откуда читать
lstrcpy(ptr+1,"Language"); //языковые настройки.
//Читаем языковые настройки текущего пользователя
if(RegOpenKeyEx(HKEY_CURRENT_USER,LangKey,0,
KEY_READ,&hKey)==ERROR_SUCCESS)
{
DWORD DataSize=80;
RegQueryValueEx(hKey,"Main",NULL,&Type,
(BYTE *)&Lang,&DataSize);
RegCloseKey(hKey);
}
if(! GetPrivateProfileSection (Lang,Msg,80,msgfile))
{
/*если требуемой секции нет, то прочитать имя
секции по умолчанию*/
GetPrivateProfileString ("Default","Language",
"Russian",Lang,80,msgfile);
if(!GetPrivateProfileSection(Lang,Msg,80,msgfile))
/*если нет требуемой секции с именем, равным
имя по умолчанию, то читать будем первую
попавшуюся секцию*/
GetPrivateProfileSectionNames (Lang,80,msgfile);
}
//читаем нужную строку
GetPrivateProfileString(Lang,MsgName,MsgName,Msg,80,
msgfile);
/*Если раскомментировать следующую строку, то в msg-файле
будут автоматически создаваться отсутствующие секции*/
/*if(lstrcmp(MsgName,Msg)==0)
WritePrivateProfileString (Lang,MsgName,Msg,msgfile);*/
//Копируем в Var полученную строку, если надо
if(Var)lstrcpy(Var,Msg);
return(Msg);
}
Файл с сообщениями должен называться ИмяПлагина.msg и является обыкновенным ini-файлом. Его структура такова (содержимое упомянутого выше template.msg):
[Default] //Данная секция сообщает из какой секции брать строки, если в //данном файле не найдено требуемой языковой секции. Данная секция //может отсутствовать, в этом случае языковой секцией по умолчанию //считается первая. Language=Russian //Далее идет описания языковых секций. //Названия ДОЛЖНЫ формироваться следующим образом: //В lng-файлах первая строка такая //.Language=Russian,Russian (Русский) // ^^^^^^^ //А вот так должна называться языковая секция [Russian] String1=Текст первого сообщения String2=Текст второго сообщения [English] String1=Text of the first message String2=Text of the second message //и т.д.
Демонстрация работы с данной функцией находится в архиве localization.rar, который можно взять здесь или еще где-нибудь.
К сожалению, Евгений Рошал не предусмотрел в API функции, выводящей определенный топик нужного hlf-файла. Но в данном случае это не страшно.
Статья писалась в то время, когда о FAR 1.70 еще и слышно не было :), поэтому данное заявление уже неверно. В FAR Manager версии 1.70 и выше вы можете для вывода нужного топика нужного hlf-файла функцией ShowHelp.
Допустим, существует плагин с поддержкой субплагинов, и имя ему mainplugin.dll, файлы помощи имеют имена mainpluginR.hlf и mainpluginE.hlf. Пользователь захочет посмотреть справку под названием MainDialog (например) для субплагинов по имени subplugin1 и subplugin2. Для этого нужно просто добавить имена данных топиков в параметры функции Dialog у данных субплагинов, а сами топики дописать к файлам mainpluginR.hlf и mainpluginE.hlf. Для первого субплагина это будет топик с именем subplugin1_MainDialog (рекомендую в качестве префикса к топику писать название субплагина, тогда не будет совпадений/противоречий с другими субплагинами), для второго - subplugin2_MainDialog. В результате нужная справка будет для субплагина показываться также как и для основного плагина.
That's all, folks :-)
07.01.2000