webmcp

diff 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 diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/framework/bin/langtool.lua	Sun Oct 25 12:00:00 2009 +0100
     1.3 @@ -0,0 +1,188 @@
     1.4 +#!/usr/bin/env lua
     1.5 +
     1.6 +if not pcall(
     1.7 +  function()
     1.8 +    require "extos"
     1.9 +  end
    1.10 +) then
    1.11 +  io.stderr:write('Could not load library "extos".\n')
    1.12 +  io.stderr:write('Hint: Set LUA_CPATH="/path_to_extos_library/?.so;;"\n')
    1.13 +end
    1.14 +
    1.15 +
    1.16 +local args = {...}
    1.17 +
    1.18 +if #args == 0 then
    1.19 +  print()
    1.20 +  print("This program creates translation files by traversing source directories.")
    1.21 +  print()
    1.22 +  print("Two formats are supported: lua files and po files.")
    1.23 +  print("At runtime a lua file is needed.")
    1.24 +  print("For use with po-file editors you may want to create po files first though.")
    1.25 +  print()
    1.26 +  print("Create or update a lua file: langtool.lua dir1/ dir2/ ... <basename>.lua")
    1.27 +  print("Create or update a po file:  langtool.lua dir1/ dir2/ ... <basename>.po")
    1.28 +  print("Convert po file to lua file: langtool.lua <basename>.po <basename>.lua")
    1.29 +  print("Convert lua file to po file: langtool.lua <basename>.lua <basename>.po")
    1.30 +  print()
    1.31 +end
    1.32 +
    1.33 +local in_filename, in_filetype, out_filename, out_filetype
    1.34 +local directories = {}
    1.35 +
    1.36 +for arg_num, arg in ipairs(args) do
    1.37 +  local function arg_error(msg)
    1.38 +    error("Illegal command line argument #" .. arg_num .. ": " .. msg)
    1.39 +  end
    1.40 +  local po = string.match(arg, "^po:(.*)$") or string.match(arg, "^(.*%.po)$")
    1.41 +  local lua = string.match(arg, "^lua:(.*)$") or string.match(arg, "^(.*%.lua)$")
    1.42 +  local filetype
    1.43 +  if po and not lua then filetype = "po"
    1.44 +    filetype = "po"
    1.45 +  elseif lua and not po then filetype = "lua"
    1.46 +    filetype = "lua"
    1.47 +  else
    1.48 +    filetype = "path"
    1.49 +  end
    1.50 +  if filetype == "path" then
    1.51 +    table.insert(directories, arg)
    1.52 +  elseif filetype == "po" or filetype == "lua" then
    1.53 +    if not out_filename then
    1.54 +      out_filename = arg
    1.55 +      out_filetype = filetype
    1.56 +    elseif not in_filename then
    1.57 +      in_filename = out_filename
    1.58 +      in_filetype = out_filetype
    1.59 +      out_filename = arg
    1.60 +      out_filetype = filetype
    1.61 +    else
    1.62 +      arg_error("Only two language files (one input and one output file) can be specified.")
    1.63 +    end
    1.64 +  else
    1.65 +    -- should not happen, as default type is "path"
    1.66 +    arg_error("Type not recognized")
    1.67 +  end
    1.68 +end
    1.69 +
    1.70 +if #directories > 0 and not os.listdir then
    1.71 +  io.stderr:write('Fatal: Cannot traverse directories without "extos" library -> Abort\n')
    1.72 +  os.exit(1)
    1.73 +end
    1.74 +
    1.75 +if out_filename and not in_filename then
    1.76 +  local file = io.open(out_filename, "r")
    1.77 +  if file then
    1.78 +    in_filename = out_filename
    1.79 +    in_filetype = out_filetype
    1.80 +    file:close()
    1.81 +  end
    1.82 +end
    1.83 +
    1.84 +local translations = { }
    1.85 +
    1.86 +local function traverse(path)
    1.87 +  local filenames = os.listdir(path)
    1.88 +  if not filenames then return false end
    1.89 +  for num, filename in ipairs(filenames) do
    1.90 +    if not string.find(filename, "^%.") then
    1.91 +      if string.find(filename, "%.lua$") then
    1.92 +        for line in io.lines(path .. "/" .. filename) do
    1.93 +          -- TODO: exact parsing of comments and escape characters
    1.94 +          for key in string.gmatch(line, "_%(?'([^'\]+)'") do
    1.95 +            if
    1.96 +              key ~= "([^" and
    1.97 +              (not string.find(key, "^%s*%.%.[^%.]")) and
    1.98 +              (not string.find(key, "^%s*,[^,]"))
    1.99 +            then
   1.100 +              translations[key] = false
   1.101 +            end
   1.102 +          end
   1.103 +          for key in string.gmatch(line, '_%(?"([^"\]+)"') do
   1.104 +            if
   1.105 +              key ~= "([^" and
   1.106 +              (not string.find(key, "^%s*%.%.[^%.]")) and
   1.107 +              (not string.find(key, "^%s*,[^,]"))
   1.108 +            then
   1.109 +              translations[key] = false
   1.110 +            end
   1.111 +          end
   1.112 +        end
   1.113 +      end
   1.114 +      traverse(path .. "/" .. filename)
   1.115 +    end
   1.116 +  end
   1.117 +  return true
   1.118 +end
   1.119 +for num, directory in ipairs(directories) do
   1.120 +  io.stderr:write('Parsing files in directory "', directory, '".\n')
   1.121 +  if not traverse(directory) then
   1.122 +    error('Could not read directory "' .. directory .. '".')
   1.123 +  end
   1.124 +end
   1.125 +
   1.126 +local function update_translation(key, value)
   1.127 +  if #directories > 0 then
   1.128 +    if translations[key] ~= nil then translations[key] = value end
   1.129 +  else
   1.130 +    translations[key] = value
   1.131 +  end
   1.132 +end
   1.133 +
   1.134 +if in_filetype == "po" then
   1.135 +  io.stderr:write('Reading translations from po file "', in_filename, '".\n')
   1.136 +  local next_line = io.lines(in_filename)
   1.137 +  for line in next_line do
   1.138 +    if not line then break end
   1.139 +    local key = string.match(line, '^msgid%s*"(.*)"%s*$')
   1.140 +    if key then
   1.141 +      local line = next_line()
   1.142 +      local value = string.match(line, '^msgstr%s*"(.*)"%s*$')
   1.143 +      if not value then
   1.144 +        error("Expected msgstr line in po file.")
   1.145 +      end
   1.146 +      if translations[key] then
   1.147 +        error("Duplicate key '" .. key .. "' in po file.")
   1.148 +      end
   1.149 +      if value == "" then value = false end
   1.150 +      update_translation(key, value)
   1.151 +    end
   1.152 +  end
   1.153 +elseif in_filetype == "lua" then
   1.154 +  io.stderr:write('Reading translations from lua file "', in_filename, '".\n')
   1.155 +  local func = assert(loadfile(in_filename))
   1.156 +  setfenv(func, {})
   1.157 +  local updates = func()
   1.158 +  for key, value in pairs(updates) do
   1.159 +    update_translation(key, value)
   1.160 +  end
   1.161 +end
   1.162 +
   1.163 +local translation_keys = {}
   1.164 +for key in pairs(translations) do
   1.165 +  table.insert(translation_keys, key)
   1.166 +end
   1.167 +table.sort(translation_keys)
   1.168 +
   1.169 +if out_filetype == "po" then
   1.170 +  io.stderr:write('Writing translations to po file "', out_filename, '".\n')
   1.171 +  local file = assert(io.open(out_filename, "w"))
   1.172 +  for num, key in ipairs(translation_keys) do
   1.173 +    local value = translations[key]
   1.174 +    file:write('msgid "', key, '"\nmsgstr "', value or "", '"\n\n')
   1.175 +  end
   1.176 +  io.close(file)
   1.177 +elseif out_filetype == "lua" then
   1.178 +  io.stderr:write('Writing translations to lua file "', out_filename, '".\n')
   1.179 +  local file = assert(io.open(out_filename, "w"))
   1.180 +  file:write("#!/usr/bin/env lua\n", "return {\n")
   1.181 +  for num, key in ipairs(translation_keys) do
   1.182 +    local value = translations[key]
   1.183 +    if value then
   1.184 +      file:write(string.format("[%q] = %q;\n", key, value))
   1.185 +    else
   1.186 +      file:write(string.format("[%q] = false;\n", key))
   1.187 +    end
   1.188 +  end
   1.189 +  file:write("}\n")
   1.190 +  io.close(file)
   1.191 +end

Impressum / About Us