This feed contains pages related to Lighttpd.
lighttpd is web server with a fast growing user base. This howto shows how redirects can be done based on the language of the user's browser.
While migrating http://blog.credativ.com from Wordpress to Movable Type we decided to show the blog's welcome message in English or German depending on the language setting of the user's browser. Since one of the reasons for the switch to the new blog engine was that Movable Type creates static html pages we avoided cgi scripts or similar workarounds.
As we are using Lighttpd to serve all pages, the use of the mighty mod_magnet module was obviously the way to go for this task. It allows to control the request handling within Lighttpd by running Lua scripts which are allowed to modify most aspects of the way how a request is handled. So now http://blog.credativ.com/ is rewritten to the file with the proper language by using the help of the following Lua snippet:
-- - do not forget to install liblua5.1-lpeg2 -- - make sure to configure the script here ----------------------------- language_targets = {} language_targets["en"] = "/en/index.html" language_targets["de"] = "/de/index.html" default_language = "en" -- - nothing to customize below this line ------------------------------- -- --[[ string:split function taken from http://lua-users.org/wiki/SplitJoin Thanks to Joan Ordinas ]] function string:split(sSeparator, nMax, bRegexp) assert(sSeparator ~= '') assert(nMax == nil or nMax >= 1) local aRecord = {} if self:len() > 0 then local bPlain = not bRegexp nMax = nMax or -1 local nField=1 nStart=1 local nFirst,nLast = self:find(sSeparator, nStart, bPlain) while nFirst and nMax ~= 0 do aRecord[nField] = self:sub(nStart, nFirst-1) nField = nField+1 nStart = nLast+1 nFirst,nLast = self:find(sSeparator, nStart, bPlain) nMax = nMax-1 end aRecord[nField] = self:sub(nStart) end return aRecord end -- Based on trim14 from http://lua-users.org/wiki/StringTrim do require 're' require 'lpeg' local ptrim = re.compile"%s* {(%s* %S+)*}" local match = lpeg.match function string:trim() return match(ptrim, self) end end lang_header = lighty.request['Accept-Language'] lighty.env["uri.path"] = language_targets[default_language] if (lang_header) then lang_header = string.lower(lang_header) local lang_order = {} for i, language in ipairs(string.split(lang_header, ",")) do language_configs = string.split(language, ";") language = string.trim(language_configs[1]) table.remove(language_configs, 1) if ((#language == 2) and string.find(language, "[a-z][a-z]")) or ((#language == 5) and string.find(language, "[a-z][a-z][-][a-z][a-z]")) then local q = 1 for i, config in ipairs(language_configs) do local config_data = string.split(config, "=") if (#config_data == 2) then local lvalue = string.trim(config_data[1]) local rvalue = string.trim(config_data[2]) if lvalue == "q" then q = tonumber(rvalue) end end end table.insert(lang_order, {language, q}) end end table.sort(lang_order, function(a,b) return (a[2] > b[2]) end) for i,v in ipairs(lang_order) do local lang = string.split(v[1], '-')[1] if language_targets[lang] then lighty.env["uri.path"] = language_targets[lang] break end end end lighty.env["physical.rel-path"] = lighty.env["uri.path"] lighty.env["physical.path"] = lighty.env["physical.doc-root"] .. lighty.env["physical.rel-path"]
Of course, the Lighttpd configuration must include mod_magnet. To actually rewrite any request to "/" the configuration must also include the following snippet:
$HTTP["url"] =~ "^/$" {
magnet.attract-physical-path-to = ( "/path/to/your/script.lua" )
}
mod_magnet caches the compiled script and executes it within the core of Lighttpd so it shouldn't introduce any noticeable delay in the delivery of your webpages.
Update: Some people complained in comments (which I lost while moderating a ton of spam comments unfortunately) that the script did not parse the full Accept-Language header. Although this was not really an issue for us as the two blogs are independent and people have to check which blog to read in any case, I've updated the script to parse the header properly. Also it should be easier to re-use for your own needs now.