webmcp

view framework/bin/langtool.lua @ 0:9fdfb27f8e67

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

Impressum / About Us