From 983017d3929f0ad5abfa4f88c0d6a6d7f5281ac2 Mon Sep 17 00:00:00 2001 From: "Y. Wang" Date: Wed, 4 Oct 2023 20:07:24 +0200 Subject: Autogenerate .tr files from .po files --- advtrains/poconvert.lua | 159 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 advtrains/poconvert.lua (limited to 'advtrains/poconvert.lua') diff --git a/advtrains/poconvert.lua b/advtrains/poconvert.lua new file mode 100644 index 0000000..c7704f6 --- /dev/null +++ b/advtrains/poconvert.lua @@ -0,0 +1,159 @@ +local unescape_string +do + local schartbl = { -- https://en.wikipedia.org/wiki/Escape_sequences_in_C + a = "\a", + b = "\b", + e = string.char(0x1b), + f = "\f", + n = "\n", + r = "\r", + t = "\t", + v = "\v", + } + local function replace_single(pfx, c) + local pl = #pfx + if pl % 2 == 0 then + return pfx .. c + end + return string.sub(pfx, 1, math.floor(pl/2)) .. (schartbl[c] or c) + end + unescape_string = function(str) + return (string.gsub(str, [[(\+)([abefnrtv'"?])]], replace_single):gsub([[\\]], [[\]])) + end +end + +local function readstring_aux(str, pos) + local _, spos = string.find(str, [[^%s*"]], pos) + if not spos then + return nil + end + local ipos = spos + while true do + local _, epos, m = string.find(str, [[(\*)"]], ipos+1) + if not epos then + return error("String extends beyond the end of input") + end + ipos = epos + if #m % 2 == 0 then + return unescape_string(string.sub(str, spos+1, epos-1)), epos+1 + end + end +end + +local function readstring(str, pos) + local st = {} + local nxt = pos + while true do + local s, npos = readstring_aux(str, nxt) + if not s then + if not st[1] then + return nil, nxt + else + return table.concat(st), nxt + end + end + nxt = npos + table.insert(st, s) + end +end + +local function readtoken(str, pos) + local _, epos, tok = string.find(str, [[^%s*(%S+)]], pos) + if not epos then + return nil, pos + end + return tok, epos+1 +end + +local function readcomment_aux(str, pos) + local _, epos, sval = string.find(str, "^\n*#%s*([^\n]*)", pos) + if not epos then + return nil + end + return sval, epos+1 +end + +local function readcomment(str, pos) + local st = {} + local nxt = pos + while true do + local s, npos = readcomment_aux(str, nxt) + if not npos then + return table.concat(st, "\n"), nxt + end + table.insert(st, s) + nxt = npos + end +end + +local function readpo(str) + local st = {} + local pos = 1 + while true do + local tok + local _, npos = readcomment(str, pos) + tok, npos = readtoken(str, npos) + if not tok then + return st + end + assert(tok == "msgid", "Invalid token: " .. tok) + local orig, tr + orig, npos = readstring(str, npos) + assert(orig ~= nil, "Missing untranslated string") + tok, npos = readtoken(str, npos) + assert(tok == "msgstr", "Invalid token: " .. tok) + tr, npos = readstring(str, npos) + assert(tr ~= nil, "Missing translated string") + if not (orig == "" or tr == "") then + st[orig] = tr + end + pos = npos + end +end + +local escape_lookup = { + ["="] = "@=", + ["\n"] = "@n" +} +local function escape_string(st) + return (string.gsub(st, "[=\n]", escape_lookup)) +end + +local function convert_po_string(textdomain, str) + local st = {string.format("# textdomain: %s", textdomain)} + for k, v in pairs(readpo(str)) do + table.insert(st, ("%s=%s"):format(escape_string(k), escape_string(v))) + end + return table.concat(st, "\n") +end + +local function convert_po_file(textdomain, inpath, outpath) + local f, err = io.open(inpath, "rb") + assert(f, err) + local str = convert_po_string(textdomain, f:read("*a")) + f:close() + minetest.safe_file_write(outpath, str) + return str +end + +local function convert_flat_po_directory(textdomain, modpath) + assert(textdomain, "No textdomain specified for po file conversion") + local mp = modpath or minetest.get_modpath(textdomain) + assert(mp ~= nil, "No path to write for " .. textdomain) + local popath = mp .. "/po" + local trpath = mp .. "/locale" + for _, infile in pairs(minetest.get_dir_list(popath, false)) do + local lang = string.match(infile, [[^([^%.]+)%.po$]]) + if lang then + local inpath = popath .. "/" .. infile + local outpath = ("%s/%s.%s.tr"):format(trpath, textdomain, lang) + convert_po_file(textdomain, inpath, outpath) + end + end +end + +return { + from_string = convert_po_string, + from_file = convert_po_file, + from_flat = convert_flat_po_directory, +} -- cgit v1.2.3