bing_translator_fix 4.5.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.
- checksums.yaml +7 -0
- data/lib/bing_translator.rb +213 -0
- metadata +87 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f0ee46cc98df19d4b842d8fea57cf904a160daa1
|
4
|
+
data.tar.gz: 259c5eba544b0b5e6991ce671aa4f1cda0a9c24b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4dcd2029d7385d3f93a8c7b9c96d29859b1606bbd1b027229bbb6d0b27ee147f72d7fe25de7fb41e5686eb0dbbd6bb4cd955b9dc6232515f75fe7423fc933159
|
7
|
+
data.tar.gz: b676f8085d6d1e2bb49718466816a9ca2a152818cdaf187e8550d1edb24e1b3d02527a38d55f35220b06961ccbc501ab70447540d9685d0dfd1debc802f8c8f8
|
@@ -0,0 +1,213 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
# (c) 2011-present. Ricky Elrod <ricky@elrod.me>
|
4
|
+
# Released under the MIT license.
|
5
|
+
require 'rubygems'
|
6
|
+
require 'cgi'
|
7
|
+
require 'uri'
|
8
|
+
require 'net/http'
|
9
|
+
require 'net/https'
|
10
|
+
require 'nokogiri'
|
11
|
+
require 'json'
|
12
|
+
require 'savon'
|
13
|
+
|
14
|
+
class BingTranslator
|
15
|
+
WSDL_URI = 'http://api.microsofttranslator.com/V2/soap.svc?wsdl'
|
16
|
+
NAMESPACE_URI = 'http://api.microsofttranslator.com/V2'
|
17
|
+
ACCESS_TOKEN_URI = 'https://datamarket.accesscontrol.windows.net/v2/OAuth2-13'
|
18
|
+
DATASETS_URI = "https://api.datamarket.azure.com/Services/My/Datasets?$format=json"
|
19
|
+
|
20
|
+
class Exception < StandardError; end
|
21
|
+
class AuthenticationException < StandardError; end
|
22
|
+
|
23
|
+
def initialize(client_id, client_secret, skip_ssl_verify = false, account_key = nil)
|
24
|
+
@client_id = client_id
|
25
|
+
@client_secret = client_secret
|
26
|
+
@account_key = account_key
|
27
|
+
@skip_ssl_verify = skip_ssl_verify
|
28
|
+
|
29
|
+
@access_token_uri = URI.parse ACCESS_TOKEN_URI
|
30
|
+
@datasets_uri = URI.parse DATASETS_URI
|
31
|
+
end
|
32
|
+
|
33
|
+
def translate(text, params = {})
|
34
|
+
raise "Must provide :to." if params[:to].nil?
|
35
|
+
|
36
|
+
# Important notice: param order makes sense in SOAP. Do not reorder or delete!
|
37
|
+
params = {
|
38
|
+
'text' => text.to_s,
|
39
|
+
'from' => params[:from].to_s,
|
40
|
+
'to' => params[:to].to_s,
|
41
|
+
'category' => 'general',
|
42
|
+
'contentType' => params[:content_type] || 'text/plain'
|
43
|
+
}
|
44
|
+
|
45
|
+
result(:translate, params)
|
46
|
+
end
|
47
|
+
|
48
|
+
def translate_array(texts, params = {})
|
49
|
+
raise "Must provide :to." if params[:to].nil?
|
50
|
+
|
51
|
+
# Important notice: param order makes sense in SOAP. Do not reorder or delete!
|
52
|
+
params = {
|
53
|
+
'texts' => { 'arr:string' => texts },
|
54
|
+
'from' => params[:from].to_s,
|
55
|
+
'to' => params[:to].to_s,
|
56
|
+
'category' => 'general',
|
57
|
+
'contentType' => params[:content_type] || 'text/plain'
|
58
|
+
}
|
59
|
+
|
60
|
+
array_wrap(result(:translate_array, params)[:translate_array_response]).map{|r| r[:translated_text]}
|
61
|
+
end
|
62
|
+
|
63
|
+
def detect(text)
|
64
|
+
params = {
|
65
|
+
'text' => text.to_s,
|
66
|
+
'language' => '',
|
67
|
+
}
|
68
|
+
|
69
|
+
result(:detect, params).to_sym
|
70
|
+
end
|
71
|
+
|
72
|
+
# format: 'audio/wav' [default] or 'audio/mp3'
|
73
|
+
# language: valid translator language code
|
74
|
+
# options: 'MinSize' [default] or 'MaxQuality'
|
75
|
+
def speak(text, params = {})
|
76
|
+
raise "Must provide :language" if params[:language].nil?
|
77
|
+
|
78
|
+
params = {
|
79
|
+
'text' => text.to_s,
|
80
|
+
'language' => params[:language].to_s,
|
81
|
+
'format' => params[:format] || 'audio/wav',
|
82
|
+
'options' => params[:options] || 'MinSize',
|
83
|
+
}
|
84
|
+
|
85
|
+
uri = URI.parse(result(:speak, params))
|
86
|
+
|
87
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
88
|
+
if uri.scheme == "https"
|
89
|
+
http.use_ssl = true
|
90
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @skip_ssl_verify
|
91
|
+
end
|
92
|
+
results = http.get(uri.to_s, {'Authorization' => "Bearer #{get_access_token['access_token']}"})
|
93
|
+
|
94
|
+
if results.response.code.to_i == 200
|
95
|
+
results.body
|
96
|
+
else
|
97
|
+
html = Nokogiri::HTML(results.body)
|
98
|
+
raise Exception, html.xpath("//text()").remove.map(&:to_s).join(' ')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def supported_language_codes
|
103
|
+
result(:get_languages_for_translate)[:string]
|
104
|
+
end
|
105
|
+
|
106
|
+
def language_names(codes, locale = 'en')
|
107
|
+
response = result(:get_language_names, locale: locale, languageCodes: {'a:string' => codes}) do
|
108
|
+
attributes 'xmlns:a' => 'http://schemas.microsoft.com/2003/10/Serialization/Arrays'
|
109
|
+
end
|
110
|
+
|
111
|
+
response[:string]
|
112
|
+
end
|
113
|
+
|
114
|
+
def balance
|
115
|
+
datasets["d"]["results"].each do |result|
|
116
|
+
return result["ResourceBalance"] if result["ProviderName"] == "Microsoft Translator"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Get a new access token and set it internally as @access_token
|
121
|
+
#
|
122
|
+
# Microsoft changed up how you get access to the Translate API.
|
123
|
+
# This gets a new token if it's required. We call this internally
|
124
|
+
# before any request we make to the Translate API.
|
125
|
+
#
|
126
|
+
# @return {hash}
|
127
|
+
# Returns existing @access_token if we don't need a new token yet,
|
128
|
+
# or returns the one just obtained.
|
129
|
+
def get_access_token
|
130
|
+
return @access_token if @access_token and
|
131
|
+
Time.now < @access_token['expires_at']
|
132
|
+
|
133
|
+
params = {
|
134
|
+
'client_id' => CGI.escape(@client_id),
|
135
|
+
'client_secret' => CGI.escape(@client_secret),
|
136
|
+
'scope' => CGI.escape('http://api.microsofttranslator.com'),
|
137
|
+
'grant_type' => 'client_credentials'
|
138
|
+
}
|
139
|
+
|
140
|
+
http = Net::HTTP.new(@access_token_uri.host, @access_token_uri.port)
|
141
|
+
http.use_ssl = true
|
142
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @skip_ssl_verify
|
143
|
+
|
144
|
+
response = http.post(@access_token_uri.path, prepare_param_string(params))
|
145
|
+
@access_token = JSON.parse(response.body)
|
146
|
+
raise AuthenticationException, @access_token['error'] if @access_token["error"]
|
147
|
+
@access_token['expires_at'] = Time.now + @access_token['expires_in'].to_i
|
148
|
+
@access_token
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
def datasets
|
153
|
+
raise AuthenticationException, "Must provide account key" if @account_key.nil?
|
154
|
+
|
155
|
+
http = Net::HTTP.new(@datasets_uri.host, @datasets_uri.port)
|
156
|
+
http.use_ssl = true
|
157
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
158
|
+
request = Net::HTTP::Get.new(@datasets_uri.request_uri)
|
159
|
+
request.basic_auth("", @account_key)
|
160
|
+
response = http.request(request)
|
161
|
+
|
162
|
+
JSON.parse response.body
|
163
|
+
end
|
164
|
+
|
165
|
+
def prepare_param_string(params)
|
166
|
+
params.map { |key, value| "#{key}=#{value}" }.join '&'
|
167
|
+
end
|
168
|
+
|
169
|
+
# Public: performs actual request to Bing Translator SOAP API
|
170
|
+
def result(action, params = {}, &block)
|
171
|
+
# Specify SOAP namespace in tag names (see https://github.com/savonrb/savon/issues/340 )
|
172
|
+
params = Hash[params.map{|k,v| ["v2:#{k}", v]}]
|
173
|
+
begin
|
174
|
+
soap_client.call(action, message: params, &block).body[:"#{action}_response"][:"#{action}_result"]
|
175
|
+
rescue AuthenticationException
|
176
|
+
raise
|
177
|
+
rescue StandardError => e
|
178
|
+
# Keep old behaviour: raise only internal Exception class
|
179
|
+
raise Exception, e.message
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Private: Constructs SOAP client
|
184
|
+
#
|
185
|
+
# Construct and store new client when called first time.
|
186
|
+
# Return stored client while access token is fresh.
|
187
|
+
# Construct and store new client when token have been expired.
|
188
|
+
def soap_client
|
189
|
+
return @client if @client and @access_token and
|
190
|
+
Time.now < @access_token['expires_at']
|
191
|
+
|
192
|
+
@client = Savon.client(
|
193
|
+
wsdl: WSDL_URI,
|
194
|
+
namespace: NAMESPACE_URI,
|
195
|
+
namespace_identifier: :v2,
|
196
|
+
namespaces: {
|
197
|
+
'xmlns:arr' => 'http://schemas.microsoft.com/2003/10/Serialization/Arrays'
|
198
|
+
},
|
199
|
+
headers: {'Authorization' => "Bearer #{get_access_token['access_token']}"},
|
200
|
+
)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Private: Array#wrap based on ActiveSupport extension
|
204
|
+
def array_wrap(object)
|
205
|
+
if object.nil?
|
206
|
+
[]
|
207
|
+
elsif object.respond_to?(:to_ary)
|
208
|
+
object.to_ary || [object]
|
209
|
+
else
|
210
|
+
[object]
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bing_translator_fix
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 4.5.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ricky Elrod
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-08-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: nokogiri
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.6.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.6.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.8.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: savon
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.10.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.10.0
|
55
|
+
description: Translate strings using the Bing HTTP API. Requires that you have a Client
|
56
|
+
ID and Secret. See README.md for information.
|
57
|
+
email: ricky@elrod.me
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- lib/bing_translator.rb
|
63
|
+
homepage: https://www.github.com/relrod/bing_translator-gem
|
64
|
+
licenses:
|
65
|
+
- MIT
|
66
|
+
metadata: {}
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
requirements: []
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 2.4.8
|
84
|
+
signing_key:
|
85
|
+
specification_version: 4
|
86
|
+
summary: Translate using the Bing HTTP API
|
87
|
+
test_files: []
|