webmcp

annotate framework/bin/langtool.lua @ 405:c5f9a1b2f225

Updated year of copyright notice
author jbe
date Wed Jan 06 02:54:45 2016 +0100 (2016-01-06)
parents 92d9218140f7
children 2c31275322db
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

Impressum / About Us