Поддержка нескольких языков - одно из возможных требований проекта. Это может связано с его спецификой или просто необходимо увеличить охват проекта.
В таких проектах при разработке на Лямбда-Мю 3 делается следующее:
Такой подход удобен, и данные легко обновлять.
Платформа Лямбда-Мю 3 может использоваться как back end сервер веб-проекта. Одним из таких проектов является «Сомнология B2C» – мобильное приложение на Android.
Мультиязычность приложения позволит получить более широкий охват при его размещении в магазине. Продемострируем как реализована мультиязычность на стороне платформы.
Файловая структура проекта представлена ниже.
Необходимые скрипты туториала находятся в репозитарии lm3.examples/multi_lang.
Чтобы запустить платформу скачайте бинарный файл и необходимые библиотеки из репозитария lm3.engine.ce и скопируйте в корень проекта.
Проект «Сомнология B2C»:
Для отладки решения будут использоваться следующие версии:
Доработать взаимодействие между [client] и [server].
Требованием к проекту является минимальные изменения исходного проекта [client] и [server]. Требование достигается использованием того же протокола, который разработан в исходном проекте.
Авторизация:
Запрос:
{ { Object = "Auth", Command = "Set", Name = "UserName", Data = <string> }, { Object = "Auth", Command = "Set", Name = "UserMail", Data = <string> }, { Object = "Settings", Command = "Event", Name = "DoChangeLang", Data = <string> }, }
Ответ:
{ { Object = "Auth", Command = "Value", Name = "TaskObject", Data = <string> } }
Запрос списка курсов:
Запрос:
{ { Object = "Info", Command = "Event", Name = "CourceList" } }
Ответ:
{ { Object = "Info", Command = "Value", Name = "CourceList", Data = <array[table[CourceID:string, Name:string, Description:string]]> } }
Смена локализации:
Запрос:
{ { Object = "Auth", Command = "Value", Name = "TaskObject", Data = <string> } }
Объекты основной логической машины:
Объекты логических машин:
main / start.lua
lm3:Log("Starting server") lm3:LoadLibrary( {Alias = "sys", FileName = "lm3system"} ) lm3:Include("main_lib.lua") lm3:CreateLObject( { LibAlias = "sys", Type = "TCPServer", Name = "server" } ) server:SetAttr("SocCount", lmconf.MaxClientCount) lm3:CreateLObject( { LibAlias = "sys", Type = "DataPack", Name = "packer" } ) packer:SetAttr("BufCount", lmconf.MaxClientCount) lm3:CreateObject( { Type = "LMList", Name = "clients" } ) init_Auth("Auth") lm3:AddHandler("OnStart", function(o, ev) -- проверка конфигурации ЛМ if clients:DoPrepare(lmconf.BasePath.."client_lm/config.lua") == false then lm3:Log("client_lm prepare failed") end end) Auth:AddHandler("OnReply", function(o, ev) lm3:Log("Auth: OnReply: tag: "..tostring(ev.Tag).." : "..lm3:DataToString(ev.Data)) end) -- связи объектов server:Connect("OnConnect", "Auth", "DoConnect") server:Connect("OnDisconnect", "Auth", "DoDisconnect") server:Connect("OnIncoming", "packer", "DoUnpack") packer:Connect("OnUnpack", "Auth", "DoIncoming") Auth:Connect("OnReply", "packer", "DoPackTagged") packer:Connect("OnPack", "server", "DoSend") Auth:Connect("OnStartClientLM", "clients", "DoStart") Auth:Connect("OnStopClientLM", "clients", "DoStop") Auth:Connect("OnClientEvent", "clients", "DoEvent") clients:Connect("OnEvent", "Auth", "DoClientEvent")
main / main_lib.lua
-- объект Auth -- авторизирует клиента -- вызывает создание ЛМ -- связывает клиента с соответвующей ЛМ function init_Auth(_name) local obj = lm3:CreateObject( { Type = "Base", Name = _name } ) obj.ClientList = {} for i = 1, lmconf.MaxClientCount do obj.ClientList[i] = { isConnected = false, UserName = "", UserMail = "", LMName = "", } end function obj.TagFromLMName(_name) return tonumber(_name:sub(5)) end -- подключение нового клиента -- старт ЛМ obj:AddInEvent("DoConnect", "int", function(o, ev) lm3:Log("New client connected:"..tostring(ev)) obj.ClientList[ev].isConnected = true obj.ClientList[ev].UserName = "N/A" obj.ClientList[ev].UserMail = "N/A" obj.ClientList[ev].LMName = "clm_"..tostring(ev) lm3:Log("Start client LM...") if obj:OnStartClientLM( { Name = obj.ClientList[ev].LMName } ) == true then lm3:Log("Start client LM complete.") else lm3:Log("ERROR: Start client LM failed.") obj.ClientList[ev].isConnected = false end end) -- отключение клиента -- остановка ЛМ obj:AddInEvent("DoDisconnect", "int", function(o,ev) lm3:Log("Client disconnected:"..tostring(ev)) obj:OnStopClientLM(obj.ClientList[ev].LMName) obj.ClientList[ev].isConnected = false end) -- распределение данных от клиента obj:AddInEvent("DoIncoming", "table[Tag:int,Data:array[table[Object:string,Command:string,Name:string,[Data]:any]]]", function(o, ev) if obj.ClientList[ev.Tag].isConnected ~= true then lm3:Log("ERROR: Incoming data from not connected client: "..tostring(ev.Tag)) else lm3:Log("Incoming data from client with tag: "..tostring(ev.Tag).." : "..lm3:DataToString(ev.Data)) local data = ev.Data for i = 1,#data do local ObjName = data[i].Object if ObjName == "Auth" then obj:DoCommand( { Tag = ev.Tag, Data = data[i] } ) elseif ObjName == "Info" or ObjName == "Settings" then obj:OnClientEvent({ LMName = obj.ClientList[ev.Tag].LMName, EventName = "OnExtEvent", Data = data[i] }) else lm3:Log("Warning: Incoming command to unknown object: "..lm3:DataToString(ObjName)) end end end end) -- обработка данных от ЛМ obj:AddInEvent("DoClientEvent", "table[LMName:string,EventName:string,Data:any]", function(o, ev) local iClient = obj.TagFromLMName(ev.LMName) obj:OnReply( { Tag = iClient, Data = ev.Data } ) end) -- обработка запросов клиента к основной ЛМ obj:AddInEvent("DoCommand", "table[Tag:int,Data:table[Object:string,Command:string,Name:string,Data:any]]", function(o, ev) if ev.Data.Command == "Set" then if ev.Data.Name == "UserName" then obj.ClientList[ev.Tag].UserName = ev.Data.Data elseif ev.Data.Name == "UserMail" then obj.ClientList[ev.Tag].UserMail = ev.Data.Data obj:OnReply( { Tag = ev.Tag, Data = { {Object = "Auth", Command = "Value", Name = "TaskObject", Data = "Task"} } } ) end end end) -- отправь данные клиенту obj:AddOutEvent("OnReply", "table[Tag:int,Data:array[table[Object:string,Command:string,Name:string,[Data]:any]]]") -- отправить данные в ЛМ obj:AddOutProc("OnClientEvent", "table[LMName:string,EventName:string,Data:any]", "bool") obj:AddOutProc("OnStartClientLM", "table[Name:string]", "bool") obj:AddOutProc("OnStopClientLM", "string", "bool") return obj end
main / client_lm / start.lua
lm3:LoadLibrary( {Alias = "sys", FileName = "lm3system"} ) lm3:Include("client_lib.lua") -- объект Timer для alive сообщение lm3:CreateObject( { Type = "Timer", Name = "timer" } ) timer:SetAttr("Interval", 30*1000) -- объект Settings -- позволяет менять конфигурацию ЛМ init_Settings("Settings") -- объект Info -- возвращает информацию о курсах init_Info("Info") lm3:CreateLObject( { LibAlias = "sys", Type = "FileSystem", Name = "files" } ) lm3:CreateObject( { Type = "LuaData", Name = "lualoader" } ) lm3:AddHandler("OnStart", function(o, ev) Info:DoInitCourceList() timer:DoEnable(true) end) -- обработчик ивента с основной логической машины -- распределяет запросы по клиентам lm3:AddHandler("OnExtEvent", function(o, ev) local work_obj = lm3:GetObject(ev.Object) if work_obj ~= nil then if ev.Command == "Event" then lm3:Log("Fire client event:"..ev.Name.."("..lm3:DataToString(ev.Data)..")") work_obj:FireEvent(ev.Name, ev.Data) end else lm3:Log("ERROR: Incoming command to unknown object:"..lm3:DataToString(ev)) end end) -- обработчик ответа от объекта Info:AddHandler("OnCourceList", function(o, ev) lm3:DoExtEvent({ { Object = "Info", Command = "Value", Name = "CourceList", Data = ev } }) end) timer:AddHandler("OnTick", function(o, ev) --lm3:Log("OnTick: send Alive") local data = {} data[1] = { Object = "Settings", Command = "Event", Name = "Alive" } lm3:DoExtEvent(data) end)
[client]
2020-11-26 18:34:50.542 23236-23236/com.example.lm3_client D/lm3: application: onCreate 2020-11-26 18:34:50.559 23236-23236/com.example.lm3_client D/lm3: application: setNetworkStatus: 2 -- подключение к серверу 2020-11-26 18:34:50.559 23236-23236/com.example.lm3_client D/lm3: connect: startServerConnection 2020-11-26 18:34:50.560 23236-23285/com.example.lm3_client D/lm3: connect: start 2020-11-26 18:34:50.561 23236-23284/com.example.lm3_client D/lm3: application: setNetworkStatus: 2 2020-11-26 18:34:50.578 23236-23285/com.example.lm3_client D/lm3: connect: setServerConnection: true 2020-11-26 18:34:50.579 23236-23285/com.example.lm3_client D/lm3: connect: done 2020-11-26 18:34:50.579 23236-23285/com.example.lm3_client D/lm3: connect: end 2020-11-26 18:34:50.579 23236-23287/com.example.lm3_client D/lm3: connect: start listen -- авторизация 2020-11-26 18:34:50.579 23236-23287/com.example.lm3_client D/lm3: auth: auth 2020-11-26 18:34:50.579 23236-23287/com.example.lm3_client D/lm3: auth: SetName: testtest 2020-11-26 18:34:50.579 23236-23287/com.example.lm3_client D/lm3: listen: serverSend 2020-11-26 18:34:50.580 23236-23287/com.example.lm3_client D/lm3: auth: SetMail: test@test.test 2020-11-26 18:34:50.580 23236-23287/com.example.lm3_client D/lm3: listen: serverSend -- установка локализации 2020-11-26 18:34:50.581 23236-23287/com.example.lm3_client D/lm3: settings: SetLanguage: EN 2020-11-26 18:34:50.581 23236-23287/com.example.lm3_client D/lm3: listen: serverSend 2020-11-26 18:34:50.589 23236-23236/com.example.lm3_client D/lm3: activity: main: OnCreate 2020-11-26 18:34:50.643 23236-23287/com.example.lm3_client D/lm3: auth: setTaskObject 2020-11-26 18:34:50.643 23236-23287/com.example.lm3_client D/lm3: info: GetCourseList 2020-11-26 18:34:50.643 23236-23287/com.example.lm3_client D/lm3: listen: serverSend 2020-11-26 18:34:50.697 23236-23236/com.example.lm3_client D/lm3: activity: main: onResume -- запрос списка курсов 2020-11-26 18:34:50.886 23236-23287/com.example.lm3_client D/lm3: info: setCourseList: 2020-11-26 18:34:50.887 23236-23287/com.example.lm3_client D/lm3: info: Introduction to Somnology 2020-11-26 18:34:50.887 23236-23287/com.example.lm3_client D/lm3: info: Snoring problems 2020-11-26 18:35:07.609 23236-23236/com.example.lm3_client D/lm3: activity: main: onPause 2020-11-26 18:35:07.624 23236-23236/com.example.lm3_client D/lm3: activity: settings: OnCreate 2020-11-26 18:35:07.674 23236-23236/com.example.lm3_client D/lm3: activity: settings: OnCreate: current locale: en 2020-11-26 18:35:07.674 23236-23236/com.example.lm3_client D/lm3: activity: settings: OnCreate: locale in memory: EN 2020-11-26 18:35:07.682 23236-23236/com.example.lm3_client D/lm3: activity: settings: onResume -- установка локализации 2020-11-26 18:35:09.775 23236-23236/com.example.lm3_client D/lm3: activity: settings: changeLocale: start: RU 2020-11-26 18:35:09.775 23236-23236/com.example.lm3_client D/lm3: activity: settings: changeLocale: change from: EN 2020-11-26 18:35:09.776 23236-23236/com.example.lm3_client D/lm3: settings: SetLanguage: RU 2020-11-26 18:35:09.777 23236-23236/com.example.lm3_client D/lm3: listen: serverSend -- запрос списка курсов 2020-11-26 18:35:09.779 23236-23236/com.example.lm3_client D/lm3: info: GetCourseList 2020-11-26 18:35:09.779 23236-23236/com.example.lm3_client D/lm3: listen: serverSend 2020-11-26 18:35:09.786 23236-23236/com.example.lm3_client D/lm3: activity: settings: changeLocale: check: ru 2020-11-26 18:35:09.822 23236-23236/com.example.lm3_client D/lm3: activity: settings: OnCreate 2020-11-26 18:35:09.828 23236-23287/com.example.lm3_client D/lm3: info: setCourseList: 2020-11-26 18:35:09.828 23236-23287/com.example.lm3_client D/lm3: info: Введение в сомнологию 2020-11-26 18:35:09.828 23236-23287/com.example.lm3_client D/lm3: info: Проблемы храпа 2020-11-26 18:35:09.872 23236-23236/com.example.lm3_client D/lm3: activity: settings: OnCreate: current locale: ru 2020-11-26 18:35:09.872 23236-23236/com.example.lm3_client D/lm3: activity: settings: OnCreate: locale in memory: RU 2020-11-26 18:35:09.877 23236-23236/com.example.lm3_client D/lm3: activity: settings: onResume
[server] LM_main.log
[2020-11-27 11:39:50][INFO:LMInit][Start logic machine v3.3(Build:555) ----------------------------------] [2020-11-27 11:39:50][LUA:LMCore][Starting server] [2020-11-27 11:39:50][TRACE:LMInit][Create library object: server] [2020-11-27 11:39:50][TRACE:LMInit][Create library object: packer] [2020-11-27 11:39:50][TRACE:LMInit][Create object: clients] [2020-11-27 11:39:50][TRACE:LMInit][Create object: Auth] [2020-11-27 11:39:50][INFO:LMInit][Initialization complete.] [2020-11-27 11:39:51][LUA:LMCore][New client connected:1] [2020-11-27 11:39:51][LUA:LMCore][Start client LM...] [2020-11-27 11:39:51][LUA:LMCore][Start client LM complete.] -- авторизация клиента [2020-11-27 11:39:51][LUA:LMCore][Incoming data from client with tag: 1 : [Array:1] 1 = [Table:4] "Command" = [String] "Set" "Data" = [String] "testtest" "Name" = [String] "UserName" "Object" = [String] "Auth"] [2020-11-27 11:39:51][LUA:LMCore][Incoming data from client with tag: 1 : [Array:1] 1 = [Table:4] "Command" = [String] "Set" "Data" = [String] "test@test.test" "Name" = [String] "UserMail" "Object" = [String] "Auth"] [2020-11-27 11:39:51][LUA:LMCore][Auth: OnReply: tag: 1 : [Array:1] 1 = [Table:4] "Command" = [String] "Value" "Data" = [String] "Task" "Name" = [String] "TaskObject" "Object" = [String] "Auth"] [2020-11-27 11:39:51][LUA:LMCore][Incoming data from client with tag: 1 : [Array:1] 1 = [Table:4] "Command" = [String] "Event" "Data" = [String] "RU" "Name" = [String] "DoChangeLang" "Object" = [String] "Settings"] -- запрос списка курсов [2020-11-27 11:39:51][LUA:LMCore][Incoming data from client with tag: 1 : [Array:1] 1 = [Table:3] "Command" = [String] "Event" "Name" = [String] "CourceList" "Object" = [String] "Info"] [2020-11-27 11:39:51][LUA:LMCore][Auth: OnReply: tag: 1 : [Array:1] 1 = [Table:4] "Command" = [String] "Value" "Data" = [Array:2] 1 = [Table:3] "CourceID" = [String] "c1" "Description" = [String] "Хотите быстро засыпать, высыпаться и чувствовать себя отлично в течение дня? Узнайте все о том, как наладить правильный сон." "Name" = [String] "Введение в сомнологию" 2 = [Table:3] "CourceID" = [String] "c2" "Description" = [String] "N/A" "Name" = [String] "Проблемы храпа" "Name" = [String] "CourceList" "Object" = [String] "Info"] -- смена локализации [2020-11-27 11:40:15][LUA:LMCore][Incoming data from client with tag: 1 : [Array:1] 1 = [Table:4] "Command" = [String] "Event" "Data" = [String] "EN" "Name" = [String] "DoChangeLang" "Object" = [String] "Settings"] -- запрос списка курсов [2020-11-27 11:40:15][LUA:LMCore][Incoming data from client with tag: 1 : [Array:1] 1 = [Table:3] "Command" = [String] "Event" "Name" = [String] "CourceList" "Object" = [String] "Info"] [2020-11-27 11:40:15][LUA:LMCore][Auth: OnReply: tag: 1 : [Array:1] 1 = [Table:4] "Command" = [String] "Value" "Data" = [Array:2] 1 = [Table:3] "CourceID" = [String] "c1" "Description" = [String] "Want to fall asleep fast, get enough sleep and feel great throughout the day? Learn all about how to get good sleep." "Name" = [String] "Introduction to Somnology" 2 = [Table:3] "CourceID" = [String] "c2" "Description" = [String] "N/A" "Name" = [String] "Snoring problems" "Name" = [String] "CourceList" "Object" = [String] "Info"]
[client] LM_clm_1.log
[2020-11-27 11:39:51][INFO:LMInit][Start logic machine v3.3(Build:555) ----------------------------------] [2020-11-27 11:39:51][TRACE:LMInit][Create object: timer] [2020-11-27 11:39:51][TRACE:LMInit][Create object: Settings] [2020-11-27 11:39:51][TRACE:LMInit][Create object: Info] [2020-11-27 11:39:51][TRACE:LMInit][Create library object: files] [2020-11-27 11:39:51][TRACE:LMInit][Create object: lualoader] [2020-11-27 11:39:51][INFO:LMInit][Initialization complete.] -- авторизация клиента [2020-11-27 11:39:51][LUA:LMCore][Fire client event:DoChangeLang([String] "RU")] -- запрос списка курсов [2020-11-27 11:39:51][LUA:LMCore][Fire client event:CourceList([Nil])] -- смена локализации клиентом [2020-11-27 11:40:15][LUA:LMCore][Fire client event:DoChangeLang([String] "EN")] [2020-11-27 11:40:15][LUA:LMCore][Settings Event: DoChangeLang: Change to: EN] -- запрос списка курсов [2020-11-27 11:40:15][LUA:LMCore][Fire client event:CourceList([Nil])]