]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - lib/rbot/load-gettext.rb
load-gettext: cope with ruby gettext 2.1.0
[user/henk/code/ruby/rbot.git] / lib / rbot / load-gettext.rb
1 #-- vim:sw=2:et
2 #++
3 #
4 # :title: GetText interface for rbot
5 #
6 # Load gettext module and provide fallback in case of failure
7
8 class GetTextVersionError < Exception
9 end
10
11 # try to load gettext, or provide fake getttext functions
12 begin
13 # workaround for gettext not checking empty LANGUAGE
14 if ENV["LANGUAGE"] and ENV["LANGUAGE"].empty?
15   ENV.delete "LANGUAGE"
16 end
17
18   require 'gettext/version'
19
20   gettext_version = GetText::VERSION.split('.').map {|n| n.to_i}
21   include Comparable # for Array#>=
22   unless gettext_version >= [1, 8, 0]
23     raise GetTextVersionError, "Unsupported ruby-gettext version installed: #{gettext_version.join '.'}; supported versions are 1.8.0 and above"
24   end
25
26   require 'gettext'
27
28   include GetText
29
30   rbot_locale_path = File.join(Irc::Bot::Config.datadir, "../locale/%{locale}/LC_MESSAGES/%{name}.mo")
31   if gettext_version < [2, 0, 0]
32     add_default_locale_path(rbot_locale_path)
33   else
34     LocalePath.add_default_rule(rbot_locale_path)
35   end
36
37   if GetText.respond_to? :cached=
38     GetText.cached = false
39   elsif TextDomain.respond_to? :cached=
40     TextDomain.cached = false
41   else
42     warning 'This version of ruby-gettext does not support non-cached mode; mo files are not reloaded when setting language'
43   end
44   bindtextdomain 'rbot'
45
46   module GetText
47     # patch for ruby-gettext 1.x to cope with anonymous modules used by rbot.
48     # bound_targets and related methods are not used nor present in 2.x, and
49     # this patch is not needed
50     if respond_to? :bound_targets, true
51       alias :orig_bound_targets :bound_targets
52
53       def bound_targets(*a)  # :nodoc:
54         bt = orig_bound_targets(*a) rescue []
55         bt.empty? ? orig_bound_targets(Object) : bt
56       end
57     end
58
59     require 'stringio'
60
61     # GetText 2.1.0 does not provide current_textdomain_info,
62     # so we adapt the one from 1.9.10
63     # TODO we would _really_ like to have a future-proof version of this,
64     # but judging by the ruby gettext source code, this isn't going to
65     # happen anytime soon.
66     if not respond_to? :current_textdomain_info
67       # Show the current textdomain information. This function is for debugging.
68       # * options: options as a Hash.
69       #   * :with_messages - show informations with messages of the current mo file. Default is false.
70       #   * :out - An output target. Default is STDOUT.
71       #   * :with_paths - show the load paths for mo-files.
72       def current_textdomain_info(options = {})
73         opts = {:with_messages => false, :with_paths => false, :out => STDOUT}.merge(options)
74         ret = nil
75         # this is for 2.1.0
76         TextDomainManager.each_textdomains(self) {|textdomain, lang|
77           opts[:out].puts "TextDomain name: #{textdomain.name.inspect}"
78           opts[:out].puts "TextDomain current locale: #{lang.to_s.inspect}"
79           opts[:out].puts "TextDomain current mo path: #{textdomain.instance_variable_get(:@locale_path).current_path(lang).inspect}"
80           if opts[:with_paths]
81             opts[:out].puts "TextDomain locale file paths:"
82             textdomain.locale_paths.each do |v|
83               opts[:out].puts "  #{v}"
84             end
85           end
86           if opts[:with_messages]
87             opts[:out].puts "The messages in the mo file:"
88             textdomain.current_mo.each{|k, v|
89               opts[:out].puts "  \"#{k}\": \"#{v}\""
90             }
91           end
92         }
93       end
94     end
95
96     # This method is used to output debug information on the GetText
97     # textdomain, and it's called by the language setting routines
98     # in rbot
99     def rbot_gettext_debug
100       begin
101         gettext_info = StringIO.new
102         current_textdomain_info(:out => gettext_info) # fails sometimes
103       rescue Exception
104         warning "failed to retrieve textdomain info. maybe an mo file doesn't exist for your locale."
105         debug $!
106       ensure
107         gettext_info.string.each_line { |l| debug l}
108       end
109     end
110   end
111
112   log "gettext loaded"
113
114 rescue LoadError, GetTextVersionError
115   warning "failed to load ruby-gettext package: #{$!}; translations are disabled"
116
117   # undefine GetText, in case it got defined because the error was caused by a
118   # wrong version
119   if defined?(GetText)
120     Object.module_eval { remove_const("GetText") }
121   end
122
123   # dummy functions that return msg_id without translation
124   def _(s)
125     s
126   end
127
128   def N_(s)
129     s
130   end
131
132   def n_(s_single, s_plural, n)
133     n > 1 ? s_plural : s_single
134   end
135
136   def Nn_(s_single, s_plural)
137     n_(s_single, s_plural)
138   end
139
140   def s_(*args)
141     args[0]
142   end
143
144   def bindtextdomain_to(*args)
145   end
146
147   # the following extension to String#% is from ruby-gettext's string.rb file.
148   # it needs to be included in the fallback since the source already use this form
149
150 =begin
151   string.rb - Extension for String.
152
153   Copyright (C) 2005,2006 Masao Mutoh
154
155   You may redistribute it and/or modify it under the same
156   license terms as Ruby.
157 =end
158
159   # Extension for String class.
160   #
161   # String#% method which accept "named argument". The translator can know
162   # the meaning of the msgids using "named argument" instead of %s/%d style.
163   class String
164     alias :_old_format_m :% # :nodoc:
165
166     # call-seq:
167     #  %(arg)
168     #  %(hash)
169     #
170     # Format - Uses str as a format specification, and returns the result of applying it to arg.
171     # If the format specification contains more than one substitution, then arg must be
172     # an Array containing the values to be substituted. See Kernel::sprintf for details of the
173     # format string. This is the default behavior of the String class.
174     # * arg: an Array or other class except Hash.
175     # * Returns: formatted String
176     #
177     #  (e.g.) "%s, %s" % ["Masao", "Mutoh"]
178     #
179     # Also you can use a Hash as the "named argument". This is recommanded way for Ruby-GetText
180     # because the translators can understand the meanings of the msgids easily.
181     # * hash: {:key1 => value1, :key2 => value2, ... }
182     # * Returns: formatted String
183     #
184     #  (e.g.) "%{firstname}, %{familyname}" % {:firstname => "Masao", :familyname => "Mutoh"}
185     def %(args)
186       if args.kind_of?(Hash)
187         ret = dup
188         args.each {|key, value|
189           ret.gsub!(/\%\{#{key}\}/, value.to_s)
190         }
191         ret
192       else
193         ret = gsub(/%\{/, '%%{')
194         begin
195     ret._old_format_m(args)
196         rescue ArgumentError
197     $stderr.puts "  The string:#{ret}"
198     $stderr.puts "  args:#{args.inspect}"
199         end
200       end
201     end
202   end
203 end