ofm_gettext 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (384) hide show
  1. data/ChangeLog +78 -0
  2. data/README.rdoc +245 -0
  3. data/Rakefile +234 -0
  4. data/bin/rgettext +23 -0
  5. data/bin/rmsgfmt +22 -0
  6. data/bin/rmsgmerge +22 -0
  7. data/gettext.gemspec +40 -0
  8. data/lib/gettext/cgi.rb +39 -0
  9. data/lib/gettext/core_ext/iconv.rb +110 -0
  10. data/lib/gettext/core_ext/string.rb +86 -0
  11. data/lib/gettext/parser/erb.rb +5 -0
  12. data/lib/gettext/parser/glade.rb +5 -0
  13. data/lib/gettext/parser/ruby.rb +172 -0
  14. data/lib/gettext/tools/rgettext.rb +251 -0
  15. data/lib/gettext/tools/rmsgfmt.rb +86 -0
  16. data/lib/gettext/tools/rmsgmerge.rb +500 -0
  17. data/lib/gettext/tools.rb +197 -0
  18. data/lib/gettext/utils.rb +39 -0
  19. data/lib/gettext/version.rb +12 -0
  20. data/lib/gettext.rb +312 -0
  21. data/po/bg/rgettext.po +139 -0
  22. data/po/bs/rgettext.po +139 -0
  23. data/po/ca/rgettext.po +138 -0
  24. data/po/cs/rgettext.po +140 -0
  25. data/po/de/rgettext.po +146 -0
  26. data/po/el/rgettext.po +137 -0
  27. data/po/eo/rgettext.po +138 -0
  28. data/po/es/rgettext.po +139 -0
  29. data/po/et/rgettext.po +136 -0
  30. data/po/fr/rgettext.po +142 -0
  31. data/po/hr/rgettext.po +139 -0
  32. data/po/hu/rgettext.po +138 -0
  33. data/po/it/rgettext.po +138 -0
  34. data/po/ja/rgettext.po +140 -0
  35. data/po/ko/rgettext.po +137 -0
  36. data/po/lv/rgettext.po +139 -0
  37. data/po/nb/rgettext.po +140 -0
  38. data/po/nl/rgettext.po +138 -0
  39. data/po/pt_BR/rgettext.po +141 -0
  40. data/po/rgettext.pot +129 -0
  41. data/po/ru/rgettext.po +140 -0
  42. data/po/sr/rgettext.po +139 -0
  43. data/po/sv/rgettext.po +131 -0
  44. data/po/vi/rgettext.po +137 -0
  45. data/po/zh/rgettext.po +138 -0
  46. data/po/zh_TW/rgettext.po +137 -0
  47. data/samples/README +16 -0
  48. data/samples/cgi/README +43 -0
  49. data/samples/cgi/Rakefile +27 -0
  50. data/samples/cgi/cookie.cgi +64 -0
  51. data/samples/cgi/gettext.css +116 -0
  52. data/samples/cgi/helloerb.rhtml +28 -0
  53. data/samples/cgi/helloerb1.cgi +58 -0
  54. data/samples/cgi/helloerb2.cgi +51 -0
  55. data/samples/cgi/hellolib.rb +18 -0
  56. data/samples/cgi/http.rb +49 -0
  57. data/samples/cgi/index.cgi +111 -0
  58. data/samples/cgi/other.rhtml +20 -0
  59. data/samples/cgi/po/bg/helloerb1.po +59 -0
  60. data/samples/cgi/po/bg/helloerb2.po +51 -0
  61. data/samples/cgi/po/bg/hellolib.po +23 -0
  62. data/samples/cgi/po/bg/main.po +83 -0
  63. data/samples/cgi/po/bs/helloerb1.po +59 -0
  64. data/samples/cgi/po/bs/helloerb2.po +51 -0
  65. data/samples/cgi/po/bs/hellolib.po +23 -0
  66. data/samples/cgi/po/bs/main.po +83 -0
  67. data/samples/cgi/po/ca/helloerb1.po +59 -0
  68. data/samples/cgi/po/ca/helloerb2.po +51 -0
  69. data/samples/cgi/po/ca/hellolib.po +23 -0
  70. data/samples/cgi/po/ca/main.po +83 -0
  71. data/samples/cgi/po/cs/helloerb1.po +61 -0
  72. data/samples/cgi/po/cs/helloerb2.po +52 -0
  73. data/samples/cgi/po/cs/hellolib.po +25 -0
  74. data/samples/cgi/po/cs/main.po +85 -0
  75. data/samples/cgi/po/de/helloerb1.po +61 -0
  76. data/samples/cgi/po/de/helloerb2.po +52 -0
  77. data/samples/cgi/po/de/hellolib.po +24 -0
  78. data/samples/cgi/po/de/main.po +86 -0
  79. data/samples/cgi/po/el/helloerb1.po +60 -0
  80. data/samples/cgi/po/el/helloerb2.po +51 -0
  81. data/samples/cgi/po/el/hellolib.po +23 -0
  82. data/samples/cgi/po/el/main.po +84 -0
  83. data/samples/cgi/po/eo/helloerb1.po +60 -0
  84. data/samples/cgi/po/eo/helloerb2.po +52 -0
  85. data/samples/cgi/po/eo/hellolib.po +24 -0
  86. data/samples/cgi/po/eo/main.po +84 -0
  87. data/samples/cgi/po/es/helloerb1.po +59 -0
  88. data/samples/cgi/po/es/helloerb2.po +50 -0
  89. data/samples/cgi/po/es/hellolib.po +22 -0
  90. data/samples/cgi/po/es/main.po +83 -0
  91. data/samples/cgi/po/fr/helloerb1.po +59 -0
  92. data/samples/cgi/po/fr/helloerb2.po +51 -0
  93. data/samples/cgi/po/fr/hellolib.po +22 -0
  94. data/samples/cgi/po/fr/main.po +85 -0
  95. data/samples/cgi/po/helloerb1.pot +60 -0
  96. data/samples/cgi/po/helloerb2.pot +52 -0
  97. data/samples/cgi/po/hellolib.pot +24 -0
  98. data/samples/cgi/po/hr/helloerb1.po +59 -0
  99. data/samples/cgi/po/hr/helloerb2.po +51 -0
  100. data/samples/cgi/po/hr/hellolib.po +23 -0
  101. data/samples/cgi/po/hr/main.po +83 -0
  102. data/samples/cgi/po/hu/helloerb1.po +59 -0
  103. data/samples/cgi/po/hu/helloerb2.po +51 -0
  104. data/samples/cgi/po/hu/hellolib.po +23 -0
  105. data/samples/cgi/po/hu/main.po +82 -0
  106. data/samples/cgi/po/it/helloerb1.po +60 -0
  107. data/samples/cgi/po/it/helloerb2.po +52 -0
  108. data/samples/cgi/po/it/hellolib.po +24 -0
  109. data/samples/cgi/po/it/main.po +84 -0
  110. data/samples/cgi/po/ja/helloerb1.po +60 -0
  111. data/samples/cgi/po/ja/helloerb2.po +52 -0
  112. data/samples/cgi/po/ja/hellolib.po +24 -0
  113. data/samples/cgi/po/ja/main.po +85 -0
  114. data/samples/cgi/po/ko/helloerb1.po +59 -0
  115. data/samples/cgi/po/ko/helloerb2.po +51 -0
  116. data/samples/cgi/po/ko/hellolib.po +23 -0
  117. data/samples/cgi/po/ko/main.po +84 -0
  118. data/samples/cgi/po/lv/helloerb1.po +65 -0
  119. data/samples/cgi/po/lv/helloerb2.po +52 -0
  120. data/samples/cgi/po/lv/hellolib.po +24 -0
  121. data/samples/cgi/po/lv/main.po +77 -0
  122. data/samples/cgi/po/main.pot +80 -0
  123. data/samples/cgi/po/nb/helloerb1.po +60 -0
  124. data/samples/cgi/po/nb/helloerb2.po +52 -0
  125. data/samples/cgi/po/nb/hellolib.po +24 -0
  126. data/samples/cgi/po/nb/main.po +84 -0
  127. data/samples/cgi/po/nl/helloerb1.po +61 -0
  128. data/samples/cgi/po/nl/helloerb2.po +52 -0
  129. data/samples/cgi/po/nl/hellolib.po +24 -0
  130. data/samples/cgi/po/nl/main.po +86 -0
  131. data/samples/cgi/po/pt_BR/helloerb1.po +59 -0
  132. data/samples/cgi/po/pt_BR/helloerb2.po +51 -0
  133. data/samples/cgi/po/pt_BR/hellolib.po +23 -0
  134. data/samples/cgi/po/pt_BR/main.po +84 -0
  135. data/samples/cgi/po/ru/helloerb1.po +58 -0
  136. data/samples/cgi/po/ru/helloerb2.po +50 -0
  137. data/samples/cgi/po/ru/hellolib.po +22 -0
  138. data/samples/cgi/po/ru/main.po +82 -0
  139. data/samples/cgi/po/sr/helloerb1.po +60 -0
  140. data/samples/cgi/po/sr/helloerb2.po +52 -0
  141. data/samples/cgi/po/sr/hellolib.po +24 -0
  142. data/samples/cgi/po/sr/main.po +80 -0
  143. data/samples/cgi/po/vi/helloerb1.po +65 -0
  144. data/samples/cgi/po/vi/helloerb2.po +52 -0
  145. data/samples/cgi/po/vi/hellolib.po +24 -0
  146. data/samples/cgi/po/vi/main.po +77 -0
  147. data/samples/cgi/po/zh/helloerb1.po +60 -0
  148. data/samples/cgi/po/zh/helloerb2.po +52 -0
  149. data/samples/cgi/po/zh/hellolib.po +24 -0
  150. data/samples/cgi/po/zh/main.po +80 -0
  151. data/samples/cgi/po/zh_TW/helloerb1.po +67 -0
  152. data/samples/cgi/po/zh_TW/helloerb2.po +54 -0
  153. data/samples/cgi/po/zh_TW/hellolib.po +26 -0
  154. data/samples/cgi/po/zh_TW/main.po +79 -0
  155. data/samples/hello.rb +36 -0
  156. data/samples/hello2.rb +23 -0
  157. data/samples/hello_glade2.glade +70 -0
  158. data/samples/hello_glade2.rb +25 -0
  159. data/samples/hello_gtk2.rb +27 -0
  160. data/samples/hello_noop.rb +31 -0
  161. data/samples/hello_plural.rb +26 -0
  162. data/samples/hello_tk.rb +19 -0
  163. data/samples/makemo.rb +6 -0
  164. data/samples/po/bg/hello.po +24 -0
  165. data/samples/po/bg/hello2.po +31 -0
  166. data/samples/po/bg/hello_glade2.po +31 -0
  167. data/samples/po/bg/hello_gtk.po +23 -0
  168. data/samples/po/bg/hello_noop.po +27 -0
  169. data/samples/po/bg/hello_plural.po +25 -0
  170. data/samples/po/bg/hello_tk.po +23 -0
  171. data/samples/po/bs/hello.po +23 -0
  172. data/samples/po/bs/hello2.po +31 -0
  173. data/samples/po/bs/hello_glade2.po +31 -0
  174. data/samples/po/bs/hello_gtk.po +23 -0
  175. data/samples/po/bs/hello_noop.po +27 -0
  176. data/samples/po/bs/hello_plural.po +26 -0
  177. data/samples/po/bs/hello_tk.po +23 -0
  178. data/samples/po/ca/hello.po +23 -0
  179. data/samples/po/ca/hello2.po +31 -0
  180. data/samples/po/ca/hello_glade2.po +31 -0
  181. data/samples/po/ca/hello_gtk.po +23 -0
  182. data/samples/po/ca/hello_noop.po +27 -0
  183. data/samples/po/ca/hello_plural.po +25 -0
  184. data/samples/po/ca/hello_tk.po +23 -0
  185. data/samples/po/cs/hello.po +23 -0
  186. data/samples/po/cs/hello2.po +31 -0
  187. data/samples/po/cs/hello_glade2.po +37 -0
  188. data/samples/po/cs/hello_gtk.po +23 -0
  189. data/samples/po/cs/hello_noop.po +27 -0
  190. data/samples/po/cs/hello_plural.po +26 -0
  191. data/samples/po/cs/hello_tk.po +23 -0
  192. data/samples/po/de/hello.po +20 -0
  193. data/samples/po/de/hello2.po +28 -0
  194. data/samples/po/de/hello_glade2.po +27 -0
  195. data/samples/po/de/hello_gtk.po +20 -0
  196. data/samples/po/de/hello_noop.po +24 -0
  197. data/samples/po/de/hello_plural.po +25 -0
  198. data/samples/po/de/hello_tk.po +20 -0
  199. data/samples/po/el/hello.po +23 -0
  200. data/samples/po/el/hello2.po +31 -0
  201. data/samples/po/el/hello_glade2.po +31 -0
  202. data/samples/po/el/hello_gtk.po +22 -0
  203. data/samples/po/el/hello_noop.po +27 -0
  204. data/samples/po/el/hello_plural.po +25 -0
  205. data/samples/po/el/hello_tk.po +23 -0
  206. data/samples/po/eo/hello.po +23 -0
  207. data/samples/po/eo/hello2.po +31 -0
  208. data/samples/po/eo/hello_glade2.po +32 -0
  209. data/samples/po/eo/hello_gtk.po +23 -0
  210. data/samples/po/eo/hello_noop.po +27 -0
  211. data/samples/po/eo/hello_plural.po +26 -0
  212. data/samples/po/eo/hello_tk.po +24 -0
  213. data/samples/po/es/hello.po +21 -0
  214. data/samples/po/es/hello2.po +28 -0
  215. data/samples/po/es/hello_glade2.po +28 -0
  216. data/samples/po/es/hello_gtk.po +20 -0
  217. data/samples/po/es/hello_noop.po +24 -0
  218. data/samples/po/es/hello_plural.po +23 -0
  219. data/samples/po/es/hello_tk.po +20 -0
  220. data/samples/po/fr/hello.po +18 -0
  221. data/samples/po/fr/hello2.po +26 -0
  222. data/samples/po/fr/hello_glade2.po +27 -0
  223. data/samples/po/fr/hello_gtk.po +18 -0
  224. data/samples/po/fr/hello_noop.po +22 -0
  225. data/samples/po/fr/hello_plural.po +21 -0
  226. data/samples/po/fr/hello_tk.po +18 -0
  227. data/samples/po/hello.pot +23 -0
  228. data/samples/po/hello2.pot +31 -0
  229. data/samples/po/hello_glade2.pot +32 -0
  230. data/samples/po/hello_gtk.pot +23 -0
  231. data/samples/po/hello_noop.pot +27 -0
  232. data/samples/po/hello_plural.pot +26 -0
  233. data/samples/po/hello_tk.pot +24 -0
  234. data/samples/po/hr/hello.po +23 -0
  235. data/samples/po/hr/hello2.po +31 -0
  236. data/samples/po/hr/hello_glade2.po +31 -0
  237. data/samples/po/hr/hello_gtk.po +23 -0
  238. data/samples/po/hr/hello_noop.po +27 -0
  239. data/samples/po/hr/hello_plural.po +26 -0
  240. data/samples/po/hr/hello_tk.po +23 -0
  241. data/samples/po/hu/hello.po +22 -0
  242. data/samples/po/hu/hello2.po +30 -0
  243. data/samples/po/hu/hello_glade2.po +31 -0
  244. data/samples/po/hu/hello_gtk.po +22 -0
  245. data/samples/po/hu/hello_noop.po +26 -0
  246. data/samples/po/hu/hello_plural.po +25 -0
  247. data/samples/po/hu/hello_tk.po +23 -0
  248. data/samples/po/it/hello.po +20 -0
  249. data/samples/po/it/hello2.po +28 -0
  250. data/samples/po/it/hello_glade2.po +28 -0
  251. data/samples/po/it/hello_gtk.po +21 -0
  252. data/samples/po/it/hello_noop.po +24 -0
  253. data/samples/po/it/hello_plural.po +23 -0
  254. data/samples/po/it/hello_tk.po +21 -0
  255. data/samples/po/ja/hello.po +20 -0
  256. data/samples/po/ja/hello2.po +28 -0
  257. data/samples/po/ja/hello_glade2.po +26 -0
  258. data/samples/po/ja/hello_gtk.po +19 -0
  259. data/samples/po/ja/hello_noop.po +23 -0
  260. data/samples/po/ja/hello_plural.po +21 -0
  261. data/samples/po/ja/hello_tk.po +19 -0
  262. data/samples/po/ko/hello.po +18 -0
  263. data/samples/po/ko/hello2.po +26 -0
  264. data/samples/po/ko/hello_glade2.po +29 -0
  265. data/samples/po/ko/hello_gtk.po +18 -0
  266. data/samples/po/ko/hello_noop.po +22 -0
  267. data/samples/po/ko/hello_plural.po +25 -0
  268. data/samples/po/ko/hello_tk.po +19 -0
  269. data/samples/po/lv/hello.po +24 -0
  270. data/samples/po/lv/hello2.po +32 -0
  271. data/samples/po/lv/hello_glade2.po +38 -0
  272. data/samples/po/lv/hello_gtk.po +24 -0
  273. data/samples/po/lv/hello_noop.po +28 -0
  274. data/samples/po/lv/hello_plural.po +26 -0
  275. data/samples/po/lv/hello_tk.po +24 -0
  276. data/samples/po/nb/hello.po +23 -0
  277. data/samples/po/nb/hello2.po +31 -0
  278. data/samples/po/nb/hello_glade2.po +31 -0
  279. data/samples/po/nb/hello_gtk.po +23 -0
  280. data/samples/po/nb/hello_noop.po +27 -0
  281. data/samples/po/nb/hello_plural.po +26 -0
  282. data/samples/po/nb/hello_tk.po +24 -0
  283. data/samples/po/nl/hello.po +24 -0
  284. data/samples/po/nl/hello2.po +32 -0
  285. data/samples/po/nl/hello_glade2.po +31 -0
  286. data/samples/po/nl/hello_gtk.po +24 -0
  287. data/samples/po/nl/hello_noop.po +28 -0
  288. data/samples/po/nl/hello_plural.po +25 -0
  289. data/samples/po/nl/hello_tk.po +24 -0
  290. data/samples/po/pt_BR/hello.po +21 -0
  291. data/samples/po/pt_BR/hello2.po +29 -0
  292. data/samples/po/pt_BR/hello_glade2.po +29 -0
  293. data/samples/po/pt_BR/hello_gtk.po +21 -0
  294. data/samples/po/pt_BR/hello_noop.po +25 -0
  295. data/samples/po/pt_BR/hello_plural.po +23 -0
  296. data/samples/po/pt_BR/hello_tk.po +21 -0
  297. data/samples/po/ru/hello.po +22 -0
  298. data/samples/po/ru/hello2.po +30 -0
  299. data/samples/po/ru/hello_glade2.po +30 -0
  300. data/samples/po/ru/hello_gtk.po +22 -0
  301. data/samples/po/ru/hello_noop.po +26 -0
  302. data/samples/po/ru/hello_plural.po +28 -0
  303. data/samples/po/ru/hello_tk.po +22 -0
  304. data/samples/po/sr/hello.po +22 -0
  305. data/samples/po/sr/hello2.po +30 -0
  306. data/samples/po/sr/hello_glade2.po +32 -0
  307. data/samples/po/sr/hello_gtk.po +22 -0
  308. data/samples/po/sr/hello_noop.po +26 -0
  309. data/samples/po/sr/hello_plural.po +26 -0
  310. data/samples/po/sr/hello_tk.po +24 -0
  311. data/samples/po/sv/hello.po +20 -0
  312. data/samples/po/sv/hello2.po +28 -0
  313. data/samples/po/sv/hello_glade2.po +28 -0
  314. data/samples/po/sv/hello_gtk.po +20 -0
  315. data/samples/po/sv/hello_noop.po +24 -0
  316. data/samples/po/sv/hello_plural.po +23 -0
  317. data/samples/po/sv/hello_tk.po +20 -0
  318. data/samples/po/test.rb +13 -0
  319. data/samples/po/vi/hello.po +23 -0
  320. data/samples/po/vi/hello2.po +31 -0
  321. data/samples/po/vi/hello_glade2.po +38 -0
  322. data/samples/po/vi/hello_gtk.po +23 -0
  323. data/samples/po/vi/hello_noop.po +27 -0
  324. data/samples/po/vi/hello_plural.po +26 -0
  325. data/samples/po/vi/hello_tk.po +24 -0
  326. data/samples/po/zh/hello.po +23 -0
  327. data/samples/po/zh/hello2.po +31 -0
  328. data/samples/po/zh/hello_glade2.po +31 -0
  329. data/samples/po/zh/hello_gtk.po +23 -0
  330. data/samples/po/zh/hello_noop.po +27 -0
  331. data/samples/po/zh/hello_plural.po +25 -0
  332. data/samples/po/zh/hello_tk.po +23 -0
  333. data/samples/po/zh_TW/hello.po +26 -0
  334. data/samples/po/zh_TW/hello2.po +34 -0
  335. data/samples/po/zh_TW/hello_glade2.po +40 -0
  336. data/samples/po/zh_TW/hello_gtk.po +25 -0
  337. data/samples/po/zh_TW/hello_noop.po +30 -0
  338. data/samples/po/zh_TW/hello_plural.po +28 -0
  339. data/samples/po/zh_TW/hello_tk.po +26 -0
  340. data/src/poparser.ry +217 -0
  341. data/test/README +1 -0
  342. data/test/Rakefile +17 -0
  343. data/test/po/cr/plural.po +23 -0
  344. data/test/po/da/plural.po +22 -0
  345. data/test/po/da/plural_error.po +22 -0
  346. data/test/po/fr/plural.po +28 -0
  347. data/test/po/fr/plural_error.po +20 -0
  348. data/test/po/fr/test1.po +23 -0
  349. data/test/po/fr/test2.po +19 -0
  350. data/test/po/ir/plural.po +23 -0
  351. data/test/po/ja/npgettext.po +46 -0
  352. data/test/po/ja/nsgettext.po +65 -0
  353. data/test/po/ja/pgettext.po +41 -0
  354. data/test/po/ja/plural.po +28 -0
  355. data/test/po/ja/plural_error.po +20 -0
  356. data/test/po/ja/rubyparser.po +43 -0
  357. data/test/po/ja/sgettext.po +47 -0
  358. data/test/po/ja/test1.po +23 -0
  359. data/test/po/ja/test2.po +19 -0
  360. data/test/po/la/plural.po +23 -0
  361. data/test/po/la/plural_error.po +21 -0
  362. data/test/po/li/plural.po +23 -0
  363. data/test/po/po/plural.po +23 -0
  364. data/test/po/sl/plural.po +24 -0
  365. data/test/test_class_info.rb +88 -0
  366. data/test/test_gettext.rb +322 -0
  367. data/test/test_parser.rb +160 -0
  368. data/test/test_string.rb +67 -0
  369. data/test/test_textdomain_multi.rb +82 -0
  370. data/test/test_textdomain_toplevel.rb +44 -0
  371. data/test/testlib/N_.rb +68 -0
  372. data/test/testlib/erb.rhtml +15 -0
  373. data/test/testlib/erb.rxml +16 -0
  374. data/test/testlib/gettext.rb +115 -0
  375. data/test/testlib/gladeparser.glade +183 -0
  376. data/test/testlib/helper.rb +13 -0
  377. data/test/testlib/multi_textdomain.rb +133 -0
  378. data/test/testlib/ngettext.rb +81 -0
  379. data/test/testlib/npgettext.rb +33 -0
  380. data/test/testlib/nsgettext.rb +44 -0
  381. data/test/testlib/pgettext.rb +38 -0
  382. data/test/testlib/sgettext.rb +48 -0
  383. data/test/testlib/simple.rb +16 -0
  384. metadata +475 -0
@@ -0,0 +1,500 @@
1
+ # encoding: utf-8
2
+
3
+ =begin
4
+ rmsgmerge.rb - Merge old .po to new .po
5
+
6
+ Copyright (C) 2005-2009 Masao Mutoh
7
+ Copyright (C) 2005,2006 speakillof
8
+
9
+ You may redistribute it and/or modify it under the same
10
+ license terms as Ruby or LGPL.
11
+ =end
12
+
13
+ require 'optparse'
14
+ require 'gettext'
15
+ require 'gettext/tools/poparser'
16
+ require 'rbconfig'
17
+
18
+ module GetText
19
+
20
+ module RMsgMerge
21
+
22
+ class PoData #:nodoc:
23
+
24
+ attr_reader :msgids
25
+
26
+ def initialize
27
+ @msgid2msgstr = {}
28
+ @msgid2comment = {}
29
+ @msgids = []
30
+ end
31
+
32
+ def set_comment(msgid_or_sym, comment)
33
+ @msgid2comment[msgid_or_sym] = comment
34
+ end
35
+
36
+ def msgstr(msgid)
37
+ @msgid2msgstr[msgid]
38
+ end
39
+
40
+ def comment(msgid)
41
+ @msgid2comment[msgid]
42
+ end
43
+
44
+ def [](msgid)
45
+ @msgid2msgstr[msgid]
46
+ end
47
+
48
+ def []=(msgid, msgstr)
49
+ # Retain the order
50
+ unless @msgid2msgstr[msgid]
51
+ @msgids << msgid
52
+ end
53
+
54
+ @msgid2msgstr[msgid] = msgstr
55
+ end
56
+
57
+ def each_msgid
58
+ arr = @msgids.delete_if{|i| Symbol === i or i == ''}
59
+ arr.each do |i|
60
+ yield i
61
+ end
62
+ end
63
+
64
+ def msgid?(msgid)
65
+ !(Symbol === msgid) and @msgid2msgstr[msgid] and (msgid != '')
66
+ end
67
+
68
+ # Is it necessary to implement this method?
69
+ def search_msgid_fuzzy(msgid, used_msgids)
70
+ nil
71
+ end
72
+
73
+ def nplural
74
+ unless @msgid2msgstr['']
75
+ return 0
76
+ else
77
+ if /\s*nplural\s*=\s*(\d+)/ =~ @msgid2msgstr['']
78
+ return $1.to_i
79
+ else
80
+ return 0
81
+ end
82
+
83
+ end
84
+ end
85
+
86
+ def generate_po
87
+ str = ''
88
+ str << generate_po_header
89
+
90
+ self.each_msgid do |id|
91
+ str << self.generate_po_entry(id)
92
+ end
93
+
94
+ str << @msgid2comment[:last]
95
+ str
96
+ end
97
+
98
+ def generate_po_header
99
+ str = ""
100
+
101
+ str << @msgid2comment[''].strip << "\n"
102
+ str << 'msgid ""' << "\n"
103
+ str << 'msgstr ""' << "\n"
104
+ msgstr = @msgid2msgstr[''].gsub(/"/, '\"').gsub(/\r/, '')
105
+ msgstr = msgstr.gsub(/^(.*)$/, '"\1\n"')
106
+ str << msgstr
107
+ str << "\n"
108
+
109
+ str
110
+ end
111
+
112
+ def generate_po_entry(msgid)
113
+ str = ""
114
+ str << @msgid2comment[msgid]
115
+ if str[-1] != "\n"[0]
116
+ str << "\n"
117
+ end
118
+
119
+ id = msgid.gsub(/"/, '\"').gsub(/\r/, '')
120
+ msgstr = @msgid2msgstr[msgid].gsub(/"/, '\"').gsub(/\r/, '')
121
+
122
+ if id.include?("\000")
123
+ ids = id.split(/\000/)
124
+ str << "msgid " << __conv(ids[0]) << "\n"
125
+ ids[1..-1].each do |single_id|
126
+ str << "msgid_plural " << __conv(single_id) << "\n"
127
+ end
128
+
129
+ msgstr.split("\000").each_with_index do |m, n|
130
+ str << "msgstr[#{n}] " << __conv(m) << "\n"
131
+ end
132
+ else
133
+ str << "msgid " << __conv(id) << "\n"
134
+ str << "msgstr " << __conv(msgstr) << "\n"
135
+ end
136
+
137
+ str << "\n"
138
+ str
139
+ end
140
+
141
+ def __conv(str)
142
+ s = ''
143
+
144
+ if str.count("\n") > 1
145
+ s << '""' << "\n"
146
+ s << str.gsub(/^(.*)$/, '"\1\n"')
147
+ else
148
+ s << '"' << str.sub("\n", "\\n") << '"'
149
+ end
150
+
151
+ s.rstrip
152
+ end
153
+
154
+ end
155
+
156
+ class Merger #:nodoc:
157
+
158
+ # From GNU gettext source.
159
+ #
160
+ # Merge the reference with the definition: take the #. and
161
+ # #: comments from the reference, take the # comments from
162
+ # the definition, take the msgstr from the definition. Add
163
+ # this merged entry to the output message list.
164
+ DOT_COMMENT_RE = /\A#\./
165
+ SEMICOLON_COMMENT_RE = /\A#\:/
166
+ FUZZY_RE = /\A#\,/
167
+ NOT_SPECIAL_COMMENT_RE = /\A#([^:.,]|\z)/
168
+
169
+ CRLF_RE = /\r?\n/
170
+ POT_DATE_EXTRACT_RE = /POT-Creation-Date:\s*(.*)?\s*$/
171
+ POT_DATE_RE = /POT-Creation-Date:.*?$/
172
+
173
+ def merge(definition, reference)
174
+ # deep copy
175
+ result = Marshal.load( Marshal.dump(reference) )
176
+
177
+ used = []
178
+ merge_header(result, definition)
179
+
180
+ result.each_msgid do |msgid|
181
+ if definition.msgid?(msgid)
182
+ used << msgid
183
+ merge_message(msgid, result, msgid, definition)
184
+ elsif other_msgid = definition.search_msgid_fuzzy(msgid, used)
185
+ used << other_msgid
186
+ merge_fuzzy_message(msgid, result, other_msgid, definition)
187
+ elsif msgid.index("\000") and ( reference.msgstr(msgid).gsub("\000", '') == '' )
188
+ # plural
189
+ result[msgid] = "\000" * definition.nplural
190
+ else
191
+ change_reference_comment(msgid, result)
192
+ end
193
+ end
194
+
195
+ ###################################################################
196
+ # msgids which are not used in reference are handled as obsolete. #
197
+ ###################################################################
198
+ last_comment = result.comment(:last) || ''
199
+ definition.each_msgid do |msgid|
200
+ unless used.include?(msgid)
201
+ last_comment << "\n"
202
+ last_comment << definition.generate_po_entry(msgid).strip.gsub(/^/, '#. ')
203
+ last_comment << "\n"
204
+ end
205
+ end
206
+ result.set_comment(:last, last_comment)
207
+
208
+ result
209
+ end
210
+
211
+ def merge_message(msgid, target, def_msgid, definition)
212
+ merge_comment(msgid, target, def_msgid, definition)
213
+
214
+ ############################################
215
+ # check mismatch of msgid and msgid_plural #
216
+ ############################################
217
+ def_msgstr = definition[def_msgid]
218
+ if msgid.index("\000")
219
+ if def_msgstr.index("\000")
220
+ # OK
221
+ target[msgid] = def_msgstr
222
+ else
223
+ # NG
224
+ s = ''
225
+ definition.nplural.times {
226
+ s << def_msgstr
227
+ s << "\000"
228
+ }
229
+ target[msgid] = s
230
+ end
231
+ else
232
+ if def_msgstr.index("\000")
233
+ # NG
234
+ target[msgid] = def_msgstr.split("\000")[0]
235
+ else
236
+ # OK
237
+ target[msgid] = def_msgstr
238
+ end
239
+ end
240
+ end
241
+
242
+ # for the future
243
+ def merge_fuzzy_message(msgid, target, def_msgid, definition)
244
+ merge_message(msgid, target, def_msgid, definition)
245
+ end
246
+
247
+ def merge_comment(msgid, target, def_msgid, definition)
248
+ ref_comment = target.comment(msgid)
249
+ def_comment = definition.comment(def_msgid)
250
+
251
+ normal_comment = []
252
+ dot_comment = []
253
+ semi_comment = []
254
+ is_fuzzy = false
255
+
256
+ def_comment.split(CRLF_RE).each do |l|
257
+ if NOT_SPECIAL_COMMENT_RE =~ l
258
+ normal_comment << l
259
+ end
260
+ end
261
+
262
+ ref_comment.split(CRLF_RE).each do |l|
263
+ if DOT_COMMENT_RE =~ l
264
+ dot_comment << l
265
+ elsif SEMICOLON_COMMENT_RE =~ l
266
+ semi_comment << l
267
+ elsif FUZZY_RE =~ l
268
+ is_fuzzy = true
269
+ end
270
+ end
271
+
272
+ str = format_comment(normal_comment, dot_comment, semi_comment, is_fuzzy)
273
+ target.set_comment(msgid, str)
274
+ end
275
+
276
+ def change_reference_comment(msgid, podata)
277
+ normal_comment = []
278
+ dot_comment = []
279
+ semi_comment = []
280
+ is_fuzzy = false
281
+
282
+ podata.comment(msgid).split(CRLF_RE).each do |l|
283
+ if DOT_COMMENT_RE =~ l
284
+ dot_comment << l
285
+ elsif SEMICOLON_COMMENT_RE =~ l
286
+ semi_comment << l
287
+ elsif FUZZY_RE =~ l
288
+ is_fuzzy = true
289
+ else
290
+ normal_comment << l
291
+ end
292
+ end
293
+
294
+ str = format_comment(normal_comment, dot_comment, semi_comment, is_fuzzy)
295
+ podata.set_comment(msgid, str)
296
+ end
297
+
298
+ def format_comment(normal_comment, dot_comment, semi_comment, is_fuzzy)
299
+ str = ''
300
+
301
+ str << normal_comment.join("\n").gsub(/^#(\s*)/){|sss|
302
+ if $1 == ""
303
+ "# "
304
+ else
305
+ sss
306
+ end
307
+ }
308
+ if normal_comment.size > 0
309
+ str << "\n"
310
+ end
311
+
312
+ str << dot_comment.join("\n").gsub(/^#.(\s*)/){|sss|
313
+ if $1 == ""
314
+ "#. "
315
+ else
316
+ sss
317
+ end
318
+ }
319
+ if dot_comment.size > 0
320
+ str << "\n"
321
+ end
322
+
323
+ str << semi_comment.join("\n").gsub(/^#:\s*/, "#: ")
324
+ if semi_comment.size > 0
325
+ str << "\n"
326
+ end
327
+
328
+ if is_fuzzy
329
+ str << "#, fuzzy\n"
330
+ end
331
+
332
+ str
333
+ end
334
+
335
+ def merge_header(target, definition)
336
+ merge_comment('', target, '', definition)
337
+
338
+ msg = target.msgstr('')
339
+ def_msg = definition.msgstr('')
340
+ if POT_DATE_EXTRACT_RE =~ msg
341
+ time = $1
342
+ def_msg = def_msg.sub(POT_DATE_RE, "POT-Creation-Date: #{time}")
343
+ end
344
+
345
+ target[''] = def_msg
346
+ end
347
+
348
+ end
349
+
350
+ end
351
+
352
+ end
353
+
354
+ module GetText::RMsgMerge #:nodoc:
355
+
356
+ class Config #:nodoc:
357
+
358
+ attr_accessor :defpo, :refpot, :output, :fuzzy, :update
359
+
360
+ # update mode options
361
+ attr_accessor :backup, :suffix
362
+
363
+ =begin
364
+ The result is written back to def.po.
365
+ --backup=CONTROL make a backup of def.po
366
+ --suffix=SUFFIX override the usual backup suffix
367
+ The version control method may be selected via the --backup option or through
368
+ the VERSION_CONTROL environment variable. Here are the values:
369
+ none, off never make backups (even if --backup is given)
370
+ numbered, t make numbered backups
371
+ existing, nil numbered if numbered backups exist, simple otherwise
372
+ simple, never always make simple backups
373
+ The backup suffix is `~', unless set with --suffix or the SIMPLE_BACKUP_SUFFIX
374
+ environment variable.
375
+ =end
376
+
377
+ def initialize
378
+ @output = STDOUT
379
+ @fuzzy = nil
380
+ @update = nil
381
+ @backup = ENV["VERSION_CONTROL"]
382
+ @suffix= ENV["SIMPLE_BACKUP_SUFFIX"] || "~"
383
+ @input_dirs = ["."]
384
+ end
385
+
386
+ end
387
+
388
+ end
389
+
390
+ module GetText
391
+
392
+ module RMsgMerge
393
+ extend GetText
394
+ extend self
395
+
396
+ bindtextdomain("rgettext")
397
+
398
+ # constant values
399
+ VERSION = GetText::VERSION
400
+ DATE = %w($Date: 2007/07/21 15:03:05 $)[1]
401
+
402
+ def check_options(config)
403
+ opts = OptionParser.new
404
+ opts.banner = _("Usage: %s def.po ref.pot [-o output.pot]") % $0
405
+ #opts.summary_width = 80
406
+ opts.separator("")
407
+ opts.separator(_("Merges two Uniforum style .po files together. The def.po file is an existing PO file with translations. The ref.pot file is the last created PO file with up-to-date source references. ref.pot is generally created by rgettext."))
408
+ opts.separator("")
409
+ opts.separator(_("Specific options:"))
410
+
411
+ opts.on("-o", "--output=FILE", _("write output to specified file")) do |out|
412
+ unless FileTest.exist? out
413
+ config.output = out
414
+ else
415
+ #$stderr.puts(_("File '%s' has already existed.") % out)
416
+ #exit 1
417
+ end
418
+ end
419
+
420
+ #opts.on("-F", "--fuzzy-matching")
421
+
422
+ opts.on_tail("--version", _("display version information and exit")) do
423
+ puts "#{$0} #{VERSION} (#{DATE})"
424
+ puts "#{File.join(::Config::CONFIG["bindir"], ::Config::CONFIG["RUBY_INSTALL_NAME"])} #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
425
+ exit
426
+ end
427
+
428
+ opts.parse!(ARGV)
429
+
430
+ if ARGV.size != 2
431
+ puts opts.help
432
+ exit 1
433
+ end
434
+
435
+ config.defpo = ARGV[0]
436
+ config.refpot = ARGV[1]
437
+ end
438
+
439
+ def run(reference = nil, definition = nil, out = STDOUT)
440
+ config = GetText::RMsgMerge::Config.new
441
+ config.refpot = reference
442
+ config.defpo = definition
443
+ config.output = out
444
+
445
+ check_options(config)
446
+
447
+ if config.defpo.nil?
448
+ raise ArgumentError, _("definition po is not given.")
449
+ elsif config.refpot.nil?
450
+ raise ArgumentError, _("reference pot is not given.")
451
+ end
452
+
453
+ parser = PoParser.new
454
+ defpo = parser.parse_file(config.defpo, PoData.new, false)
455
+ refpot = parser.parse_file(config.refstrrefstr, PoData.new, false)
456
+
457
+ m = Merger.new
458
+ result = m.merge(defpo, refpot)
459
+ p result if $DEBUG
460
+ print result.generate_po if $DEBUG
461
+
462
+ begin
463
+ if out.is_a? String
464
+ File.open(File.expand_path(out), "w+") do |file|
465
+ file.write(result.generate_po)
466
+ end
467
+ else
468
+ out.puts(result.generate_po)
469
+ end
470
+ ensure
471
+ out.close
472
+ end
473
+ end
474
+
475
+ end
476
+
477
+ end
478
+
479
+
480
+
481
+ module GetText
482
+
483
+ # Experimental
484
+ def rmsgmerge(reference = nil, definition = nil, out = STDOUT)
485
+ RMsgMerge.run(reference, definition, out)
486
+ end
487
+
488
+ end
489
+
490
+
491
+
492
+ if $0 == __FILE__ then
493
+ require 'pp'
494
+
495
+ #parser = GetText::RMsgMerge::PoParser.new;
496
+ #parser = GetText::PoParser.new;
497
+ #pp parser.parse(ARGF.read)
498
+
499
+ GetText.rmsgmerge
500
+ end
@@ -0,0 +1,197 @@
1
+ # encoding: utf-8
2
+
3
+ =begin
4
+ tools.rb - Utility functions
5
+
6
+ Copyright (C) 2005-2008 Masao Mutoh
7
+
8
+ You may redistribute it and/or modify it under the same
9
+ license terms as Ruby or LGPL.
10
+ =end
11
+
12
+ require 'rbconfig'
13
+ if /mingw|mswin|mswin32/ =~ RUBY_PLATFORM
14
+ ENV['PATH'] = %w(bin lib).collect{|dir|
15
+ "#{Config::CONFIG["prefix"]}\\lib\\GTK\\#{dir};"
16
+ }.join('') + ENV['PATH']
17
+ end
18
+
19
+ require 'gettext/tools/rgettext'
20
+ require 'gettext/tools/rmsgfmt'
21
+ require 'gettext/runtime/mofile'
22
+ require 'fileutils'
23
+
24
+ module GetText
25
+ bindtextdomain "rgettext"
26
+
27
+ BOM_UTF8 = [0xef, 0xbb, 0xbf].pack("c3")
28
+
29
+ # Currently, GNU msgmerge doesn't accept BOM.
30
+ # This mesthod remove the UTF-8 BOM from the po-file.
31
+ def remove_bom(path) #:nodoc:
32
+ bom = IO.read(path, 3)
33
+ if bom == BOM_UTF8
34
+ data = IO.read(path)[3..-1]
35
+ File.open(path, "w") {|f| f.write(data)}
36
+ end
37
+ end
38
+
39
+ # Merges two Uniforum style .po files together.
40
+ #
41
+ # *Note* This function requires "msgmerge" tool included in GNU GetText. So you need to install GNU GetText.
42
+ #
43
+ # The def.po file is an existing PO file with translations which will be taken
44
+ # over to the newly created file as long as they still match; comments will be preserved,
45
+ # but extracted comments and file positions will be discarded.
46
+ #
47
+ # The ref.pot file is the last created PO file with up-to-date source references but
48
+ # old translations, or a PO Template file (generally created by rgettext);
49
+ # any translations or comments in the file will be discarded, however dot
50
+ # comments and file positions will be preserved. Where an exact match
51
+ # cannot be found, fuzzy matching is used to produce better results.
52
+ #
53
+ # Usually you don't need to call this function directly. Use GetText.update_pofiles instead.
54
+ #
55
+ # * defpo: a po-file. translations referring to old sources
56
+ # * refpo: a po-file. references to new sources
57
+ # * app_version: the application information which appears "Project-Id-Version: #{app_version}" in the pot/po-files.
58
+ # * Returns: self
59
+ def msgmerge(defpo, refpo, app_version, options={})
60
+ verbose = options.delete(:verbose)
61
+ puts "msgmerge called" if verbose
62
+ $stderr.print defpo + " "
63
+
64
+ content = merge_po_files(defpo,refpo,options.delete(:msgmerge),verbose)
65
+
66
+ if content.empty?
67
+ # report failure
68
+ failed_filename = refpo + "~"
69
+ FileUtils.cp(refpo, failed_filename)
70
+ $stderr.puts _("Failed to merge with %{defpo}") % {:defpo => defpo}
71
+ $stderr.puts _("New .pot was copied to %{failed_filename}") %{:failed_filename => failed_filename}
72
+ raise _("Check these po/pot-files. It may have syntax errors or something wrong.")
73
+ else
74
+ # update version and save merged data
75
+ content.sub!(/(Project-Id-Version\:).*$/, "\\1 #{app_version}\\n\"")
76
+ File.open(defpo, "w") {|f|f.write(content)}
77
+ end
78
+
79
+ self
80
+ end
81
+
82
+ # Creates mo-files using #{po_root}/#{lang}/*.po an put them to
83
+ # #{targetdir}/#{targetdir_rule}/.
84
+ #
85
+ # This is a convenience function of GetText.rmsgfmt for multiple target files.
86
+ # * options: options as a Hash.
87
+ # * verbose: true if verbose mode, otherwise false
88
+ # * po_root: the root directory of po-files.
89
+ # * mo_root: the target root directory where the mo-files are stored.
90
+ # * mo_path_rule: the target directory for each mo-files.
91
+ def create_mofiles(options = {})
92
+ options = {:po_root => "./po"}.merge(options)
93
+
94
+ Dir.glob(File.join(options[:po_root], "*/*.po")) do |po_file|
95
+ mo_file = mo_file_from_po_file(po_file,options)
96
+ $stderr.print %Q[#{po_file} -> #{mo_file} ... ] if options[:verbose]
97
+ FileUtils.mkdir_p(File.dirname(mo_file))
98
+ rmsgfmt(po_file, mo_file)
99
+ $stderr.puts "Done." if options[:verbose]
100
+ end
101
+ end
102
+
103
+
104
+ # At first, this creates the #{po_root}/#{domainname}.pot file using GetText.rgettext.
105
+ # In the second step, this updates(merges) the #{po_root}/#{domainname}.pot and all of the
106
+ # #{po_root}/#{lang}/#{domainname}.po files under "po_root" using "msgmerge".
107
+ #
108
+ # *Note* "msgmerge" tool is included in GNU GetText. So you need to install GNU GetText.
109
+ #
110
+ # See <HOWTO maintain po/mo files(http://www.yotabanana.com/hiki/ruby-gettext-howto-manage.html)> for more detals.
111
+ # * domainname: the textdomain name.
112
+ # * targetfiles: An Array of target files, that should be parsed for messages (See GetText.rgettext for more details).
113
+ # * app_version: the application information which appears "Project-Id-Version: #{app_version}" in the pot/po-files.
114
+ # * options: a hash with following possible settings
115
+ # :lang - update files only for one language - the language specified by this option
116
+ # :po_root - the root directory of po-files
117
+ # :msgmerge - an array with the options, passed through to the gnu msgmerge tool
118
+ # symbols are automatically translated to options with dashes,
119
+ # example: [:no_wrap, :no_fuzzy_matching, :sort_output] translated to '--no-fuzzy-matching --sort-output'
120
+ # :verbose - true to show verbose messages. default is false.
121
+ #
122
+ # Example: GetText.update_pofiles("myapp", Dir.glob("lib/*.rb"), "myapp 1.0.0", :verbose => true)
123
+ def update_pofiles(textdomain, files, app_version, options = {})
124
+ puts options.inspect if options[:verbose]
125
+
126
+ #write found messages to tmp.pot
127
+ temp_pot = "tmp.pot"
128
+ rgettext(files, temp_pot)
129
+
130
+ #merge tmp.pot and existing pot
131
+ po_root = options.delete(:po_root) || "po"
132
+ FileUtils.mkdir_p(po_root)
133
+ msgmerge("#{po_root}/#{textdomain}.pot", temp_pot, app_version, options.dup)
134
+
135
+ #update local po-files
136
+ only_one_language = options.delete(:lang)
137
+ if only_one_language
138
+ msgmerge("#{po_root}/#{only_one_language}/#{textdomain}.po", temp_pot, app_version, options.dup)
139
+ else
140
+ Dir.glob("#{po_root}/*/#{textdomain}.po") do |po_file|
141
+ msgmerge(po_file, temp_pot, app_version, options.dup)
142
+ end
143
+ end
144
+
145
+ File.delete(temp_pot)
146
+ end
147
+
148
+ private
149
+
150
+ # Merge 2 po files, using msgmerge
151
+ def merge_po_files(po_a,po_b,msgmerge_options=[],verbose=false)
152
+ return File.read(po_b) unless FileTest.exist? po_a
153
+
154
+ cmd = ENV["MSGMERGE_PATH"] || "msgmerge"
155
+ ensure_command_exists(cmd)
156
+
157
+ remove_bom(po_a)
158
+
159
+ cmd_params = array_to_cli_options(msgmerge_options)
160
+ to_run = "#{cmd} #{cmd_params} #{po_a} #{po_b}"
161
+ puts "\nrunning #{to_run}" if verbose
162
+ `#{to_run}`
163
+ end
164
+
165
+ # convert an array of String/Symbol to cli options
166
+ def array_to_cli_options(array)
167
+ [*array].map do |o|
168
+ o.kind_of?(Symbol) ? "--#{o}".gsub('_','-') : o.to_s
169
+ end.join(' ')
170
+ end
171
+
172
+ def ensure_command_exists(cmd)
173
+ `#{cmd} --help`
174
+ unless $? && $?.success?
175
+ raise _("`%{cmd}' can not be found. \nInstall GNU Gettext then set PATH or MSGMERGE_PATH correctly.") % {:cmd => cmd}
176
+ end
177
+ end
178
+
179
+ # where lies the mo file for a given po_file
180
+ # generare directory unless it exists
181
+ def mo_file_from_po_file(po_file,options)
182
+ options = {
183
+ :mo_root => "./data/locale",
184
+ :mo_path_rule => "%{lang}/LC_MESSAGES"
185
+ }.merge(options)
186
+
187
+ lang, textdomain = %r[/([^/]+?)/(.*)\.po].match(po_file[options[:po_root].size..-1]).to_a[1,2]
188
+
189
+ mo_dir_rule = File.join(options[:mo_root], options[:mo_path_rule])
190
+ mo_dir = mo_dir_rule % {:lang => lang}
191
+ File.join(mo_dir, "#{textdomain}.mo")
192
+ end
193
+ end
194
+
195
+ if __FILE__ == $0
196
+ GetText.update_pofiles("foo", ARGV, "foo 1.1.0")
197
+ end