Google, mostly known for its search engine and extremely popular email service, Gmail, also provides an incredible amount of APIs, which are extremely powerful and useful, no matter your needs. From image recognition to maps, their offering is almost unmatched. In this article, we’d like to take a look at the Google Translate API. Google’s translation offering is extremely accurate, and we’d like to show you how to take advantage of it using Ruby.
Get Access to the API
First and foremost, we’re going to need access to the API. If you head to RapidAPI’s website, you’ll quickly find it if you search for “Google Translate”. In case you want a direct link, just click here. You’ll need to sign up for an account and then subscribe to the API to use it. Click on the “Subscribe to Test” button, then select the “Basic” plan.
Once you’re signed up and subscribed, you’re ready to go! This API provides three endpoints:
languages
detect
translate
The first endpoint just gives you a list of the languages the API supports, while the second allows detecting the language a text is written in (with a certain degree of confidence). The last one is probably the most useful and powerful, allowing you to translate from one language to another.
Test the API
One great way of getting to know the API and testing the different endpoints is to use the in-browser tester. On the list to the left, you can select an endpoint, and in the middle column, you can see the different parameters it takes. For example, select the detect
endpoint, and in the middle, scroll down to find the q
parameter. Enter any text you like, then at the top click the “Test Endpoint” button. To the right, you’ll see the API response, which should include one or more languages with varying degrees of confidence.
Go ahead and test the other endpoints, as we’ll be needing them later.
How to use the API with Ruby on Rails
We’re going to be showing you how to use this API using Ruby on Rails. For this, we’re going to build a simple Google Translate clone, where a user can translate text, selecting the source and destination language, or by automatically detecting the language (did you notice how the translate
endpoint can detect the language automatically?).
For this you’ll need:
- Ruby
- Ruby on Rails
- Excon
- Bootstrap
To install Ruby, refer to their documentation for installation instructions depending on your platform. To install Ruby on Rails, you can just run gem install rails
on your terminal (after installing Ruby of course). We’re going to install Excon later using Bundler, but just know that this is going to be our HTTP client to use the API from our Rails app. To use Bootstrap (the layout and design library), there are two ways:
- Use the
bootstrap-ruby
gem - Include dependencies using CDNs
The first option is the best if you’re planning on building something that’s going to go to production environments, as it takes advantage of Rails’ dependency management. The second option is much simpler and quicker, so we’re going to use that one for this article.
Step 1: Create our App
The first step with a Rails app is to create it. Since our app is not going to use a database, we can run this to create it:
rails new translate --skip-active-record --skip-test
We’ve also skipped the test bundle for simplicity (but you should always test your code!). You should now be able to cd
into your application directory and run the rails server:
cd translate rails server
If you use your browser to go to localhost:3000, you should be greeted with Ruby on Rails!
Step 2: Setup Dependencies
Let’s setup our dependencies now. Edit the Gemfile
and add this to the bottom:
gem 'excon' gem 'i18n_data'
Now run bundle install
in your terminal to install the dependencies. We need the i18n_data
gem because the API only returns two-letter codes for each language, and we need a way to translate that to the language name. Once that’s done, edit the application layout in app/views/layouts/application.html.erb
, and make it look like this:
<!DOCTYPE html> <html> <head> <title>Translate</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> </head> <body> <%= yield %> <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> </body> </html>
Here, we’re just adding our Bootstrap dependencies directly into the application layout. This is the layout that all of our views are going to use to render.
Step 3: Create the Form
Our main page is going to be the translate form, where the user can enter the text to translate on the left, select the languages (to and from), and see the translated text on the right. First, we’re going to create a new route. To do this, just run this on your terminal:
rails generate controller translations index translate
This will generate a bunch of files, like the controller and the views, and it will also add some routes to the routes file. Edit that file (it’s in config/routes.rb
), so that it looks like this:
Rails.application.routes.draw do root to: 'translations#index' post 'translations/translate', as: :translate end
This sets our index route as the default route to render, and the second line allows POST
ing to the translate
method on the TranslationsController
, adding a translate
shorthand method to refer to it in our views (you’ll see this soon). Now, let’s create the form by editing the app/views/translations/index.html.erb
:
<div class="container"> <h1 class="text-center">Translator</h1> <%= form_with url: translate_path, method: :post, local: true do %> <div class="row"> <div class="col-lg-5"> <div class="form-group"> <label for="source">Translate</label> <%= text_area_tag :source, @source, class: 'form-control', style: 'width: 100%; height: 100px' %> </div> <div class="form-group"> <label for="source_language">From</label> <%= select_tag :source_language, options_for_select(@languages, @source_language), class: 'form-control', include_blank: 'Auto-detect' %> </div> </div> <div class="col-lg-2 d-flex align-items-center justify-content-center"> <button type="submit" class="btn btn-primary"> Translate <i class="fa fa-arrow-right"></i> </button> </div> <div class="col-lg-5"> <div class="form-group"> <label for="translation">Translation</label> <%= text_area_tag :translation, @translation, class: 'form-control', style: 'width: 100%; height: 100px', readonly: true %> </div> <div class="form-group"> <label for="destination_language">To</label> <%= select_tag :destination_language, options_for_select(@languages, @destination_language), class: 'form-control' %> </div> </div> </div> <% end %> </div>
This is quite a big file, but most of it is Bootstrap formatting. We’re creating a form that will POST
to the translate_path
path. The local: true
option makes sure the form is sent to a new page, and doesn’t use AJAX (which is outside the scope of this tutorial). We then set up two text areas, two select dropdowns with languages and a submit button. The form is using quite a few instance variables (the ones starting with @
), which we need to define in our controller. Let’s do that in the next step.
Step 4: Translations Controller
In your app/controllers/translations_controller.rb
file, add the following methods so it looks more like this:
class TranslationsController < ApplicationController before_action :set_defaults def index end def translate end private def set_defaults @languages = fetch_languages end def api_request(path, method: :get, body: nil) params = { headers: { 'x-rapidapi-key': 'YOUR_API_KEY', 'content-type': 'application/x-www-form-urlencoded' } } params[:body] = body if body response = Excon.send(method, "https://google-translate1.p.rapidapi.com/#{path}", params ) JSON.parse(response.body) end def fetch_languages languages = api_request('language/translate/v2/languages') keys = languages['data']['languages'].map { |l| l['language'].upcase } I18nData .languages .slice(*keys) .each_with_object([]) do |(iso, name), memo| memo << [name, iso] end end end
There’s a lot going on, but we’re setting up for the next steps as well, so bear with us. We’re creating a before_action
that will populate our @languages
array. For this we need to fetch the languages from the API, so we’re also creating a generic api_request
method that we can use for both requesting the languages and also translating text. Remember to replace YOUR_API_KEY
with your own, which you can find on RapidAPI. The fetch_languages
method also does some processing. Since the API returns only the ISO code for each language, we need to “translate” that into something we can show to the user. For this, we use the i18n_data gem we installed earlier. With some loops and mapping, we can get an array that can be used by the options_for_select
method in our view (check out the previous step).
You should now be able to run rails server
again and go to your website. You should be greeted with a nice translation form:
Notice how the dropdowns show the actual language name, and that the left dropdown (the “from” language) allows selecting “Auto-detect”.
Step 5: Translate
Let’s implement the final method: the translate method in our controller. Change it so it looks like this:
def translate @source = translate_params[:source] @source_language = translate_params[:source_language] @destination_language = translate_params[:destination_language] body = { q: @source, target: @destination_language.upcase } body[:source] = @source_language.downcase unless @source_language.empty? translation = api_request( 'language/translate/v2', method: :post, body: URI.encode_www_form(body) ) @translation = translation['data']['translations'].first['translatedText'] render action: :index end
We grab our parameters from the form, then we construct the request body the API expects to get a translation. If the user selects the “Auto-detect” option in the form, we just don’t send that parameter. The request is sent and then we set the @translation
variable with the result. Finally, we render the same view again (the index
view).
We also need to define a translate_params
method in our controller for it to work:
def translate_params params.permit(:source, :source_language, :destination_language) end
Take a look at the documentation for Strong Parameters to understand how this works. You should now be able to get translations! Give it a go.
Conclusion
This article should’ve given you a good baseline to use the Google Translate API in a Ruby on Rails (or just plain Ruby) app. We’ll leave implementing the “detect” language feature as an exercise to the reader, but you should be able to quickly add it using the generic api_request
method we implemented. Check out the API’s documentation on RapidAPI for a quick reference to get you started.
How to get access to the Google Translate API on RapidAPI?
You can find the Google Translate API on RapidAPI. Use the search function and select the API from the list of results.
How to use the Google Translate API for free on RapidAPI?
The Google Translate API offers different plans, one of them free with certain monthly limitations. In the subscribe page, select the Basic plan.
How to use the Google Translate API with Ruby On Rails on RapidAPI?
This article should give you the information you need to get started with the Google Translate API with Ruby on Rails.
bwali says
Your controller code throws an error:
NoMethodError in TranslationsController#index
undefined method `[]’ for nil:NilClass
Extracted source (around line #37):
35
36
37
38
39
40
languages = api_request(‘language/translate/v2/languages’)
keys = languages[‘data’][‘languages’].map { |l| l[‘language’].upcase }
I18nData
.languages
Ian Murray says
Hi bwali, I’m sorry you’re having trouble with the tutorial. As far as I can see the code works fine. In order to help you debug the issue, could you see what the contents of the “languages” variable is after doing the api request? A simple “puts languages” would suffice.
Thanks.