Мой текущий пример поддержки многоязычности в программе.
Покритикуйте, может есть что улучшить.
Концепция следующая:
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)