webmcp
view framework/bin/langtool.lua @ 117:82c1daccd7cf
Default to "lua" and "luac" binaries in Makefile.options
| author | jbe | 
|---|---|
| date | Thu Jul 10 00:27:22 2014 +0200 (2014-07-10) | 
| parents | a54cc7dcabf1 | 
| children | 92d9218140f7 | 
 line source
     1 #!/usr/bin/env lua
     3 if not pcall(
     4   function()
     5     extos = 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 extos.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 = extos.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               local key = key:gsub("\\n", "\n")
    98               translations[key] = false
    99             end
   100           end
   101           for key in string.gmatch(line, '_%(?"([^"\]+)"') do
   102             if
   103               key ~= "([^" and
   104               (not string.find(key, "^%s*%.%.[^%.]")) and
   105               (not string.find(key, "^%s*,[^,]"))
   106             then
   107               local key = key:gsub("\\n", "\n")
   108               translations[key] = false
   109             end
   110           end
   111         end
   112       end
   113       traverse(path .. "/" .. filename)
   114     end
   115   end
   116   return true
   117 end
   118 for num, directory in ipairs(directories) do
   119   io.stderr:write('Parsing files in directory "', directory, '".\n')
   120   if not traverse(directory) then
   121     error('Could not read directory "' .. directory .. '".')
   122   end
   123 end
   125 local function update_translation(key, value)
   126   if #directories > 0 then
   127     if translations[key] ~= nil then translations[key] = value end
   128   else
   129     translations[key] = value
   130   end
   131 end
   133 if in_filetype == "po" then
   134   io.stderr:write('Reading translations from po file "', in_filename, '".\n')
   135   local next_line = io.lines(in_filename)
   136   for line in next_line do
   137     if not line then break end
   138     local key = string.match(line, '^msgid%s*"(.*)"%s*$')
   139     if key then
   140       local line = next_line()
   141       local value = string.match(line, '^msgstr%s*"(.*)"%s*$')
   142       if not value then
   143         error("Expected msgstr line in po file.")
   144       end
   145       if translations[key] then
   146         error("Duplicate key '" .. key .. "' in po file.")
   147       end
   148       if value == "" then value = false end
   149       update_translation(key, value)
   150     end
   151   end
   152 elseif in_filetype == "lua" then
   153   io.stderr:write('Reading translations from lua file "', in_filename, '".\n')
   154   local func
   155   if _ENV then
   156     func = assert(loadfile(in_filename, "t", {}))
   157   else
   158     func = assert(loadfile(in_filename))
   159     setfenv(func, {})
   160   end
   161   local updates = func()
   162   for key, value in pairs(updates) do
   163     update_translation(key, value)
   164   end
   165 end
   167 local translation_keys = {}
   168 for key in pairs(translations) do
   169   table.insert(translation_keys, key)
   170 end
   171 table.sort(translation_keys)
   173 if out_filetype == "po" then
   174   io.stderr:write('Writing translations to po file "', out_filename, '".\n')
   175   local file = assert(io.open(out_filename, "w"))
   176   for num, key in ipairs(translation_keys) do
   177     local value = translations[key]
   178     file:write('msgid "', key, '"\nmsgstr "', value or "", '"\n\n')
   179   end
   180   io.close(file)
   181 elseif out_filetype == "lua" then
   182   io.stderr:write('Writing translations to lua file "', out_filename, '".\n')
   183   local file = assert(io.open(out_filename, "w"))
   184   file:write("#!/usr/bin/env lua\n", "return {\n")
   185   for num, key in ipairs(translation_keys) do
   186     local value = translations[key]
   187     if value then
   188       file:write((string.format("[%q] = %q;\n", key, value):gsub("\\\n", "\\n"))) -- double () important to hide second result of gsub
   189     else
   190       file:write((string.format("[%q] = false;\n", key):gsub("\\\n", "\\n"))) -- double () important to hide second result of gsub
   191     end
   192   end
   193   file:write("}\n")
   194   io.close(file)
   195 end
