webmcp

annotate framework/bin/langtool.lua @ 564:6141ab127861

Fixed handling of derived translation tables
author jbe
date Sun Mar 07 17:21:12 2021 +0100 (2021-03-07)
parents 2c31275322db
children
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@564 125 local updates
jbe/bsw@0 126
jbe/bsw@0 127 if in_filetype == "po" then
jbe@564 128 updates = {}
jbe/bsw@0 129 io.stderr:write('Reading translations from po file "', in_filename, '".\n')
jbe/bsw@0 130 local next_line = io.lines(in_filename)
jbe/bsw@0 131 for line in next_line do
jbe/bsw@0 132 if not line then break end
jbe/bsw@0 133 local key = string.match(line, '^msgid%s*"(.*)"%s*$')
jbe/bsw@0 134 if key then
jbe/bsw@0 135 local line = next_line()
jbe/bsw@0 136 local value = string.match(line, '^msgstr%s*"(.*)"%s*$')
jbe/bsw@0 137 if not value then
jbe/bsw@0 138 error("Expected msgstr line in po file.")
jbe/bsw@0 139 end
jbe/bsw@0 140 if translations[key] then
jbe/bsw@0 141 error("Duplicate key '" .. key .. "' in po file.")
jbe/bsw@0 142 end
jbe/bsw@0 143 if value == "" then value = false end
jbe@564 144 updates[key] = value
jbe/bsw@0 145 end
jbe/bsw@0 146 end
jbe/bsw@0 147 elseif in_filetype == "lua" then
jbe/bsw@0 148 io.stderr:write('Reading translations from lua file "', in_filename, '".\n')
jbe@64 149 local func
jbe@64 150 if _ENV then
jbe@64 151 func = assert(loadfile(in_filename, "t", {}))
jbe@64 152 else
jbe@64 153 func = assert(loadfile(in_filename))
jbe@64 154 setfenv(func, {})
jbe@64 155 end
jbe@564 156 updates = func()
jbe@564 157 end
jbe@564 158
jbe@564 159 if updates.__parent then
jbe@564 160 for key in pairs(updates) do
jbe@564 161 if translations[key] == nil and key ~= "__parent" then
jbe@564 162 updates[key] = nil
jbe@564 163 end
jbe@564 164 end
jbe@564 165 translations = updates
jbe@564 166 else
jbe/bsw@0 167 for key, value in pairs(updates) do
jbe@564 168 if translations[key] ~= nil or #directories == 0 then
jbe@564 169 translations[key] = value
jbe@564 170 end
jbe/bsw@0 171 end
jbe/bsw@0 172 end
jbe/bsw@0 173
jbe/bsw@0 174 local translation_keys = {}
jbe/bsw@0 175 for key in pairs(translations) do
jbe/bsw@0 176 table.insert(translation_keys, key)
jbe/bsw@0 177 end
jbe/bsw@0 178 table.sort(translation_keys)
jbe/bsw@0 179
jbe/bsw@0 180 if out_filetype == "po" then
jbe/bsw@0 181 io.stderr:write('Writing translations to po file "', out_filename, '".\n')
jbe/bsw@0 182 local file = assert(io.open(out_filename, "w"))
jbe/bsw@0 183 for num, key in ipairs(translation_keys) do
jbe/bsw@0 184 local value = translations[key]
jbe/bsw@0 185 file:write('msgid "', key, '"\nmsgstr "', value or "", '"\n\n')
jbe/bsw@0 186 end
jbe/bsw@0 187 io.close(file)
jbe/bsw@0 188 elseif out_filetype == "lua" then
jbe/bsw@0 189 io.stderr:write('Writing translations to lua file "', out_filename, '".\n')
jbe/bsw@0 190 local file = assert(io.open(out_filename, "w"))
jbe/bsw@0 191 file:write("#!/usr/bin/env lua\n", "return {\n")
jbe/bsw@0 192 for num, key in ipairs(translation_keys) do
jbe/bsw@0 193 local value = translations[key]
jbe/bsw@0 194 if value then
jbe/bsw@4 195 file:write((string.format("[%q] = %q;\n", key, value):gsub("\\\n", "\\n"))) -- double () important to hide second result of gsub
jbe/bsw@0 196 else
jbe/bsw@4 197 file:write((string.format("[%q] = false;\n", key):gsub("\\\n", "\\n"))) -- double () important to hide second result of gsub
jbe/bsw@0 198 end
jbe/bsw@0 199 end
jbe/bsw@0 200 file:write("}\n")
jbe/bsw@0 201 io.close(file)
jbe/bsw@0 202 end

Impressum / About Us