├── .github └── workflows │ └── test.yml ├── .gitignore ├── .rspec ├── Gemfile ├── README.md ├── Rakefile ├── easy_translate.gemspec ├── lib ├── easy_translate.rb └── easy_translate │ ├── detection.rb │ ├── easy_translate_exception.rb │ ├── languages.rb │ ├── request.rb │ ├── threadable.rb │ ├── translation.rb │ ├── translation_target.rb │ └── version.rb └── spec ├── examples ├── detection_spec.rb ├── easy_translate_spec.rb ├── real_world_spec.rb ├── request_spec.rb ├── translation_spec.rb └── translation_target_spec.rb └── spec_helper.rb /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | push: 4 | branches: [ main ] 5 | pull_request: 6 | branches: ['*'] 7 | 8 | jobs: 9 | test_sqlite: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | include: 15 | ### TEST ALL RUBY VERSIONS 16 | - ruby: 2.3 ### min version supported by Bundler 2.x, ruby: 2.3 17 | - ruby: 2.4 18 | - ruby: 2.5 19 | - ruby: 2.6 20 | - ruby: 2.7 21 | - ruby: "3.0" ### must be quoted otherwise will be treated as "3" which resolves to latest 3.x version 22 | - ruby: 3.1 23 | 24 | env: 25 | BUNDLE_GEMFILE: "${{ matrix.gemfile }}" 26 | 27 | steps: 28 | - uses: actions/checkout@v2 29 | 30 | - name: Install ruby 31 | uses: ruby/setup-ruby@v1 32 | with: 33 | ruby-version: "${{ matrix.ruby }}" 34 | bundler-cache: true 35 | 36 | - name: Run tests 37 | run: | 38 | bundle exec rake 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | *.gem 4 | .ruby-version 5 | coverage/* 6 | 7 | Gemfile.lock 8 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | -c -fd 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gemspec 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## EasyTranslate 2 | 3 | CI Status 4 | 5 | This is a Ruby library for Google Translate that makes working with bulk calls, 6 | user_ips and access via API Key easy. 7 | 8 | Unlike the official google client, `easy_translate` does not have a dependency on the `grpc` gem. This can be an advantage because `grpc` may be difficult to install on some systems or configurations. 9 | 10 | --- 11 | 12 | ### Installation 13 | 14 | ```bash 15 | $ gem install easy_translate 16 | ``` 17 | 18 | Or in your Gemfile: 19 | 20 | ```ruby 21 | gem 'easy_translate' 22 | ``` 23 | 24 | --- 25 | 26 | ## Single translation 27 | 28 | ```ruby 29 | # auto-detect 30 | EasyTranslate.translate('Hello, world', to: :spanish) # => "Hola, mundo" 31 | EasyTranslate.translate('Hello, world', to: 'es') # => "Hola, mundo" 32 | 33 | # feel free to specify explicitly 34 | EasyTranslate.translate('Hola, mundo', from: :spanish, to: :en) # => "Hello, world" 35 | ``` 36 | 37 | ## Batch translation (Yay!) 38 | 39 | ```ruby 40 | # multiple strings 41 | EasyTranslate.translate(['Hello', 'Goodbye'], to: :spanish) # => ["¡Hola", "Despedida"] 42 | ``` 43 | 44 | ## API Keys 45 | 46 | ```ruby 47 | # make google happy - (NOTE: use these anywhere) 48 | EasyTranslate.translate('Hello, world', to: :es, key: 'xxx') 49 | 50 | # don't want to set the key on every call? ** Me either! ** 51 | EasyTranslate.api_key = 'xxx' 52 | ``` 53 | 54 | ## You want language detection too? 55 | 56 | ```ruby 57 | # detect language 58 | EasyTranslate.detect "This is definitely English!" # => 'en' 59 | ``` 60 | 61 | ## Batch detection (Woohoo!) 62 | 63 | ```ruby 64 | # detect language 65 | EasyTranslate.detect ['Hello World', '我姓譚'] # => ['en', 'zh-CN'] 66 | ``` 67 | 68 | ## Need confidence in your detections? 69 | 70 | ```ruby 71 | # detect language with confidence 72 | EasyTranslate.detect "This is definitely English!", confidence: true # => { :language => 'en', :confidence => 0.77272725 } 73 | ``` 74 | 75 | ```ruby 76 | # detect batch languages with confidence 77 | EasyTranslate.detect ['This is definitely English!', '我姓譚'], confidence: true # => [{ :language => 'en', :confidence => 0.77272725 }, { :language => 'zh-CN', :confidence => 1.0 }] 78 | ``` 79 | 80 | ## Explicitly select translation model (NMT, PBMT) 81 | Google Translate now replaces Phrase Based Machine Translation (PBMT) with Neural Machine Translation (NMT) automatically where possible. If you prefer PBMT or need to compare the results, you can use the `model:` parameter with either `nmt` or `base` to force the model selection: 82 | 83 | ```ruby 84 | EasyTranslate.translate("El cuervo americano es un ave con plumas negras iridiscentes sobre todo su cuerpo.", from: "es", to: "en", model: "nmt") 85 | # => "The American Raven is a bird with iridescent black feathers over its entire body." 86 | ``` 87 | 88 | ```ruby 89 | EasyTranslate.translate("El cuervo americano es un ave con plumas negras iridiscentes sobre todo su cuerpo.", from: "es", to: "en", model: "base") 90 | # => "The American crow is a bird with iridescent black feathers over her body." 91 | ``` 92 | 93 | See https://research.googleblog.com/2016/09/a-neural-network-for-machine.html for more background 94 | 95 | ## Google Translate supports HTML (default) and plain text formats 96 | 97 | ```ruby 98 | EasyTranslate.translate "Las doce en punto", format: 'text', to: :en 99 | # => "Twelve o'clock" 100 | EasyTranslate.translate "Las doce en punto", format: 'html', to: :en 101 | # => "Twelve o'clock" 102 | ``` 103 | 104 | --- 105 | 106 | ## A note on concurrency as of v0.4.0 107 | 108 | Due to limitations with the Google Translate batch API, above a certain 109 | number of translations - this library will begin making calls concurrently. 110 | 111 | The default concurrency is 4, but if you'd prefer to run without threads, 112 | you can set `:concurrency => 1` to run the translation calls serially. 113 | 114 | --- 115 | 116 | ## List of languages 117 | 118 | ```ruby 119 | # list from 120 | EasyTranslate::LANGUAGES # => { 'en' => 'english', ... } 121 | ``` 122 | 123 | ### List of supported languages 124 | 125 | ```ruby 126 | # List all languages (from API) 127 | EasyTranslate.translations_available 128 | 129 | # List all languages supported by some language 130 | EasyTranslate.translations_available('zh-CN') 131 | ``` 132 | 133 | --- 134 | 135 | ### EasyTranslate in PHP 136 | 137 | [Kofel](https://github.com/Kofel) ported this library to PHP. 138 | You can find the port [on GitHub](https://github.com/Kofel/EasyTranslate) 139 | 140 | --- 141 | 142 | ### Contributors 143 | 144 | * John Crepezzi - john.crepezzi@gmail.com 145 | * Guy Maliar - gmaliar@gmail.com 146 | * [Gleb Mazovetskiy](https://github.com/glebm) 147 | 148 | Full contributor data at: 149 | https://github.com/seejohnrun/easy_translate/contributors 150 | 151 | --- 152 | 153 | ### License 154 | 155 | (The MIT License) 156 | 157 | Copyright © 2010-2018 John Crepezzi 158 | 159 | Permission is hereby granted, free of charge, to any person obtaining a copy of 160 | this software and associated documentation files (the ‘Software’), to deal in 161 | the Software without restriction, including without limitation the rights to 162 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 163 | of the Software, and to permit persons to whom the Software is furnished to do 164 | so, subject to the following conditions: 165 | 166 | The above copyright notice and this permission notice shall be included in all 167 | copies or substantial portions of the Software. 168 | 169 | THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 170 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 171 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 172 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 173 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 174 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 175 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rspec/core/rake_task' 2 | require 'bundler' 3 | 4 | task :build => :test do 5 | system "gem build easy_translate.gemspec" 6 | end 7 | 8 | task :release => :build do 9 | # tag and push 10 | version = Bundler.load_gemspec('easy_translate.gemspec').version 11 | system "git tag v#{version}" 12 | system "git push origin --tags" 13 | # push the gem 14 | system "gem push easy_translate-#{version}.gem" 15 | end 16 | 17 | RSpec::Core::RakeTask.new(:test) do |t| 18 | t.pattern = 'spec/**/*_spec.rb' 19 | fail_on_error = true # be explicit 20 | end 21 | 22 | task :default => :test 23 | 24 | desc "Cache API languages into lib/easy_translate/languages.rb, must set GOOGLE_TRANSLATE_API_KEY" 25 | task :cache_languages do 26 | $: << "lib" 27 | require "easy_translate" 28 | EasyTranslate.api_key = ENV.fetch("GOOGLE_TRANSLATE_API_KEY") 29 | 30 | language_filename = "lib/easy_translate/languages.rb" 31 | previous_contents = File.read(language_filename) 32 | 33 | response = JSON.parse(EasyTranslate::TranslationTarget::TranslationTargetRequest.new("en").perform_raw) 34 | language_keys = response.dig("data", "languages").map do |info| 35 | [info["name"].downcase.gsub(/[^a-z ]/, "").tr(" ", "_"), info["language"]] 36 | end.sort.map do |n, l| 37 | " '#{l}' => '#{n}'" 38 | end.join(",\n") 39 | new_contents = previous_contents.sub(/(LANGUAGES = {).*?(})/m, "\\1\n#{language_keys}\n \\2") 40 | 41 | File.open(language_filename, "w") do |f| 42 | f.write(new_contents) 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /easy_translate.gemspec: -------------------------------------------------------------------------------- 1 | require File.expand_path('lib/easy_translate/version', File.dirname(__FILE__)) 2 | 3 | spec = Gem::Specification.new do |s| 4 | s.name = 'easy_translate' 5 | s.author = 'John Crepezzi' 6 | s.add_development_dependency('rspec') 7 | s.add_development_dependency('rake') 8 | s.add_dependency 'thread' 9 | s.add_dependency 'thread_safe' 10 | s.description = 'easy_translate is a wrapper for the google translate API that makes sense programatically, and implements API keys' 11 | s.email = 'john.crepezzi@gmail.com' 12 | s.files = Dir['lib/**/*.rb'] 13 | s.has_rdoc = true 14 | s.homepage = 'https://github.com/seejohnrun/easy_translate' 15 | s.platform = Gem::Platform::RUBY 16 | s.require_paths = ['lib'] 17 | s.summary = 'Google Translate API Wrapper for Ruby' 18 | s.test_files = Dir.glob('spec/*.rb') 19 | s.version = EasyTranslate::VERSION 20 | s.license = 'MIT' 21 | end 22 | -------------------------------------------------------------------------------- /lib/easy_translate.rb: -------------------------------------------------------------------------------- 1 | require 'easy_translate/detection' 2 | require 'easy_translate/translation' 3 | require 'easy_translate/translation_target' 4 | 5 | module EasyTranslate 6 | 7 | autoload :EasyTranslateException, 'easy_translate/easy_translate_exception' 8 | autoload :Request, 'easy_translate/request' 9 | 10 | autoload :LANGUAGES, 'easy_translate/languages' 11 | autoload :VERSION, 'easy_translate/version' 12 | 13 | extend Detection # Language Detection 14 | extend Translation # Language Translation 15 | extend TranslationTarget # Language Translation Targets 16 | 17 | class << self 18 | attr_accessor :api_key 19 | end 20 | 21 | end 22 | -------------------------------------------------------------------------------- /lib/easy_translate/detection.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | require 'cgi' 3 | require 'easy_translate/request' 4 | require 'easy_translate/threadable' 5 | 6 | module EasyTranslate 7 | 8 | module Detection 9 | include Threadable 10 | 11 | # Detect language 12 | # @param [String, Array] texts - A single string or set of strings to detect for 13 | # @param [Hash] options - Extra options to pass along with the request 14 | # @return [String, Array] The resultant language or languages 15 | def detect(texts, options = {}, http_options = {}) 16 | threaded_process(:request_detection, texts, options, http_options) 17 | end 18 | 19 | private 20 | def request_detection(texts, options, http_options) 21 | request = DetectionRequest.new(texts, options, http_options) 22 | raw = request.perform_raw 23 | detections = JSON.parse(raw)['data']['detections'].map do |res| 24 | res.empty? ? nil : 25 | options[:confidence] ? 26 | { :language => res.first['language'], :confidence => res.first['confidence'] } : res.first['language'] 27 | end 28 | end 29 | 30 | # A convenience class for wrapping a detection request 31 | class DetectionRequest < EasyTranslate::Request 32 | 33 | # Set the texts and options 34 | # @param [String, Array] texts - The text (or texts) to translate 35 | # @param [Hash] options - Options to override or pass along with the request 36 | def initialize(texts, options = {}, http_options = {}) 37 | super(options, http_options) 38 | if replacement_api_key = @options.delete(:api_key) 39 | @options[:key] = replacement_api_key 40 | end 41 | self.texts = texts 42 | end 43 | 44 | # The params for this request 45 | # @return [Hash] the params for the request 46 | def params 47 | params = super || {} 48 | params.merge! @options if @options 49 | params 50 | end 51 | 52 | # The path for the request 53 | # @return [String] The path for the request 54 | def path 55 | '/language/translate/v2/detect' 56 | end 57 | 58 | # The body for the request 59 | # @return [String] the body for the request, URL escaped 60 | def body 61 | @texts.map { |t| "q=#{CGI::escape(t)}" }.join '&' 62 | end 63 | 64 | # Whether or not this was a request for multiple texts 65 | # @return [Boolean] 66 | def multi? 67 | @multi 68 | end 69 | 70 | private 71 | 72 | # Set the texts for this request 73 | # @param [String, Array] texts - The text or texts for this request 74 | def texts=(texts) 75 | if texts.is_a?(String) 76 | @multi = false 77 | @texts = [texts] 78 | else 79 | @multi = true 80 | @texts = texts 81 | end 82 | end 83 | 84 | end 85 | 86 | end 87 | 88 | end 89 | -------------------------------------------------------------------------------- /lib/easy_translate/easy_translate_exception.rb: -------------------------------------------------------------------------------- 1 | module EasyTranslate 2 | 3 | class EasyTranslateException < StandardError 4 | end 5 | 6 | end 7 | -------------------------------------------------------------------------------- /lib/easy_translate/languages.rb: -------------------------------------------------------------------------------- 1 | module EasyTranslate 2 | 3 | LANGUAGES = { 4 | 'af' => 'afrikaans', 5 | 'sq' => 'albanian', 6 | 'am' => 'amharic', 7 | 'ar' => 'arabic', 8 | 'hy' => 'armenian', 9 | 'as' => 'assamese', 10 | 'ay' => 'aymara', 11 | 'az' => 'azerbaijani', 12 | 'bm' => 'bambara', 13 | 'eu' => 'basque', 14 | 'be' => 'belarusian', 15 | 'bn' => 'bengali', 16 | 'bho' => 'bhojpuri', 17 | 'bs' => 'bosnian', 18 | 'bg' => 'bulgarian', 19 | 'ca' => 'catalan', 20 | 'ceb' => 'cebuano', 21 | 'ny' => 'chichewa', 22 | 'zh' => 'chinese_simplified', 23 | 'zh-CN' => 'chinese_simplified', 24 | 'zh-TW' => 'chinese_traditional', 25 | 'co' => 'corsican', 26 | 'hr' => 'croatian', 27 | 'cs' => 'czech', 28 | 'da' => 'danish', 29 | 'dv' => 'divehi', 30 | 'doi' => 'dogri', 31 | 'nl' => 'dutch', 32 | 'en' => 'english', 33 | 'eo' => 'esperanto', 34 | 'et' => 'estonian', 35 | 'ee' => 'ewe', 36 | 'tl' => 'filipino', 37 | 'fi' => 'finnish', 38 | 'fr' => 'french', 39 | 'fy' => 'frisian', 40 | 'gl' => 'galician', 41 | 'lg' => 'ganda', 42 | 'ka' => 'georgian', 43 | 'de' => 'german', 44 | 'el' => 'greek', 45 | 'gn' => 'guarani', 46 | 'gu' => 'gujarati', 47 | 'ht' => 'haitian_creole', 48 | 'ha' => 'hausa', 49 | 'haw' => 'hawaiian', 50 | 'he' => 'hebrew', 51 | 'iw' => 'hebrew', 52 | 'hi' => 'hindi', 53 | 'hmn' => 'hmong', 54 | 'hu' => 'hungarian', 55 | 'is' => 'icelandic', 56 | 'ig' => 'igbo', 57 | 'ilo' => 'iloko', 58 | 'id' => 'indonesian', 59 | 'ga' => 'irish_gaelic', 60 | 'it' => 'italian', 61 | 'ja' => 'japanese', 62 | 'jv' => 'javanese', 63 | 'jw' => 'javanese', 64 | 'kn' => 'kannada', 65 | 'kk' => 'kazakh', 66 | 'km' => 'khmer', 67 | 'rw' => 'kinyarwanda', 68 | 'gom' => 'konkani', 69 | 'ko' => 'korean', 70 | 'kri' => 'krio', 71 | 'ku' => 'kurdish_kurmanji', 72 | 'ckb' => 'kurdish_sorani', 73 | 'ky' => 'kyrgyz', 74 | 'lo' => 'lao', 75 | 'la' => 'latin', 76 | 'lv' => 'latvian', 77 | 'ln' => 'lingala', 78 | 'lt' => 'lithuanian', 79 | 'lb' => 'luxembourgish', 80 | 'mk' => 'macedonian', 81 | 'mai' => 'maithili', 82 | 'mg' => 'malagasy', 83 | 'ms' => 'malay', 84 | 'ml' => 'malayalam', 85 | 'mt' => 'maltese', 86 | 'mi' => 'maori', 87 | 'mr' => 'marathi', 88 | 'mni-Mtei' => 'meiteilon_manipuri', 89 | 'lus' => 'mizo', 90 | 'mn' => 'mongolian', 91 | 'my' => 'myanmar_burmese', 92 | 'ne' => 'nepali', 93 | 'nso' => 'northern_sotho', 94 | 'no' => 'norwegian', 95 | 'or' => 'odia_oriya', 96 | 'om' => 'oromo', 97 | 'ps' => 'pashto', 98 | 'fa' => 'persian', 99 | 'pl' => 'polish', 100 | 'pt' => 'portuguese', 101 | 'pa' => 'punjabi', 102 | 'qu' => 'quechua', 103 | 'ro' => 'romanian', 104 | 'ru' => 'russian', 105 | 'sm' => 'samoan', 106 | 'sa' => 'sanskrit', 107 | 'gd' => 'scots_gaelic', 108 | 'sr' => 'serbian', 109 | 'st' => 'sesotho', 110 | 'sn' => 'shona', 111 | 'sd' => 'sindhi', 112 | 'si' => 'sinhala', 113 | 'sk' => 'slovak', 114 | 'sl' => 'slovenian', 115 | 'so' => 'somali', 116 | 'es' => 'spanish', 117 | 'su' => 'sundanese', 118 | 'sw' => 'swahili', 119 | 'sv' => 'swedish', 120 | 'tg' => 'tajik', 121 | 'ta' => 'tamil', 122 | 'tt' => 'tatar', 123 | 'te' => 'telugu', 124 | 'th' => 'thai', 125 | 'ti' => 'tigrinya', 126 | 'ts' => 'tsonga', 127 | 'tr' => 'turkish', 128 | 'tk' => 'turkmen', 129 | 'ak' => 'twi', 130 | 'uk' => 'ukrainian', 131 | 'ur' => 'urdu', 132 | 'ug' => 'uyghur', 133 | 'uz' => 'uzbek', 134 | 'vi' => 'vietnamese', 135 | 'cy' => 'welsh', 136 | 'xh' => 'xhosa', 137 | 'yi' => 'yiddish', 138 | 'yo' => 'yoruba', 139 | 'zu' => 'zulu' 140 | } 141 | 142 | end 143 | -------------------------------------------------------------------------------- /lib/easy_translate/request.rb: -------------------------------------------------------------------------------- 1 | require 'net/http' 2 | require 'net/https' 3 | require 'uri' 4 | 5 | module EasyTranslate 6 | 7 | class Request 8 | attr_accessor :http_options 9 | 10 | def initialize(options = {}, http_options = {}) 11 | @options = options 12 | @http_options = http_options 13 | end 14 | 15 | # Body, blank by default 16 | # @return [String] The body for this request 17 | def body 18 | '' 19 | end 20 | 21 | # The path for the request 22 | # @return [String] The path for this request 23 | def path 24 | raise NotImplementedError.new('path is not implemented') 25 | end 26 | 27 | # The base params for a request 28 | # @return [Hash] a hash of the base parameters for any request 29 | def params 30 | params = {} 31 | params[:key] = EasyTranslate.api_key if EasyTranslate.api_key 32 | params[:prettyPrint] = 'false' # eliminate unnecessary overhead 33 | params 34 | end 35 | 36 | # Perform the given request 37 | # @return [String] The response String 38 | def perform_raw 39 | # Construct the request 40 | request = Net::HTTP::Post.new(uri.request_uri) 41 | request.add_field('X-HTTP-Method-Override', 'GET') 42 | request.body = body 43 | # Fire and return 44 | response = http.request(request) 45 | raise_exception(response) unless response.code == '200' 46 | response.body 47 | end 48 | 49 | private 50 | 51 | def raise_exception(response) 52 | err = JSON.parse(response.body)['error']['errors'].first['message'] 53 | rescue JSON::ParserError => _e 54 | err = "#{response.code} - #{response.message}" 55 | ensure 56 | raise EasyTranslateException.new(err) 57 | end 58 | 59 | def uri 60 | @uri ||= URI.parse("https://translation.googleapis.com#{path}?#{param_s}") 61 | end 62 | 63 | def http 64 | @http ||= Net::HTTP.new(uri.host, uri.port).tap do |http| 65 | configure_timeouts(http) 66 | configure_ssl(http) 67 | end 68 | end 69 | 70 | def configure_timeouts(http) 71 | http.read_timeout = http.open_timeout = http_options[:timeout] if http_options[:timeout] 72 | http.open_timeout = http_options[:open_timeout] if http_options[:open_timeout] 73 | end 74 | 75 | def configure_ssl(http) 76 | http.use_ssl = true 77 | http.verify_mode = OpenSSL::SSL::VERIFY_PEER 78 | http.cert_store = ssl_cert_store 79 | 80 | http.cert = ssl_options[:client_cert] if ssl_options[:client_cert] 81 | http.key = ssl_options[:client_key] if ssl_options[:client_key] 82 | http.ca_file = ssl_options[:ca_file] if ssl_options[:ca_file] 83 | http.ca_path = ssl_options[:ca_path] if ssl_options[:ca_path] 84 | http.verify_depth = ssl_options[:verify_depth] if ssl_options[:verify_depth] 85 | http.ssl_version = ssl_options[:version] if ssl_options[:version] 86 | end 87 | 88 | def ssl_cert_store 89 | return ssl_options[:cert_store] if ssl_options[:cert_store] 90 | # Use the default cert store by default, i.e. system ca certs 91 | cert_store = OpenSSL::X509::Store.new 92 | cert_store.set_default_paths 93 | cert_store 94 | end 95 | 96 | def ssl_options 97 | http_options[:ssl] || {} 98 | end 99 | 100 | # Stringify the params 101 | # @return [String] The params as a string 102 | def param_s 103 | params.map do |k, v| 104 | "#{k}=#{v}" unless v.nil? 105 | end.compact.join('&') 106 | end 107 | 108 | end 109 | 110 | end 111 | -------------------------------------------------------------------------------- /lib/easy_translate/threadable.rb: -------------------------------------------------------------------------------- 1 | require 'thread/pool' 2 | require 'thread_safe' 3 | 4 | module EasyTranslate 5 | 6 | module Threadable 7 | def threaded_process(method, *args) 8 | texts = args[0] 9 | options = args[1] 10 | http_options = args[2] 11 | options = options.dup 12 | batch_size = options.delete(:batch_size) || 100 13 | concurrency = options.delete(:concurrency) || 4 14 | batches = Array(texts).each_slice(batch_size).to_a 15 | if concurrency > 1 && batches.size > 1 16 | pool = Thread::Pool.new([concurrency, 1 + (texts.length - 1) / batch_size].min) 17 | batch_results = ThreadSafe::Array.new 18 | batches.each_with_index do |texts_batch, i| 19 | pool.process { batch_results[i] = self.send(method, texts_batch, options, http_options) } 20 | end 21 | pool.shutdown 22 | results = batch_results.reduce(:+) 23 | else 24 | results = batches.map { |texts_batch| self.send(method, texts_batch, options, http_options) }.reduce(:+) 25 | end 26 | # if they only asked for one, only give one back 27 | texts.is_a?(String) ? results[0] : results 28 | ensure 29 | pool.shutdown! if pool && !pool.shutdown? 30 | end 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /lib/easy_translate/translation.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | require 'cgi' 3 | require 'easy_translate/request' 4 | require 'easy_translate/threadable' 5 | 6 | module EasyTranslate 7 | 8 | module Translation 9 | include Threadable 10 | 11 | # Translate text 12 | # @param [String, Array] texts - A single string or set of strings to translate 13 | # @option options [Fixnum] :batch_size - Maximum keys per request (optional, default 100) 14 | # @option options [Fixnum] :concurrency - Maximum concurrent requests (optional, default 4) 15 | # @option options [String, Symbol] :source - The source language (optional) 16 | # @option options [String, Symbol] :target - The target language (required) 17 | # @option options [Boolean] :html - Whether or not the supplied string is HTML (optional) 18 | # @return [String, Array] Translated text or texts 19 | def translate(texts, options = {}, http_options = {}) 20 | threaded_process(:request_translations, texts, options, http_options) 21 | end 22 | 23 | private 24 | 25 | # Perform a single request to translate texts 26 | # @param [Array] texts - Texts to translate 27 | # @option options [String, Symbol] :source - The source language (optional) 28 | # @option options [String, Symbol] :target - The target language (required) 29 | # @option options [Boolean] :html - Whether or not the supplied string is HTML (optional) 30 | # @return [String, Array] Translated text or texts 31 | def request_translations(texts, options = {}, http_options = {}) 32 | request = TranslationRequest.new(texts, options, http_options) 33 | # Turn the response into an array of translations 34 | raw = request.perform_raw 35 | JSON.parse(raw)['data']['translations'].map do |res| 36 | raw_translation = res['translatedText'] 37 | CGI.unescapeHTML(raw_translation) 38 | end 39 | end 40 | 41 | # A convenience class for wrapping a translation request 42 | class TranslationRequest < EasyTranslate::Request 43 | 44 | # Set the texts and options 45 | # @param [String, Array] texts - the text (or texts) to translate 46 | # @param [Hash] options - Options to override or pass along with the request 47 | def initialize(texts, options, http_options = {}) 48 | options = options.dup 49 | self.texts = texts 50 | self.html = options.delete(:html) 51 | @source = options.delete(:from) 52 | @target = options.delete(:to) 53 | @model = options.delete(:model) 54 | raise ArgumentError.new('No target language provided') unless @target 55 | raise ArgumentError.new('Support for multiple targets dropped in V2') if @target.is_a?(Array) 56 | @http_options = http_options 57 | if options 58 | @options = options 59 | if replacement_api_key = @options.delete(:api_key) 60 | @options[:key] = replacement_api_key 61 | end 62 | end 63 | end 64 | 65 | # The params for this request 66 | # @return [Hash] the params for the request 67 | def params 68 | params = super || {} 69 | params[:source] = lang(@source) unless @source.nil? 70 | params[:target] = lang(@target) unless @target.nil? 71 | params[:model] = @model unless @model.nil? 72 | params[:format] = @format unless @format.nil? 73 | params.merge! @options if @options 74 | params 75 | end 76 | 77 | # The path for the request 78 | # @return [String] The path for the request 79 | def path 80 | '/language/translate/v2' 81 | end 82 | 83 | # The body for the request 84 | # @return [String] the body for the request, URL escaped 85 | def body 86 | @texts.map { |t| "q=#{CGI::escape(t)}" }.join '&' 87 | end 88 | 89 | # Whether or not this was a request for multiple texts 90 | # @return [Boolean] 91 | def multi? 92 | @multi 93 | end 94 | 95 | private 96 | 97 | # Look up a language in the table (if needed) 98 | def lang(orig) 99 | look = orig.is_a?(String) ? orig : orig.to_s 100 | return look if LANGUAGES[look] # shortcut iteration 101 | if val = LANGUAGES.detect { |k, v| v == look } 102 | return val.first 103 | end 104 | look 105 | end 106 | 107 | # Set the HTML attribute, if true add a format 108 | # @param [Boolean] b - Whether or not the text supplied iS HTML 109 | def html=(b) 110 | @format = b ? 'html' : nil 111 | end 112 | 113 | # Set the texts for this request 114 | # @param [String, Array] texts - The text or texts for this request 115 | def texts=(texts) 116 | if texts.is_a?(String) 117 | @multi = false 118 | @texts = [texts] 119 | else 120 | @multi = true 121 | @texts = texts 122 | end 123 | end 124 | 125 | end 126 | 127 | end 128 | 129 | end 130 | -------------------------------------------------------------------------------- /lib/easy_translate/translation_target.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | require 'easy_translate/request' 3 | 4 | module EasyTranslate 5 | 6 | module TranslationTarget 7 | 8 | # Determine what translations are available 9 | # @param [String] source - The source language (optional) 10 | # @param [Hash] options - extra options 11 | # @return [Array] an array of strings representing languages 12 | def translations_available(target = nil, options = {}) 13 | request = TranslationTargetRequest.new(target, options) 14 | raw = request.perform_raw 15 | languages = JSON.parse(raw)['data']['languages'].map do |res| 16 | res['language'] 17 | end 18 | 19 | languages.push('zh-CN') if !languages.index('zh').nil? 20 | 21 | languages 22 | end 23 | 24 | class TranslationTargetRequest < EasyTranslate::Request 25 | 26 | def initialize(target = nil, options = nil) 27 | super(options) 28 | @target = target 29 | if @options 30 | if replacement_api_key = @options.delete(:api_key) 31 | @options[:key] = replacement_api_key 32 | end 33 | end 34 | end 35 | 36 | def params 37 | params = super || {} 38 | params[:target] = @target unless @target.nil? 39 | params.merge! @options if @options 40 | params 41 | end 42 | 43 | def path 44 | '/language/translate/v2/languages' 45 | end 46 | 47 | end 48 | 49 | end 50 | 51 | end 52 | -------------------------------------------------------------------------------- /lib/easy_translate/version.rb: -------------------------------------------------------------------------------- 1 | module EasyTranslate 2 | 3 | VERSION = '0.5.0' 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/examples/detection_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | 3 | require 'spec_helper' 4 | 5 | describe EasyTranslate::Detection do 6 | 7 | it 'should return a single if given a single - from doc' do 8 | expect(EasyTranslate::Detection::DetectionRequest).to receive(:new).and_return(OpenStruct.new({ 9 | :perform_raw => '{"data":{"detections":[[{"language":"en","isReliable":false,"confidence":0.6595744}]]}}', 10 | :multi? => false 11 | })) 12 | lang = EasyTranslate.detect 'Google Translate Rocks' 13 | expect(lang).to eq('en') 14 | end 15 | 16 | it 'should return a single with confidence if given a single with confidence - from doc' do 17 | expect(EasyTranslate::Detection::DetectionRequest).to receive(:new).and_return(OpenStruct.new({ 18 | :perform_raw => '{"data":{"detections":[[{"language":"en","isReliable":false,"confidence":0.6595744}]]}}', 19 | :multi? => false 20 | })) 21 | lang = EasyTranslate.detect 'Google Translate Rocks', :confidence => true 22 | expect(lang).to eq({ :language => 'en', :confidence => 0.6595744 }) 23 | end 24 | 25 | it 'should return a multiple if given multiple - from doc' do 26 | expect(EasyTranslate::Detection::DetectionRequest).to receive(:new).and_return(OpenStruct.new({ 27 | :perform_raw => '{"data":{"detections":[[{"language":"en","isReliable":false,"confidence":0.6315789}],[{"language":"zh-CN","isReliable":false,"confidence":1.0}]]}}', 28 | :multi? => true 29 | })) 30 | lang = EasyTranslate.detect ['Hello World', '我姓譚'] 31 | expect(lang).to eq(['en', 'zh-CN']) 32 | end 33 | 34 | it 'should return a multiple with confidence if given multiple with confidence - from doc' do 35 | expect(EasyTranslate::Detection::DetectionRequest).to receive(:new).and_return(OpenStruct.new({ 36 | :perform_raw => '{"data":{"detections":[[{"language":"en","isReliable":false,"confidence":0.6315789}],[{"language":"zh-CN","isReliable":false,"confidence":1.0}]]}}', 37 | :multi? => true 38 | })) 39 | lang = EasyTranslate.detect ['Hello World', '我姓譚'], :confidence => true 40 | expect(lang).to eq([{ :language => 'en', :confidence => 0.6315789 }, { :language => 'zh-CN', :confidence => 1.0 }]) 41 | end 42 | 43 | klass = EasyTranslate::Detection::DetectionRequest 44 | describe klass do 45 | 46 | describe :path do 47 | 48 | it 'should have a valid path' do 49 | request = klass.new('abc') 50 | expect(request.path).not_to be_empty 51 | end 52 | 53 | end 54 | 55 | describe :body do 56 | 57 | it 'should insert the texts into the body' do 58 | request = klass.new(['abc', 'def']) 59 | expect(request.body).to eq('q=abc&q=def') 60 | end 61 | 62 | it 'should insert the text into the body' do 63 | request = klass.new('abc') 64 | expect(request.body).to eq('q=abc') 65 | end 66 | 67 | it 'should URI escape the body' do 68 | request = klass.new('%') 69 | expect(request.body).to eq('q=%25') 70 | end 71 | 72 | end 73 | 74 | describe :params do 75 | 76 | it 'should use default params' do 77 | EasyTranslate.api_key = 'abc' 78 | request = klass.new('abc') 79 | expect(request.params[:key]).to eq('abc') 80 | end 81 | 82 | it 'should allow overriding of params' do 83 | EasyTranslate.api_key = 'abc' 84 | request = klass.new('abc', :key => 'def') 85 | expect(request.params[:key]).to eq('def') 86 | end 87 | 88 | it 'should allow overriding of key as api_key' do 89 | EasyTranslate.api_key = 'abc' 90 | request = klass.new('abc', :api_key => 'def') 91 | expect(request.params[:key]).to eq('def') 92 | expect(request.params[:api_key]).to be_nil 93 | end 94 | 95 | end 96 | 97 | describe :options do 98 | 99 | it 'should accept timeouts options' do 100 | request = EasyTranslate::Detection::DetectionRequest.new "test", {}, {:timeout => 1, :open_timeout => 2} 101 | http = request.send(:http) 102 | expect(http.open_timeout).to eq(2) 103 | expect(http.read_timeout).to eq(1) 104 | end 105 | 106 | it 'should accept ssl options' do 107 | request = EasyTranslate::Detection::DetectionRequest.new "test", {}, {:ssl => {:verify_depth => 3, :ca_file => 'path/to/ca/file'}} 108 | http = request.send(:http) 109 | expect(http.verify_depth).to eq(3) 110 | expect(http.ca_file).to eq('path/to/ca/file') 111 | end 112 | 113 | it 'should accept confidence option' do 114 | request = EasyTranslate::Detection::DetectionRequest.new "test", {:confidence => true}, {} 115 | expect(request.params[:confidence]).to eq(true) 116 | end 117 | 118 | end 119 | 120 | describe :multi? do 121 | 122 | it 'should be true if multiple are passed' do 123 | request = klass.new(['abc', 'def']) 124 | expect(request).to be_multi 125 | end 126 | 127 | it 'should be true if one is passed, but in an array' do 128 | request = klass.new(['abc']) 129 | expect(request).to be_multi 130 | end 131 | 132 | it 'should be true if one is passed as a string' do 133 | request = klass.new('abc') 134 | expect(request).not_to be_multi 135 | end 136 | 137 | end 138 | 139 | end 140 | 141 | end 142 | -------------------------------------------------------------------------------- /spec/examples/easy_translate_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe EasyTranslate do 4 | 5 | it 'should have LANGUAGES' do 6 | expect(EasyTranslate::LANGUAGES).to be_a(Hash) 7 | expect(EasyTranslate::LANGUAGES['en']).to eq('english') 8 | end 9 | 10 | it 'should have a version' do 11 | expect(EasyTranslate::VERSION.split('.').length).to eq(3) 12 | end 13 | 14 | end 15 | -------------------------------------------------------------------------------- /spec/examples/real_world_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require 'spec_helper' 3 | 4 | describe EasyTranslate do 5 | 6 | before :each do 7 | if ENV['API_KEY'] 8 | EasyTranslate.api_key = ENV['API_KEY'] 9 | else 10 | pending 'please provide an API_KEY for this suite' 11 | end 12 | end 13 | 14 | describe :translate do 15 | 16 | it 'should be able to translate one' do 17 | res = EasyTranslate.translate 'hello world', :to => :spanish 18 | expect(res).to eq('Hola Mundo') 19 | end 20 | 21 | it 'should be able to translate multiple' do 22 | res = EasyTranslate.translate ['hello world', 'i love you'], :to => :spanish 23 | expect(res).to eq(['Hola Mundo', 'te quiero']) 24 | end 25 | 26 | it 'should work concurrently' do 27 | res = EasyTranslate.translate ['hello world', 'i love you', 'good morning'], :to => :spanish, :concurrency => 2, :batch_size => 1 28 | expect(res).to eq(['Hola Mundo', 'te quiero', 'Buenos días']) 29 | end 30 | end 31 | 32 | describe :detect do 33 | 34 | it 'should be able to detect one' do 35 | res = EasyTranslate.detect 'hello world' 36 | expect(res).to eq('en') 37 | end 38 | 39 | it 'should be able to detect multiple' do 40 | res = EasyTranslate.detect ['hello world', 'hola mundo'] 41 | expect(res).to eq(['en', 'es']) 42 | end 43 | 44 | end 45 | 46 | describe :translations_available_from do 47 | 48 | it 'should be able to get a list of all' do 49 | res = EasyTranslate.translations_available 50 | expect(res).to be_a Array 51 | end 52 | 53 | it 'should be able to get a list of all from es' do 54 | res = EasyTranslate.translations_available('yi') 55 | expect(res).to be_a Array 56 | end 57 | 58 | end 59 | 60 | end 61 | -------------------------------------------------------------------------------- /spec/examples/request_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe EasyTranslate::Request do 4 | 5 | describe :path do 6 | 7 | it 'should raise a NotImplementedError on this base class' do 8 | request = EasyTranslate::Request.new 9 | expect do 10 | request.path 11 | end.to raise_error NotImplementedError 12 | end 13 | 14 | end 15 | 16 | describe :body do 17 | 18 | it 'should be blank by default' do 19 | request = EasyTranslate::Request.new 20 | expect(request.body).to be_empty 21 | end 22 | 23 | end 24 | 25 | describe :params do 26 | 27 | it 'should include the key if given at the base' do 28 | EasyTranslate.api_key = 'abc' 29 | request = EasyTranslate::Request.new 30 | expect(request.params[:key]).to eq('abc') 31 | end 32 | 33 | it 'should turn off prettyPrint' do 34 | request = EasyTranslate::Request.new 35 | expect(request.params[:prettyPrint]).to eq('false') 36 | end 37 | 38 | end 39 | 40 | describe :param_s do 41 | 42 | it 'should skip nil parameters' do 43 | request = EasyTranslate::Request.new 44 | expect(request).to receive(:params).and_return({ :something => nil }) 45 | expect(request.send(:param_s)).to be_empty 46 | end 47 | 48 | end 49 | 50 | end 51 | -------------------------------------------------------------------------------- /spec/examples/translation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe EasyTranslate::Translation do 4 | 5 | it 'should return a single if given a single - from doc' do 6 | fake_request( 7 | :perform_raw => '{"data":{"translations":[{"translatedText":"Hallo Welt"}]}}', 8 | :multi? => false 9 | ) 10 | trans = EasyTranslate.translate 'Hello world', :to => 'de' 11 | expect(trans).to eq('Hallo Welt') 12 | end 13 | 14 | it 'should return a multiple if given multiple - from doc' do 15 | fake_request( 16 | :perform_raw => '{"data":{"translations":[{"translatedText": "Hallo Welt"},{"translatedText":"Mein Name ist Jeff"}]}}', 17 | :multi? => true 18 | ) 19 | trans = EasyTranslate.translate ['Hello world', 'my name is jeff'], :to => 'de' 20 | expect(trans).to eq(['Hallo Welt', 'Mein Name ist Jeff']) 21 | end 22 | 23 | it 'should decode HTML entities in the response' do 24 | fake_request( 25 | :perform_raw => '{"data":{"translations":[{"translatedText":"Hallo ' & " Welt"}]}}', 26 | :multi? => false 27 | ) 28 | trans = EasyTranslate.translate %{Hello ' & " world}, :to => 'de' 29 | expect(trans).to eq(%{Hallo ' & " Welt}) 30 | end 31 | 32 | context 'detecting availale language' do 33 | before :each do 34 | pending 'please provide an API_KEY for this suite' if ENV['API_KEY'].nil? 35 | 36 | EasyTranslate.api_key = ENV['API_KEY'] 37 | end 38 | 39 | it 'should detect simplified chinese as zh-CN' do 40 | expect(EasyTranslate.translations_available.include?('zh-CN')).to eq(true) 41 | expect(EasyTranslate.translations_available.include?('zh')).to eq(true) 42 | end 43 | end 44 | 45 | def fake_request(hash) 46 | expect(EasyTranslate::Translation::TranslationRequest).to receive(:new).and_return(OpenStruct.new(hash)) 47 | end 48 | 49 | klass = EasyTranslate::Translation::TranslationRequest 50 | describe klass do 51 | 52 | describe :path do 53 | 54 | it 'should have a valid path' do 55 | request = klass.new('abc', :to => 'en') 56 | expect(request.path).not_to be_empty 57 | end 58 | 59 | end 60 | 61 | describe :initialize do 62 | 63 | it 'should raise an error when there is no to given' do 64 | expect do 65 | req = klass.new('abc', :from => 'en') 66 | end.to raise_error ArgumentError 67 | end 68 | 69 | it 'should raise an error when tos are given as an array' do 70 | expect do 71 | req = klass.new('abc', :from => 'en', :to => ['es', 'de']) 72 | end.to raise_error ArgumentError 73 | end 74 | 75 | end 76 | 77 | describe :params do 78 | 79 | it 'should include from in params if given' do 80 | req = klass.new('abc', :from => 'en', :to => 'es') 81 | expect(req.params[:source]).to eq('en') 82 | end 83 | 84 | it 'should not include from by default' do 85 | req = klass.new('abc', :to => 'es') 86 | expect(req.params[:source]).to be_nil 87 | end 88 | 89 | it 'should include to' do 90 | req = klass.new('abc', :to => 'es') 91 | expect(req.params[:target]).to eq('es') 92 | end 93 | 94 | it 'should not include format by default' do 95 | req = klass.new('abc', :to => 'es') 96 | expect(req.params[:format]).to be_nil 97 | end 98 | 99 | it 'should not include format when given as false' do 100 | req = klass.new('abc', :html => false, :to => 'es') 101 | expect(req.params[:format]).to be_nil 102 | end 103 | 104 | it 'should include format when html is true' do 105 | req = klass.new('abc', :html => true, :to => 'es') 106 | expect(req.params[:format]).to eq('html') 107 | end 108 | 109 | it 'should include format when specified as text' do 110 | req = klass.new('abc', :format => 'text', :to => 'es') 111 | expect(req.params[:format]).to eq('text') 112 | end 113 | 114 | it 'should use default params' do 115 | EasyTranslate.api_key = 'abc' 116 | request = klass.new('abc', :to => 'es') 117 | expect(request.params[:key]).to eq('abc') 118 | end 119 | 120 | it 'should allow overriding of params' do 121 | EasyTranslate.api_key = 'abc' 122 | request = klass.new('abc', :key => 'def', :to => 'es') 123 | expect(request.params[:key]).to eq('def') 124 | end 125 | 126 | it 'should allow overriding of key as api_key' do 127 | EasyTranslate.api_key = 'abc' 128 | request = klass.new('abc', :api_key => 'def', :to => 'es') 129 | expect(request.params[:key]).to eq('def') 130 | expect(request.params[:api_key]).to be_nil 131 | end 132 | 133 | it 'should be able to supply a language as a string' do 134 | request = klass.new('abc', :to => 'es') 135 | expect(request.params[:target]).to eq('es') 136 | end 137 | 138 | it 'should be able to supply a language as a symbol' do 139 | request = klass.new('abc', :to => :es) 140 | expect(request.params[:target]).to eq('es') 141 | end 142 | 143 | it 'should be able to supply a language as a word' do 144 | request = klass.new('abc', :to => 'spanish') 145 | expect(request.params[:target]).to eq('es') 146 | end 147 | 148 | it 'should be able to supply a language as a word symbol' do 149 | request = klass.new('abc', :to => :spanish) 150 | expect(request.params[:target]).to eq('es') 151 | end 152 | 153 | it 'should fall back when a word is not in the lookup' do 154 | request = klass.new('abc', :to => 'zzz') 155 | expect(request.params[:target]).to eq('zzz') 156 | end 157 | 158 | end 159 | 160 | describe :multi? do 161 | 162 | it 'should be true if multiple are passed' do 163 | request = klass.new(['abc', 'def'], :to => 'es') 164 | expect(request).to be_multi 165 | end 166 | 167 | it 'should be true if one is passed, but in an array' do 168 | request = klass.new(['abc'], :to => 'es') 169 | expect(request).to be_multi 170 | end 171 | 172 | it 'should be true if one is passed as a string' do 173 | request = klass.new('abc', :to => 'es') 174 | expect(request).not_to be_multi 175 | end 176 | 177 | end 178 | 179 | describe :body do 180 | 181 | it 'should insert the texts into the body' do 182 | request = klass.new(['abc', 'def'], :to => 'es') 183 | expect(request.body).to eq('q=abc&q=def') 184 | end 185 | 186 | it 'should insert the text into the body' do 187 | request = klass.new('abc', :to => 'es') 188 | expect(request.body).to eq('q=abc') 189 | end 190 | 191 | it 'should URI escape the body' do 192 | request = klass.new('%', :to => 'es') 193 | expect(request.body).to eq('q=%25') 194 | end 195 | 196 | end 197 | 198 | end 199 | 200 | end 201 | -------------------------------------------------------------------------------- /spec/examples/translation_target_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | klass = EasyTranslate::TranslationTarget::TranslationTargetRequest 4 | describe klass do 5 | 6 | describe :params do 7 | 8 | it 'should include target in params if given' do 9 | req = klass.new('en') 10 | expect(req.params[:target]).to eq('en') 11 | end 12 | 13 | it 'should not include target by default' do 14 | req = klass.new 15 | expect(req.params[:target]).to be_nil 16 | end 17 | 18 | it 'should use default key' do 19 | EasyTranslate.api_key = 'abc' 20 | request = klass.new('en') 21 | expect(request.params[:key]).to eq('abc') 22 | end 23 | 24 | it 'should allow overriding of params' do 25 | EasyTranslate.api_key = 'abc' 26 | request = klass.new('en', :key => 'def') 27 | expect(request.params[:key]).to eq('def') 28 | end 29 | 30 | it 'should allow overriding of key as api_key' do 31 | EasyTranslate.api_key = 'abc' 32 | request = klass.new('abc', :api_key => 'def', :to => 'es') 33 | expect(request.params[:key]).to eq('def') 34 | expect(request.params[:api_key]).to be_nil 35 | end 36 | 37 | end 38 | 39 | end 40 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # Start SimpleCov 2 | begin 3 | require 'ostruct' 4 | require 'simplecov' 5 | SimpleCov.start 6 | rescue LoadError 7 | puts 'for coverage please install SimpleCov' 8 | end 9 | 10 | require 'ostruct' 11 | 12 | # Require the actual project 13 | $: << File.expand_path('../lib', __FILE__) 14 | require 'easy_translate' 15 | --------------------------------------------------------------------------------