2014-06-08 13:32:45 +00:00
|
|
|
local isAndroid, android = pcall(require, "android")
|
2016-12-29 08:10:38 +00:00
|
|
|
local logger = require("logger")
|
2013-04-07 08:09:33 +00:00
|
|
|
|
2014-05-22 20:47:14 +00:00
|
|
|
local GetText = {
|
|
|
|
translation = {},
|
|
|
|
current_lang = "C",
|
|
|
|
dirname = "l10n",
|
|
|
|
textdomain = "koreader"
|
|
|
|
}
|
|
|
|
|
|
|
|
local GetText_mt = {
|
|
|
|
__index = {}
|
|
|
|
}
|
2013-04-07 08:09:33 +00:00
|
|
|
|
2019-08-21 17:40:15 +00:00
|
|
|
function GetText_mt.__call(gettext, msgstr)
|
|
|
|
return gettext.translation[msgstr] or msgstr
|
2014-05-22 20:47:14 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
local function c_escape(what)
|
|
|
|
if what == "\n" then return ""
|
|
|
|
elseif what == "a" then return "\a"
|
|
|
|
elseif what == "b" then return "\b"
|
|
|
|
elseif what == "f" then return "\f"
|
|
|
|
elseif what == "n" then return "\n"
|
|
|
|
elseif what == "r" then return "\r"
|
|
|
|
elseif what == "t" then return "\t"
|
|
|
|
elseif what == "v" then return "\v"
|
|
|
|
elseif what == "0" then return "\0" -- shouldn't happen, though
|
|
|
|
else
|
|
|
|
return what
|
|
|
|
end
|
2013-04-07 08:09:33 +00:00
|
|
|
end
|
|
|
|
|
2014-05-22 20:47:14 +00:00
|
|
|
-- for PO file syntax, see
|
|
|
|
-- https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
|
|
|
|
-- we only implement a sane subset for now
|
|
|
|
|
|
|
|
function GetText_mt.__index.changeLang(new_lang)
|
2019-08-21 17:40:15 +00:00
|
|
|
GetText.context = {}
|
2014-05-22 20:47:14 +00:00
|
|
|
GetText.translation = {}
|
|
|
|
GetText.current_lang = "C"
|
|
|
|
|
2017-10-11 12:22:11 +00:00
|
|
|
-- the "C" locale disables localization altogether
|
|
|
|
-- can be various things such as `en_US` or `en_US:en`
|
|
|
|
if new_lang == "C" or new_lang == nil or new_lang == ""
|
|
|
|
or new_lang:match("^en_US") == "en_US" then return end
|
2014-06-08 12:48:33 +00:00
|
|
|
|
|
|
|
-- strip encoding suffix in locale like "zh_CN.utf8"
|
|
|
|
new_lang = new_lang:sub(1, new_lang:find(".%."))
|
2014-05-22 20:47:14 +00:00
|
|
|
|
|
|
|
local file = GetText.dirname .. "/" .. new_lang .. "/" .. GetText.textdomain .. ".po"
|
|
|
|
local po = io.open(file, "r")
|
|
|
|
|
|
|
|
if not po then
|
2019-01-17 20:44:15 +00:00
|
|
|
logger.dbg("cannot open translation file:", file)
|
2017-10-11 12:22:11 +00:00
|
|
|
return false
|
2014-05-22 20:47:14 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
local data = {}
|
|
|
|
local what = nil
|
|
|
|
while true do
|
|
|
|
local line = po:read("*l")
|
|
|
|
if line == nil or line == "" then
|
2014-05-23 09:57:33 +00:00
|
|
|
if data.msgid and data.msgstr and data.msgstr ~= "" then
|
2019-08-21 17:40:15 +00:00
|
|
|
local unescaped_string = string.gsub(data.msgstr, "\\(.)", c_escape)
|
|
|
|
if data.msgctxt and data.msgctxt ~= "" then
|
|
|
|
if not GetText.context[data.msgctxt] then
|
|
|
|
GetText.context[data.msgctxt] = {}
|
|
|
|
end
|
|
|
|
GetText.context[data.msgctxt][data.msgid] = unescaped_string
|
|
|
|
else
|
|
|
|
GetText.translation[data.msgid] = unescaped_string
|
|
|
|
end
|
2014-05-22 20:47:14 +00:00
|
|
|
end
|
|
|
|
-- stop at EOF:
|
|
|
|
if line == nil then break end
|
|
|
|
data = {}
|
|
|
|
what = nil
|
|
|
|
else
|
|
|
|
-- comment
|
|
|
|
if not line:match("^#") then
|
|
|
|
-- new data item (msgid, msgstr, ...
|
|
|
|
local w, s = line:match("^%s*(%a+)%s+\"(.*)\"%s*$")
|
|
|
|
if w then
|
|
|
|
what = w
|
|
|
|
else
|
|
|
|
-- string continuation
|
|
|
|
s = line:match("^%s*\"(.*)\"%s*$")
|
|
|
|
end
|
|
|
|
if what and s then
|
2014-11-19 20:32:33 +00:00
|
|
|
-- unescape \n or msgid won't match
|
|
|
|
s = s:gsub("\\n", "\n")
|
2017-04-04 09:19:07 +00:00
|
|
|
-- unescape " or msgid won't match
|
|
|
|
s = s:gsub('\\"', '"')
|
2014-05-22 20:47:14 +00:00
|
|
|
data[what] = (data[what] or "") .. s
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
GetText.current_lang = new_lang
|
2013-04-07 08:09:33 +00:00
|
|
|
end
|
2013-10-18 20:38:07 +00:00
|
|
|
|
2019-08-21 17:40:15 +00:00
|
|
|
function GetText_mt.__index.pgettext(msgctxt, msgstr)
|
|
|
|
return GetText.context[msgctxt] and GetText.context[msgctxt][msgstr] or msgstr
|
|
|
|
end
|
|
|
|
|
2013-10-18 20:38:07 +00:00
|
|
|
setmetatable(GetText, GetText_mt)
|
|
|
|
|
2014-05-22 20:47:14 +00:00
|
|
|
if os.getenv("LANGUAGE") then
|
|
|
|
GetText.changeLang(os.getenv("LANGUAGE"))
|
|
|
|
elseif os.getenv("LC_ALL") then
|
|
|
|
GetText.changeLang(os.getenv("LC_ALL"))
|
|
|
|
elseif os.getenv("LC_MESSAGES") then
|
|
|
|
GetText.changeLang(os.getenv("LC_MESSAGES"))
|
|
|
|
elseif os.getenv("LANG") then
|
|
|
|
GetText.changeLang(os.getenv("LANG"))
|
|
|
|
end
|
|
|
|
|
2014-06-08 13:32:45 +00:00
|
|
|
if isAndroid then
|
|
|
|
local ffi = require("ffi")
|
|
|
|
local buf = ffi.new("char[?]", 16)
|
2017-09-23 21:58:34 +00:00
|
|
|
android.lib.AConfiguration_getLanguage(android.app.config, buf)
|
2014-06-08 13:32:45 +00:00
|
|
|
local lang = ffi.string(buf)
|
2017-09-23 21:58:34 +00:00
|
|
|
android.lib.AConfiguration_getCountry(android.app.config, buf)
|
2014-06-08 13:32:45 +00:00
|
|
|
local country = ffi.string(buf)
|
|
|
|
if lang and country then
|
|
|
|
GetText.changeLang(lang.."_"..country)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-10-18 20:38:07 +00:00
|
|
|
return GetText
|