Question

The following Ruby code accesses Google Translate's API:

require 'google/api_client'
client = Google::APIClient.new
translate = client.discovered_api('translate','v2')
client.authorization.access_token = '123' # dummy
client.key = "<My Google API Key>"
response = client.execute(
               :api_method => translate.translations.list,
               :parameters => {
                 'format' => 'text',
                 'source' => 'eng',
                 'target' => 'fre',
                 'q' => 'This is the text to be translated'
                 }
               )

The response comes back in JSON format.

This code works for text-to-be-translated (the q argument) of less than approximately 750 characters, but generates the following error for longer text:

Error 414 (Request-URI Too Large)!!1Error 414 (Request-URI Too Large)!!1

I have Googled this problem and found the following pages:

https://developers.google.com/translate/ https://github.com/google/google-api-ruby-client

It seems that the Google API Client code is placing the call to the Google API using a GET instead of a POST. As various systems place limits on the length of URLs, this restricts the length of text that can be translated.

The form of the solution to this problem seems to be that I should instruct the Google API interface to place the call to the Google API using a POST instead of a GET. However, I so far haven't been able to figure out how to do this.

I see that there are a few other StackOverflow questions relating to this issue in other languages. However, I so far haven't been able to figure out how to apply it to my Ruby code.


Thanks very much Dave Sag. Your approach worked, and I have developed it into a working example that other Stack Overflow users might find useful. (Note: Stack Overflow won't let me post this as an answer for eight hours, so I'm editing my question instead.) Here is the example:

#!/usr/local/rvm/rubies/ruby-1.9.3-p194/bin/ruby
#
# This is a self-contained Unix/Linux Ruby script.
#
# Replace the first line above with the location of your ruby executable. e.g.
#!/usr/bin/ruby
#
################################################################################
#
# Author  : Ross Williams.
# Date    : 1 January 2014.
# Version : 1.
# Licence : Public Domain. No warranty or liability.
# 
# WARNING: This code is example code designed only to help Stack Overflow
# users solve a specific problem. It works, but it does not contain
# comprehensive error checking which would probably double the length
# of the code.

require 'uri'
require 'net/http'
require 'net/https'
require 'rubygems'
require 'json'

################################################################################
#
# This method translates a string of up to 5K from one language to another using
# the Google Translate API.
# 
# google_api_key
#    This is a string of about 39 characters which identifies you
#    as a user of the Google Translate API. At the time of writing,
#    this API costs US$20/MB of source text. You can obtain a key
#    by registering at:
#       https://developers.google.com/translate/
#       https://developers.google.com/translate/v2/getting_started
#
# source_language_code
# target_language_code
#    These arguments identify the source and target language.
#    Each of these arguments should be a string containing one
#    of Google's two-letter language identification codes.
#    A list of these codes can be found at:
#       https://sites.google.com/site/opti365/translate_codes
#
# text_to_be_translated
#    This is a string to be translated. Ruby provides excellent
#    Unicode support and this string can contain non-ASCII characters.
#    This string must not be longer than 5K characters long.
#
def google_translate(google_api_key,source_language_code,target_language_code,text_to_be_translated)

   # Note:  The 5K limit on text_to_be_translated is stated at:
   # https://developers.google.com/translate/v2/using_rest?hl=ja
   # It is not clear to me whether this is 5*1024 or 5*1000.

   # The Google Translate API is served at this HTTPS address.
   # See http://stackoverflow.com/questions/13152264/sending-http-post-request-in-ruby-by-nethttp
   uri = URI.parse("https://www.googleapis.com/language/translate/v2")
   request = Net::HTTP::Post.new(uri.path)

   # The API accepts only the GET method. However, the GET method has URL length
   # limitations so we have to use POST method instead. We need to use a trick for
   # deliverying the form fields using POST but having the API perceive it as a GET.
   # Setting a key/value pair in request adds a field to the HTTP header to do this.
   request['X-HTTP-Method-Override'] = 'GET'

   # Load the arguments to the API into the POST form fields.
   params = {
      'access_token' => '123',           # Dummy parameter seems to be required.
      'key'          => google_api_key,
      'format'       => 'text',
      'source'       => source_language_code,
      'target'       => target_language_code,
      'q'            => text_to_be_translated
      }
   request.set_form_data(params)

   # Execute the request.
   # It's important to use HTTPS, as the API key is being transmitted.
   https = Net::HTTP.new(uri.host,uri.port)
   https.use_ssl = true
   response = https.request(request)

   # The API returns a record in JSON format.
   # See http://en.wikipedia.org/wiki/JSON
   # See http://www.json.org/
   json_text = response.body

   # Parse the JSON record, yielding a nested hash/list data structure.
   json_structure = JSON.parse(json_text)

   # Navigate down into the data structure to get the result.
   # This navigation was coded by examining the JSON text from an actual run.
   data_hash = json_structure['data']
   translations_list = data_hash['translations']
   translation_hash = translations_list[0]
   translated_text = translation_hash['translatedText']
   return translated_text

end # def google_translate

################################################################################

google_api_key = '<INSERT YOUR GOOGLE TRANSLATE API KEY HERE>'
source_language_code = 'en' # English
target_language_code = 'fr' # French

# To test the code, I have chosen a sample text of about 3393 characters.
# This is large enough to exceed the GET URL length limit, but small enough
# not to exceed the Google Translate API length limit of 5K.
# Sample text is from http://www.gutenberg.org/cache/epub/2701/pg2701.txt
text_to_be_translated = <<END
Call me Ishmael. Some years ago--never mind how long precisely--having
little or no money in my purse, and nothing particular to interest me on
shore, I thought I would sail about a little and see the watery part of
the world. It is a way I have of driving off the spleen and regulating
the circulation. Whenever I find myself growing grim about the mouth;
whenever it is a damp, drizzly November in my soul; whenever I find
myself involuntarily pausing before coffin warehouses, and bringing up
the rear of every funeral I meet; and especially whenever my hypos get
such an upper hand of me, that it requires a strong moral principle to
prevent me from deliberately stepping into the street, and methodically
knocking people's hats off--then, I account it high time to get to sea
as soon as I can. This is my substitute for pistol and ball. With a
philosophical flourish Cato throws himself upon his sword; I quietly
take to the ship. There is nothing surprising in this. If they but knew
it, almost all men in their degree, some time or other, cherish very
nearly the same feelings towards the ocean with me.

There now is your insular city of the Manhattoes, belted round by
wharves as Indian isles by coral reefs--commerce surrounds it with
her surf. Right and left, the streets take you waterward. Its extreme
downtown is the battery, where that noble mole is washed by waves, and
cooled by breezes, which a few hours previous were out of sight of land.
Look at the crowds of water-gazers there.

Circumambulate the city of a dreamy Sabbath afternoon. Go from Corlears
Hook to Coenties Slip, and from thence, by Whitehall, northward. What
do you see?--Posted like silent sentinels all around the town, stand
thousands upon thousands of mortal men fixed in ocean reveries. Some
leaning against the spiles; some seated upon the pier-heads; some
looking over the bulwarks of ships from China; some high aloft in the
rigging, as if striving to get a still better seaward peep. But these
are all landsmen; of week days pent up in lath and plaster--tied to
counters, nailed to benches, clinched to desks. How then is this? Are
the green fields gone? What do they here?

But look! here come more crowds, pacing straight for the water, and
seemingly bound for a dive. Strange! Nothing will content them but the
extremest limit of the land; loitering under the shady lee of yonder
warehouses will not suffice. No. They must get just as nigh the water
as they possibly can without falling in. And there they stand--miles of
them--leagues. Inlanders all, they come from lanes and alleys, streets
and avenues--north, east, south, and west. Yet here they all unite.
Tell me, does the magnetic virtue of the needles of the compasses of all
those ships attract them thither?

Once more. Say you are in the country; in some high land of lakes. Take
almost any path you please, and ten to one it carries you down in a
dale, and leaves you there by a pool in the stream. There is magic
in it. Let the most absent-minded of men be plunged in his deepest
reveries--stand that man on his legs, set his feet a-going, and he will
infallibly lead you to water, if water there be in all that region.
Should you ever be athirst in the great American desert, try this
experiment, if your caravan happen to be supplied with a metaphysical
professor. Yes, as every one knows, meditation and water are wedded for
ever.
END

translated_text =
   google_translate(google_api_key,
                    source_language_code,
                    target_language_code,
                    text_to_be_translated)

puts(translated_text)

################################################################################
Was it helpful?

Solution

I'd use the REST API directly rather than the whole Google API which seems to encompass everything but when I searched the source for 'translate' it turned up nothing.

Create a request, set the appropriate header as per these docs

Note: You can also use POST to invoke the API if you want to send more data in a single request. The q parameter in the POST body must be less than 5K characters. To use POST, you must use the X-HTTP-Method-Override header to tell the Translate API to treat the request as a GET (useX-HTTP-Method-Override: GET).

code (not tested) might look like

  require 'net/http'
  require 'net/https'

  uri = URI.parse('https://www.googleapis.com/language/translate/v2')
  request = Net::HTTP::Post.new(uri, {'X-HTTP-Method-Override' => 'GET'})
  params = {
   'format' => 'text',
   'source' => 'eng',
   'target' => 'fre',
   'q' => 'This is the text to be translated'
   }
  request.set_form_data(params)
  https = Net::HTTP.new(uri.host, uri.port)
  https.use_ssl = true
  response = https.request request
  parsed = JSON.parse(response)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top