updatetext.lua 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #! /usr/bin/env lua
  2. local me = arg[0]:gsub(".*[/\\](.*)$", "%1")
  3. local function err(fmt, ...)
  4. io.stderr:write(("%s: %s\n"):format(me, fmt:format(...)))
  5. os.exit(1)
  6. end
  7. local output, outfile, template
  8. local catalogs = { }
  9. local function usage()
  10. print([[
  11. Usage: ]]..me..[[ [OPTIONS] TEMPLATE CATALOG...
  12. Update a catalog with new strings from a template.
  13. Available options:
  14. -h,--help Show this help screen and exit.
  15. -o,--output X Set output file (default: stdout).
  16. Messages in the template that are not on the catalog are added to the
  17. catalog at the end.
  18. This tool also checks messages that are in the catalog but not in the
  19. template, and reports such lines. It's up to the user to remove such
  20. lines, if so desired.
  21. ]])
  22. os.exit(0)
  23. end
  24. local i = 1
  25. while i <= #arg do
  26. local a = arg[i]
  27. if (a == "-h") or (a == "--help") then
  28. usage()
  29. elseif (a == "-o") or (a == "--output") then
  30. i = i + 1
  31. if i > #arg then
  32. err("missing required argument to `%s'", a)
  33. end
  34. output = arg[i]
  35. elseif a:sub(1, 1) ~= "-" then
  36. if not template then
  37. template = a
  38. else
  39. table.insert(catalogs, a)
  40. end
  41. else
  42. err("unrecognized option `%s'", a)
  43. end
  44. i = i + 1
  45. end
  46. if not template then
  47. err("no template specified")
  48. elseif #catalogs == 0 then
  49. err("no catalogs specified")
  50. end
  51. local f, e = io.open(template, "r")
  52. if not f then
  53. err("error opening template: %s", e)
  54. end
  55. local escapes = {
  56. ["\n"] = "@n",
  57. ["="] = "@=",
  58. }
  59. local function escape(s)
  60. local r = s:gsub("\\n", "@n"):gsub("[\n=]", escapes)
  61. if r == "" or not r:sub(1, 1) == "#" then
  62. return r
  63. else
  64. -- Escape '#' at beginning of line
  65. return "@" .. r
  66. end
  67. end
  68. if output then
  69. outfile, e = io.open(output, "w")
  70. if not outfile then
  71. err("error opening file for writing: %s", e)
  72. end
  73. end
  74. local function load_strings(file)
  75. local infile, e = io.open(file, "r")
  76. local messages = {}
  77. local textdomain = ""
  78. messages[""] = {}
  79. if infile then
  80. for line in infile:lines() do
  81. for td in line:gmatch('# textdomain: (%S+)') do
  82. textdomain = td
  83. messages[textdomain] = messages[textdomain] or {}
  84. end
  85. if not (line == "" or line:sub(1, 1) == "#") then
  86. local i = 1
  87. while i < line:len() do
  88. if line:sub(i, i) == "@" then
  89. i = i + 2
  90. elseif line:sub(i, i) == "=" then
  91. break
  92. else
  93. i = i + 1
  94. end
  95. end
  96. local untranslated = line:sub(1, i - 1)
  97. local translated = line:sub(i + 1)
  98. messages[textdomain][untranslated] = translated
  99. print(file, textdomain, untranslated, translated)
  100. end
  101. end
  102. infile:close()
  103. else
  104. io.stderr:write(("%s: WARNING: error opening file: %s\n"):format(me, e))
  105. end
  106. return messages
  107. end
  108. local template_msgs = load_strings(template)
  109. for _, file in ipairs(catalogs) do
  110. print("Processing: "..file)
  111. local catalog_msgs = load_strings(file)
  112. local dirty_lines = {}
  113. local dirty = false
  114. if catalog_msgs then
  115. -- Add new entries from template.
  116. for textdomain, tm in pairs(template_msgs) do
  117. for k in pairs(tm) do
  118. if not catalog_msgs[textdomain][k] then
  119. print("NEW: "..textdomain.." "..k)
  120. dirty_lines[textdomain] = dirty_lines[textdomain] or {}
  121. table.insert(dirty_lines[textdomain], k.."=")
  122. dirty = true
  123. end
  124. end
  125. end
  126. -- Check for old messages.
  127. for textdomain, cm in pairs(catalog_msgs) do
  128. for k, v in pairs(cm) do
  129. if not template_msgs[textdomain][k] then
  130. print("OLD: "..textdomain.." "..k)
  131. dirty_lines[textdomain] = dirty_lines[textdomain] or {}
  132. table.insert(dirty_lines[textdomain], "# OLD: "..k.."="..v)
  133. dirty = true
  134. end
  135. end
  136. end
  137. if dirty then
  138. local outf
  139. outf, e = io.open(file, "a+")
  140. if outf then
  141. for textdomain, dl in pairs(dirty_lines) do
  142. outf:write("\n")
  143. outf:write("# textdomain: " .. textdomain .. "\n")
  144. for _, line in ipairs(dl) do
  145. outf:write(line)
  146. outf:write("\n")
  147. end
  148. end
  149. outf:close()
  150. else
  151. io.stderr:write(("%s: WARNING: cannot write: %s\n"):format(me, e))
  152. end
  153. end
  154. else
  155. io.stderr:write(("%s: WARNING: could not load catalog\n"):format(me))
  156. end
  157. end