Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -610,9 +610,10 @@ Google Translate
#### Preview

Here's a snippet showing a simple usage example. The example shows how to detect the language of
some text and how to translate some text. The example assumes that the `GOOGLE_API_KEY` is set and
contains a valid API key. Alternatively, you can use the `apiKey(String)` setter in
`TranslateOptions.Builder` to set the API key. Complete source code can be found at
some text and how to translate some text. The example assumes that either default application
credentials or a valid api key are available. An api key stored in the `GOOGLE_API_KEY` environment
variable will be automatically detected. Alternatively, you can use the `apiKey(String)` setter in
`TranslateOptions.Builder`. Complete source code can be found at
[DetectLanguageAndTranslate.java](./google-cloud-examples/src/main/java/com/google/cloud/examples/translate/snippets/DetectLanguageAndTranslate.java).

```java
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public class DetectLanguageAndTranslate {

public static void main(String... args) {
// Create a service object
// API key is read from the GOOGLE_API_KEY environment variable
// Default application credentials or an API key from the GOOGLE_API_KEY environment variable
// are used to authenticate requests
Translate translate = TranslateOptions.getDefaultInstance().getService();

// Detect the language of some text
Expand Down
31 changes: 20 additions & 11 deletions google-cloud-translate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,25 @@ Getting Started
---------------
#### Prerequisites
For this tutorial, you need a [Google Developers Console](https://console.developers.google.com/)
project with "Translate API" enabled via the console's API Manager. You will also need a to enable
billing via the [Google Developers Console](https://console.developers.google.com/) project and to
retrieve an API key. See [Translate quickstart](https://cloud.google.com/translate/v2/quickstart)
for more details.
project with "Translate API" enabled via the console's API Manager. You also need to enable
billing via the [Google Developers Console](https://console.developers.google.com/).

Finally, you must set up the local development environment by
[installing the Google Cloud SDK](https://cloud.google.com/sdk/) and running the following command
in command line: `gcloud auth application-default login`. Alternatively, you can authenticate
Translate requests using an API key. See
[Translate quickstart](https://cloud.google.com/translate/v2/quickstart) for more details.

#### Installation and setup
You'll need to obtain the `google-cloud-translate` library. See the [Quickstart](#quickstart)
section to add `google-cloud-translate` as a dependency in your code.

#### Creating an authorized service object
To make authenticated requests to Google Translates, you must create a service object with an API
key. By default, API key is looked for in the `GOOGLE_API_KEY` environment variable. Once the API
key is set, you can make API calls by invoking methods on the Translate service object. To create a
service object, given that `GOOGLE_API_KEY` is set, use the following code:
To make authenticated requests to Google Translate, you must create a service object with
credentials or with an API key. The simplest way to authenticate is to use
[Application Default Credentials](https://developers.google.com/identity/protocols/application-default-credentials).
These credentials are automatically inferred from your environment, so you only need the following
code to create your service object:

```java
import com.google.cloud.translate.Translate;
Expand All @@ -86,7 +91,11 @@ import com.google.cloud.translate.TranslateOptions;
Translate translate = TranslateOptions.getDefaultInstance().getService();
```

Or you can explicitly set the API key as follows:
Notice that this code can be also used with an API key. By default, an API key is looked for in the
`GOOGLE_API_KEY` environment variable. Once the API key is set, you can make API calls by invoking
methods on the Translate service created via `TranslateOptions.getDefaultInstance().getService()`.

You can also explicitly set the API key as follows:
```java
Translate translate = TranslateOptions.newBuilder().setApiKey("myKey").getService();
```
Expand Down Expand Up @@ -131,8 +140,8 @@ Translation translation = translate.translate(

In
[DetectLanguageAndTranslate.java](../google-cloud-examples/src/main/java/com/google/cloud/examples/translate/snippets/DetectLanguageAndTranslate.java)
we put together all the code shown above into one program. The program assumes that a valid api key
is available.
we put together all the code shown above into one program. The program assumes that either default
application credentials or a valid api key are available.

Troubleshooting
---------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,19 @@ public static TranslateOption sourceLanguage(String sourceLanguage) {
public static TranslateOption targetLanguage(String targetLanguage) {
return new TranslateOption(TranslateRpc.Option.TARGET_LANGUAGE, targetLanguage);
}

/**
* Sets the language translation model. You can use this parameter to take advantage of Neural
* Machine Translation. Possible values are {@code base} and {@code nmt}. Google Translate could
* use a different model to translate your text, use {@link Translation#getModel()} to know
* which model was used for translation. Please notice that you must be whitelisted to use this
* option, otherwise translation will fail.
*
* @param model the language translation model
*/
public static TranslateOption model(String model) {
return new TranslateOption(TranslateRpc.Option.MODEL, model);
}
}

/**
Expand Down Expand Up @@ -170,6 +183,8 @@ public static TranslateOption targetLanguage(String targetLanguage) {
* @param texts the texts to translate
* @return a list of objects containing information on the language translation, one for each
* provided text, in order.
* @throws TranslateException upon failure or if {@link TranslateOption#model(String)} is used by
* a non-whitelisted user
*/
List<Translation> translate(List<String> texts, TranslateOption... options);

Expand All @@ -189,6 +204,8 @@ public static TranslateOption targetLanguage(String targetLanguage) {
*
* @param text the text to translate
* @return an object containing information on the language translation
* @throws TranslateException upon failure or if {@link TranslateOption#model(String)} is used by
* a non-whitelisted user
*/
Translation translate(String text, TranslateOption... options);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,17 @@

import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;

public class TranslateOptions extends
HttpServiceOptions<Translate, TranslateRpc, TranslateOptions> {

private static final long serialVersionUID = -572597134540398216L;
private static final String DEFAULT_HOST = "https://translation.googleapis.com";
private static final String API_KEY_ENV_NAME = "GOOGLE_API_KEY";
private static final Set<String> SCOPES = ImmutableSet.of();
private static final Set<String> SCOPES =
ImmutableSet.of("https://www.googleapis.com/auth/cloud-platform");

private final String apiKey;
private final String targetLanguage;
Expand Down Expand Up @@ -97,17 +100,6 @@ public Builder setProjectId(String projectId) {
return self();
}

/**
* Sets the service authentication credentials. Setting credentials has no impact on the
* {@link Translate} service.
*
* @return the builder
*/
public Builder setCredentials(Credentials credentials) {
super.setCredentials(credentials);
return self();
}

/**
* Sets the API key used to issue requets. If not set, the API key is looked for in the
* {@code GOOGLE_API_KEY} environment variable. For instructions on how to get an API key see
Expand Down Expand Up @@ -158,18 +150,13 @@ public Builder setTargetLanguage(String targetLanguage) {

@Override
public TranslateOptions build() {
// Auth credentials are not used by Translate
setCredentials(NoCredentials.getInstance());
return new TranslateOptions(this);
}
}

private TranslateOptions(Builder builder) {
super(TranslateFactory.class, TranslateRpcFactory.class, builder);
this.apiKey = builder.apiKey != null ? builder.apiKey : getDefaultApiKey();
checkArgument(this.apiKey != null,
"An API key is required for this service but could not be determined from the builder "
+ "or the environment. Please set an API key using the builder.");
this.targetLanguage = firstNonNull(builder.targetLanguage, Locale.ENGLISH.getLanguage());
}

Expand All @@ -193,6 +180,11 @@ protected Set<String> getScopes() {
return SCOPES;
}

@Override
protected String getDefaultHost() {
return DEFAULT_HOST;
}

@Deprecated
protected String defaultApiKey() {
return getDefaultApiKey();
Expand Down Expand Up @@ -250,8 +242,8 @@ public boolean equals(Object obj) {
}
TranslateOptions options = (TranslateOptions) obj;
return baseEquals(options)
&& apiKey.equals(options.apiKey)
&& targetLanguage.equals(options.targetLanguage);
&& Objects.equals(apiKey, options.apiKey)
&& Objects.equals(targetLanguage, options.targetLanguage);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.common.base.MoreObjects;

import java.io.Serializable;
import java.util.List;
import java.util.Objects;

/**
Expand All @@ -43,10 +44,12 @@ public Translation apply(TranslationsResource translationPb) {

private final String translatedText;
private final String sourceLanguage;
private final String model;

private Translation(String translatedText, String sourceLanguage) {
private Translation(String translatedText, String sourceLanguage, String model) {
this.translatedText = translatedText;
this.sourceLanguage = sourceLanguage;
this.model = model;
}

/**
Expand Down Expand Up @@ -81,6 +84,18 @@ public String getSourceLanguage() {
return sourceLanguage;
}

/**
* Returns the translation model used to translate the text. This value is only available if
* {@link Translate.TranslateOption#model(String)} was passed to
* {@link Translate#translate(List, Translate.TranslateOption...)}.
*
* <p>Please notice that you must be whitelisted to use the
* {@link Translate.TranslateOption#model(String)} option, otherwise translation will fail.
*/
public String getModel() {
return model;
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
Expand Down Expand Up @@ -108,7 +123,8 @@ public final boolean equals(Object obj) {
}

static Translation fromPb(TranslationsResource translationPb) {
// TODO remove get("model") as soon as REST apiary supports model
return new Translation(translationPb.getTranslatedText(),
translationPb.getDetectedSourceLanguage());
translationPb.getDetectedSourceLanguage(), (String) translationPb.get("model"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,28 @@

package com.google.cloud.translate.spi;

import static com.google.cloud.translate.spi.TranslateRpc.Option.MODEL;
import static com.google.cloud.translate.spi.TranslateRpc.Option.SOURCE_LANGUAGE;
import static com.google.cloud.translate.spi.TranslateRpc.Option.TARGET_LANGUAGE;
import static com.google.common.base.MoreObjects.firstNonNull;

import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.json.JsonHttpContent;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.translate.Translate;
import com.google.api.services.translate.model.DetectionsListResponse;
import com.google.api.services.translate.model.DetectionsResourceItems;
import com.google.api.services.translate.model.LanguagesListResponse;
import com.google.api.services.translate.model.LanguagesResource;
import com.google.api.services.translate.model.TranslationsResource;
import com.google.cloud.translate.TranslateException;
import com.google.cloud.translate.TranslateOptions;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;

import java.io.IOException;
Expand All @@ -56,11 +63,27 @@ private static TranslateException translate(IOException exception) {
return new TranslateException(exception);
}

private GenericUrl buildTargetUrl(String path) {
GenericUrl genericUrl = new GenericUrl(translate.getBaseUrl() + "v2/" + path);
if (options.getApiKey() != null) {
genericUrl.put("key", options.getApiKey());
}
return genericUrl;
}

@Override
public List<List<DetectionsResourceItems>> detect(List<String> texts) {
try {
Map<String, ?> content = ImmutableMap.of("q", texts);
HttpRequest httpRequest = translate.getRequestFactory()
.buildPostRequest(buildTargetUrl("detect"),
new JsonHttpContent(translate.getJsonFactory(), content))
.setParser(translate.getObjectParser());
List<List<DetectionsResourceItems>> detections =
translate.detections().list(texts).setKey(options.getApiKey()).execute().getDetections();
httpRequest.execute().parseAs(DetectionsListResponse.class).getDetections();
// TODO use REST apiary as soon as it supports POST
// List<List<DetectionsResourceItems>> detections =
// translate.detections().list(texts).setKey(options.getApiKey()).execute().getDetections();
return detections != null ? detections : ImmutableList.<List<DetectionsResourceItems>>of();
} catch (IOException ex) {
throw translate(ex);
Expand All @@ -70,12 +93,21 @@ public List<List<DetectionsResourceItems>> detect(List<String> texts) {
@Override
public List<LanguagesResource> listSupportedLanguages(Map<Option, ?> optionMap) {
try {
List<LanguagesResource> languages = translate.languages()
.list()
.setKey(options.getApiKey())
.setTarget(
firstNonNull(TARGET_LANGUAGE.getString(optionMap), options.getTargetLanguage()))
.execute().getLanguages();
Map<String, ?> content = ImmutableMap.of("target",
firstNonNull(TARGET_LANGUAGE.getString(optionMap), options.getTargetLanguage()));
HttpRequest httpRequest = translate.getRequestFactory()
.buildPostRequest(buildTargetUrl("languages"),
new JsonHttpContent(translate.getJsonFactory(), content))
.setParser(translate.getObjectParser());
List<LanguagesResource> languages =
httpRequest.execute().parseAs(LanguagesListResponse.class).getLanguages();
// TODO use REST apiary as soon as it supports POST
// List<LanguagesResource> languages = translate.languages()
// .list()
// .setKey(options.getApiKey())
// .setTarget(
// firstNonNull(TARGET_LANGUAGE.getString(optionMap), options.getTargetLanguage()))
// .execute().getLanguages();
return languages != null ? languages : ImmutableList.<LanguagesResource>of();
} catch (IOException ex) {
throw translate(ex);
Expand All @@ -85,6 +117,8 @@ public List<LanguagesResource> listSupportedLanguages(Map<Option, ?> optionMap)
@Override
public List<TranslationsResource> translate(List<String> texts, Map<Option, ?> optionMap) {
try {
// TODO use POST as soon as usage of "model" correctly reports an error in non-whitelisted
// projects
String targetLanguage =
firstNonNull(TARGET_LANGUAGE.getString(optionMap), options.getTargetLanguage());
final String sourceLanguage = SOURCE_LANGUAGE.getString(optionMap);
Expand All @@ -93,6 +127,7 @@ public List<TranslationsResource> translate(List<String> texts, Map<Option, ?> o
.list(texts, targetLanguage)
.setSource(sourceLanguage)
.setKey(options.getApiKey())
.set("model", MODEL.getString(optionMap))
.execute()
.getTranslations();
return Lists.transform(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public interface TranslateRpc {

enum Option {
SOURCE_LANGUAGE("source"),
TARGET_LANGUAGE("target");
TARGET_LANGUAGE("target"),
MODEL("model");

private final String value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,11 @@ public class TranslateImplTest {
TranslateOption.targetLanguage("en");
private static final TranslateOption SOURCE_LANGUAGE_OPTION =
TranslateOption.sourceLanguage("de");
private static final TranslateOption MODEL_OPTION = TranslateOption.model("nmt");
private static final Map<TranslateRpc.Option, ?> TRANSLATE_OPTIONS = ImmutableMap.of(
TranslateRpc.Option.TARGET_LANGUAGE, TARGET_LANGUAGE_OPTION.getValue(),
TranslateRpc.Option.SOURCE_LANGUAGE, SOURCE_LANGUAGE_OPTION.getValue());
TranslateRpc.Option.SOURCE_LANGUAGE, SOURCE_LANGUAGE_OPTION.getValue(),
TranslateRpc.Option.MODEL, "nmt");

private TranslateOptions options;
private TranslateRpcFactory rpcFactoryMock;
Expand Down Expand Up @@ -285,7 +287,7 @@ public void testTranslateWithOptions() {
EasyMock.replay(translateRpcMock);
initializeService();
assertEquals(TRANSLATION2,
translate.translate(text, TARGET_LANGUAGE_OPTION, SOURCE_LANGUAGE_OPTION));
translate.translate(text, TARGET_LANGUAGE_OPTION, SOURCE_LANGUAGE_OPTION, MODEL_OPTION));
}

@Test
Expand All @@ -309,7 +311,7 @@ public void testTranslateListWithOptions() {
EasyMock.replay(translateRpcMock);
initializeService();
assertEquals(ImmutableList.of(TRANSLATION2),
translate.translate(texts, TARGET_LANGUAGE_OPTION, SOURCE_LANGUAGE_OPTION));
translate.translate(texts, TARGET_LANGUAGE_OPTION, SOURCE_LANGUAGE_OPTION, MODEL_OPTION));
}

@Test
Expand Down
Loading