nadoka 0.8.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.
- data/.gitignore +5 -0
- data/ChangeLog.old +1553 -0
- data/Gemfile +4 -0
- data/README.org +31 -0
- data/Rakefile +1 -0
- data/bin/nadoka +13 -0
- data/lib/rss_check.rb +206 -0
- data/lib/tagparts.rb +206 -0
- data/nadoka.gemspec +29 -0
- data/nadoka.rb +123 -0
- data/nadokarc +267 -0
- data/ndk/bot.rb +241 -0
- data/ndk/client.rb +288 -0
- data/ndk/config.rb +571 -0
- data/ndk/error.rb +61 -0
- data/ndk/logger.rb +311 -0
- data/ndk/server.rb +784 -0
- data/ndk/server_state.rb +324 -0
- data/ndk/version.rb +44 -0
- data/plugins/autoawaybot.nb +66 -0
- data/plugins/autodumpbot.nb +227 -0
- data/plugins/autoop.nb +56 -0
- data/plugins/backlogbot.nb +88 -0
- data/plugins/checkbot.nb +64 -0
- data/plugins/cronbot.nb +20 -0
- data/plugins/dictbot.nb +53 -0
- data/plugins/drbcl.rb +39 -0
- data/plugins/drbot.nb +93 -0
- data/plugins/evalbot.nb +49 -0
- data/plugins/gonzuibot.nb +41 -0
- data/plugins/googlebot.nb +345 -0
- data/plugins/identifynickserv.nb +43 -0
- data/plugins/mailcheckbot.nb +0 -0
- data/plugins/marldiabot.nb +99 -0
- data/plugins/messagebot.nb +96 -0
- data/plugins/modemanager.nb +150 -0
- data/plugins/opensearchbot.nb +156 -0
- data/plugins/opshop.nb +23 -0
- data/plugins/pastebot.nb +46 -0
- data/plugins/roulettebot.nb +33 -0
- data/plugins/rss_checkbot.nb +121 -0
- data/plugins/samplebot.nb +24 -0
- data/plugins/sendpingbot.nb +17 -0
- data/plugins/shellbot.nb +59 -0
- data/plugins/sixamobot.nb +77 -0
- data/plugins/tenkibot.nb +111 -0
- data/plugins/timestampbot.nb +62 -0
- data/plugins/titlebot.nb +226 -0
- data/plugins/translatebot.nb +301 -0
- data/plugins/twitterbot.nb +138 -0
- data/plugins/weba.nb +209 -0
- data/plugins/xibot.nb +113 -0
- data/rice/irc.rb +780 -0
- metadata +102 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
# -*-ruby-*-
|
2
|
+
#
|
3
|
+
# Copyright (c) 2004-2005 SASADA Koichi <ko1 at atdot.net>
|
4
|
+
#
|
5
|
+
# This program is free software with ABSOLUTELY NO WARRANTY.
|
6
|
+
# You can re-distribute and/or modify this program under
|
7
|
+
# the same terms of the Ruby's license.
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# $Id$
|
11
|
+
#
|
12
|
+
|
13
|
+
=begin
|
14
|
+
|
15
|
+
== Abstract
|
16
|
+
|
17
|
+
Add time stamp to each log.
|
18
|
+
|
19
|
+
|
20
|
+
== Configuration
|
21
|
+
BotConfig = [
|
22
|
+
{
|
23
|
+
:name => :TimeStampBot,
|
24
|
+
:interval => 60 * 60, # sec
|
25
|
+
:stampformat => '== %y/%m/%d-%H:%M:%S ==========================================',
|
26
|
+
:client => false,
|
27
|
+
}
|
28
|
+
]
|
29
|
+
|
30
|
+
=end
|
31
|
+
|
32
|
+
class TimeStampBot < Nadoka::NDK_Bot
|
33
|
+
def bot_initialize
|
34
|
+
@interval = @bot_config.fetch(:interval, 60 * 60) # default: 1 hour
|
35
|
+
@stampformat = @bot_config.fetch(:stampformat,
|
36
|
+
'== %y/%m/%d-%H:%M:%S ==========================================')
|
37
|
+
@client = @bot_config.fetch(:client, false)
|
38
|
+
@nexttime = nexttime
|
39
|
+
end
|
40
|
+
|
41
|
+
def nexttime
|
42
|
+
t = (Time.now.to_i + @interval)
|
43
|
+
Time.at(t - (t % @interval))
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_timer tm
|
47
|
+
if tm >= @nexttime
|
48
|
+
stamp_log
|
49
|
+
@nexttime = nexttime
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def stamp_log
|
54
|
+
msg = @nexttime.strftime(@stampformat)
|
55
|
+
@state.channels.each{|ch|
|
56
|
+
@logger.clog(ch, msg, true)
|
57
|
+
}
|
58
|
+
@logger.slog(msg, true) if @client
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
data/plugins/titlebot.nb
ADDED
@@ -0,0 +1,226 @@
|
|
1
|
+
# -*-ruby-*-
|
2
|
+
#
|
3
|
+
# Copyright (c) 2009, 2011 Kazuhiro NISHIYAMA
|
4
|
+
#
|
5
|
+
# This program is free software with ABSOLUTELY NO WARRANTY.
|
6
|
+
# You can re-distribute and/or modify this program under
|
7
|
+
# the same terms of the Ruby's license.
|
8
|
+
#
|
9
|
+
|
10
|
+
=begin
|
11
|
+
|
12
|
+
== Abstract
|
13
|
+
|
14
|
+
Reply title of URL.
|
15
|
+
|
16
|
+
== Configuration
|
17
|
+
|
18
|
+
BotConfig << {
|
19
|
+
:name => :TitleBot,
|
20
|
+
:ch => //,
|
21
|
+
:timeout => 10,
|
22
|
+
}
|
23
|
+
|
24
|
+
=end
|
25
|
+
|
26
|
+
require 'nkf'
|
27
|
+
require 'open-uri'
|
28
|
+
require 'timeout'
|
29
|
+
require 'tmpdir'
|
30
|
+
|
31
|
+
begin
|
32
|
+
require 'rubygems'
|
33
|
+
require 'nokogiri'
|
34
|
+
rescue LoadError
|
35
|
+
end
|
36
|
+
|
37
|
+
module URL2Title
|
38
|
+
module_function
|
39
|
+
|
40
|
+
def get_title(url)
|
41
|
+
uri = URI(url)
|
42
|
+
info = { :uri => uri }
|
43
|
+
info[:errors] = []
|
44
|
+
case uri.host
|
45
|
+
when /localhost/, /\A127\./, /\A192\.168\./, /\A10\./
|
46
|
+
info[:title] = "(ignored)"
|
47
|
+
return info
|
48
|
+
end
|
49
|
+
uri.open(:content_length_proc => proc{|x| raise Errno::EFBIG if x && x > 1048576}) do |f|
|
50
|
+
info[:uri] = f.base_uri
|
51
|
+
body = f.read
|
52
|
+
|
53
|
+
if /\.blog\d+\.fc2\.com\z/ =~ uri.host
|
54
|
+
# set last content-type only
|
55
|
+
f.meta_add_field("content-type", f.meta["content-type"].split(/, /)[-1])
|
56
|
+
end
|
57
|
+
|
58
|
+
case f.content_type
|
59
|
+
when /\Atext\//
|
60
|
+
charset = f.charset{} # without block, returns "iso-8859-1"
|
61
|
+
|
62
|
+
# Content-Encoding
|
63
|
+
case
|
64
|
+
when f.content_encoding.empty?
|
65
|
+
# ignore
|
66
|
+
when f.content_encoding.any?{|c_e| /deflate/ =~ c_e }
|
67
|
+
require "zlib"
|
68
|
+
body = Zlib::Inflate.inflate(body)
|
69
|
+
when f.content_encoding.any?{|c_e| /gzip/ =~ c_e }
|
70
|
+
require "zlib"
|
71
|
+
body = Zlib::GzipReader.new(StringIO.new(body)).read || ''
|
72
|
+
end
|
73
|
+
|
74
|
+
# encoding
|
75
|
+
if NKF.guess(body) == NKF::BINARY
|
76
|
+
info[:title] = "(binary)"
|
77
|
+
return info
|
78
|
+
end
|
79
|
+
body = NKF.nkf("-wm0x --numchar-input", body)
|
80
|
+
|
81
|
+
title = nil
|
82
|
+
case uri.host
|
83
|
+
when /\A(?:www\.so-net\.ne\.jp)\z/
|
84
|
+
if %r"<title\b(?>[^<>]*)>(.*?)</title(?>[^<>]*)>"miu =~ body
|
85
|
+
title = $1
|
86
|
+
end
|
87
|
+
if %r!<dt id="ttl">(.*?)</dt>!miu =~ body
|
88
|
+
title = $1
|
89
|
+
end
|
90
|
+
else
|
91
|
+
if %r"<title\b(?>[^<>]*)>(.*?)</title(?>[^<>]*)>"miu =~ body
|
92
|
+
title = $1
|
93
|
+
end
|
94
|
+
if uri.fragment && defined?(::Nokogiri)
|
95
|
+
begin
|
96
|
+
doc = Nokogiri::HTML(body, uri.to_s, 'utf-8')
|
97
|
+
xpath = "//*[@id='#{uri.fragment}' or @name='#{uri.fragment}']"
|
98
|
+
fragment_element = doc.xpath(xpath)
|
99
|
+
# tDiary style
|
100
|
+
unless fragment_element.xpath("span[@class='sanchor']").empty?
|
101
|
+
fragment_element = fragment_element.xpath("..")
|
102
|
+
end
|
103
|
+
info[:fragment_text] = truncate(fragment_element.text)
|
104
|
+
rescue Exception => e
|
105
|
+
info[:errors] << e
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
info[:title] = title || body
|
110
|
+
return info
|
111
|
+
when /\Aimage\//
|
112
|
+
if f.respond_to?(:path) && f.path
|
113
|
+
info[:title] = `identify '#{f.path}'`.sub(/\A#{Regexp.quote(f.path)}/, '').strip
|
114
|
+
return info
|
115
|
+
else
|
116
|
+
info[:title] = "(unknown image format)"
|
117
|
+
return info
|
118
|
+
end
|
119
|
+
else
|
120
|
+
info[:title] = "#{f.content_type} #{f.size} bytes"
|
121
|
+
return info
|
122
|
+
end
|
123
|
+
end
|
124
|
+
rescue Errno::EFBIG
|
125
|
+
info[:title] = "(too big)"
|
126
|
+
return info
|
127
|
+
end
|
128
|
+
|
129
|
+
def truncate s
|
130
|
+
if /\A(?>(.{197})....)/mu =~ s
|
131
|
+
return $1+'...'
|
132
|
+
else
|
133
|
+
return s
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def prepare_url(url)
|
138
|
+
url.sub(/\/\#!\//, '/')
|
139
|
+
end
|
140
|
+
|
141
|
+
def url2title(url)
|
142
|
+
url = prepare_url(url)
|
143
|
+
info = get_title(url)
|
144
|
+
info[:title] = truncate(info[:title])
|
145
|
+
info
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
if __FILE__ == $0
|
150
|
+
def u2t(url)
|
151
|
+
URL2Title.url2title(url)
|
152
|
+
rescue
|
153
|
+
$!.inspect
|
154
|
+
end
|
155
|
+
if ARGV.empty?
|
156
|
+
# TODO: test
|
157
|
+
else
|
158
|
+
ARGV.each do |url|
|
159
|
+
info = u2t(url)
|
160
|
+
p info
|
161
|
+
puts url
|
162
|
+
puts info[:title]
|
163
|
+
end
|
164
|
+
end
|
165
|
+
exit
|
166
|
+
end
|
167
|
+
|
168
|
+
class TitleBot < Nadoka::NDK_Bot
|
169
|
+
include URL2Title
|
170
|
+
|
171
|
+
def bot_initialize
|
172
|
+
if @bot_config.key?(:channels)
|
173
|
+
channels = '\A(?:' + @bot_config[:channels].collect{|ch|
|
174
|
+
Regexp.quote(ch)
|
175
|
+
}.join('|') + ')\z'
|
176
|
+
@available_channel = Regexp.compile(channels)
|
177
|
+
else
|
178
|
+
@available_channel = @bot_config.fetch(:ch, //)
|
179
|
+
end
|
180
|
+
|
181
|
+
@same_bot = @bot_config.fetch(:same_bot, /(?!)/)
|
182
|
+
@nkf_options = @bot_config.fetch(:nkf, "--oc=CP50221 --numchar-input --fb-xml")
|
183
|
+
@timeout = @bot_config.fetch(:timeout, 10)
|
184
|
+
@too_long_threshold = @bot_config.fetch(:too_long_threshold, 250)
|
185
|
+
end
|
186
|
+
|
187
|
+
def send_notice(ch, msg)
|
188
|
+
msg = msg.tr("\r\n", " ")
|
189
|
+
if @nkf_options
|
190
|
+
msg = NKF.nkf(@nkf_options, msg)
|
191
|
+
end
|
192
|
+
super(ch, msg)
|
193
|
+
end
|
194
|
+
|
195
|
+
def on_privmsg prefix, ch, msg
|
196
|
+
return unless @available_channel === ch
|
197
|
+
|
198
|
+
if /https?:/ === msg
|
199
|
+
return if @state.channel_users(ccn(ch)).find{|x| @same_bot =~ x }
|
200
|
+
|
201
|
+
url, = URI.extract(msg, ["http", "https"])
|
202
|
+
info = Timeout.timeout(@timeout) do
|
203
|
+
url2title(url)
|
204
|
+
end
|
205
|
+
return unless info[:title]
|
206
|
+
if url != info[:uri].to_s
|
207
|
+
send_notice(ch, "title bot: #{info[:title]} - #{info[:uri]}")
|
208
|
+
else
|
209
|
+
send_notice(ch, "title bot: #{info[:title]}")
|
210
|
+
end
|
211
|
+
if info[:fragment_text]
|
212
|
+
# ignore when fragment_text is too long
|
213
|
+
if info[:fragment_text].size < @too_long_threshold
|
214
|
+
send_notice(ch, "title bot:: #{info[:fragment_text]}")
|
215
|
+
end
|
216
|
+
end
|
217
|
+
info[:errors].each do |e|
|
218
|
+
@manager.ndk_error e
|
219
|
+
send_notice(ch, "title bot error: #{e}")
|
220
|
+
end
|
221
|
+
end
|
222
|
+
rescue Exception => e
|
223
|
+
send_notice(ch, "title bot error! #{e}")
|
224
|
+
@manager.ndk_error e
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,301 @@
|
|
1
|
+
# -*-ruby-*-
|
2
|
+
#
|
3
|
+
# Copyright (c) 2010 SASADA Koichi <ko1 at atdot.net>
|
4
|
+
#
|
5
|
+
# This program is free software with ABSOLUTELY NO WARRANTY.
|
6
|
+
# You can re-distribute and/or modify this program under
|
7
|
+
# the same terms of the Ruby's license.
|
8
|
+
#
|
9
|
+
|
10
|
+
=begin
|
11
|
+
|
12
|
+
== Usage with irc client
|
13
|
+
|
14
|
+
trans> hello
|
15
|
+
-> translate hello as a English to Japanese.
|
16
|
+
|
17
|
+
trans:ja> hello
|
18
|
+
-> ditto.
|
19
|
+
|
20
|
+
trans:en,ja> hello
|
21
|
+
-> ditto.
|
22
|
+
|
23
|
+
trans:(([lang_from],)[lang_to])> [phrase]
|
24
|
+
-> translate [phrase] as lang_from to lang_to.
|
25
|
+
|
26
|
+
transj> [phrase]
|
27
|
+
-> translate to Japanese
|
28
|
+
|
29
|
+
transe> [phrase]
|
30
|
+
-> translate to English
|
31
|
+
|
32
|
+
== Configuration:
|
33
|
+
|
34
|
+
BotConfig = [
|
35
|
+
{
|
36
|
+
:name => :TranslateBot,
|
37
|
+
:ch => /.*/,
|
38
|
+
:referer => 'http://rubyforge.org/projects/nadoka/',
|
39
|
+
# Register URL at http://code.google.com/intl/ja/apis/ajaxsearch/signup.html
|
40
|
+
# and set your URL to :referer and your API key to :api_key if you want.
|
41
|
+
:to_lang => 'ja',
|
42
|
+
:to_lang2 => 'en',
|
43
|
+
:ch_kcode => :tojis,
|
44
|
+
},
|
45
|
+
]
|
46
|
+
|
47
|
+
=end
|
48
|
+
|
49
|
+
require 'iconv'
|
50
|
+
require 'kconv'
|
51
|
+
require 'shellwords'
|
52
|
+
require 'cgi'
|
53
|
+
require 'open-uri'
|
54
|
+
begin
|
55
|
+
require 'json'
|
56
|
+
rescue LoadError
|
57
|
+
require 'rubygems'
|
58
|
+
require 'json'
|
59
|
+
end
|
60
|
+
|
61
|
+
class TranslateBot < Nadoka::NDK_Bot
|
62
|
+
def bot_initialize
|
63
|
+
@available_channel = @bot_config[:ch] || /.*/
|
64
|
+
@search_default_lang = (@bot_config[:search_default_lang] || 'ja').sub(/^lang_/, '')
|
65
|
+
@referer = @bot_config[:referer] || 'http://rubyforge.org/projects/nadoka/'
|
66
|
+
@ch_kcode = @bot_config.fetch(:ch_kcode, :tojis)
|
67
|
+
@to_lang = @bot_config.fetch(:to_lang, 'ja')
|
68
|
+
@to_lang2 = @bot_config.fetch(:to_lang2, 'en')
|
69
|
+
@bing_appid = @bot_config.fetch(:bing_appid, nil)
|
70
|
+
end
|
71
|
+
|
72
|
+
def on_privmsg prefix, ch, msg
|
73
|
+
if @available_channel === ch and /^tr/ =~ msg
|
74
|
+
if response = dispatch_command(msg)
|
75
|
+
response.each{|r|
|
76
|
+
send_notice(ch, r) if r
|
77
|
+
}
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
SHORT_LANG = {'e' => 'en', 'j' => 'ja'}
|
83
|
+
|
84
|
+
def dispatch_command msg
|
85
|
+
begin
|
86
|
+
case msg
|
87
|
+
when /^trans(?:late)?(:(.*?))?>\s*(.+)/o
|
88
|
+
translate($3, *parse_trans_option($2, $3))
|
89
|
+
when /^trans([ej])>\s*(.+)/o
|
90
|
+
translate($2, nil, SHORT_LANG[$1])
|
91
|
+
when /^trans(?:late)?r(:(.*?))?>\s*(.+)/o
|
92
|
+
translate_r($3, *parse_trans_option($2, $3))
|
93
|
+
when /^translang>(.+)/
|
94
|
+
lang = $1.strip
|
95
|
+
desc = 'Unknown. See http://code.google.com/intl/ja/apis/ajaxlanguage/documentation/reference.html#LangNameArray'
|
96
|
+
r = LANGUAGE_MAP_S2L.fetch(lang.downcase,
|
97
|
+
LANGUAGE_MAP.fetch(lang.upcase, desc))
|
98
|
+
"translang> #{lang} = #{r}"
|
99
|
+
end
|
100
|
+
rescue Exception => e
|
101
|
+
"translate bot: #{e.message}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def detect_lang str
|
106
|
+
uri = "http://ajax.googleapis.com/ajax/services/language/detect?v=1.0&q="
|
107
|
+
uri << CGI.escape(str.toutf8)
|
108
|
+
|
109
|
+
result = open(uri, "Referer" => @referer) do |f|
|
110
|
+
JSON.parse(f.read)
|
111
|
+
end
|
112
|
+
|
113
|
+
if result["responseData"]
|
114
|
+
result["responseData"]["language"]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def parse_trans_option opt, str
|
119
|
+
case opt
|
120
|
+
when nil
|
121
|
+
from_lang = detect_lang(str)
|
122
|
+
to_lang = @to_lang
|
123
|
+
if to_lang == from_lang
|
124
|
+
to_lang = @to_lang2
|
125
|
+
end
|
126
|
+
[from_lang, to_lang]
|
127
|
+
when /\A([\w\-]+)[, \>]([\w\-]+)\z/
|
128
|
+
[$1, $2]
|
129
|
+
when /\A([\w\-]+)\z/
|
130
|
+
[nil, $1]
|
131
|
+
else
|
132
|
+
raise "can't parse translation option: #{opt}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def translate phrase, from_lang, to_lang
|
137
|
+
r = []
|
138
|
+
|
139
|
+
gr = translate_ggl(phrase, from_lang, to_lang)
|
140
|
+
r << "g:translate bot (#{gr[1]}): #{gr[0]}"
|
141
|
+
|
142
|
+
if @bing_appid
|
143
|
+
mr = translate_ms(phrase, from_lang, to_lang) if @bing_appid
|
144
|
+
r << "m:translate bot (#{mr[1]}): #{mr[0]}"
|
145
|
+
end
|
146
|
+
r
|
147
|
+
end
|
148
|
+
|
149
|
+
def translate_r phrase, from_lang, to_lang
|
150
|
+
rs = []
|
151
|
+
%w(ggl ms).each{|system|
|
152
|
+
r = send("translate_#{system}", phrase, from_lang, to_lang)
|
153
|
+
from_lang = r[2]
|
154
|
+
first = r[0]
|
155
|
+
if from_lang
|
156
|
+
r = send("translate_#{system}", r[0], to_lang, from_lang)
|
157
|
+
rs << "#{system.split(//)[0]}:trans_r (#{from_lang}>#{to_lang}>#{from_lang}): #{r[0]} (#{first})"
|
158
|
+
end
|
159
|
+
}
|
160
|
+
rs
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
def translate_ggl(phrase, from_lang, to_lang)
|
165
|
+
uri = 'http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q='
|
166
|
+
uri << CGI.escape(phrase.toutf8)
|
167
|
+
uri << "&langpair=#{from_lang}%7C#{to_lang}"
|
168
|
+
|
169
|
+
result = open(uri, "Referer" => @referer) do |f|
|
170
|
+
JSON.parse(f.read)
|
171
|
+
end
|
172
|
+
|
173
|
+
if result["responseData"]
|
174
|
+
text = CGI.unescapeHTML(result["responseData"]["translatedText"])
|
175
|
+
text = text.send(@ch_kcode) if @ch_kcode
|
176
|
+
from_lang ||= result["responseData"]["detectedSourceLanguage"]
|
177
|
+
opts = "#{from_lang}>#{to_lang}"
|
178
|
+
[text, opts, from_lang]
|
179
|
+
else
|
180
|
+
opts = "#{from_lang ? "from #{from_lang} to " : ''}#{to_lang}"
|
181
|
+
["#{result["responseDetails"]} (#{uri})", opts]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
## ms translate
|
186
|
+
|
187
|
+
def get_result_ms result
|
188
|
+
# puts result
|
189
|
+
doc = REXML::Document.new(result)
|
190
|
+
doc.elements.map{|e| e.text}[0]
|
191
|
+
end
|
192
|
+
|
193
|
+
def translate_ms phrase, from_lang, to_lang
|
194
|
+
api_url = 'http://api.microsofttranslator.com/V2/Http.svc/Translate'
|
195
|
+
uri = "#{api_url}?appId=#{@bing_appid}&text=#{CGI.escape(phrase.toutf8)}&to=#{CGI.escape(to_lang)}"
|
196
|
+
begin
|
197
|
+
text = get_result_ms open(uri, "Referer" => @referer).read
|
198
|
+
text = text.send(@ch_kcode) if @ch_kcode
|
199
|
+
opts = "#{from_lang}>#{to_lang}"
|
200
|
+
[text, opts, from_lang]
|
201
|
+
rescue OpenURI::HTTPError => e
|
202
|
+
opts = "#{from_lang ? "from #{from_lang} to " : ''}#{to_lang}"
|
203
|
+
["#{e.message} (uri)", opts]
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# copy from http://code.google.com/intl/ja/apis/ajaxlanguage/documentation/reference.html
|
208
|
+
LANGUAGE_MAP = {
|
209
|
+
'AFRIKAANS' => 'af',
|
210
|
+
'ALBANIAN' => 'sq',
|
211
|
+
'AMHARIC' => 'am',
|
212
|
+
'ARABIC' => 'ar',
|
213
|
+
'ARMENIAN' => 'hy',
|
214
|
+
'AZERBAIJANI' => 'az',
|
215
|
+
'BASQUE' => 'eu',
|
216
|
+
'BELARUSIAN' => 'be',
|
217
|
+
'BENGALI' => 'bn',
|
218
|
+
'BIHARI' => 'bh',
|
219
|
+
'BULGARIAN' => 'bg',
|
220
|
+
'BURMESE' => 'my',
|
221
|
+
'CATALAN' => 'ca',
|
222
|
+
'CHEROKEE' => 'chr',
|
223
|
+
'CHINESE' => 'zh',
|
224
|
+
'CHINESE_SIMPLIFIED' => 'zh-CN',
|
225
|
+
'CHINESE_TRADITIONAL' => 'zh-TW',
|
226
|
+
'CROATIAN' => 'hr',
|
227
|
+
'CZECH' => 'cs',
|
228
|
+
'DANISH' => 'da',
|
229
|
+
'DHIVEHI' => 'dv',
|
230
|
+
'DUTCH'=> 'nl',
|
231
|
+
'ENGLISH' => 'en',
|
232
|
+
'ESPERANTO' => 'eo',
|
233
|
+
'ESTONIAN' => 'et',
|
234
|
+
'FILIPINO' => 'tl',
|
235
|
+
'FINNISH' => 'fi',
|
236
|
+
'FRENCH' => 'fr',
|
237
|
+
'GALICIAN' => 'gl',
|
238
|
+
'GEORGIAN' => 'ka',
|
239
|
+
'GERMAN' => 'de',
|
240
|
+
'GREEK' => 'el',
|
241
|
+
'GUARANI' => 'gn',
|
242
|
+
'GUJARATI' => 'gu',
|
243
|
+
'HEBREW' => 'iw',
|
244
|
+
'HINDI' => 'hi',
|
245
|
+
'HUNGARIAN' => 'hu',
|
246
|
+
'ICELANDIC' => 'is',
|
247
|
+
'INDONESIAN' => 'id',
|
248
|
+
'INUKTITUT' => 'iu',
|
249
|
+
'ITALIAN' => 'it',
|
250
|
+
'JAPANESE' => 'ja',
|
251
|
+
'KANNADA' => 'kn',
|
252
|
+
'KAZAKH' => 'kk',
|
253
|
+
'KHMER' => 'km',
|
254
|
+
'KOREAN' => 'ko',
|
255
|
+
'KURDISH'=> 'ku',
|
256
|
+
'KYRGYZ'=> 'ky',
|
257
|
+
'LAOTHIAN'=> 'lo',
|
258
|
+
'LATVIAN' => 'lv',
|
259
|
+
'LITHUANIAN' => 'lt',
|
260
|
+
'MACEDONIAN' => 'mk',
|
261
|
+
'MALAY' => 'ms',
|
262
|
+
'MALAYALAM' => 'ml',
|
263
|
+
'MALTESE' => 'mt',
|
264
|
+
'MARATHI' => 'mr',
|
265
|
+
'MONGOLIAN' => 'mn',
|
266
|
+
'NEPALI' => 'ne',
|
267
|
+
'NORWEGIAN' => 'no',
|
268
|
+
'ORIYA' => 'or',
|
269
|
+
'PASHTO' => 'ps',
|
270
|
+
'PERSIAN' => 'fa',
|
271
|
+
'POLISH' => 'pl',
|
272
|
+
'PORTUGUESE' => 'pt-PT',
|
273
|
+
'PUNJABI' => 'pa',
|
274
|
+
'ROMANIAN' => 'ro',
|
275
|
+
'RUSSIAN' => 'ru',
|
276
|
+
'SANSKRIT' => 'sa',
|
277
|
+
'SERBIAN' => 'sr',
|
278
|
+
'SINDHI' => 'sd',
|
279
|
+
'SINHALESE' => 'si',
|
280
|
+
'SLOVAK' => 'sk',
|
281
|
+
'SLOVENIAN' => 'sl',
|
282
|
+
'SPANISH' => 'es',
|
283
|
+
'SWAHILI' => 'sw',
|
284
|
+
'SWEDISH' => 'sv',
|
285
|
+
'TAJIK' => 'tg',
|
286
|
+
'TAMIL' => 'ta',
|
287
|
+
'TAGALOG' => 'tl',
|
288
|
+
'TELUGU' => 'te',
|
289
|
+
'THAI' => 'th',
|
290
|
+
'TIBETAN' => 'bo',
|
291
|
+
'TURKISH' => 'tr',
|
292
|
+
'UKRAINIAN' => 'uk',
|
293
|
+
'URDU' => 'ur',
|
294
|
+
'UZBEK' => 'uz',
|
295
|
+
'UIGHUR' => 'ug',
|
296
|
+
'VIETNAMESE' => 'vi',
|
297
|
+
'UNKNOWN' => ''
|
298
|
+
}
|
299
|
+
|
300
|
+
LANGUAGE_MAP_S2L = LANGUAGE_MAP.invert
|
301
|
+
end
|