feat: Add lang module

This commit is contained in:
Qwreey 2023-02-17 09:25:39 +09:00
parent a857b9be51
commit 7361c012db
8 changed files with 323 additions and 19 deletions

View file

@ -25,6 +25,8 @@ function module.init(shared)
local parseStyles = style.ParseStyles local parseStyles = style.ParseStyles
local advancedTween = shared.Tween ---@type quad_module_tween local advancedTween = shared.Tween ---@type quad_module_tween
local round = shared.Round ---@type quad_module_round local round = shared.Round ---@type quad_module_round
local signal = shared.Signal ---@type quad_module_signal
local bindable = signal.Bindable
local function InstanceNewWithName(classname,parent,name) local function InstanceNewWithName(classname,parent,name)
local item = InstanceNew(classname,parent) local item = InstanceNew(classname,parent)
@ -114,6 +116,7 @@ function module.init(shared)
if ok then return err end if ok then return err end
return nil return nil
end end
new.PcallGetProperty = PcallGetProperty
local function ProcessQuadProperty(processedProperty,iprop,holder,item,className,index,value) local function ProcessQuadProperty(processedProperty,iprop,holder,item,className,index,value)
if processedProperty[index] then if processedProperty[index] then
@ -341,15 +344,21 @@ function module.init(shared)
end end
function this:GetPropertyChangedSignal(propertyName) function this:GetPropertyChangedSignal(propertyName)
local signal = self.__propertyChangedSignals[propertyName] local thisSignal = self.__propertyChangedSignals[propertyName]
if not signal then if thisSignal then
signal = {} return thisSignal
self.__propertyChangedSignals[propertyName] = signal
end end
thisSignal = bindable.New()
self.__propertyChangedSignals[propertyName] = thisSignal
return thisSignal
end end
function this:EmitPropertyChangedSignal(propertyName,value) function this:EmitPropertyChangedSignal(propertyName,value)
local thisSignal = self.__propertyChangedSignals[propertyName]
if not thisSignal then
return
end
thisSignal:Fire(value)
end end
--- re-render object (if some props chaged, call this to render again) --- re-render object (if some props chaged, call this to render again)
@ -453,9 +462,18 @@ function module.init(shared)
if this.UpdateTriggers[k] then if this.UpdateTriggers[k] then
self:Update() self:Update()
end end
-- call PropertyChangedSignal
if self.__propertyChangedSignals[k] and self[k] ~= v then
self:EmitPropertyChangedSignal(k,v)
end
end end
this.Getter = {} this.Getter = {
Parent = function(self)
return rawget(self,"__parent")
end
}
this.Setter = { this.Setter = {
Parent = function(self,parent,object) Parent = function(self,parent,object)
rawset(self,"__parent",parent) rawset(self,"__parent",parent)

View file

@ -1,8 +1,12 @@
---@class quad ---@class quad
local module = {} local module = {}
if not Instance then
print("Instance is not exist, Using custom Instance and print result as string . . .")
end
local IS_TEST = true local IS_TEST = true
local VER = "1.14" .. (IS_TEST and "B" or "") local VER = "2.14" .. (IS_TEST and "B" or "")
if IS_TEST then if IS_TEST then
warn("You are using BETA version of quad now. Many features may change in the future and unstable. AS USING BETA VERSION OF QUAD, YOU SHOULD KNOW IT WILL BUGGY SOMETIME. still on development - you can ignore this message if have no issue. if you have issue on using quad, please report issue on github. VERSION: "..VER) warn("You are using BETA version of quad now. Many features may change in the future and unstable. AS USING BETA VERSION OF QUAD, YOU SHOULD KNOW IT WILL BUGGY SOMETIME. still on development - you can ignore this message if have no issue. if you have issue on using quad, please report issue on github. VERSION: "..VER)
end end

View file

@ -1,11 +1,174 @@
local module = {} local module = {}
function module.init(shared) local insert = table.insert
---@class quad_module_lang local gsub = string.gsub
local new = {}
return new function module.init(shared)
---@class quad_module_lang
local new = {}
local warn = shared.warn
local store = shared.Store
local class = shared.Class
local PcallGetProperty = class.PcallGetProperty
new.Locales = {
["English"] = "en_us";
["Spanish"] = "es_es";
["French"] = "fr_fr";
["Indonesian"] = "id_id";
["Italian"] = "it_it";
["Japanese"] = "ja_jp";
["Korean"] = "ko_kr";
["Russian"] = "ru_ru";
["Thai"] = "th_th";
["Turkish"] = "tr_tr";
["Vietnamese"] = "vi_vn";
["Portuguese"] = "pt_br";
["German"] = "de_de";
["ChineseSimplified"] = "zh_cn";
["ChineseTraditional"] = "zh_tw";
["Bulgarian"] = "bg_bg";
["Bengali"] = "bn_bd";
["Czech"] = "cs_cz";
["Danish"] = "da_dk";
["Greek"] = "el_gr";
["Estonian"] = "et_ee";
["Finnish"] = "fi_fi";
["Hindi"] = "hi_in";
["Croatian"] = "hr_hr";
["Hungarian"] = "hu_hu";
["Georgian"] = "ka_ge";
["Kazakh"] = "kk_kz";
["Khmer"] = "km_kh";
["Lithuanian"] = "lt_lt";
["Latvian"] = "lv_lv";
["Malay"] = "ms_my";
["Burmese"] = "my_mm";
["Bokmal"] = "nb_no";
["Dutch"] = "nl_nl";
["Filipino"] = "fil_ph";
["Polish"] = "pl_pl";
["Romanian"] = "ro_ro";
["Ukrainian"] = "uk_ua";
["Sinhala"] = "si_lk";
["Slovak"] = "sk_sk";
["Slovenian"] = "sl_sl";
["Albanian"] = "sq_al";
["Bosnian"] = "bs_ba";
["Serbian"] = "sr_rs";
["Swedish"] = "sv_se";
["Arabic"] = "ar_001";
}
new.Lang = game:GetService("LocalizationService").RobloxLocaleId
new.Default = new.Locales.English
local lang = {}
lang.__index = lang
function lang.New(id,handlers)
local this = {handlers=handlers,id=id,store=store.New(),index=1}
lang[id] = this
setmetatable(this,lang)
end
-- read options, and make string and save into store for updating
function lang.Update(valueStore,handler,index,options)
if not index then
error(("Index must be a number, but got %s"):format(type(index)))
end
index = tostring(index)
-- parsing options
local parsedOptions = {}
for optionName,option in pairs(options) do
local quadType = PcallGetProperty(option,"__type")
local optionType = type(option)
local formatted
if quadType == "quad_register" then
local default = option.dvalue
local with = option.wfunc
local tstore = option.store
local rawKey = option.key
local value = tstore[rawKey]
if value == nil then
value = default
elseif with then
value = with(tstore,value,rawKey)
end
formatted = value
elseif optionType == "number" then
if option%1 == 0 then
-- int
formatted = ("%d"):format(option)
else
-- float
formatted = tostring(option)
end
else
formatted = tostring(option)
end
parsedOptions[optionName] = formatted
end
-- set store value
local handlerType = type(handler)
if handlerType == "function" then
valueStore[index] = handler(parsedOptions)
elseif handlerType == "string" then
valueStore[index] = gsub(handler,"{(.-)}",parsedOptions)
end
end
local Update = lang.Update
function lang:Format(options)
-- find handler
local handler = self.handlers[new.Lang]
if not handler then
handler = self.handlers[new.Default]
end
if not handler then
warn(("Langauge handle %s is not found on Localization %s"):format(new.Default,self.id))
end
local index = self.index
self.index = index + 1
-- setup updater
for _,option in pairs(options) do
local quadType = PcallGetProperty(option,"__type")
-- if it is register, setup updater
if quadType == "quad_register" then
local function regFn()
-- !HOLD IT SELF TO PREVENT THIS REGISTER BEGIN REMOVED FROM MEMORY
Update(self.store,handler,index,options)
end
option:Register(regFn)
insert(self.store.__keep,regFn)
end
end
-- update once
Update(self.store,handler,index,options)
-- return resiter
return self.store(tostring(index))
end
function new.New(id,handlers)
return lang.New(id,handlers)
end
setmetatable(new,{
__call = function(_,id)
return function (options)
local data = lang[id]
if not data then
error(("Localization %s is not definded"):format(id))
end
return data:Format(options)
end
end;
})
return new
end end
return module return module

View file

@ -142,7 +142,7 @@ function module.init(shared)
local self = {waitting={},onceConnection={},connection={}} local self = {waitting={},onceConnection={},connection={}}
setmetatable(self,signal) setmetatable(self,signal)
end end
new.Signal = signal new.Bindable = signal
return new return new
end end

View file

@ -187,7 +187,113 @@ export type module_round = {
------------------- -------------------
-- module_signal -- module_signal
------------------- -------------------
export type module_lang = {} export type langOptions = {
[string]: register|string|number|any;
}
export type langHandler = {
[string]: string|(langOptions:langOptions)->string;
}
export type Locale = string
export type module_lang = {
New: (id:string,handlers:{
en_us: langHandler;
es_es: langHandler;
fr_fr: langHandler;
id_id: langHandler;
it_it: langHandler;
ja_jp: langHandler;
ko_kr: langHandler;
ru_ru: langHandler;
th_th: langHandler;
tr_tr: langHandler;
vi_vn: langHandler;
pt_br: langHandler;
de_de: langHandler;
zh_cn: langHandler;
zh_tw: langHandler;
bg_bg: langHandler;
bn_bd: langHandler;
cs_cz: langHandler;
da_dk: langHandler;
el_gr: langHandler;
et_ee: langHandler;
fi_fi: langHandler;
hi_in: langHandler;
hr_hr: langHandler;
hu_hu: langHandler;
ka_ge: langHandler;
kk_kz: langHandler;
km_kh: langHandler;
lt_lt: langHandler;
lv_lv: langHandler;
ms_my: langHandler;
my_mm: langHandler;
nb_no: langHandler;
nl_nl: langHandler;
fil_ph: langHandler;
pl_pl: langHandler;
ro_ro: langHandler;
uk_ua: langHandler;
si_lk: langHandler;
sk_sk: langHandler;
sl_sl: langHandler;
sq_al: langHandler;
bs_ba: langHandler;
sr_rs: langHandler;
sv_se: langHandler;
ar_001: langHandler;
})->();
Locales: {
English: Locale & "en_us";
Spanish: Locale & "es_es";
French: Locale & "fr_fr";
Indonesian: Locale & "id_id";
Italian: Locale & "it_it";
Japanese: Locale & "ja_jp";
Korean: Locale & "ko_kr";
Russian: Locale & "ru_ru";
Thai: Locale & "th_th";
Turkish: Locale & "tr_tr";
Vietnamese: Locale & "vi_vn";
Portuguese: Locale & "pt_br";
German: Locale & "de_de";
ChineseSimplified: Locale & "zh_cn";
ChineseTraditional: Locale & "zh_tw";
Bulgarian: Locale & "bg_bg";
Bengali: Locale & "bn_bd";
Czech: Locale & "cs_cz";
Danish: Locale & "da_dk";
Greek: Locale & "el_gr";
Estonian: Locale & "et_ee";
Finnish: Locale & "fi_fi";
Hindi: Locale & "hi_in";
Croatian: Locale & "hr_hr";
Hungarian: Locale & "hu_hu";
Georgian: Locale & "ka_ge";
Kazakh: Locale & "kk_kz";
Khmer: Locale & "km_kh";
Lithuanian: Locale & "lt_lt";
Latvian: Locale & "lv_lv";
Malay: Locale & "ms_my";
Burmese: Locale & "my_mm";
Bokmal: Locale & "nb_no";
Dutch: Locale & "nl_nl";
Filipino: Locale & "fil_ph";
Polish: Locale & "pl_pl";
Romanian: Locale & "ro_ro";
Ukrainian: Locale & "uk_ua";
Sinhala: Locale & "si_lk";
Slovak: Locale & "sk_sk";
Slovenian: Locale & "sl_sl";
Albanian: Locale & "sq_al";
Bosnian: Locale & "bs_ba";
Serbian: Locale & "sr_rs";
Swedish: Locale & "sv_se";
Arabic: Locale & "ar_001";
};
Lang: Locale;
Default: Locale;
} & (id:string)->(langOptions)->register;
------------------- -------------------
-- module -- module

View file

@ -44,8 +44,8 @@ end
function module.init() function module.init()
---@module Quad.src.types ---@module Quad.src.types
local types = require(script.Parent.Quad.types) local types = require(script.Quad.types)
local quad = (require(script.Parent.Quad) :: types.module).Init("ui") local quad = (require(script.Quad) :: types.module).Init("ui")
local Round,Class,Mount,Store,Event,Tween,Style,Signal local Round,Class,Mount,Store,Event,Tween,Style,Signal
= quad.Round,quad.Class,quad.Mount,quad.Store,quad.Event,quad.Tween,quad.Style,quad.Signal = quad.Round,quad.Class,quad.Mount,quad.Store,quad.Event,quad.Tween,quad.Style,quad.Signal

View file

@ -41,7 +41,7 @@ return {
track = function () track = function ()
reload() reload()
wait()
if not _G.uichangetracker then if not _G.uichangetracker then
local tracker = require(script.tracker) local tracker = require(script.tracker)
local changeTracker = tracker.new(script.Parent) local changeTracker = tracker.new(script.Parent)

View file

@ -4,8 +4,8 @@ local module = {}
---@module Quad.src.types ---@module Quad.src.types
local types = require(script.Parent.Quad.types) local types = require(script.Parent.Quad.types)
local quad = (require(script.Parent.Quad) :: types.module).Init("ui") local quad = (require(script.Parent.Quad) :: types.module).Init("ui")
local Round,Class,Mount,Store,Event,Tween,Style local Round,Class,Mount,Store,Event,Tween,Style,Lang
= quad.Round,quad.Class,quad.Mount,quad.Store,quad.Event,quad.Tween,quad.Style = quad.Round,quad.Class,quad.Mount,quad.Store,quad.Event,quad.Tween,quad.Style,quad.Lang
local Global = Store.GetStore "global" local Global = Store.GetStore "global"
@ -26,15 +26,22 @@ Style "tweenTestFrame" {
BackgroundColor3 = Color3.fromRGB(0, 0, 0); BackgroundColor3 = Color3.fromRGB(0, 0, 0);
} }
Lang.New("tweenCount",{
[Lang.Locales.Korean] = "{count}번 실행했어요";
[Lang.Locales.English] = "Ran {count} times";
})
-- Create GUI -- Create GUI
local tweenTest = Class.Extend() local tweenTest = Class.Extend()
function tweenTest:Init(Prop) function tweenTest:Init(Prop)
Prop:Default("Count",0)
Prop:Default("Position",UDim2.fromOffset(50,0)) Prop:Default("Position",UDim2.fromOffset(50,0))
local on = false local on = false
task.spawn(function() task.spawn(function()
while task.wait(2) do while task.wait(2) do
on = not on on = not on
Prop.Count = Prop.Count + 1
Prop.Position = on and UDim2.new(1,-50-60,0,0) or UDim2.fromOffset(50,0) Prop.Position = on and UDim2.new(1,-50-60,0,0) or UDim2.fromOffset(50,0)
end end
end) end)
@ -42,6 +49,12 @@ end
function tweenTest:Render(Prop) function tweenTest:Render(Prop)
return Frame { return Frame {
TextLabel {
Size = UDim2.new(1,0,0,30);
Text = Lang "tweenCount" {
count = Prop "Count":With(function(_,value) return value*2 end);
};
};
Size = UDim2.fromScale(1,1); Size = UDim2.fromScale(1,1);
TextLabel "tweenTestFrame" { TextLabel "tweenTestFrame" {
Text = "Linear"; Text = "Linear";