diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/cbi/luasrc/view/cbi/header.htm | 2 | ||||
-rw-r--r-- | libs/core/luasrc/init.lua | 2 | ||||
-rw-r--r-- | libs/core/luasrc/util.lua | 79 | ||||
-rw-r--r-- | libs/fastindex/Makefile | 4 | ||||
-rw-r--r-- | libs/sgi-haserl/luasrc/sgi/haserl.lua | 107 | ||||
-rwxr-xr-x | libs/sgi-haserl/root/www/cgi-bin/luci | 4 | ||||
-rw-r--r-- | libs/sgi-webuci/luasrc/sgi/webuci.lua | 113 | ||||
-rw-r--r-- | libs/sgi-webuci/root/usr/lib/boa/luci.lua | 3 | ||||
-rw-r--r-- | libs/uci/luasrc/model/uci.lua | 2 | ||||
-rw-r--r-- | libs/web/luasrc/dispatcher.lua | 116 | ||||
-rw-r--r-- | libs/web/luasrc/http.lua | 136 | ||||
-rw-r--r-- | libs/web/luasrc/i18n.lua | 29 | ||||
-rw-r--r-- | libs/web/luasrc/template.lua | 14 |
13 files changed, 369 insertions, 242 deletions
diff --git a/libs/cbi/luasrc/view/cbi/header.htm b/libs/cbi/luasrc/view/cbi/header.htm index 0af52b49e..ca6ef2fdd 100644 --- a/libs/cbi/luasrc/view/cbi/header.htm +++ b/libs/cbi/luasrc/view/cbi/header.htm @@ -1,5 +1,5 @@ <%+header%> - <form method="post" action="<%=luci.http.env.REQUEST_URI%>"> + <form method="post" action="<%=luci.http.getenv("REQUEST_URI")%>"> <div> <script type="text/javascript" src="<%=resource%>/cbi.js"></script> <input type="hidden" name="cbi.submit" value="1" /> diff --git a/libs/core/luasrc/init.lua b/libs/core/luasrc/init.lua index b390df3ac..b4ecb93c1 100644 --- a/libs/core/luasrc/init.lua +++ b/libs/core/luasrc/init.lua @@ -25,5 +25,5 @@ limitations under the License. ]]-- module("luci", package.seeall) -__version__ = "0.6" +__version__ = "0.7" __appname__ = "LuCI" diff --git a/libs/core/luasrc/util.lua b/libs/core/luasrc/util.lua index ad53138e6..fda4563ad 100644 --- a/libs/core/luasrc/util.lua +++ b/libs/core/luasrc/util.lua @@ -36,7 +36,7 @@ function class(base) setmetatable(inst, {__index = class}) if inst.__init__ then - local stat, err = pcall(inst.__init__, inst, ...) + local stat, err = copcall(inst.__init__, inst, ...) if not stat then error(err) end @@ -152,6 +152,12 @@ function pcdata(value) end +-- Returns an error message to stdout +function perror(obj) + io.stderr:write(tostring(obj) .. "\n") +end + + -- Resets the scope of f doing a shallow copy of its scope into a new table function resfenv(f) setfenv(f, clone(getfenv(f))) @@ -255,6 +261,34 @@ function strip_bytecode(dump) end +-- Creates a new threadlocal store +function threadlocal() + local tbl = {} + + local function get(self, key) + local c = coroutine.running() + local thread = coxpt[c] or c or 0 + if not rawget(self, thread) then + rawset(self, thread, {}) + end + return rawget(self, thread)[key] + end + + local function set(self, key, value) + local c = coroutine.running() + local thread = coxpt[c] or c or 0 + if not rawget(self, thread) then + rawset(self, thread, {}) + end + rawget(self, thread)[key] = value + end + + setmetatable(tbl, {__index = get, __newindex = set}) + + return tbl +end + + -- Removes whitespace from beginning and end of a string function trim(str) local s = str:gsub("^%s*(.-)%s*$", "%1") @@ -355,3 +389,46 @@ end function vspairs(t) return _sortiter( t, function (a,b) return t[a] < t[b] end ) end + + +-- Coroutine safe xpcall and pcall versions modified for Luci +-- original version: +-- coxpcall 1.13 - Copyright 2005 - Kepler Project (www.keplerproject.org) +local performResume, handleReturnValue +local oldpcall, oldxpcall = pcall, xpcall +coxpt = {} + +function handleReturnValue(err, co, status, ...) + if not status then + return false, err(debug.traceback(co, (...)), ...) + end + if coroutine.status(co) == 'suspended' then + return performResume(err, co, coroutine.yield(...)) + else + return true, ... + end +end + +function performResume(err, co, ...) + return handleReturnValue(err, co, coroutine.resume(co, ...)) +end + +function coxpcall(f, err, ...) + local res, co = oldpcall(coroutine.create, f) + if not res then + local params = {...} + local newf = function() return f(unpack(params)) end + co = coroutine.create(newf) + end + local c = coroutine.running() + coxpt[co] = coxpt[c] or c or 0 + return performResume(err, co, ...) +end + +local function id(trace, ...) + return ... +end + +function copcall(f, ...) + return coxpcall(f, id, ...) +end diff --git a/libs/fastindex/Makefile b/libs/fastindex/Makefile index 566b38d0b..ee1a40ea8 100644 --- a/libs/fastindex/Makefile +++ b/libs/fastindex/Makefile @@ -6,8 +6,8 @@ include ../../build/gccconfig.mk $(COMPILE) $(LUA_CFLAGS) $(FPIC) -c -o $@ $< compile: src/fastindex.o - mkdir -p dist$(LUCI_INSTALLDIR) - $(LINK) $(SHLIB_FLAGS) -o dist$(LUCI_INSTALLDIR)/fastindex.so src/fastindex.o $(LUA_SHLIBS) + mkdir -p dist$(LUCI_LIBRARYDIR) + $(LINK) $(SHLIB_FLAGS) -o dist$(LUCI_LIBRARYDIR)/fastindex.so src/fastindex.o $(LUA_SHLIBS) clean: rm -f src/*.o diff --git a/libs/sgi-haserl/luasrc/sgi/haserl.lua b/libs/sgi-haserl/luasrc/sgi/haserl.lua index 35bc1c902..315b4da73 100644 --- a/libs/sgi-haserl/luasrc/sgi/haserl.lua +++ b/libs/sgi-haserl/luasrc/sgi/haserl.lua @@ -24,80 +24,49 @@ limitations under the License. ]]-- module("luci.sgi.haserl", package.seeall) -require("luci.fs") - --- Environment Table -luci.http.env = ENV - --- Enforces user authentification -function luci.http.basic_auth(verify_callback, realm) - -- Dummy for Haserl - return true -end - --- Returns the main dispatcher URL -function luci.http.dispatcher() - return luci.http.env.SCRIPT_NAME or "" -end - --- Returns the upload dispatcher URL -function luci.http.dispatcher_upload() - return luci.http.dispatcher() .. "-upload" -end - --- Returns a table of all COOKIE, GET and POST Parameters -function luci.http.formvalues() - return FORM -end - --- Gets form value from key -function luci.http.formvalue(key, default) - local c = luci.http.formvalues() +require("luci.http") +require("luci.util") +require("luci.dispatcher") + +function run() + local r = luci.http.Request() + r.env = ENV + r.request = normalize_table(FORM) - for match in key:gmatch("[%w-_]+") do - c = c[match] - if c == nil then - return default + local x = coroutine.create(luci.dispatcher.httpdispatch) + while coroutine.status(x) ~= "dead" do + local res, id, data1, data2 = coroutine.resume(x, r) + + if not res then + print("Status: 500 Internal Server Error") + print("Content-Type: text/plain\n") + print(id) + break; + end + + if id == 1 then + io.write("Status: " .. tostring(data1) .. " " .. data2 .. "\n") + elseif id == 2 then + io.write(data1 .. ": " .. data2 .. "\n") + elseif id == 3 then + io.write("\n") + elseif id == 4 then + io.write(data1) end end - - return c end --- Gets a table of values with a certain prefix -function luci.http.formvaluetable(prefix) - return luci.http.formvalue(prefix, {}) -end - --- Sends a custom HTTP-Header -function luci.http.header(key, value) - print(key .. ": " .. value) -end - --- Set Content-Type -function luci.http.prepare_content(type) - print("Content-Type: "..type.."\n") -end - --- Asks the browser to redirect to "url" -function luci.http.redirect(url) - luci.http.status(302, "Found") - luci.http.header("Location", url) - print() -end - --- Returns the path of an uploaded file --- WARNING! File uploads can be easily spoofed! Do additional sanity checks! -function luci.http.upload(name) - local fpath = luci.http.formvalue(name) - local fname = luci.http.formvalue(name .. "_name") +function normalize_table(table, prefix) + prefix = prefix and prefix .. "." or "" + local new = {} - if fpath and fname and luci.fs.isfile(fpath) then - return fpath + for k,v in pairs(table) do + if type(v) == "table" and #v == 0 then + luci.util.update(new, normalize_table(v, prefix .. k)) + else + new[prefix .. k] = v + end end -end - --- Sets HTTP-Status-Header -function luci.http.status(code, message) - print("Status: " .. tostring(code) .. " " .. message) + + return new end diff --git a/libs/sgi-haserl/root/www/cgi-bin/luci b/libs/sgi-haserl/root/www/cgi-bin/luci index ab2a3e18f..fd8e5941a 100755 --- a/libs/sgi-haserl/root/www/cgi-bin/luci +++ b/libs/sgi-haserl/root/www/cgi-bin/luci @@ -1,4 +1,4 @@ #!/usr/bin/haserl --shell=luac -require("luci.dispatcher") +require("luci.sgi.haserl") luci.dispatcher.indexcache = "/tmp/.luciindex" -luci.dispatcher.httpdispatch()
\ No newline at end of file +luci.sgi.haserl.run()
\ No newline at end of file diff --git a/libs/sgi-webuci/luasrc/sgi/webuci.lua b/libs/sgi-webuci/luasrc/sgi/webuci.lua index a40888e7e..abe279d05 100644 --- a/libs/sgi-webuci/luasrc/sgi/webuci.lua +++ b/libs/sgi-webuci/luasrc/sgi/webuci.lua @@ -24,93 +24,36 @@ limitations under the License. ]]-- module("luci.sgi.webuci", package.seeall) - -local status_set = false - --- Initialize the environment -function initenv(env, vars) - luci.http.env = env - luci.http.vars = vars -end - --- Enforces user authentification -function luci.http.basic_auth(verify_callback, realm) - local user = luci.http.env.auth_user - local pass = luci.http.env.auth_password - realm = realm or "" +require("luci.http") +require("luci.util") +require("luci.dispatcher") + +function run(env, vars) + local r = luci.http.Request() + r.env = env + r.request = vars - if not user or not verify_callback(user, pass) then - luci.http.status("401", "Unauthorized") - luci.http.header("WWW-Authenticate", string.format('Basic realm="%s"', realm)) - return false - else - return true - end -end - --- Returns the main dispatcher URL -function luci.http.dispatcher() - return luci.http.env.SCRIPT_NAME or "" -end - --- Returns the upload dispatcher URL -function luci.http.dispatcher_upload() - -- To be implemented -end - --- Returns a table of all COOKIE, GET and POST Parameters -function luci.http.formvalues() - return luci.http.vars -end - --- Gets form value from key -function luci.http.formvalue(key, default) - return luci.http.formvalues()[key] or default -end - --- Gets a table of values with a certain prefix -function luci.http.formvaluetable(prefix) - local vals = {} - prefix = prefix and prefix .. "." or "." + local x = coroutine.create(luci.dispatcher.httpdispatch) - for k, v in pairs(luci.http.formvalues()) do - if k:find(prefix, 1, true) == 1 then - vals[k:sub(#prefix + 1)] = v + while coroutine.status(x) ~= "dead" do + local res, id, data1, data2 = coroutine.resume(x, r) + + if not res then + print(env.SERVER_PROTOCOL .. " 500 Internal Server Error") + print("Content-Type: text/plain\n") + print(id) + break; end + + if id == 1 then + io.write(env.SERVER_PROTOCOL .. " " .. tostring(data1) .. " " .. data2 .. "\n") + elseif id == 2 then + io.write(data1 .. ": " .. data2 .. "\n") + elseif id == 3 then + io.write("\n") + elseif id == 4 then + io.write(data1) + end + end - - return vals -end - --- Sends a custom HTTP-Header -function luci.http.header(key, value) - print(key .. ": " .. value) -end - --- Set Content-Type -function luci.http.prepare_content(type) - if not status_set then - luci.http.status(200, "OK") - end - - print("Content-Type: "..type.."\n") -end - --- Asks the browser to redirect to "url" -function luci.http.redirect(url) - luci.http.status(302, "Found") - luci.http.header("Location", url) - print() -end - --- Returns the path of an uploaded file --- WARNING! File uploads can be easily spoofed! Do additional sanity checks! -function luci.http.upload(name) - -- To be implemented -end - --- Sets HTTP-Status-Header -function luci.http.status(code, message) - print(luci.http.env.SERVER_PROTOCOL .. " " .. tostring(code) .. " " .. message) - status_set = true end diff --git a/libs/sgi-webuci/root/usr/lib/boa/luci.lua b/libs/sgi-webuci/root/usr/lib/boa/luci.lua index 39cee1c60..879ef19b4 100644 --- a/libs/sgi-webuci/root/usr/lib/boa/luci.lua +++ b/libs/sgi-webuci/root/usr/lib/boa/luci.lua @@ -60,6 +60,5 @@ function handle_req(context) env.SERVER_ADDR = context.server_addr env.SCRIPT_NAME = env.REQUEST_URI:sub(1, #env.REQUEST_URI - #env.PATH_INFO) - luci.sgi.webuci.initenv(env, vars) - luci.dispatcher.httpdispatch() + luci.sgi.webuci.run(env, vars) end diff --git a/libs/uci/luasrc/model/uci.lua b/libs/uci/luasrc/model/uci.lua index bd6aba41a..6662943cf 100644 --- a/libs/uci/luasrc/model/uci.lua +++ b/libs/uci/luasrc/model/uci.lua @@ -27,7 +27,7 @@ local uci = require("uci") local util = require("luci.util") local setmetatable, rawget, rawset = setmetatable, rawget, rawset local error, pairs, ipairs, tostring = error, pairs, ipairs, tostring -local table, print = table, print +local table = table module("luci.model.uci", function(m) setmetatable(m, {__index = uci}) end) diff --git a/libs/web/luasrc/dispatcher.lua b/libs/web/luasrc/dispatcher.lua index 64355439b..8516c6f1b 100644 --- a/libs/web/luasrc/dispatcher.lua +++ b/libs/web/luasrc/dispatcher.lua @@ -34,21 +34,10 @@ if (os.time() < 1000000000) then os.execute('date -s '..os.date('%m%d%H%M%Y', luci.fs.mtime(luci.sys.libpath() .. "/dispatcher.lua"))..' > /dev/null 2>&1') end --- Local dispatch database -local tree = {nodes={}} +context = luci.util.threadlocal() -- Index table -local index = {} - --- Global request object -request = {} - --- Active dispatched node -dispatched = nil - --- Status fields -built_index = false -built_tree = false +local index = nil -- Fastindex local fi @@ -64,9 +53,9 @@ function error401(message) message = message or "Unauthorized" require("luci.template") - if not pcall(luci.template.render, "error401") then + if not luci.util.copcall(luci.template.render, "error401") then luci.http.prepare_content("text/plain") - print(message) + luci.http.write(message) end return false end @@ -77,9 +66,9 @@ function error404(message) message = message or "Not Found" require("luci.template") - if not pcall(luci.template.render, "error404") then + if not luci.util.copcall(luci.template.render, "error404") then luci.http.prepare_content("text/plain") - print(message) + luci.http.write(message) end return false end @@ -89,31 +78,39 @@ function error500(message) luci.http.status(500, "Internal Server Error") require("luci.template") - if not pcall(luci.template.render, "error500", {message=message}) then + if not luci.util.copcall(luci.template.render, "error500", {message=message}) then luci.http.prepare_content("text/plain") - print(message) + luci.http.write(message) end return false end -- Creates a request object for dispatching -function httpdispatch() - local pathinfo = luci.http.env.PATH_INFO or "" +function httpdispatch(request) + luci.http.context.request = request + context.request = {} + local pathinfo = request.env.PATH_INFO or "" for node in pathinfo:gmatch("[^/]+") do - table.insert(request, node) + table.insert(context.request, node) end - dispatch() + dispatch(context.request) + luci.http.close() end -- Dispatches a request -function dispatch() - if not built_tree then +function dispatch(request) + context.path = request + + require("luci.i18n") + luci.i18n.setlanguage(require("luci.config").main.lang) + + if not context.tree then createtree() end - - local c = tree + + local c = context.tree local track = {} for i, s in ipairs(request) do @@ -131,6 +128,7 @@ function dispatch() local accs = track.sysauth accs = (type(accs) == "string") and {accs} or accs + --[[ local function sysauth(user, password) return (luci.util.contains(accs, user) and luci.sys.user.checkpasswd(user, password)) @@ -140,6 +138,7 @@ function dispatch() error401() return end + ]]-- end if track.i18n then @@ -156,22 +155,24 @@ function dispatch() -- Init template engine local tpl = require("luci.template") - tpl.viewns.translate = function(...) return require("luci.i18n").translate(...) end - tpl.viewns.controller = luci.http.dispatcher() - tpl.viewns.uploadctrl = luci.http.dispatcher_upload() -- DEPRECATED - tpl.viewns.media = luci.config.main.mediaurlbase - tpl.viewns.resource = luci.config.main.resourcebase - tpl.viewns.REQUEST_URI = luci.http.env.SCRIPT_NAME .. (luci.http.env.PATH_INFO or "") + local viewns = {} + tpl.context.viewns = viewns + viewns.write = luci.http.write + viewns.translate = function(...) return require("luci.i18n").translate(...) end + viewns.controller = luci.http.getenv("SCRIPT_NAME") + viewns.media = luci.config.main.mediaurlbase + viewns.resource = luci.config.main.resourcebase + viewns.REQUEST_URI = luci.http.getenv("SCRIPT_NAME") .. (luci.http.getenv("PATH_INFO") or "") if c and type(c.target) == "function" then - dispatched = c - stat, mod = pcall(require, c.module) + context.dispatched = c + stat, mod = luci.util.copcall(require, c.module) if stat then luci.util.updfenv(c.target, mod) end - stat, err = pcall(c.target) + stat, err = luci.util.copcall(c.target) if not stat then error500(err) end @@ -182,21 +183,20 @@ end -- Generates the dispatching tree function createindex() - index = {} local path = luci.sys.libpath() .. "/controller/" local suff = ".lua" - if pcall(require, "luci.fastindex") then + if luci.util.copcall(require, "luci.fastindex") then createindex_fastindex(path, suff) else createindex_plain(path, suff) end - - built_index = true end -- Uses fastindex to create the dispatching tree -function createindex_fastindex(path, suffix) +function createindex_fastindex(path, suffix) + index = {} + if not fi then fi = luci.fastindex.new("index") fi.add(path .. "*" .. suffix) @@ -212,9 +212,7 @@ end -- Calls the index function of all available controllers -- Fallback for transition purposes / Leave it in as long as it works otherwise throw it away function createindex_plain(path, suffix) - if built_index then - return - end + index = {} local cache = nil @@ -246,7 +244,7 @@ function createindex_plain(path, suffix) end if not cache or stime > ctime then - stat, mod = pcall(require, module) + stat, mod = luci.util.copcall(require, module) if stat and mod and type(mod.index) == "function" then index[module] = mod.index @@ -263,10 +261,11 @@ end -- Creates the dispatching tree from the index function createtree() - if not built_index then + if not index then createindex() end + context.tree = {nodes={}} require("luci.i18n") -- Load default translation @@ -283,14 +282,12 @@ function createtree() scope._NAME = k setfenv(v, scope) - local stat, err = pcall(v) + local stat, err = luci.util.copcall(v) if not stat then error500(err) os.exit(1) end end - - built_tree = true end -- Reassigns a node to another position @@ -302,7 +299,7 @@ function assign(path, clone, title, order) obj.title = title obj.order = order - local c = tree + local c = context.tree for k, v in ipairs(clone) do if not c.nodes[v] then c.nodes[v] = {nodes={}} @@ -330,8 +327,7 @@ end -- Fetch a dispatching node function node(...) - local c = tree - + local c = context.tree arg.n = nil if arg[1] then if type(arg[1]) == "table" then @@ -357,8 +353,7 @@ end function alias(...) local req = arg return function() - request = req - dispatch() + dispatch(req) end end @@ -366,19 +361,20 @@ function rewrite(n, ...) local req = arg return function() for i=1,n do - table.remove(request, 1) + table.remove(context.path, 1) end for i,r in ipairs(req) do - table.insert(request, i, r) + table.insert(context.path, i, r) end dispatch() end end -function call(name) - return function() getfenv()[name]() end +function call(name, ...) + local argv = {...} + return function() return getfenv()[name](unpack(argv)) end end function template(name) @@ -391,13 +387,13 @@ function cbi(model) require("luci.template") return function() - local stat, res = pcall(luci.cbi.load, model) + local stat, res = luci.util.copcall(luci.cbi.load, model) if not stat then error500(res) return true end - local stat, err = pcall(res.parse, res) + local stat, err = luci.util.copcall(res.parse, res) if not stat then error500(err) return true diff --git a/libs/web/luasrc/http.lua b/libs/web/luasrc/http.lua index 3bff28add..8ee864ac7 100644 --- a/libs/web/luasrc/http.lua +++ b/libs/web/luasrc/http.lua @@ -28,13 +28,141 @@ limitations under the License. ]]-- module("luci.http", package.seeall) +require("luci.util") +context = luci.util.threadlocal() -if ENV and ENV.HASERLVER then - require("luci.sgi.haserl") -elseif webuci then - require("luci.sgi.webuci") + +Request = luci.util.class() +function Request.__init__(self) + self.headers = {} + self.request = {} + self.uploads = {} + self.env = {} + self.data = "" +end + +function Request.formvalue(self, name, default) + return self.request[name] or default +end + +function Request.formvalues(self) + return self.request +end + +function Request.formvaluetable(self, prefix) + local vals = {} + prefix = prefix and prefix .. "." or "." + + for k, v in pairs(self.request) do + if k:find(prefix, 1, true) == 1 then + vals[k:sub(#prefix + 1)] = v + end + end + + return vals +end + +function Request.getenv(self, name) + return self.env[name] +end + +function Request.upload(self, name) + return self.uploads[name] +end + + +function close() + if not context.eoh then + context.eoh = true + coroutine.yield(3) + end + + if not context.closed then + context.closed = true + coroutine.yield(5) + end +end + +function formvalue(...) + return context.request:formvalue(...) +end + +function formvalues(...) + return context.request:formvalues(...) +end + +function formvaluetable(...) + return context.request:formvaluetable(...) end +function getenv(...) + return context.request:getenv(...) +end + +function header(key, value) + if not context.status then + status() + end + if not context.headers then + context.headers = {} + end + context.headers[key:lower()] = value + coroutine.yield(2, key, value) +end + +function prepare_content(mime) + header("Content-Type", mime) +end + +function status(code, message) + code = code or 200 + message = message or "OK" + context.status = code + coroutine.yield(1, code, message) +end + +function write(content) + if not content or #content == 0 then + return + end + if not context.eoh then + if not context.status then + status() + end + if not context.headers or not context.headers["content-type"] then + header("Content-Type", "text/html; charset=utf-8") + end + + context.eoh = true + coroutine.yield(3) + end + coroutine.yield(4, content) +end + + +function basic_auth(realm, errorpage) + header("Status", "401 Unauthorized") + header("WWW-Authenticate", string.format('Basic realm="%s"', realm or "")) + + if errorpage then + errorpage() + end + + close() +end + +function redirect(url) + header("Status", "302 Found") + header("Location", url) + close() +end + +function upload(...) + return context.request:upload(...) +end + + + function build_querystring(table) local s="?" diff --git a/libs/web/luasrc/i18n.lua b/libs/web/luasrc/i18n.lua index 3ed1ce017..35ad0965d 100644 --- a/libs/web/luasrc/i18n.lua +++ b/libs/web/luasrc/i18n.lua @@ -30,6 +30,8 @@ require("luci.sys") table = {} i18ndir = luci.sys.libpath() .. "/i18n/" loaded = {} +context = luci.util.threadlocal() +default = "en" -- Clears the translation table function clear() @@ -37,13 +39,17 @@ function clear() end -- Loads a translation and copies its data into the global translation table -function load(file, force) - if force or not loaded[file] then - local f = loadfile(i18ndir..file..".lua") or loadfile(i18ndir..file) +function load(file, lang, force) + lang = lang or "" + if force or not loaded[lang] or not loaded[lang][file] then + local f = loadfile(i18ndir .. file .. "." .. lang .. ".lua") + or loadfile(i18ndir .. file .. "." .. lang) if f then - setfenv(f, table) + table[lang] = table[lang] or {} + setfenv(f, table[lang]) f() - loaded[file] = true + loaded[lang] = loaded[lang] or {} + loaded[lang][file] = true return true else return false @@ -55,13 +61,20 @@ end -- Same as load but autocompletes the filename with .LANG from config.lang function loadc(file, force) - load(file .. ".en", force) - return load(file .. "." .. require("luci.config").main.lang, force) + load(file, default, force) + return load(file, context.lang, force) +end + +-- Sets the context language +function setlanguage(lang) + context.lang = lang end -- Returns the i18n-value defined by "key" or if there is no such: "default" function translate(key, default) - return table[key] or default + return (table[context.lang] and table[context.lang][key]) + or (table[default] and table[default][key]) + or default end -- Translate shourtcut with sprintf/string.format inclusion diff --git a/libs/web/luasrc/template.lua b/libs/web/luasrc/template.lua index 61e4e39ec..29aedcdad 100644 --- a/libs/web/luasrc/template.lua +++ b/libs/web/luasrc/template.lua @@ -44,9 +44,10 @@ compiler_mode = luci.config.template.compiler_mode or "memory" -- Define the namespace for template modules +context = luci.util.threadlocal() + viewns = { - write = io.write, - include = function(name) Template(name):render(getfenv(2)) end, + include = function(name) Template(name):render(getfenv(2)) end, } -- Compiles a given template into an executable Lua module @@ -113,7 +114,7 @@ end -- Oldstyle render shortcut function render(name, scope, ...) scope = scope or getfenv(2) - local s, t = pcall(Template, name) + local s, t = luci.util.copcall(Template, name) if not s then error(t) else @@ -141,9 +142,10 @@ function Template.__init__(self, name) self.viewns = {} -- Copy over from general namespace - for k, v in pairs(viewns) do - self.viewns[k] = v - end + luci.util.update(self.viewns, viewns) + if context.viewns then + luci.util.update(self.viewns, context.viewns) + end -- If we have a cached template, skip compiling and loading if self.template then |