class GoogleWebTranslate::API

interface to the google web translation api

Constants

DEFAULT_DT
DEFAULT_RATE_LIMIT
DEFAULT_TOKEN_TTL
TRANSLATE_PATH
URL_MAIN

Public Class Methods

new(options = {}) click to toggle source
# File lib/google_web_translate/api.rb, line 7
def initialize(options = {})
  @dt = options[:dt] || DEFAULT_DT
  @token_ttl = options[:token_ttl] || DEFAULT_TOKEN_TTL
  @debug = options[:debug]
  @http_client = options[:http_client] || HTTPClient.new(options)
  @rate_limit = options[:rate_limit] || DEFAULT_RATE_LIMIT
end

Public Instance Methods

languages() click to toggle source
# File lib/google_web_translate/api.rb, line 20
def languages
  @languages ||= begin
    html = fetch_main
    html.scan(/\['(\w{2})','(\w{2})'\]/).flatten.uniq.sort
  end
end
translate(string, from, to) click to toggle source
# File lib/google_web_translate/api.rb, line 15
def translate(string, from, to)
  data = fetch_translation(string, from, to)
  Result.new(data)
end

Private Instance Methods

compile_js(html) click to toggle source
# File lib/google_web_translate/api.rb, line 79
def compile_js(html)
  desktop_module_js = munge_module(fetch_desktop_module(html))
  window_js = File.read(File.join(__dir__, '..', 'js', 'window.js'))
  js = window_js + desktop_module_js
  # File.write('generated.js', js) if debug?
  @tk_function = detect_tk_function(desktop_module_js)
  debug("detected tk function: #{@tk_function}")
  ExecJS.compile(js)
end
debug(msg) click to toggle source
# File lib/google_web_translate/api.rb, line 141
def debug(msg)
  puts msg if debug?
end
debug?() click to toggle source
# File lib/google_web_translate/api.rb, line 145
def debug?
  @debug
end
detect_tk_function(js) click to toggle source
# File lib/google_web_translate/api.rb, line 89
def detect_tk_function(js)
  js =~ /translate_tts.*,\s*(\w+)\(.*\)/
  Regexp.last_match(1) || 'vq'
end
extract_tkk(html) click to toggle source
# File lib/google_web_translate/api.rb, line 114
def extract_tkk(html)
  raise 'TKK not found' unless html =~ /TKK=eval\('(.*?)'\);/
  tkk_code = Regexp.last_match(1)
  # tkk_code = Translatomatic::StringEscaping.unescape(tkk_code)
  tkk_code = StringEscaping.unescape(tkk_code)
  debug("tkk code unescaped: #{tkk_code}")
  tkk = ExecJS.eval(tkk_code)
  # tkk = context.call(nil)
  debug("evaluated tkk: #{tkk}")
  tkk
end
fetch_desktop_module(html) click to toggle source
# File lib/google_web_translate/api.rb, line 66
def fetch_desktop_module(html)
  html =~ /([^="]*desktop_module_main.js)/
  url = Regexp.last_match(1)
  raise 'unable to find desktop module' unless url
  fetch_url_body(url)
end
fetch_main(options = {}) click to toggle source
# File lib/google_web_translate/api.rb, line 61
def fetch_main(options = {})
  @html = nil if options[:no_cache]
  @html ||= fetch_url_body(URL_MAIN)
end
fetch_translation(string, from, to) click to toggle source
# File lib/google_web_translate/api.rb, line 35
def fetch_translation(string, from, to)
  debug('getting next server')
  server = ServerList.next_server(@rate_limit)
  debug("using server #{server}")
  json = fetch_url_body(translate_url(server, string, from, to))
  # File.write("response.json", json) if debug?
  debug("response: #{json}")
  JSON.parse(json)
end
fetch_url_body(url) click to toggle source
# File lib/google_web_translate/api.rb, line 49
def fetch_url_body(url)
  uri = URI.parse(url)
  uri = URI.join(URL_MAIN, url) if uri.relative?
  debug("fetch #{uri}")
  response = fetch_url_response(uri)
  response.body
end
fetch_url_response(url) click to toggle source
# File lib/google_web_translate/api.rb, line 45
def fetch_url_response(url)
  @http_client.get(url.to_s)
end
munge_module(js) click to toggle source
# File lib/google_web_translate/api.rb, line 73
def munge_module(js)
  js.gsub(/((?:var\s+)?\w+\s*=\s*\w+\.createElement.*?;)/) do |_i|
    'return "";'
  end
end
tk(string) click to toggle source
# File lib/google_web_translate/api.rb, line 104
def tk(string)
  update_token unless valid_token?
  tk = @js_context.call('generateToken', @tk_function, @tkk, string)
  (tk.split('=') || [])[1]
end
tk_js() click to toggle source
# File lib/google_web_translate/api.rb, line 110
def tk_js
  File.read(File.join(__dir__, 'google_web.js'))
end
translate_url(server, string, from, to) click to toggle source
# File lib/google_web_translate/api.rb, line 126
def translate_url(server, string, from, to)
  tk = tk(string)
  debug("tk: #{tk}")
  query = {
    sl: from, tl: to, ie: 'UTF-8', oe: 'UTF-8',
    q: string, dt: @dt, tk: tk,
    # not sure what these are for
    client: 't', hl: 'en', otf: 1, ssel: 4, tsel: 6, kc: 5
  }
  url = "https://#{server.host}" + TRANSLATE_PATH
  uri = URI.parse(url)
  uri.query = URI.encode_www_form(query)
  uri.to_s
end
update_token() click to toggle source
# File lib/google_web_translate/api.rb, line 94
def update_token
  # download main page
  html = fetch_main(no_cache: true)
  # extract tkk from html
  @tkk = extract_tkk(html)
  # compile desktop module javascript
  @js_context = compile_js(html)
  @token_updated_at = Time.now
end
valid_token?() click to toggle source
# File lib/google_web_translate/api.rb, line 57
def valid_token?
  @token_updated_at && Time.now - @token_updated_at < @token_ttl
end