bing_translator 6.0.0.beta.1 → 6.2.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.
Files changed (3) hide show
  1. checksums.yaml +5 -5
  2. data/lib/bing_translator.rb +177 -165
  3. metadata +4 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9106de975569bef3303a4940318a78b536beaf10
4
- data.tar.gz: e40c556e6f474d185b74f6753635a448720600f6
2
+ SHA256:
3
+ metadata.gz: 7135526b9017a66474ba77d994758c3f9bed0133527133f8d1abc5bf9461bad1
4
+ data.tar.gz: 4fce05ccdbb038f514dd80e7420951bad1e70e9d7b13be2d653fd7df71c5b347
5
5
  SHA512:
6
- metadata.gz: 8b84d0f6c1b4a405ee631221a961f8e5462c7de1b0ca3eb26b0f0b2dc105e3b0e8ac19c085c8de320191a66895af313fc1b1f718f81b13505a6b31ab8a20108c
7
- data.tar.gz: c22b944db83f5b437b9fa56e8df83da1bd69f7b81f9ef65dedb51a66d82c79714fba29701da46a6bd1b027e56ff69e54f3e5c21bddfccacddfadd3daa252e3a4
6
+ metadata.gz: 17393a3b1cf0e224f57cfefa1a0f9aac02cf235d415415b68c0a12c0740cb56051f4aa324c58cb822f892255ff086edd337a31c3c41efe1511fa9add84e5eb9f
7
+ data.tar.gz: 5368fa7751bebf485142e5b6a7e6821c25544c7a9a6e8524ef033f6cc65de7e71616935d51a8ed92a2a442634e6eff57be4bbdb6b53a3da0ed13879174766bc6
@@ -1,165 +1,177 @@
1
- #!/usr/bin/env ruby
2
-
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 'json'
11
-
12
- class BingTranslator
13
- class Exception < StandardError; end
14
-
15
- class ApiClient
16
- API_HOST = 'https://api.cognitive.microsofttranslator.com'.freeze
17
- COGNITIVE_ACCESS_TOKEN_URI =
18
- URI.parse('https://api.cognitive.microsoft.com/sts/v1.0/issueToken').freeze
19
-
20
- def initialize(subscription_key, skip_ssl_verify)
21
- @subscription_key = subscription_key
22
- @skip_ssl_verify = skip_ssl_verify
23
- end
24
-
25
- def get(path, params: {}, headers: {}, authorization: false)
26
- uri = request_uri(path, params)
27
- request = Net::HTTP::Get.new(uri.request_uri, default_headers(authorization).merge(headers))
28
-
29
- json_response(uri, request)
30
- end
31
-
32
- def post(path, params: {}, headers: {}, data: {}, authorization: true)
33
- uri = request_uri(path, params)
34
-
35
- request = Net::HTTP::Post.new(uri.request_uri, default_headers(authorization).merge(headers))
36
- request.body = data
37
-
38
- json_response(uri, request)
39
- end
40
-
41
- private
42
-
43
- def default_headers(authorization = true)
44
- headers = { 'Content-Type' => 'application/json' }
45
- headers['Authorization'] = "Bearer #{access_token}" if authorization
46
- headers
47
- end
48
-
49
- def json_response(uri, request)
50
- http = http_client(uri)
51
-
52
- response = http.request(request)
53
-
54
- raise Exception.new("Unsuccessful API call: Code: #{response.code}") unless response.code == '200'
55
- JSON.parse(response.body)
56
- end
57
-
58
- def http_client(uri)
59
- http = Net::HTTP.new(uri.host, 443)
60
- http.use_ssl = true
61
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @skip_ssl_verify
62
- http
63
- end
64
-
65
- def request_uri(path, params)
66
- encoded_params = URI.encode_www_form(params.merge('api-version' => '3.0'))
67
- uri = URI.parse("#{API_HOST}#{path}")
68
- uri.query = encoded_params
69
- uri
70
- end
71
-
72
- def access_token
73
- if @access_token.nil? || Time.now < @access_token_expiration_time
74
- @access_token = request_new_access_token
75
- end
76
- @access_token
77
- end
78
-
79
- def request_new_access_token
80
- headers = {
81
- 'Ocp-Apim-Subscription-Key' => @subscription_key
82
- }
83
-
84
- http = Net::HTTP.new(COGNITIVE_ACCESS_TOKEN_URI.host, COGNITIVE_ACCESS_TOKEN_URI.port)
85
- http.use_ssl = true
86
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @skip_ssl_verify
87
-
88
- response = http.post(COGNITIVE_ACCESS_TOKEN_URI.path, '', headers)
89
- if response.code != '200'
90
- raise Exception.new('Invalid credentials')
91
- else
92
- @access_token_expiration_time = Time.now + 480
93
- response.body
94
- end
95
- end
96
- end
97
-
98
- def initialize(subscription_key, options = {})
99
- skip_ssl_verify = options.fetch(:skip_ssl_verify, false)
100
- @api_client = ApiClient.new(subscription_key, skip_ssl_verify)
101
- end
102
-
103
- def translate(text, params)
104
- translate_array([text], params).first
105
- end
106
-
107
- def translate_array(texts, params = {})
108
- translations = translation_request(texts, params)
109
- translations.map do |translation|
110
- translation['text'] if translation.is_a?(Hash)
111
- end
112
- end
113
-
114
- def translate_array2(texts, params = {})
115
- translations = translation_request(texts, params.merge('includeAlignment' => true))
116
- translations.map do |translation|
117
- [translation['text'], translation['alignment']['proj']] if translation.is_a?(Hash)
118
- end
119
- end
120
-
121
- def detect(text)
122
- data = [{ 'Text' => text }].to_json
123
-
124
- response_json = api_client.post('/detect', data: data)
125
- best_detection = response_json.sort_by { |detection| -detection['score'] }.first
126
- best_detection['language'].to_sym
127
- end
128
-
129
- def speak(text, params = {})
130
- raise Exception.new('Not supported since 3.0.0')
131
- end
132
-
133
- def supported_language_codes
134
- response_json = api_client.get('/languages',
135
- params: { scope: 'translation' },
136
- authorization: false)
137
- response_json['translation'].keys
138
- end
139
-
140
- def language_names(codes, locale = 'en')
141
- response_json = api_client.get('/languages',
142
- params: { scope: 'translation' },
143
- headers: { 'Accept-Language' => locale },
144
- authorization: false)
145
- codes.map do |code|
146
- response = response_json['translation'][code.to_s]
147
- response['name'] unless response.nil?
148
- end
149
- end
150
-
151
- private
152
-
153
- attr_reader :api_client
154
-
155
- def translation_request(texts, params)
156
- raise Exception.new('Must provide :to.') if params[:to].nil?
157
-
158
- data = texts.map { |text| { 'Text' => text } }.to_json
159
- response_json = api_client.post('/translate', params: params, data: data)
160
- response_json.map do |translation|
161
- # There should be just one translation, but who knows...
162
- translation['translations'].find { |result| result['to'] == params[:to].to_s }
163
- end
164
- end
165
- end
1
+ #!/usr/bin/env ruby
2
+ # Released under the MIT license, see LICENSE.
3
+ require 'rubygems'
4
+ require 'cgi'
5
+ require 'uri'
6
+ require 'net/http'
7
+ require 'net/https'
8
+ require 'json'
9
+
10
+ class BingTranslator
11
+ class Exception < StandardError; end
12
+ class ApiException < BingTranslator::Exception; end
13
+ class UsageException < BingTranslator::Exception; end
14
+ class UnavailableException < BingTranslator::Exception; end
15
+ class AuthenticationException < BingTranslator::Exception; end
16
+
17
+ class ApiClient
18
+ API_HOST = 'https://api.cognitive.microsofttranslator.com'.freeze
19
+ COGNITIVE_ACCESS_TOKEN_URI =
20
+ URI.parse('https://api.cognitive.microsoft.com/sts/v1.0/issueToken').freeze
21
+
22
+ def initialize(subscription_key, skip_ssl_verify, read_timeout = 60, open_timeout = 60)
23
+ @subscription_key = subscription_key
24
+ @skip_ssl_verify = skip_ssl_verify
25
+ @read_timeout = read_timeout
26
+ @open_timeout = open_timeout
27
+ end
28
+
29
+ def get(path, params: {}, headers: {}, authorization: false)
30
+ uri = request_uri(path, params)
31
+ request = Net::HTTP::Get.new(uri.request_uri, default_headers(authorization).merge(headers))
32
+
33
+ json_response(uri, request)
34
+ end
35
+
36
+ def post(path, params: {}, headers: {}, data: {}, authorization: true)
37
+ uri = request_uri(path, params)
38
+
39
+ request = Net::HTTP::Post.new(uri.request_uri, default_headers(authorization).merge(headers))
40
+ request.body = data
41
+
42
+ json_response(uri, request)
43
+ end
44
+
45
+ private
46
+
47
+ def default_headers(authorization = true)
48
+ headers = { 'Content-Type' => 'application/json' }
49
+ headers['Authorization'] = "Bearer #{access_token}" if authorization
50
+ headers
51
+ end
52
+
53
+ def json_response(uri, request)
54
+ http = http_client(uri)
55
+
56
+ response = http.request(request)
57
+
58
+ raise ApiException.new("Unsuccessful API call: Code: #{response.code}") unless response.code == '200'
59
+ JSON.parse(response.body)
60
+ end
61
+
62
+ def http_client(uri)
63
+ http = Net::HTTP.new(uri.host, 443)
64
+ http.use_ssl = true
65
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @skip_ssl_verify
66
+ http.read_timeout = @read_timeout
67
+ http.open_timeout = @open_timeout
68
+ http
69
+ end
70
+
71
+ def request_uri(path, params)
72
+ encoded_params = URI.encode_www_form(params.merge('api-version' => '3.0'))
73
+ uri = URI.parse("#{API_HOST}#{path}")
74
+ uri.query = encoded_params
75
+ uri
76
+ end
77
+
78
+ def access_token
79
+ if @access_token.nil? || Time.now >= @access_token_expiration_time
80
+ @access_token = request_new_access_token
81
+ end
82
+ @access_token
83
+ end
84
+
85
+ def request_new_access_token
86
+ headers = {
87
+ 'Ocp-Apim-Subscription-Key' => @subscription_key
88
+ }
89
+
90
+ http = Net::HTTP.new(COGNITIVE_ACCESS_TOKEN_URI.host, COGNITIVE_ACCESS_TOKEN_URI.port)
91
+ http.use_ssl = true
92
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @skip_ssl_verify
93
+
94
+ response = http.post(COGNITIVE_ACCESS_TOKEN_URI.path, '', headers)
95
+ case response
96
+ when Net::HTTPSuccess
97
+ @access_token_expiration_time = Time.now + 480
98
+ response.body
99
+ when Net::HTTPServerError
100
+ raise UnavailableException.new("#{response.code}: Credentials server unavailable")
101
+ else
102
+ raise AuthenticationException.new("Unsuccessful Access Token call: Code: #{response.code} (Invalid credentials?)")
103
+ end
104
+ end
105
+ end
106
+
107
+ def initialize(subscription_key, options = {})
108
+ skip_ssl_verify = options.fetch(:skip_ssl_verify, false)
109
+ read_timeout = options.fetch(:read_timeout, 60)
110
+ open_timeout = options.fetch(:open_timeout, 60)
111
+ @api_client = ApiClient.new(subscription_key, skip_ssl_verify, read_timeout, open_timeout)
112
+ end
113
+
114
+ def translate(text, params)
115
+ translate_array([text], params).first
116
+ end
117
+
118
+ def translate_array(texts, params = {})
119
+ translations = translation_request(texts, params)
120
+ translations.map do |translation|
121
+ translation['text'] if translation.is_a?(Hash)
122
+ end
123
+ end
124
+
125
+ def translate_array2(texts, params = {})
126
+ translations = translation_request(texts, params.merge('includeAlignment' => true))
127
+ translations.map do |translation|
128
+ [translation['text'], translation['alignment']['proj']] if translation.is_a?(Hash)
129
+ end
130
+ end
131
+
132
+ def detect(text)
133
+ data = [{ 'Text' => text }].to_json
134
+
135
+ response_json = api_client.post('/detect', data: data)
136
+ best_detection = response_json.sort_by { |detection| -detection['score'] }.first
137
+ best_detection['language'].to_sym
138
+ end
139
+
140
+ def speak(text, params = {})
141
+ raise UsageException.new('Not supported since 3.0.0')
142
+ end
143
+
144
+ def supported_language_codes
145
+ response_json = api_client.get('/languages',
146
+ params: { scope: 'translation' },
147
+ authorization: false)
148
+ response_json['translation'].keys
149
+ end
150
+
151
+ def language_names(codes, locale = 'en')
152
+ response_json = api_client.get('/languages',
153
+ params: { scope: 'translation' },
154
+ headers: { 'Accept-Language' => locale },
155
+ authorization: false)
156
+ codes.map do |code|
157
+ response = response_json['translation'][code.to_s]
158
+ response['name'] unless response.nil?
159
+ end
160
+ end
161
+
162
+ private
163
+
164
+ attr_reader :api_client
165
+
166
+ def translation_request(texts, params)
167
+ raise UsageException.new('Must provide :to.') if params[:to].nil?
168
+
169
+ data = texts.map { |text| { 'Text' => text } }.to_json
170
+ response_json = api_client.post('/translate', params: params, data: data)
171
+ to_lang = params[:to].to_s
172
+ response_json.map do |translation|
173
+ # There should be just one translation, but who knows...
174
+ translation['translations'].find { |result| result['to'].casecmp(to_lang).zero? }
175
+ end
176
+ end
177
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bing_translator
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.0.beta.1
4
+ version: 6.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ricky Elrod
@@ -47,14 +47,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
47
47
  version: '0'
48
48
  required_rubygems_version: !ruby/object:Gem::Requirement
49
49
  requirements:
50
- - - ">"
50
+ - - ">="
51
51
  - !ruby/object:Gem::Version
52
- version: 1.3.1
52
+ version: '0'
53
53
  requirements: []
54
- rubyforge_project:
55
- rubygems_version: 2.4.5.1
54
+ rubygems_version: 3.2.22
56
55
  signing_key:
57
56
  specification_version: 4
58
57
  summary: Translate using the Bing HTTP API
59
58
  test_files: []
60
- has_rdoc: