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