seen: use gettext
[rbot] / Rakefile
1 require 'rubygems'
2 require 'rake'
3 require 'rake/gempackagetask'
4
5 task :default => [:buildext]
6
7 spec = Gem::Specification.new do |s|
8   s.name = 'rbot'
9   s.version = '0.9.15'
10   s.summary = <<-EOF
11     A modular ruby IRC bot.
12   EOF
13   s.description = <<-EOF
14     A modular ruby IRC bot specifically designed for ease of extension via plugins.
15   EOF
16   s.requirements << 'Ruby, version 1.8.0 (or newer)'
17
18   s.files = FileList[
19           'lib/**/*.rb',
20           'bin/*',
21           'data/rbot/**/*',
22           'AUTHORS',
23           'COPYING',
24           'README',
25           'REQUIREMENTS',
26           'TODO',
27           'ChangeLog',
28           'INSTALL',
29           'Usage_en.txt',
30           'setup.rb',
31           'launch_here.rb',
32           'po/*.pot',
33           'po/**/*.po'
34   ]
35
36   s.bindir = 'bin'
37   s.executables = ['rbot', 'rbot-remote']
38   s.default_executable = 'rbot'
39   s.extensions = 'Rakefile'
40
41 #  s.autorequire = 'rbot/ircbot'
42   s.has_rdoc = true
43   s.rdoc_options = ['--exclude', 'post-install.rb',
44   '--title', 'rbot API Documentation', '--main', 'README', 'README']
45
46   s.author = 'Tom Gilbert'
47   s.email = 'tom@linuxbrit.co.uk'
48   s.homepage = 'http://ruby-rbot.org'
49   s.rubyforge_project = 'rbot'
50 end
51
52 Rake::GemPackageTask.new(spec) do |pkg|
53   pkg.need_zip = true
54   pkg.need_tar = true
55 end
56
57 # normalize a po/pot file
58 def normalize_po(fn)
59   content = File.read(fn)
60
61   # sort the messages by file location
62   if MSGCAT
63     sorted = `#{MSGCAT} --width=79 --sort-by-file #{fn}`
64     if sorted != content
65       content = sorted
66       modified = true
67     end
68   end
69
70   # replace project-id-version placholder
71   modified |= content.sub!(/^("Project-Id-Version: )PACKAGE VERSION(\\n")$/) {
72     "#{$1}rbot#{$2}"
73   }
74
75   if modified
76     File.open(fn, 'w') {|f| f.write content}
77   end
78 end
79
80 PLUGIN_FILES = FileList['data/rbot/plugins/**/*.rb']
81 NON_PLUGIN_FILES = FileList["{lib,bin,data}/**/*.{rb,rhtml}"] - PLUGIN_FILES
82
83 # this task defines how po files and pot files are made. those rules are not defined
84 # normally because po and pot files should be only updated in the updatepo task,
85 # but po files are also prereqs for makemo
86 task :define_po_rules do
87   # generate pot file from rb files
88   rgettext_proc = proc do |t|
89     require 'gettext/utils'
90     source_files, pot_file = t.prerequisites, t.name
91     new_pot_file = "#{pot_file}.new"
92     puts "#{source_files.join(', ')} => #{pot_file}"
93     GetText.rgettext(source_files, new_pot_file)
94
95     # only use the new pot file if it contains unique messages
96     if File.exists?(pot_file) && MSGCOMM && `#{MSGCOMM} --unique #{pot_file} #{new_pot_file}`.empty?
97       rm new_pot_file
98     else
99       mv new_pot_file, pot_file
100     end
101
102     normalize_po(pot_file)
103     
104     # save all this work until rb files are updated again
105     touch pot_file
106   end
107
108   # generate pot file for non-plugin files
109   file('po/rbot.pot' => NON_PLUGIN_FILES, &rgettext_proc)
110
111   # generate pot files for plugin files
112   rule(%r'^po/.+\.pot$' => proc {|fn|
113     PLUGIN_FILES.select {|f| f.pathmap('rbot-%n') == fn.pathmap('%n')}
114   }, &rgettext_proc)
115
116   # map the po file to its source pot file
117   pot_for_po = proc {|fn| fn.pathmap '%{^po/.+/,po/}X.pot'}
118
119   # update po file from pot file
120   msgmerge_proc = proc do |t|
121     require 'gettext/utils'
122     po_file, pot_file = t.name, t.source
123     puts "#{pot_file} => #{po_file}"
124     if File.exists? po_file
125       sh "#{MSGMERGE} --backup=off --update #{po_file} #{pot_file}"
126     elsif MSGINIT
127       locale = po_file[%r'^po/(.+)/.+\.po$', 1]
128       sh "#{MSGINIT} --locale=#{locale} --no-translator --input=#{pot_file} --output-file=#{po_file}"
129     else
130       warn "#{po_file} is missing and cannot be generated without msginit"
131       next
132     end
133     normalize_po(po_file)
134     touch po_file
135   end
136
137   # generate English po files
138   file(%r'^po/en_US/.+\.po$' => pot_for_po) do |t|
139     po_file, pot_file = t.name, t.source
140     if MSGEN
141       sh "#{MSGEN} --output-file=#{po_file} #{pot_file}"
142       normalize_po(po_file)
143       touch po_file
144     else
145       msgmerge_proc.call t
146     end
147   end
148
149   # update po files
150   rule(%r'^po/.+/.+\.po$' => pot_for_po, &msgmerge_proc)
151 end
152
153 # generate mo files
154 rule(%r'^data/locale/.+/LC_MESSAGES/.+\.mo$' => proc {|fn|
155   [ fn.pathmap('%{^data/locale,po;LC_MESSAGES/,}X.po'), 
156     # the directory is created if not existing
157     fn.pathmap('%d') ]
158 }) do |t|
159   po_file, mo_file = t.source, t.name
160   puts "#{po_file} => #{mo_file}"
161   require 'gettext/utils'
162   GetText.rmsgfmt po_file, mo_file
163 end
164
165 task :check_po_tools do
166   have = {}
167
168   po_tools = {
169     'msgmerge' => {
170       :options => %w[--backup= --update],
171       :message => 'Cannot update po files' },
172     'msginit' => {
173       :options => %w[--locale= --no-translator --input= --output-file=],
174       :message => 'Cannot generate missing po files' },
175     'msgcomm' => {
176       :options => %w[--unique],
177       :message => 'Pot files may be modified even without message change' },
178     'msgen' => {
179       :options => %w[--output-file],
180       :message => 'English po files will not be generated' },
181     'msgcat' => {
182       :options => %w[--width= --sort-by-file],
183       :message => 'Pot files will not be normalized' }
184   }
185
186   po_tools.each_pair do |command, value|
187     path = ENV["#{command.upcase}_PATH"] || command
188     have_it = have[command] = value[:options].all? do |option|
189       `#{path} --help`.include? option
190     end
191     Object.const_set(command.upcase, have_it ? path : false)
192     warn "#{command} not found. #{value[:message]}" unless have_it
193   end
194   abort unless MSGMERGE
195 end
196
197 PLUGIN_BASENAMES = PLUGIN_FILES.map {|f| f.pathmap('%n')}
198 LOCALES = FileList['po/*/'].map {|d| d.pathmap('%n')}
199
200 LOCALES.each do |l|
201   directory "data/locale/#{l}/LC_MESSAGES"
202 end
203
204 desc 'Update po files'
205 task :updatepo => [:define_po_rules, :check_po_tools] + LOCALES.map {|l|
206   ["po/#{l}/rbot.po"] +
207   PLUGIN_BASENAMES.map {|n| "po/#{l}/rbot-#{n}.po"}
208 }.flatten
209
210 desc 'Normalize po files'
211 task :normalizepo => :check_po_tools do
212   FileList['po/*/*.po'].each {|fn| normalize_po(fn)}
213 end
214
215 # this task invokes makemo if ruby-gettext is available, but otherwise succeeds
216 # with a warning instead of failing. it is to be used by Gem's extension builder
217 # to make installation not fail because of lack of ruby-gettext
218 task :buildext do
219   begin
220     require 'gettext/utils'
221     Rake::Task[:makemo].invoke
222   rescue LoadError
223     warn 'Ruby-gettext cannot be located, so mo files cannot be built and installed' 
224   end
225 end
226
227 desc 'Generate mo files'
228 task :makemo =>
229   FileList['po/*/*.po'].pathmap('%{^po,data/locale}d/LC_MESSAGES/%n.mo')
230
231