summaryrefslogtreecommitdiff
path: root/lib/rbot/language.rb
blob: 8055ea0e8e986ae588ff624408617daef803d0f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#-- vim:sw=2:et
#++
#
# :title: Language module for rbot
#
# This module takes care of language handling for rbot:
# setting the core.language value, loading the appropriate
# .lang file etc.

module Irc
class Bot
  class Language

    # Access needed for tests:
    attr_reader :strings

    # This constant hash holds the mapping
    # from long language names to the usual POSIX
    # locale specifications
    Lang2Locale = {
      :english  => 'en',
      :british_english  => 'en_GB',
      :american_english  => 'en_US',
      :italian  => 'it',
      :french   => 'fr',
      :german   => 'de',
      :dutch    => 'nl',
      :japanese => 'ja',
      :russian  => 'ru',
      :finnish  => 'fi',
      :traditional_chinese => 'zh_TW',
      :simplified_chinese => 'zh_CN'
    }
    # On WIN32 it appears necessary to have ".UTF-8" explicitly for gettext to use UTF-8
    Lang2Locale.each_value {|v| v.replace(v + '.UTF-8')}

    # Return the shortest language for the current
    # GetText locale
    def Language.from_locale
      return 'english' unless defined?(GetText)
      lang = locale.language
      if locale.country
        str = lang + "_#{locale.country}"
        if Lang2Locale.value?(str)
          # Get the shortest key in Lang2Locale which maps to the given lang_country
          lang_str = Lang2Locale.select { |k, v| v == str }.transpose.first.map { |v| v.to_s }.sort { |a, b| a.length <=> b.length }.first
          if File.exist?(File.join(Config::datadir, "languages/#{lang_str}.lang"))
            return lang_str
          end
        end
      end
      # lang_country didn't work, let's try lan
      if Lang2Locale.value?(lang)
        # Get the shortest key in Lang2Locale which maps to the given lang
        lang_str = Lang2Locale.select { |k, v| v == lang }.transpose.first.map { |v| v.to_s }.sort { |a, b| a.length <=> b.length }.first
        if File.exist?(File.join(Config::datadir, "/languages/#{lang_str}.lang"))
          return lang_str
        end
      end
      # all else fail, return 'english'
      return 'english'
    end

    Config.register Config::EnumValue.new('core.language',
      :default => Irc::Bot::Language.from_locale, :wizard => true,
      :values => Proc.new{|bot|
            Dir.new(Config::datadir + "/languages").collect {|f|
              f =~ /\.lang$/ ? f.gsub(/\.lang$/, "") : nil
            }.compact
          },
      :on_change => Proc.new {|bot, v| bot.lang.set_language v},
      :desc => "Which language file the bot should use")

    def initialize(bot, language)
      @bot = bot
      set_language language
    end
    attr_reader :language

    def set_language(language)
      lang_str = language.to_s.downcase.gsub(/\s+/,'_')
      lang_sym = lang_str.intern
      if defined?(GetText) and Lang2Locale.key?(lang_sym)
        GetText.set_locale(Lang2Locale[lang_sym])
        debug "locale set to #{locale}"
        rbot_gettext_debug
      else
        warning "Unable to set locale, unknown language #{language} (#{lang_str})"
      end

      file = Config::datadir + "/languages/#{lang_str}.lang"
      unless(FileTest.exist?(file))
        raise "no such language: #{lang_str} (no such file #{file})"
      end
      @language = lang_str
      @file = file
      scan
      return if @bot.plugins.nil?
      @bot.plugins.core_modules.each { |p|
        if p.respond_to?('set_language')
          p.set_language(@language)
        end
      }
      @bot.plugins.plugins.each { |p|
        if p.respond_to?('set_language')
          p.set_language(@language)
        end
      }
    end

    def scan
      @strings = Hash.new
      current_key = nil
      IO.foreach(@file) {|l|
        next if l =~ /^$/
        next if l =~ /^\s*#/
        if(l =~ /^(\S+):$/)
          @strings[$1] = Array.new
          current_key = $1
        elsif(l =~ /^\s*(.*)$/)
          @strings[current_key] << $1
        end
      }
    end

    def rescan
      scan
    end

    def get(key)
      if(@strings.has_key?(key))
        return @strings[key][rand(@strings[key].length)]
      else
        raise "undefined language key"
      end
    end

    def save
      File.open(@file, "w") {|file|
        @strings.each {|key,val|
          file.puts "#{key}:"
          val.each_value {|v|
            file.puts "   #{v}"
          }
        }
      }
    end
  end

end
end