Мой текущий пример поддержки многоязычности в программе.
Покритикуйте, может есть что улучшить.
Концепция следующая:
1. Так как мы русские, ну или можно сказать русскоязычные, то я стремлюсь, чтобы русский язык присутствовал в проге без заморочек. Открыл и всё на русском сразу. То есть проверка русского языка в ОС по числовому коду 1049.
2. Если открывает с не русской ОС, то язык остаётся англ. по умолчанию.
3. Если человек не русский и не англоязычный, то ему придётся открыть Lang.txt и заменить строки своим языком. Обычно я в комплекте кладу 2 файла Lang.txt на русском и на английском языке.
4. Не так давно решил добавить флаг ForceLang (принудительный язык). Суть его в союзных республиках или даже других странах могут находится русскоязычные с нерусскоязычной Windows, и запрос языка системы оставит по умолчанию английский язык, вот здесь и пригодится ForceLang=2, чтобы без языковых файлов включить второй язык, то есть русский. Жаль только что этот трюк не такой очевидный окажется для многих, не все читают Readme и справки и в большинстве воспользуются внешним файлом. По крайней мере кто спросит, есть что ответить.
5. Любые другие программисты могут вписать свой второй язык прямо в код и использовать такой же метод в отношении себя, то есть из коробки со своим языком.
6. Флаг ForceLang + 4 будет создавать Lang.txt. ForceLang=5 (1+4) или ForceLang=6 (2+4) будут создавать для первого и второго языка, при этом флаг сбрасывается в ноль ForceLang=0, чтобы использовать Lang.txt при последующих запусках.
;- TOP EnableExplicit ; Определяет язык ОС Define isUserLang Define ForceLang Define ini$, w, h, isINI CompilerSelect #PB_Compiler_OS CompilerCase #PB_OS_Windows Global *Lang If OpenLibrary(0, "kernel32.dll") *Lang = GetFunction(0, "GetUserDefaultUILanguage") If *Lang And CallFunctionFast(*Lang) = 1049 ; ru. Здесь вы используете код своего языка isUserLang = 1 EndIf CloseLibrary(0) EndIf CompilerCase #PB_OS_Linux If ExamineEnvironmentVariables() While NextEnvironmentVariable() If Left(EnvironmentVariableName(), 4) = "LANG" And Left(EnvironmentVariableValue(), 2) = "ru" ; LANG=ru_RU.UTF-8 ; LANGUAGE=ru isUserLang = 1 Break EndIf Wend EndIf CompilerEndSelect #ArrSizeStrLang = 2 Global Dim Lng.s(#ArrSizeStrLang) ;- Language En Lng(0) = "text0" Lng(1) = "text1" Lng(2) = "text2" Global PathConfig$ = GetPathPart(ProgramFilename()) ; Если конфиг рядом с исполняемым файлом не существует, то назначаем конфиги в папки настроек If FileSize(PathConfig$ + "MyProgramName.ini") = -1 CompilerSelect #PB_Compiler_OS CompilerCase #PB_OS_Windows PathConfig$ = GetHomeDirectory() + "AppData\Roaming\MyProgramName\" CompilerCase #PB_OS_Linux PathConfig$ = GetHomeDirectory() + ".config/MyProgramName/" ; If FileSize(PathConfig$) = -1 And FileSize("/usr/share/MyCompanyName/MyProgramName/MyProgramName.ini") > 0 ; CopyFile("/usr/share/MyCompanyName/MyProgramName/MyProgramName.ini", PathConfig$) ; EndIf ; CompilerCase #PB_OS_MacOS ; PathConfig$ = GetHomeDirectory() + "Library/Application Support/MyProgramName/" CompilerEndSelect EndIf ini$ = PathConfig$ + "MyProgramName.ini" ;- ini If FileSize(ini$) > -1 And OpenPreferences(ini$) PreferenceGroup("Set") w = ReadPreferenceInteger("width", w) ; настроки размера окна, как пример блока взятия всех настроек программы из ini h = ReadPreferenceInteger("height", h) ForceLang = ReadPreferenceInteger("forcelang", ForceLang) ; принудительно выставить язык isINI = 1 ; чтобы больше не использовать FileSize(), хотя он в OpenPreferences() наверняка есть. ClosePreferences() EndIf ; Принудительный язык ; 0 - автоматически ; 1 - принудительно первый ; 2 - принудительно второй ; +4 генерировать языковой файл If ForceLang & 1 isUserLang = 0 ElseIf ForceLang & 2 isUserLang = 1 EndIf ;- Language Ru If isUserLang Lng(0) = "текст0" Lng(1) = "текст1" Lng(2) = "текст2" EndIf ; Функция построчного взятия текста с внешнего файла Procedure SetLangTxt(PathLang$) Protected file_id, Format, i, tmp$ file_id = ReadFile(#PB_Any, PathLang$) If file_id ; Если удалось открыть дескриптор файла, то Format = ReadStringFormat(file_id) ; перемещаем указатель после метки BOM i = 0 While Eof(file_id) = 0 ; Цикл, пока не будет достигнут конец файла. (Eof = 'Конец файла') tmp$ = ReadString(file_id, Format) ; читаем строку ; If Left(tmp$, 1) = ";" ; Continue ; EndIf ; tmp$ = ReplaceString(tmp$ , #CR$ , "") ; коррекция если в Windows tmp$ = RTrim(tmp$ , #CR$) ; коррекция если в Windows If Asc(tmp$) And Asc(tmp$) <> ';' If i > #ArrSizeStrLang ; массив Lng() уже задан, но если строк больше нужного, то не разрешаем лишнее Break EndIf ; Lng(i) = UnescapeString(tmp$) ; позволяет в строке иметь экранированные метасимволы, \n \t и т.д. Lng(i) = ReplaceString(tmp$, "\n", #LF$) ; В ini-файле проблема только с переносами, поэтому заменяем только \n i + 1 Else Continue EndIf Wend CloseFile(file_id) EndIf EndProcedure Procedure CreateLang() Protected file_id, i file_id = CreateFile(#PB_Any, PathConfig$ + "Lang.txt", #PB_UTF8) If file_id ; Если удалось открыть дескриптор файла, то WriteStringFormat(file_id, #PB_UTF8) For i = 0 To #ArrSizeStrLang CompilerIf #PB_Compiler_OS = #PB_OS_Windows tmp$ = ReplaceString(Lng(i), #CRLF$, "\n") CompilerElse tmp$ = ReplaceString(Lng(i), #LF$, "\n") CompilerEndIf WriteStringN(file_id, tmp$) Next EndIf EndProcedure ; Если языковой файл существует, то использует его If ForceLang = 0 And FileSize(PathConfig$ + "Lang.txt") > 100 SetLangTxt(PathConfig$ + "Lang.txt") ElseIf ForceLang & 4 CreateLang() If OpenPreferences(ini$) PreferenceGroup("Set") WritePreferenceInteger("forcelang", 0) ; сбросить флаг после создания файла ClosePreferences() EndIf EndIf ;-┌──GUI──┐ If OpenWindow(0, 0, 0, 220, 110, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) ButtonGadget(1, 10, 10, 111, 27, Lng(0)) ButtonGadget(2, 10, 40, 111, 27, Lng(1)) ButtonGadget(3, 10, 70, 111, 27, Lng(2)) ;-┌──Loop──┐ Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow EndIf
Отредактировано AZJIO (03.07.2024 21:22:02)