webmcp
annotate framework/bin/langtool.lua @ 6:5cba83b3f411
Version 1.0.6
Bugfix: class_prototype:add_reference{...} uses now qualified names in SQL queries to allow JOINs
Fixes in the documentation of slot.put_into and trace.debug
Bugfix: class_prototype:add_reference{...} uses now qualified names in SQL queries to allow JOINs
Fixes in the documentation of slot.put_into and trace.debug
| author | jbe/bsw | 
|---|---|
| date | Fri Jan 22 12:00:00 2010 +0100 (2010-01-22) | 
| parents | 5e32ef998acf | 
| children | 3d43a5cf17c1 | 
| 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/bsw@0 | 5 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/bsw@0 | 67 if #directories > 0 and not os.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/bsw@0 | 84 local filenames = os.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/bsw@0 | 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/bsw@0 | 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/bsw@0 | 154 local func = assert(loadfile(in_filename)) | 
| jbe/bsw@0 | 155 setfenv(func, {}) | 
| jbe/bsw@0 | 156 local updates = func() | 
| jbe/bsw@0 | 157 for key, value in pairs(updates) do | 
| jbe/bsw@0 | 158 update_translation(key, value) | 
| jbe/bsw@0 | 159 end | 
| jbe/bsw@0 | 160 end | 
| jbe/bsw@0 | 161 | 
| jbe/bsw@0 | 162 local translation_keys = {} | 
| jbe/bsw@0 | 163 for key in pairs(translations) do | 
| jbe/bsw@0 | 164 table.insert(translation_keys, key) | 
| jbe/bsw@0 | 165 end | 
| jbe/bsw@0 | 166 table.sort(translation_keys) | 
| jbe/bsw@0 | 167 | 
| jbe/bsw@0 | 168 if out_filetype == "po" then | 
| jbe/bsw@0 | 169 io.stderr:write('Writing translations to po file "', out_filename, '".\n') | 
| jbe/bsw@0 | 170 local file = assert(io.open(out_filename, "w")) | 
| jbe/bsw@0 | 171 for num, key in ipairs(translation_keys) do | 
| jbe/bsw@0 | 172 local value = translations[key] | 
| jbe/bsw@0 | 173 file:write('msgid "', key, '"\nmsgstr "', value or "", '"\n\n') | 
| jbe/bsw@0 | 174 end | 
| jbe/bsw@0 | 175 io.close(file) | 
| jbe/bsw@0 | 176 elseif out_filetype == "lua" then | 
| jbe/bsw@0 | 177 io.stderr:write('Writing translations to lua file "', out_filename, '".\n') | 
| jbe/bsw@0 | 178 local file = assert(io.open(out_filename, "w")) | 
| jbe/bsw@0 | 179 file:write("#!/usr/bin/env lua\n", "return {\n") | 
| jbe/bsw@0 | 180 for num, key in ipairs(translation_keys) do | 
| jbe/bsw@0 | 181 local value = translations[key] | 
| jbe/bsw@0 | 182 if value then | 
| jbe/bsw@4 | 183 file:write((string.format("[%q] = %q;\n", key, value):gsub("\\\n", "\\n"))) -- double () important to hide second result of gsub | 
| jbe/bsw@0 | 184 else | 
| jbe/bsw@4 | 185 file:write((string.format("[%q] = false;\n", key):gsub("\\\n", "\\n"))) -- double () important to hide second result of gsub | 
| jbe/bsw@0 | 186 end | 
| jbe/bsw@0 | 187 end | 
| jbe/bsw@0 | 188 file:write("}\n") | 
| jbe/bsw@0 | 189 io.close(file) | 
| jbe/bsw@0 | 190 end |