# # tk/msgcat.rb : methods for Tcl message catalog # by Hidetoshi Nagai # require 'tk' #class TkMsgCatalog class TkMsgCatalog < TkObject include TkCore extend Tk #extend TkMsgCatalog TkCommandNames = [ '::msgcat::mc'.freeze, '::msgcat::mcmax'.freeze, '::msgcat::mclocale'.freeze, '::msgcat::mcpreferences'.freeze, '::msgcat::mcload'.freeze, '::msgcat::mcset'.freeze, '::msgcat::mcmset'.freeze, '::msgcat::mcunknown'.freeze ].freeze tk_call_without_enc('package', 'require', 'Tcl', '8.2') PACKAGE_NAME = 'msgcat'.freeze def self.package_name PACKAGE_NAME end if self.const_defined? :FORCE_VERSION tk_call_without_enc('package', 'require', 'msgcat', FORCE_VERSION) else tk_call_without_enc('package', 'require', 'msgcat') end MSGCAT_EXT = '.msg' UNKNOWN_CBTBL = Hash.new{|hash,key| hash[key] = {}}.taint TkCore::INTERP.add_tk_procs('::msgcat::mcunknown', 'args', <<-'EOL') if {[set st [catch {eval {ruby_cmd TkMsgCatalog callback} [namespace current] $args} ret]] != 0} { #return -code $st $ret set idx [string first "\n\n" $ret] if {$idx > 0} { return -code $st \ -errorinfo [string range $ret [expr $idx + 2] \ [string length $ret]] \ [string range $ret 0 [expr $idx - 1]] } else { return -code $st $ret } } else { return $ret } EOL def self.callback(namespace, locale, src_str, *args) src_str = sprintf(src_str, *args) unless args.empty? cmd_tbl = TkMsgCatalog::UNKNOWN_CBTBL[TkCore::INTERP.__getip] cmd = cmd_tbl[namespace] cmd = cmd_tbl['::'] unless cmd # use global scope as interp default return src_str unless cmd # no cmd -> return src-str (default action) begin cmd.call(locale, src_str) rescue SystemExit exit(0) rescue Interrupt exit!(1) rescue Exception => e begin msg = _toUTF8(e.class.inspect) + ': ' + _toUTF8(e.message) + "\n" + "\n---< backtrace of Ruby side >-----\n" + _toUTF8(e.backtrace.join("\n")) + "\n---< backtrace of Tk side >-------" msg.instance_variable_set(:@encoding, 'utf-8') rescue Exception msg = e.class.inspect + ': ' + e.message + "\n" + "\n---< backtrace of Ruby side >-----\n" + e.backtrace.join("\n") + "\n---< backtrace of Tk side >-------" end fail(e, msg) end end def initialize(namespace = nil) if namespace.kind_of?(TkNamespace) @namespace = namespace elsif namespace == nil @namespace = TkNamespace.new('::') # global namespace else @namespace = TkNamespace.new(namespace) end @path = @namespace.path @msgcat_ext = '.msg' end attr_accessor :msgcat_ext def method_missing(id, *args) # locale(src, trans) ==> set_translation(locale, src, trans) loc = id.id2name case args.length when 0 # set locale self.locale=(loc) when 1 # src only, or trans_list if args[0].kind_of?(Array) # trans_list #list = args[0].collect{|src, trans| # [ Tk::UTF8_String.new(src), Tk::UTF8_String.new(trans) ] #} self.set_translation_list(loc, args[0]) else # src #self.set_translation(loc, Tk::UTF8_String.new(args[0])) self.set_translation(loc, args[0]) end when 2 # src and trans, or, trans_list and enc if args[0].kind_of?(Array) else #self.set_translation(loc, args[0], Tk::UTF8_String.new(args[1])) self.set_translation(loc, *args) end when 3 # src and trans and enc self.set_translation(loc, *args) else super(id, *args) # fail NameError, "undefined method `#{name}' for #{self.to_s}", error_at end end # *args ::= form, arg, arg, ... def self.translate(*args) dst = args.collect{|src| tk_call_without_enc('::msgcat::mc', _get_eval_string(src, true)) } Tk.UTF8_String(sprintf(*dst)) end class << self alias mc translate alias [] translate end def translate(*args) dst = args.collect{|src| @namespace.eval{tk_call_without_enc('::msgcat::mc', _get_eval_string(src, true))} } Tk.UTF8_String(sprintf(*dst)) end alias mc translate alias [] translate def self.maxlen(*src_strings) tk_call('::msgcat::mcmax', *src_strings).to_i end def maxlen(*src_strings) @namespace.eval{tk_call('::msgcat::mcmax', *src_strings).to_i} end def self.locale tk_call('::msgcat::mclocale') end def locale @namespace.eval{tk_call('::msgcat::mclocale')} end def self.locale=(locale) tk_call('::msgcat::mclocale', locale) end def locale=(locale) @namespace.eval{tk_call('::msgcat::mclocale', locale)} end def self.preferences tk_split_simplelist(tk_call('::msgcat::mcpreferences')) end def preferences tk_split_simplelist(@namespace.eval{tk_call('::msgcat::mcpreferences')}) end def self.load_tk(dir) number(tk_call('::msgcat::mcload', dir)) end def self.load_rb(dir) count = 0 preferences().each{|loc| file = File.join(dir, loc + self::MSGCAT_EXT) if File.readable?(file) count += 1 eval(open(file){|f| f.read}) end } count end def load_tk(dir) number(@namespace.eval{tk_call('::msgcat::mcload', dir)}) end def load_rb(dir) count = 0 preferences().each{|loc| file = File.join(dir, loc + @msgcat_ext) if File.readable?(file) count += 1 @namespace.eval(open(file){|f| f.read}) end } count end def self.load(dir) self.load_rb(dir) end alias load load_rb def self.set_translation(locale, src_str, trans_str=None, enc='utf-8') if trans_str && trans_str != None trans_str = Tk.UTF8_String(_toUTF8(trans_str, enc)) Tk.UTF8_String(tk_call_without_enc('::msgcat::mcset', locale, _get_eval_string(src_str, true), trans_str)) else Tk.UTF8_String(tk_call_without_enc('::msgcat::mcset', locale, _get_eval_string(src_str, true))) end end def set_translation(locale, src_str, trans_str=None, enc='utf-8') if trans_str && trans_str != None trans_str = Tk.UTF8_String(_toUTF8(trans_str, enc)) Tk.UTF8_String(@namespace.eval{ tk_call_without_enc('::msgcat::mcset', locale, _get_eval_string(src_str, true), trans_str) }) else Tk.UTF8_String(@namespace.eval{ tk_call_without_enc('::msgcat::mcset', locale, _get_eval_string(src_str, true))}) end end def self.set_translation_list(locale, trans_list, enc='utf-8') # trans_list ::= [ [src, trans], [src, trans], ... ] list = [] trans_list.each{|src, trans| if trans && trans != None list << _get_eval_string(src, true) list << Tk.UTF8_Stirng(_toUTF8(trans, enc)) else list << _get_eval_string(src, true) << '' end } number(tk_call_without_enc('::msgcat::mcmset', locale, list)) end def set_translation_list(locale, trans_list, enc='utf-8') # trans_list ::= [ [src, trans], [src, trans], ... ] list = [] trans_list.each{|src, trans| if trans && trans != None list << _get_eval_string(src, true) list << Tk.UTF8_String(_toUTF8(trans, enc)) else list << _get_eval_string(src, true) << '' end } number(@namespace.eval{ tk_call_without_enc('::msgcat::mcmset', locale, list) }) end def self.def_unknown_proc(cmd=Proc.new) TkMsgCatalog::UNKNOWN_CBTBL[TkCore::INTERP.__getip]['::'] = cmd end def def_unknown_proc(cmd=Proc.new) TkMsgCatalog::UNKNOWN_CBTBL[TkCore::INTERP.__getip][@namespace.path] = cmd end end TkMsgCat = TkMsgCatalog