aboutsummaryrefslogtreecommitdiff
path: root/advtrains/poconvert.lua
blob: c7704f62ce1514f99f1eeae9bcd5c6558d20cdcd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
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,
}