rev |
line source |
jbe/bsw@0
|
1 #!/usr/bin/env lua
|
jbe/bsw@0
|
2
|
jbe/bsw@0
|
3 if not pcall(
|
jbe/bsw@0
|
4 function()
|
jbe@64
|
5 extos = require "extos"
|
jbe/bsw@0
|
6 end
|
jbe/bsw@0
|
7 ) then
|
jbe/bsw@0
|
8 io.stderr:write('Could not load library "extos".\n')
|
jbe/bsw@0
|
9 io.stderr:write('Hint: Set LUA_CPATH="/path_to_extos_library/?.so;;"\n')
|
jbe/bsw@0
|
10 end
|
jbe/bsw@0
|
11
|
jbe/bsw@0
|
12
|
jbe/bsw@0
|
13 local args = {...}
|
jbe/bsw@0
|
14
|
jbe/bsw@0
|
15 if #args == 0 then
|
jbe/bsw@0
|
16 print()
|
jbe/bsw@0
|
17 print("This program creates translation files by traversing source directories.")
|
jbe/bsw@0
|
18 print()
|
jbe/bsw@0
|
19 print("Two formats are supported: lua files and po files.")
|
jbe/bsw@0
|
20 print("At runtime a lua file is needed.")
|
jbe/bsw@0
|
21 print("For use with po-file editors you may want to create po files first though.")
|
jbe/bsw@0
|
22 print()
|
jbe/bsw@0
|
23 print("Create or update a lua file: langtool.lua dir1/ dir2/ ... <basename>.lua")
|
jbe/bsw@0
|
24 print("Create or update a po file: langtool.lua dir1/ dir2/ ... <basename>.po")
|
jbe/bsw@0
|
25 print("Convert po file to lua file: langtool.lua <basename>.po <basename>.lua")
|
jbe/bsw@0
|
26 print("Convert lua file to po file: langtool.lua <basename>.lua <basename>.po")
|
jbe/bsw@0
|
27 print()
|
jbe/bsw@0
|
28 end
|
jbe/bsw@0
|
29
|
jbe/bsw@0
|
30 local in_filename, in_filetype, out_filename, out_filetype
|
jbe/bsw@0
|
31 local directories = {}
|
jbe/bsw@0
|
32
|
jbe/bsw@0
|
33 for arg_num, arg in ipairs(args) do
|
jbe/bsw@0
|
34 local function arg_error(msg)
|
jbe/bsw@0
|
35 error("Illegal command line argument #" .. arg_num .. ": " .. msg)
|
jbe/bsw@0
|
36 end
|
jbe/bsw@0
|
37 local po = string.match(arg, "^po:(.*)$") or string.match(arg, "^(.*%.po)$")
|
jbe/bsw@0
|
38 local lua = string.match(arg, "^lua:(.*)$") or string.match(arg, "^(.*%.lua)$")
|
jbe/bsw@0
|
39 local filetype
|
jbe/bsw@0
|
40 if po and not lua then filetype = "po"
|
jbe/bsw@0
|
41 filetype = "po"
|
jbe/bsw@0
|
42 elseif lua and not po then filetype = "lua"
|
jbe/bsw@0
|
43 filetype = "lua"
|
jbe/bsw@0
|
44 else
|
jbe/bsw@0
|
45 filetype = "path"
|
jbe/bsw@0
|
46 end
|
jbe/bsw@0
|
47 if filetype == "path" then
|
jbe/bsw@0
|
48 table.insert(directories, arg)
|
jbe/bsw@0
|
49 elseif filetype == "po" or filetype == "lua" then
|
jbe/bsw@0
|
50 if not out_filename then
|
jbe/bsw@0
|
51 out_filename = arg
|
jbe/bsw@0
|
52 out_filetype = filetype
|
jbe/bsw@0
|
53 elseif not in_filename then
|
jbe/bsw@0
|
54 in_filename = out_filename
|
jbe/bsw@0
|
55 in_filetype = out_filetype
|
jbe/bsw@0
|
56 out_filename = arg
|
jbe/bsw@0
|
57 out_filetype = filetype
|
jbe/bsw@0
|
58 else
|
jbe/bsw@0
|
59 arg_error("Only two language files (one input and one output file) can be specified.")
|
jbe/bsw@0
|
60 end
|
jbe/bsw@0
|
61 else
|
jbe/bsw@0
|
62 -- should not happen, as default type is "path"
|
jbe/bsw@0
|
63 arg_error("Type not recognized")
|
jbe/bsw@0
|
64 end
|
jbe/bsw@0
|
65 end
|
jbe/bsw@0
|
66
|
jbe@65
|
67 if #directories > 0 and not extos.listdir then
|
jbe/bsw@0
|
68 io.stderr:write('Fatal: Cannot traverse directories without "extos" library -> Abort\n')
|
jbe/bsw@0
|
69 os.exit(1)
|
jbe/bsw@0
|
70 end
|
jbe/bsw@0
|
71
|
jbe/bsw@0
|
72 if out_filename and not in_filename then
|
jbe/bsw@0
|
73 local file = io.open(out_filename, "r")
|
jbe/bsw@0
|
74 if file then
|
jbe/bsw@0
|
75 in_filename = out_filename
|
jbe/bsw@0
|
76 in_filetype = out_filetype
|
jbe/bsw@0
|
77 file:close()
|
jbe/bsw@0
|
78 end
|
jbe/bsw@0
|
79 end
|
jbe/bsw@0
|
80
|
jbe/bsw@0
|
81 local translations = { }
|
jbe/bsw@0
|
82
|
jbe/bsw@0
|
83 local function traverse(path)
|
jbe@65
|
84 local filenames = extos.listdir(path)
|
jbe/bsw@0
|
85 if not filenames then return false end
|
jbe/bsw@0
|
86 for num, filename in ipairs(filenames) do
|
jbe/bsw@0
|
87 if not string.find(filename, "^%.") then
|
jbe/bsw@0
|
88 if string.find(filename, "%.lua$") then
|
jbe/bsw@0
|
89 for line in io.lines(path .. "/" .. filename) do
|
jbe/bsw@0
|
90 -- TODO: exact parsing of comments and escape characters
|
jbe@118
|
91 for key in string.gmatch(line, "_%(?'([^']+)'") do
|
jbe/bsw@0
|
92 if
|
jbe/bsw@0
|
93 key ~= "([^" and
|
jbe/bsw@0
|
94 (not string.find(key, "^%s*%.%.[^%.]")) and
|
jbe/bsw@0
|
95 (not string.find(key, "^%s*,[^,]"))
|
jbe/bsw@0
|
96 then
|
jbe/bsw@4
|
97 local key = key:gsub("\\n", "\n")
|
jbe/bsw@0
|
98 translations[key] = false
|
jbe/bsw@0
|
99 end
|
jbe/bsw@0
|
100 end
|
jbe@118
|
101 for key in string.gmatch(line, '_%(?"([^"]+)"') do
|
jbe/bsw@0
|
102 if
|
jbe/bsw@0
|
103 key ~= "([^" and
|
jbe/bsw@0
|
104 (not string.find(key, "^%s*%.%.[^%.]")) and
|
jbe/bsw@0
|
105 (not string.find(key, "^%s*,[^,]"))
|
jbe/bsw@0
|
106 then
|
jbe/bsw@4
|
107 local key = key:gsub("\\n", "\n")
|
jbe/bsw@0
|
108 translations[key] = false
|
jbe/bsw@0
|
109 end
|
jbe/bsw@0
|
110 end
|
jbe/bsw@0
|
111 end
|
jbe/bsw@0
|
112 end
|
jbe/bsw@0
|
113 traverse(path .. "/" .. filename)
|
jbe/bsw@0
|
114 end
|
jbe/bsw@0
|
115 end
|
jbe/bsw@0
|
116 return true
|
jbe/bsw@0
|
117 end
|
jbe/bsw@0
|
118 for num, directory in ipairs(directories) do
|
jbe/bsw@0
|
119 io.stderr:write('Parsing files in directory "', directory, '".\n')
|
jbe/bsw@0
|
120 if not traverse(directory) then
|
jbe/bsw@0
|
121 error('Could not read directory "' .. directory .. '".')
|
jbe/bsw@0
|
122 end
|
jbe/bsw@0
|
123 end
|
jbe/bsw@0
|
124
|
jbe/bsw@0
|
125 local function update_translation(key, value)
|
jbe/bsw@0
|
126 if #directories > 0 then
|
jbe/bsw@0
|
127 if translations[key] ~= nil then translations[key] = value end
|
jbe/bsw@0
|
128 else
|
jbe/bsw@0
|
129 translations[key] = value
|
jbe/bsw@0
|
130 end
|
jbe/bsw@0
|
131 end
|
jbe/bsw@0
|
132
|
jbe/bsw@0
|
133 if in_filetype == "po" then
|
jbe/bsw@0
|
134 io.stderr:write('Reading translations from po file "', in_filename, '".\n')
|
jbe/bsw@0
|
135 local next_line = io.lines(in_filename)
|
jbe/bsw@0
|
136 for line in next_line do
|
jbe/bsw@0
|
137 if not line then break end
|
jbe/bsw@0
|
138 local key = string.match(line, '^msgid%s*"(.*)"%s*$')
|
jbe/bsw@0
|
139 if key then
|
jbe/bsw@0
|
140 local line = next_line()
|
jbe/bsw@0
|
141 local value = string.match(line, '^msgstr%s*"(.*)"%s*$')
|
jbe/bsw@0
|
142 if not value then
|
jbe/bsw@0
|
143 error("Expected msgstr line in po file.")
|
jbe/bsw@0
|
144 end
|
jbe/bsw@0
|
145 if translations[key] then
|
jbe/bsw@0
|
146 error("Duplicate key '" .. key .. "' in po file.")
|
jbe/bsw@0
|
147 end
|
jbe/bsw@0
|
148 if value == "" then value = false end
|
jbe/bsw@0
|
149 update_translation(key, value)
|
jbe/bsw@0
|
150 end
|
jbe/bsw@0
|
151 end
|
jbe/bsw@0
|
152 elseif in_filetype == "lua" then
|
jbe/bsw@0
|
153 io.stderr:write('Reading translations from lua file "', in_filename, '".\n')
|
jbe@64
|
154 local func
|
jbe@64
|
155 if _ENV then
|
jbe@64
|
156 func = assert(loadfile(in_filename, "t", {}))
|
jbe@64
|
157 else
|
jbe@64
|
158 func = assert(loadfile(in_filename))
|
jbe@64
|
159 setfenv(func, {})
|
jbe@64
|
160 end
|
jbe/bsw@0
|
161 local updates = func()
|
jbe/bsw@0
|
162 for key, value in pairs(updates) do
|
jbe/bsw@0
|
163 update_translation(key, value)
|
jbe/bsw@0
|
164 end
|
jbe/bsw@0
|
165 end
|
jbe/bsw@0
|
166
|
jbe/bsw@0
|
167 local translation_keys = {}
|
jbe/bsw@0
|
168 for key in pairs(translations) do
|
jbe/bsw@0
|
169 table.insert(translation_keys, key)
|
jbe/bsw@0
|
170 end
|
jbe/bsw@0
|
171 table.sort(translation_keys)
|
jbe/bsw@0
|
172
|
jbe/bsw@0
|
173 if out_filetype == "po" then
|
jbe/bsw@0
|
174 io.stderr:write('Writing translations to po file "', out_filename, '".\n')
|
jbe/bsw@0
|
175 local file = assert(io.open(out_filename, "w"))
|
jbe/bsw@0
|
176 for num, key in ipairs(translation_keys) do
|
jbe/bsw@0
|
177 local value = translations[key]
|
jbe/bsw@0
|
178 file:write('msgid "', key, '"\nmsgstr "', value or "", '"\n\n')
|
jbe/bsw@0
|
179 end
|
jbe/bsw@0
|
180 io.close(file)
|
jbe/bsw@0
|
181 elseif out_filetype == "lua" then
|
jbe/bsw@0
|
182 io.stderr:write('Writing translations to lua file "', out_filename, '".\n')
|
jbe/bsw@0
|
183 local file = assert(io.open(out_filename, "w"))
|
jbe/bsw@0
|
184 file:write("#!/usr/bin/env lua\n", "return {\n")
|
jbe/bsw@0
|
185 for num, key in ipairs(translation_keys) do
|
jbe/bsw@0
|
186 local value = translations[key]
|
jbe/bsw@0
|
187 if value then
|
jbe/bsw@4
|
188 file:write((string.format("[%q] = %q;\n", key, value):gsub("\\\n", "\\n"))) -- double () important to hide second result of gsub
|
jbe/bsw@0
|
189 else
|
jbe/bsw@4
|
190 file:write((string.format("[%q] = false;\n", key):gsub("\\\n", "\\n"))) -- double () important to hide second result of gsub
|
jbe/bsw@0
|
191 end
|
jbe/bsw@0
|
192 end
|
jbe/bsw@0
|
193 file:write("}\n")
|
jbe/bsw@0
|
194 io.close(file)
|
jbe/bsw@0
|
195 end
|