diff --git a/README.md b/README.md index 018ce7eee1db..611552a34d74 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ This client supports the following Google Cloud Platform services: - [Google Cloud Pub/Sub] (#google-cloud-pubsub-alpha) (Alpha - Not working on App Engine Standard) - [Google Cloud Resource Manager] (#google-cloud-resource-manager-alpha) (Alpha) - [Google Cloud Storage] (#google-cloud-storage) +- [Google Cloud Translate] (#google-translate) (Alpha) > Note: This client is a work-in-progress, and may occasionally > make backwards-incompatible changes. @@ -569,6 +570,40 @@ if (blob != null) { } ``` +Google Translate +---------------- + +- [API Documentation][translate-api] +- [Official Documentation][translate-docs] + +#### 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 +[DetectLanguageAndTranslate.java](./gcloud-java-examples/src/main/java/com/google/cloud/examples/translate/snippets/DetectLanguageAndTranslate.java). + +```java +import com.google.cloud.translate.Detection; +import com.google.cloud.translate.Translate; +import com.google.cloud.translate.Translate.TranslateOption; +import com.google.cloud.translate.TranslateOptions; +import com.google.cloud.translate.Translation; + +Translate translate = TranslateOptions.defaultInstance().service(); + +Detection detection = translate.detect("Hola"); +String detectedLanguage = detection.language(); + +Translation translation = translate.translate( + "World", + TranslateOption.sourceLanguage("en"), + TranslateOption.targetLanguage(detectedLanguage)); + +System.out.printf("Hola %s%n", translation.translatedText()); +``` + Troubleshooting --------------- @@ -648,3 +683,6 @@ Apache 2.0 - See [LICENSE] for more information. [cloud-compute]: https://cloud.google.com/compute/ [cloud-compute-docs]: https://cloud.google.com/compute/docs/overview [compute-api]: http://googlecloudplatform.github.io/gcloud-java/apidocs/index.html?com/google/cloud/compute/package-summary.html + +[translate-docs]: https://cloud.google.com/translate/docs/ +[translate-api]: http://googlecloudplatform.github.io/gcloud-java/apidocs/index.html?com/google/cloud/translate/package-summary.html diff --git a/TESTING.md b/TESTING.md index a3d0ad770bc9..7ce657931f45 100644 --- a/TESTING.md +++ b/TESTING.md @@ -270,5 +270,25 @@ Here is an example that clears the bucket created in Step 3 with a timeout of 5 RemoteStorageHelper.forceDelete(storage, bucket, 5, TimeUnit.SECONDS); ``` +### Testing code that uses Translate + +`RemoteTranslateHelper` contains convenience methods to make is easier to run tests against the +Google Translate service. + +1. Create a test Google Cloud project. + +2. Follow [Translate Quickstart](https://cloud.google.com/translate/v2/quickstart) to get an API +key. + +3. Create a `RemoteTranslateHelper` object using your project ID and API key. Here is an example +that uses the `RemoteTranslateHelper` to list supported languages. + ```java + RemoteTranslateHelper translateHelper = RemoteTranslateHelper.create(PROJECT_ID, API_KEY); + Translate translate = translateHelper.options().service(); + List languages = translate.listSupportedLanguages(); + ``` + +4. Run your tests. + [cloud-platform-storage-authentication]:https://cloud.google.com/storage/docs/authentication?hl=en#service_accounts [create-service-account]:https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount diff --git a/gcloud-java-examples/README.md b/gcloud-java-examples/README.md index 0eed7ca402f5..4db9fed26be2 100644 --- a/gcloud-java-examples/README.md +++ b/gcloud-java-examples/README.md @@ -168,6 +168,16 @@ To run examples from your command line: via the NIO API. It lists gcloud-java-nio as a dependency, and that enables it to interpret `gs://` paths. + * Here's an example run of `TranslateExample`. + + Before running the example, go to the [Google Developers Console][developers-console] to ensure that "Google Translate API" is enabled and that you have a valid API key. + ``` + target/appassembler/bin/TranslateExample languages + target/appassembler/bin/TranslateExample detect Hello,\ World! + target/appassembler/bin/TranslateExample translate ¡Hola\ Mundo! + target/appassembler/bin/TranslateExample es translate Hello,\ World! + ``` + Troubleshooting --------------- diff --git a/gcloud-java-examples/pom.xml b/gcloud-java-examples/pom.xml index 6a1052a49e21..42f3d2671586 100644 --- a/gcloud-java-examples/pom.xml +++ b/gcloud-java-examples/pom.xml @@ -32,6 +32,12 @@ maven-assembly-plugin 2.5.4 + + junit + junit + 4.12 + test + @@ -100,6 +106,10 @@ com.google.cloud.examples.storage.StorageExample StorageExample + + com.google.cloud.examples.translate.TranslateExample + TranslateExample + diff --git a/gcloud-java-examples/src/main/java/com/google/cloud/examples/translate/TranslateExample.java b/gcloud-java-examples/src/main/java/com/google/cloud/examples/translate/TranslateExample.java new file mode 100644 index 000000000000..0e9666d23818 --- /dev/null +++ b/gcloud-java-examples/src/main/java/com/google/cloud/examples/translate/TranslateExample.java @@ -0,0 +1,220 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.examples.translate; + +import com.google.cloud.translate.Detection; +import com.google.cloud.translate.Language; +import com.google.cloud.translate.Translate; +import com.google.cloud.translate.TranslateOptions; +import com.google.cloud.translate.Translation; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * An example of using Google Translate. + * + *

This example demonstrates a simple/typical Translate usage. + * + *

See the + * + * README for compilation instructions. Run this code with + *

{@code target/appassembler/bin/TranslateExample
+ *  -Dexec.args=" []
+ *  list languages ?
+ *  detect +
+ *  translate +"}
+ * + *

The first parameter is an optional {@code targetLanguage}. If the target language is not + * supplied, {@code en} is used (see {@link TranslateOptions.Builder#targetLanguage(String)}). + */ +public class TranslateExample { + + private static final Map ACTIONS = new HashMap<>(); + + private abstract static class TranslateAction { + + abstract void run(Translate translate, T arg) throws Exception; + + abstract T parse(String... args) throws Exception; + + protected String params() { + return ""; + } + } + + /** + * This class demonstrates how to list supported languages. + * + * @see + * Discovering Supported Languages + */ + private static class ListLanguagesAction extends TranslateAction { + @Override + public void run(Translate translate, Void arg) { + List languages = translate.listSupportedLanguages(); + System.out.println("Supported languages:"); + for (Language language : languages) { + System.out.println(language); + } + } + + @Override + Void parse(String... args) throws Exception { + if (args.length == 0) { + return null; + } + throw new IllegalArgumentException("This action takes no arguments."); + } + } + + /** + * This class demonstrates how detect the language of some texts. + * + * @see Detecting + * Language + */ + private static class DetectLanguageAction extends TranslateAction> { + @Override + public void run(Translate translate, List texts) { + List detections = translate.detect(texts); + if (texts.size() == 1) { + System.out.println("Detected language is:"); + } else { + System.out.println("Detected languages are:"); + } + for (Detection detection : detections) { + System.out.println(detection); + } + } + + @Override + List parse(String... args) throws Exception { + if (args.length >= 1) { + return Arrays.asList(args); + } else { + throw new IllegalArgumentException("Missing required texts."); + } + } + + @Override + public String params() { + return "+"; + } + } + + /** + * This class demonstrates how to translate some texts. + * + * @see Translating + * Text + */ + private static class TranslateTextAction extends TranslateAction> { + @Override + public void run(Translate translate, List texts) { + List translations = translate.translate(texts); + if (texts.size() == 1) { + System.out.println("Translation is:"); + } else { + System.out.println("Translations are:"); + } + for (Translation translation : translations) { + System.out.println(translation); + } + } + + @Override + List parse(String... args) throws Exception { + if (args.length >= 1) { + return Arrays.asList(args); + } else { + throw new IllegalArgumentException("Missing required texts."); + } + } + + @Override + public String params() { + return "+"; + } + } + + static { + ACTIONS.put("languages", new ListLanguagesAction()); + ACTIONS.put("detect", new DetectLanguageAction()); + ACTIONS.put("translate", new TranslateTextAction()); + } + + private static void printUsage() { + StringBuilder actionAndParams = new StringBuilder(); + for (Map.Entry entry : ACTIONS.entrySet()) { + actionAndParams.append(System.lineSeparator()).append('\t').append(entry.getKey()); + String param = entry.getValue().params(); + if (param != null && !param.isEmpty()) { + actionAndParams.append(' ').append(param); + } + } + System.out.printf("Usage: %s [] [] operation *%s%n", + TranslateExample.class.getSimpleName(), actionAndParams); + } + + @SuppressWarnings("unchecked") + public static void main(String... args) throws Exception { + if (args.length < 1) { + System.out.println("Missing required action"); + printUsage(); + return; + } + TranslateOptions.Builder optionsBuilder = TranslateOptions.builder(); + TranslateAction action; + String actionName; + if (args.length >= 3 && !ACTIONS.containsKey(args[1])) { + optionsBuilder.apiKey(args[0]); + actionName = args[2]; + optionsBuilder.targetLanguage(args[1]); + args = Arrays.copyOfRange(args, 3, args.length); + } else if (args.length >= 2 && !ACTIONS.containsKey(args[0])) { + optionsBuilder.apiKey(args[0]); + actionName = args[1]; + args = Arrays.copyOfRange(args, 2, args.length); + } else { + actionName = args[0]; + args = Arrays.copyOfRange(args, 1, args.length); + } + action = ACTIONS.get(actionName); + if (action == null) { + System.out.println("Unrecognized action."); + printUsage(); + return; + } + Object arg; + try { + arg = action.parse(args); + } catch (IllegalArgumentException ex) { + System.out.printf("Invalid input for action '%s'. %s%n", actionName, ex.getMessage()); + System.out.printf("Expected: %s%n", action.params()); + return; + } catch (Exception ex) { + System.out.println("Failed to parse arguments."); + ex.printStackTrace(); + return; + } + Translate translate = optionsBuilder.build().service(); + action.run(translate, arg); + } +} diff --git a/gcloud-java-examples/src/main/java/com/google/cloud/examples/translate/snippets/DetectLanguageAndTranslate.java b/gcloud-java-examples/src/main/java/com/google/cloud/examples/translate/snippets/DetectLanguageAndTranslate.java new file mode 100644 index 000000000000..994ff40852fe --- /dev/null +++ b/gcloud-java-examples/src/main/java/com/google/cloud/examples/translate/snippets/DetectLanguageAndTranslate.java @@ -0,0 +1,54 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * EDITING INSTRUCTIONS + * This file is referenced in READMEs and javadoc. Any change to this file should be reflected in + * the project's READMEs and package-info.java. + */ + +package com.google.cloud.examples.translate.snippets; + +import com.google.cloud.translate.Detection; +import com.google.cloud.translate.Translate; +import com.google.cloud.translate.Translate.TranslateOption; +import com.google.cloud.translate.TranslateOptions; +import com.google.cloud.translate.Translation; + +/** + * A snippet for Google Translate showing how to detect the language of some text and translate + * some other text. + */ +public class DetectLanguageAndTranslate { + + public static void main(String... args) { + // Create a service object + // API key is read from the GOOGLE_API_KEY environment variable + Translate translate = TranslateOptions.defaultInstance().service(); + + // Detect the language of some text + Detection detection = translate.detect("Hola"); + String detectedLanguage = detection.language(); + + // Translate some text + Translation translation = translate.translate( + "World", + TranslateOption.sourceLanguage("en"), + TranslateOption.targetLanguage(detectedLanguage)); + + System.out.printf("Hola %s%n", translation.translatedText()); + } +} diff --git a/gcloud-java-examples/src/main/java/com/google/cloud/examples/translate/snippets/TranslateSnippets.java b/gcloud-java-examples/src/main/java/com/google/cloud/examples/translate/snippets/TranslateSnippets.java new file mode 100644 index 000000000000..9305c57bf79a --- /dev/null +++ b/gcloud-java-examples/src/main/java/com/google/cloud/examples/translate/snippets/TranslateSnippets.java @@ -0,0 +1,157 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * EDITING INSTRUCTIONS + * This file is referenced in Translate's javadoc. Any change to this file should be reflected in + * Translate's javadoc. + */ + +package com.google.cloud.examples.translate.snippets; + +import com.google.cloud.translate.Detection; +import com.google.cloud.translate.Language; +import com.google.cloud.translate.Translate; +import com.google.cloud.translate.Translate.LanguageListOption; +import com.google.cloud.translate.Translate.TranslateOption; +import com.google.cloud.translate.TranslateOptions; +import com.google.cloud.translate.Translation; + +import java.util.LinkedList; +import java.util.List; + +/** + * This class contains a number of snippets for the {@link Translate} interface. + */ +public class TranslateSnippets { + + private final Translate translate; + + public TranslateSnippets(Translate translate) { + this.translate = translate; + } + + /** + * Example of listing supported languages, localized according to + * {@link TranslateOptions#targetLanguage()}. + */ + // [TARGET listSupportedLanguages(LanguageListOption...)] + public List listSupportedLanguages() { + // [START listSupportedLanguages] + List languages = translate.listSupportedLanguages(); + // [END listSupportedLanguages] + return languages; + } + + /** + * Example of listing supported languages, localized according to a provided language. + */ + // [TARGET listSupportedLanguages(LanguageListOption...)] + public List listSupportedLanguagesWithTarget() { + // [START listSupportedLanguagesWithTarget] + List languages = translate.listSupportedLanguages( + LanguageListOption.targetLanguage("es")); + // [END listSupportedLanguagesWithTarget] + return languages; + } + + /** + * Example of detecting the language of some texts. + */ + // [TARGET detect(List)] + public List detectLanguageOfTextList() { + // [START detectLanguageOfTextList] + List texts = new LinkedList<>(); + texts.add("Hello, World!"); + texts.add("¡Hola Mundo!"); + List detections = translate.detect(texts); + // [END detectLanguageOfTextList] + return detections; + } + + /** + * Example of detecting the language of some texts. + */ + // [TARGET detect(String...)] + public List detectLanguageOfTexts() { + // [START detectLanguageOfTexts] + List detections = translate.detect("Hello, World!", "¡Hola Mundo!"); + // [END detectLanguageOfTexts] + return detections; + } + + /** + * Example of detecting the language of a text. + */ + // [TARGET detect(String)] + public Detection detectLanguageOfText() { + // [START detect] + Detection detection = translate.detect("Hello, World!"); + // [END detect] + return detection; + } + + /** + * Example of translating some texts. + */ + // [TARGET translate(List, TranslateOption...)] + public List translateTexts() { + // [START translateTexts] + List texts = new LinkedList<>(); + texts.add("Hello, World!"); + texts.add("¡Hola Mundo!"); + List translations = translate.translate(texts); + // [END translateTexts] + return translations; + } + + /** + * Example of translating some texts, specifying source and target language. + */ + // [TARGET translate(List, TranslateOption...)] + public List translateTextsWithOptions() { + // [START translateTextsWithOptions] + List texts = new LinkedList<>(); + texts.add("¡Hola Mundo!"); + List translations = translate.translate(texts, + TranslateOption.sourceLanguage("es"), TranslateOption.targetLanguage("de")); + // [END translateTextsWithOptions] + return translations; + } + + /** + * Example of translating a text. + */ + // [TARGET translate(String, TranslateOption...)] + public Translation translateText() { + // [START translateText] + Translation translation = translate.translate("¡Hola Mundo!"); + // [END translateText] + return translation; + } + + /** + * Example of translating a text, specifying source and target language. + */ + // [TARGET translate(String, TranslateOption...)] + public Translation translateTextWithOptions() { + // [START translateTextWithOptions] + Translation translation = translate.translate("¡Hola Mundo!", + TranslateOption.sourceLanguage("es"), TranslateOption.targetLanguage("de")); + // [END translateTextWithOptions] + return translation; + } +} diff --git a/gcloud-java-examples/src/test/java/com/google/cloud/examples/translate/snippets/ITTranslateSnippets.java b/gcloud-java-examples/src/test/java/com/google/cloud/examples/translate/snippets/ITTranslateSnippets.java new file mode 100644 index 000000000000..0aaaa2952772 --- /dev/null +++ b/gcloud-java-examples/src/test/java/com/google/cloud/examples/translate/snippets/ITTranslateSnippets.java @@ -0,0 +1,127 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.examples.translate.snippets; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.google.cloud.translate.Detection; +import com.google.cloud.translate.Language; +import com.google.cloud.translate.Translation; +import com.google.cloud.translate.testing.RemoteTranslateHelper; + +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class ITTranslateSnippets { + + private static TranslateSnippets translateSnippets; + + private static final String[] LANGUAGES = {"af", "sq", "ar", "hy", "az", "eu", "be", "bn", "bs", + "bg", "ca", "ceb", "ny", "zh-TW", "hr", "cs", "da", "nl", "en", "eo", "et", "tl", "fi", "fr", + "gl", "ka", "de", "el", "gu", "ht", "ha", "iw", "hi", "hmn", "hu", "is", "ig", "id", "ga", + "it", "ja", "jw", "kn", "kk", "km", "ko", "lo", "la", "lv", "lt", "mk", "mg", "ms", "ml", + "mt", "mi", "mr", "mn", "my", "ne", "no", "fa", "pl", "pt", "ro", "ru", "sr", "st", "si", + "sk", "sl", "so", "es", "su", "sw", "sv", "tg", "ta", "te", "th", "tr", "uk", "ur", "uz", + "vi", "cy", "yi", "yo", "zu"}; + + @BeforeClass + public static void beforeClass() { + RemoteTranslateHelper helper = RemoteTranslateHelper.create(); + translateSnippets = new TranslateSnippets(helper.options().service()); + } + + @Test + public void testListSupportedLanguages() { + Set supportedLanguages = new HashSet<>(); + List languages = translateSnippets.listSupportedLanguages(); + for (Language language : languages) { + supportedLanguages.add(language.code()); + assertNotNull(language.name()); + } + for (String code : LANGUAGES) { + assertTrue(supportedLanguages.contains(code)); + } + } + + @Test + public void testListSupportedLanguagesWithTarget() { + Set supportedLanguages = new HashSet<>(); + List languages = translateSnippets.listSupportedLanguagesWithTarget(); + for (Language language : languages) { + supportedLanguages.add(language.code()); + assertNotNull(language.name()); + } + for (String code : LANGUAGES) { + assertTrue(supportedLanguages.contains(code)); + } + } + + @Test + public void testDetectLanguageOfTexts() { + List detections = translateSnippets.detectLanguageOfTexts(); + Detection detection = detections.get(0); + assertEquals("en", detection.language()); + detection = detections.get(1); + assertEquals("es", detection.language()); + } + + @Test + public void testDetectLanguageOfTextList() { + List detections = translateSnippets.detectLanguageOfTextList(); + Detection detection = detections.get(0); + assertEquals("en", detection.language()); + detection = detections.get(1); + assertEquals("es", detection.language()); + } + + @Test + public void testDetectLanguageOfText() { + Detection detection = translateSnippets.detectLanguageOfText(); + assertEquals("en", detection.language()); + } + + @Test + public void testTranslateTextList() { + List translations = translateSnippets.translateTexts(); + Translation translation = translations.get(0); + assertEquals("Hello, World!", translation.translatedText()); + assertEquals("en", translation.sourceLanguage()); + translation = translations.get(1); + assertEquals("Hello World!", translation.translatedText()); + assertEquals("es", translation.sourceLanguage()); + } + + @Test + public void testTranslateText() { + Translation translation = translateSnippets.translateText(); + assertEquals("Hello World!", translation.translatedText()); + assertEquals("es", translation.sourceLanguage()); + } + + @Test + public void testTranslateTextWithOptions() { + Translation translation = translateSnippets.translateTextWithOptions(); + assertEquals("Hallo Welt!", translation.translatedText()); + assertEquals("es", translation.sourceLanguage()); + } +} diff --git a/gcloud-java-translate/README.md b/gcloud-java-translate/README.md new file mode 100644 index 000000000000..592f80fbb30c --- /dev/null +++ b/gcloud-java-translate/README.md @@ -0,0 +1,185 @@ +Google Cloud Java Client for Translate +==================================== + +Java idiomatic client for [Google Translate](https://cloud.google.com/translate/). + +[![Build Status](https://travis-ci.org/GoogleCloudPlatform/gcloud-java.svg?branch=master)](https://travis-ci.org/GoogleCloudPlatform/gcloud-java) +[![Coverage Status](https://coveralls.io/repos/GoogleCloudPlatform/gcloud-java/badge.svg?branch=master)](https://coveralls.io/r/GoogleCloudPlatform/gcloud-java?branch=master) +[![Maven](https://img.shields.io/maven-central/v/com.google.cloud/gcloud-java-translate.svg)]( https://img.shields.io/maven-central/v/com.google.cloud/gcloud-java-translate.svg) +[![Codacy Badge](https://api.codacy.com/project/badge/grade/9da006ad7c3a4fe1abd142e77c003917)](https://www.codacy.com/app/mziccard/gcloud-java) +[![Dependency Status](https://www.versioneye.com/user/projects/56bd8ee72a29ed002d2b0969/badge.svg?style=flat)](https://www.versioneye.com/user/projects/56bd8ee72a29ed002d2b0969) + +- [Homepage](https://googlecloudplatform.github.io/gcloud-java/) +- [API Documentation](http://googlecloudplatform.github.io/gcloud-java/apidocs/index.html?com/google/cloud/translate/package-summary.html) + +> Note: This client is a work-in-progress, and may occasionally +> make backwards-incompatible changes. + +Quickstart +---------- +If you are using Maven, add this to your pom.xml file +```xml + + com.google.cloud + gcloud-java-translate + 0.2.7 + +``` +If you are using Gradle, add this to your dependencies +```Groovy +compile 'com.google.cloud:gcloud-java-translate:0.2.7' +``` +If you are using SBT, add this to your dependencies +```Scala +libraryDependencies += "com.google.cloud" % "gcloud-java-translate" % "0.2.7" +``` + +Example Application +------------------- + +[`TranslateExample`](../gcloud-java-examples/src/main/java/com/google/cloud/examples/translate/TranslateExample.java) is a simple command line interface that provides some of Google Translate's functionality. Read more about using the application on the [`TranslateExample` docs page](http://googlecloudplatform.github.io/gcloud-java/apidocs/?com/google/cloud/examples/translate/TranslateExample.html). + +Authentication +-------------- + +Google Translate requires an API key to be passed with every request. For instructions on how to +get an API key follow the [Translate quickstart](https://cloud.google.com/translate/v2/quickstart). + +About Google Translate +-------------------- + +[Google Translate][google-translate] provides a simple programmatic interface for translating an +arbitrary string into any supported language. Translate is highly responsive, so websites and +applications can integrate with Translate API for fast, dynamic translation of source text from the +source language to a target language (e.g., French to English). Language detection is also +available In cases where the source language is unknown. + +See the [Translate quickstart](https://cloud.google.com/translate/v2/quickstart) for more details +on how to activate Google Translate for your project. + +See the ``gcloud-java`` API [Translate documentation][translate-api] to learn how to interact with +the Google Translate using this Client Library. + +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. + +#### Installation and setup +You'll need to obtain the `gcloud-java-translate` library. See the [Quickstart](#quickstart) +section to add `gcloud-java-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: + +```java +import com.google.cloud.translate.Translate; +import com.google.cloud.translate.TranslateOptions; + +Translate translate = TranslateOptions.defaultInstance().service(); +``` + +Or you can explicitly set the API key as follows: +```java +Translate translate = TranslateOptions.builder().apiKey("myKey").service(); +``` + +#### Detecting language +With Google Translate you can detect the language of some text. The service will provide you with +the code of the detected language and a level of confidence. + +Add the following import at the top of your file: + +```java +import com.google.cloud.translate.Detection; +``` + +Then add the following code to detect the text's language: + +```java +String detectedLanguage = detection.language(); +``` +#### Translating text + +Google translate allows you to translate some text. When translating one or more texts you can +either provide the source language or let the service detect it for you. + +Add the following imports at the top of your file: + +```java +import com.google.cloud.translate.Translate.TranslateOption; +import com.google.cloud.translate.Translation; +``` + +Then add the following code to translate a text (specifying its source language): + +```java +Translation translation = translate.translate( + "World", + TranslateOption.sourceLanguage("en"), + TranslateOption.targetLanguage(detectedLanguage)); +``` + +#### Complete source code + +In +[DetectLanguageAndTranslate.java](../gcloud-java-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. + +Troubleshooting +--------------- + +To get help, follow the `gcloud-java` links in the `gcloud-*` [shared Troubleshooting document](https://github.com/GoogleCloudPlatform/gcloud-common/blob/master/troubleshooting/readme.md#troubleshooting). + +Java Versions +------------- + +Java 7 or above is required for using this client. + +Testing +------- + +This library has tools to help make tests for code using Cloud Translate. + +See [TESTING] to read more about testing. + +Versioning +---------- + +This library follows [Semantic Versioning](http://semver.org/). + +It is currently in major version zero (``0.y.z``), which means that anything +may change at any time and the public API should not be considered +stable. + +Contributing +------------ + +Contributions to this library are always welcome and highly encouraged. + +See `gcloud-java`'s [CONTRIBUTING] documentation and the `gcloud-*` [shared documentation](https://github.com/GoogleCloudPlatform/gcloud-common/blob/master/contributing/readme.md#how-to-contribute-to-gcloud) for more information on how to get started. + +Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms. See [Code of Conduct][code-of-conduct] for more information. + +License +------- + +Apache 2.0 - See [LICENSE] for more information. + +[CONTRIBUTING]:https://github.com/GoogleCloudPlatform/gcloud-java/blob/master/CONTRIBUTING.md +[code-of-conduct]:https://github.com/GoogleCloudPlatform/gcloud-java/blob/master/CODE_OF_CONDUCT.md#contributor-code-of-conduct +[LICENSE]: https://github.com/GoogleCloudPlatform/gcloud-java/blob/master/LICENSE +[TESTING]: https://github.com/GoogleCloudPlatform/gcloud-java/blob/master/TESTING.md#testing-code-that-uses-translate +[cloud-platform]: https://cloud.google.com/ + +[google-translate]: https://cloud.google.com/translate/ +[google-translate-docs]: https://cloud.google.com/translate/docs/ +[translate-api]: http://googlecloudplatform.github.io/gcloud-java/apidocs/index.html?com/google/cloud/translate/package-summary.html diff --git a/gcloud-java-translate/pom.xml b/gcloud-java-translate/pom.xml new file mode 100644 index 000000000000..20aa12809a89 --- /dev/null +++ b/gcloud-java-translate/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + gcloud-java-translate + jar + GCloud Java translate + https://github.com/GoogleCloudPlatform/gcloud-java/tree/master/gcloud-java-translate + + Java idiomatic client for Google Translate. + + + com.google.cloud + gcloud-java-pom + 0.2.8-SNAPSHOT + + + gcloud-java-translate + + + + ${project.groupId} + gcloud-java-core + ${project.version} + + + com.google.apis + google-api-services-translate + v2-rev47-1.22.0 + compile + + + com.google.guava + guava-jdk5 + + + com.google.api-client + google-api-client + + + + + ${project.groupId} + gcloud-java-core + ${project.version} + test-jar + test + + + junit + junit + 4.12 + test + + + org.easymock + easymock + 3.4 + test + + + diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/Detection.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/Detection.java new file mode 100644 index 000000000000..8b924e5e9173 --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/Detection.java @@ -0,0 +1,92 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import com.google.api.services.translate.model.DetectionsResourceItems; +import com.google.common.base.MoreObjects; + +import java.io.Serializable; +import java.util.Objects; + +/** + * Information about a language detection. Objects of this class contain the detected language and + * possibly a confidence level. + * + * Detecting Language + * + */ +public class Detection implements Serializable { + + private static final long serialVersionUID = 5767106557994900916L; + + private final String language; + private final Float confidence; + + private Detection(String language, Float confidence) { + this.language = language; + this.confidence = confidence; + } + + /** + * Returns the code of the detected language. + * + * @see + * Supported Languages + */ + public String language() { + return language; + } + + /** + * Returns an optional confidence value in the interval [0,1]. The closer this value is to 1, the + * higher the confidence level for the language detection. Note that this value is not always + * available. + */ + public float confidence() { + return confidence; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("language", language) + .add("confidence", confidence) + .toString(); + } + + @Override + public final int hashCode() { + return Objects.hash(language, confidence); + } + + @Override + public final boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj == null || !obj.getClass().equals(Detection.class)) { + return false; + } + Detection other = (Detection) obj; + return Objects.equals(language, other.language) + && Objects.equals(confidence, other.confidence); + } + + static Detection fromPb(DetectionsResourceItems detectionPb) { + return new Detection(detectionPb.getLanguage(), detectionPb.getConfidence()); + } +} diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/Language.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/Language.java new file mode 100644 index 000000000000..4847b5ebb540 --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/Language.java @@ -0,0 +1,97 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import com.google.api.services.translate.model.LanguagesResource; +import com.google.common.base.Function; +import com.google.common.base.MoreObjects; + +import java.io.Serializable; +import java.util.Objects; + +/** + * Information about a language supported by Google Translate. Objects of this class contain + * language's code and the language name. + * + * @see + * Discovering Supported Languages + * @see + * Supported Languages + */ +public class Language implements Serializable { + + private static final long serialVersionUID = 5205240279371907020L; + static final Function FROM_PB_FUNCTION = + new Function() { + @Override + public Language apply(LanguagesResource languagePb) { + return Language.fromPb(languagePb); + } + }; + + private final String code; + private final String name; + + private Language(String code, String name) { + this.code = code; + this.name = name; + } + + /** + * Returns the code of the language. + */ + public String code() { + return code; + } + + /** + * Returns the name of the language. + */ + public String name() { + return name; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("code", code) + .add("name", name) + .toString(); + } + + @Override + public final int hashCode() { + return Objects.hash(code, name); + } + + @Override + public final boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj == null || !obj.getClass().equals(Language.class)) { + return false; + } + Language other = (Language) obj; + return Objects.equals(code, other.code) + && Objects.equals(name, other.name); + } + + static Language fromPb(LanguagesResource languagePb) { + return new Language(languagePb.getLanguage(), languagePb.getName()); + } +} diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/Option.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/Option.java new file mode 100644 index 000000000000..7fc05678e39e --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/Option.java @@ -0,0 +1,72 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.cloud.translate.spi.TranslateRpc; +import com.google.common.base.MoreObjects; + +import java.io.Serializable; +import java.util.Objects; + +/** + * Base class for Translate operation option. + */ +abstract class Option implements Serializable { + + private static final long serialVersionUID = 8546712558603322394L; + + private final TranslateRpc.Option rpcOption; + private final Object value; + + Option(TranslateRpc.Option rpcOption, Object value) { + this.rpcOption = checkNotNull(rpcOption); + this.value = value; + } + + TranslateRpc.Option rpcOption() { + return rpcOption; + } + + Object value() { + return value; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Option)) { + return false; + } + Option other = (Option) obj; + return Objects.equals(rpcOption, other.rpcOption) + && Objects.equals(value, other.value); + } + + @Override + public int hashCode() { + return Objects.hash(rpcOption, value); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("name", rpcOption.value()) + .add("value", value) + .toString(); + } +} diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/Translate.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/Translate.java new file mode 100644 index 000000000000..57f3a4a1137d --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/Translate.java @@ -0,0 +1,194 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import com.google.cloud.Service; +import com.google.cloud.translate.spi.TranslateRpc; + +import java.util.List; + +/** + * An interface for Google Translate. + * + * @see Google Translate + */ +public interface Translate extends Service { + + /** + * Class for specifying supported language listing options. + */ + class LanguageListOption extends Option { + + private static final long serialVersionUID = 1982978040516658597L; + + private LanguageListOption(TranslateRpc.Option rpcOption, String value) { + super(rpcOption, value); + } + + /** + * Returns an option for setting the target language. If this option is not provided, the value + * returned by {@link TranslateOptions#targetLanguage()} is used. When provided, the returned + * {@link Language#name()} will be in the language specified by the {@code targetLanguage} code. + * + * @param targetLanguage the target language code + */ + public static LanguageListOption targetLanguage(String targetLanguage) { + return new LanguageListOption(TranslateRpc.Option.TARGET_LANGUAGE, targetLanguage); + } + } + + /** + * Class for specifying translate options. + */ + class TranslateOption extends Option { + + private static final long serialVersionUID = 1347871763933507106L; + + private TranslateOption(TranslateRpc.Option rpcOption, String value) { + super(rpcOption, value); + } + + /** + * Returns an option for setting the source language. If not provided, Google Translate will try + * to detect the language of the text to translate. + * + * @param sourceLanguage the source language code + */ + public static TranslateOption sourceLanguage(String sourceLanguage) { + return new TranslateOption(TranslateRpc.Option.SOURCE_LANGUAGE, sourceLanguage); + } + + /** + * Returns an option for setting the target language. If this option is not provided, the value + * returned by {@link TranslateOptions#targetLanguage()} is used. + * + * @param targetLanguage the target language code + */ + public static TranslateOption targetLanguage(String targetLanguage) { + return new TranslateOption(TranslateRpc.Option.TARGET_LANGUAGE, targetLanguage); + } + } + + /** + * Returns the list of languages supported by Google Translate. If + * {@link LanguageListOption#targetLanguage(String)} is provided, {@link Language#name()} values + * are localized according to the provided target language. If no such option is passed, + * {@link Language#name()} values are localized according to + * {@link TranslateOptions#targetLanguage()}. + * + *

Example of listing supported languages, localized according to + * {@link TranslateOptions#targetLanguage()}. + *

 {@code
+   * List languages = translate.listSupportedLanguages();
+   * }
+ * + *

Example of listing supported languages, localized according to a provided language. + *

 {@code
+   * List languages = translate.listSupportedLanguages(
+   *     LanguageListOption.targetLanguage("es"));
+   * }
+ * + */ + List listSupportedLanguages(LanguageListOption... options); + + /** + * Detects the language of the provided texts. + * + *

Example of detecting the language of some texts. + *

 {@code
+   * List texts = new LinkedList<>();
+   * texts.add("Hello, World!");
+   * texts.add("¡Hola Mundo!");
+   * List detections = translate.detect(texts);
+   * }
+ * + * @param texts the texts for which language should be detected + * @return a list of objects containing information on the language detection, one for each + * provided text, in order. + */ + List detect(List texts); + + /** + * Detects the language of the provided texts. + * + *

Example of detecting the language of some texts. + *

 {@code
+   * List detections = translate.detect("Hello, World!", "¡Hola Mundo!");
+   * }
+ * + * @param texts the texts for which language should be detected + * @return a list of objects containing information on the language detection, one for each + * provided text, in order. + */ + List detect(String... texts); + + /** + * Detects the language of the provided text. Returns an object containing information on the + * language detection. + * + *

Example of detecting the language of a text. + *

 {@code
+   * Detection detection = translate.detect("Hello, World!");
+   * }
+ * + */ + Detection detect(String text); + + /** + * Translates the provided texts. + * + *

Example of translating some texts. + *

 {@code
+   * List texts = new LinkedList<>();
+   * texts.add("Hello, World!");
+   * texts.add("¡Hola Mundo!");
+   * List translations = translate.translate(texts);
+   * }
+ * + *

Example of translating some texts, specifying source and target language. + *

 {@code
+   * List texts = new LinkedList<>();
+   * texts.add("¡Hola Mundo!");
+   * List translations = translate.translate(texts,
+   *     TranslateOption.sourceLanguage("es"), TranslateOption.targetLanguage("de"));
+   * }
+ * + * @param texts the texts to translate + * @return a list of objects containing information on the language translation, one for each + * provided text, in order. + */ + List translate(List texts, TranslateOption... options); + + /** + * Translates the provided texts. + * + *

Example of translating a text. + *

 {@code
+   * Translation translation = translate.translate("¡Hola Mundo!");
+   * }
+ * + *

Example of translating a text, specifying source and target language. + *

 {@code
+   * Translation translation = translate.translate("¡Hola Mundo!",
+   *     TranslateOption.sourceLanguage("es"), TranslateOption.targetLanguage("de"));
+   * }
+ * + * @param text the text to translate + * @return an object containing information on the language translation + */ + Translation translate(String text, TranslateOption... options); +} diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateException.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateException.java new file mode 100644 index 000000000000..f1d3c18fed8e --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateException.java @@ -0,0 +1,63 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import com.google.cloud.BaseServiceException; +import com.google.cloud.RetryHelper.RetryHelperException; +import com.google.cloud.RetryHelper.RetryInterruptedException; +import com.google.common.collect.ImmutableSet; + +import java.io.IOException; +import java.util.Set; + +/** + * Google Translate service exception. + */ +public class TranslateException extends BaseServiceException { + + private static final Set RETRYABLE_ERRORS = ImmutableSet.of(new Error(500, null)); + private static final long serialVersionUID = 4747004866996469418L; + + TranslateException(int code, String message) { + super(code, message, null, true, null); + } + + TranslateException(int code, String message, Throwable cause) { + super(code, message, null, true, cause); + } + + public TranslateException(IOException exception) { + super(exception, true); + } + + @Override + protected Set retryableErrors() { + return RETRYABLE_ERRORS; + } + + /** + * Translate RetryHelperException to the TranslateException that caused the error. This method + * will always throw an exception. + * + * @throws TranslateException when {@code ex} was caused by a {@code TranslateException} + * @throws RetryInterruptedException when {@code ex} is a {@code RetryInterruptedException} + */ + static BaseServiceException translateAndThrow(RetryHelperException ex) { + BaseServiceException.translateAndPropagateIfPossible(ex); + throw new TranslateException(UNKNOWN_CODE, ex.getMessage(), ex.getCause()); + } +} diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateFactory.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateFactory.java new file mode 100644 index 000000000000..8c31c5505bd3 --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateFactory.java @@ -0,0 +1,25 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import com.google.cloud.ServiceFactory; + +/** + * An interface for Translates factories. + */ +public interface TranslateFactory extends ServiceFactory { +} diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateImpl.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateImpl.java new file mode 100644 index 000000000000..3d02ac898660 --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateImpl.java @@ -0,0 +1,134 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import static com.google.cloud.RetryHelper.runWithRetries; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +import com.google.api.services.translate.model.DetectionsResourceItems; +import com.google.api.services.translate.model.LanguagesResource; +import com.google.api.services.translate.model.TranslationsResource; +import com.google.cloud.BaseService; +import com.google.cloud.RetryHelper.RetryHelperException; +import com.google.cloud.translate.spi.TranslateRpc; +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; + +final class TranslateImpl extends BaseService implements Translate { + + private final TranslateRpc translateRpc; + + private static final Function, Detection> + DETECTION_FROM_PB_FUNCTION = new Function, Detection>() { + @Override + public Detection apply(List detectionPb) { + return Detection.fromPb(detectionPb.get(0)); + } + }; + + TranslateImpl(TranslateOptions options) { + super(options); + translateRpc = options.rpc(); + } + + @Override + public List listSupportedLanguages(final LanguageListOption... options) { + try { + return Lists.transform(runWithRetries(new Callable>() { + @Override + public List call() { + return translateRpc.listSupportedLanguages(optionMap(options)); + } + }, options().retryParams(), EXCEPTION_HANDLER, options().clock()), Language.FROM_PB_FUNCTION); + } catch (RetryHelperException e) { + throw TranslateException.translateAndThrow(e); + } + } + + @Override + public List detect(final List texts) { + try { + List> detectionsPb = + runWithRetries(new Callable>>() { + @Override + public List> call() { + return translateRpc.detect(texts); + } + }, options().retryParams(), EXCEPTION_HANDLER, options().clock()); + Iterator> detectionIterator = detectionsPb.iterator(); + Iterator textIterator = texts.iterator(); + while (detectionIterator.hasNext() && textIterator.hasNext()) { + List detectionPb = detectionIterator.next(); + String text = textIterator.next(); + checkState(detectionPb != null && !detectionPb.isEmpty(), + "No detection found for text: %s", text); + checkState(detectionPb.size() == 1, "Multiple detections found for text: %s", text); + } + return Lists.transform(detectionsPb, DETECTION_FROM_PB_FUNCTION); + } catch (RetryHelperException e) { + throw TranslateException.translateAndThrow(e); + } + } + + @Override + public List detect(String... texts) { + return detect(Arrays.asList(texts)); + } + + @Override + public Detection detect(String text) { + return detect(Collections.singletonList(text)).get(0); + } + + @Override + public List translate(final List texts, final TranslateOption... options) { + try { + return Lists.transform(runWithRetries(new Callable>() { + @Override + public List call() { + return translateRpc.translate(texts, optionMap(options)); + } + }, options().retryParams(), EXCEPTION_HANDLER, options().clock()), + Translation.FROM_PB_FUNCTION); + } catch (RetryHelperException e) { + throw TranslateException.translateAndThrow(e); + } + } + + @Override + public Translation translate(String text, TranslateOption... options) { + return translate(Collections.singletonList(text), options).get(0); + } + + private Map optionMap(Option... options) { + Map optionMap = Maps.newEnumMap(TranslateRpc.Option.class); + for (Option option : options) { + Object prev = optionMap.put(option.rpcOption(), option.value()); + checkArgument(prev == null, "Duplicate option %s", option); + } + return optionMap; + } +} diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateOptions.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateOptions.java new file mode 100644 index 000000000000..86f3507aed01 --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/TranslateOptions.java @@ -0,0 +1,213 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import static com.google.common.base.MoreObjects.firstNonNull; +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.cloud.AuthCredentials; +import com.google.cloud.HttpServiceOptions; +import com.google.cloud.translate.Translate.TranslateOption; +import com.google.cloud.translate.spi.DefaultTranslateRpc; +import com.google.cloud.translate.spi.TranslateRpc; +import com.google.cloud.translate.spi.TranslateRpcFactory; +import com.google.common.collect.ImmutableSet; + +import java.util.List; +import java.util.Locale; +import java.util.Set; + +public class TranslateOptions extends + HttpServiceOptions { + + private static final long serialVersionUID = 5997441123713672886L; + private static final String API_KEY_ENV_NAME = "GOOGLE_API_KEY"; + private static final Set SCOPES = ImmutableSet.of(); + + private final String apiKey; + private final String targetLanguage; + + public static class DefaultTranslateFactory implements TranslateFactory { + + private static final TranslateFactory INSTANCE = new DefaultTranslateFactory(); + + @Override + public Translate create(TranslateOptions options) { + return new TranslateImpl(options); + } + } + + public static class DefaultTranslateRpcFactory implements TranslateRpcFactory { + + private static final TranslateRpcFactory INSTANCE = new DefaultTranslateRpcFactory(); + + @Override + public TranslateRpc create(TranslateOptions options) { + return new DefaultTranslateRpc(options); + } + } + + public static class Builder extends + HttpServiceOptions.Builder { + + private String apiKey; + private String targetLanguage; + + private Builder() {} + + private Builder(TranslateOptions options) { + super(options); + this.apiKey = options.apiKey; + } + + /** + * Sets project id. Setting a project id has no impact on the {@link Translate} service. + * + * @return the builder + */ + @Override + public Builder projectId(String projectId) { + super.projectId(projectId); + return self(); + } + + /** + * Sets the service authentication credentials. Setting credentials has no impact on the + * {@link Translate} service. + * + * @return the builder + */ + public Builder authCredentials(AuthCredentials authCredentials) { + super.authCredentials(authCredentials); + 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 + * Translate quickstart. + */ + public Builder apiKey(String apiKey) { + this.apiKey = apiKey; + return this; + } + + /** + * Sets the code for the default target language. If not set, english ({@code en}) is used. + * {@link Translate#translate(List, TranslateOption...)} and + * {@link Translate#translate(String, TranslateOption...)} calls will use this + * value unless a {@link TranslateOption#targetLanguage(String)} option is explicitly + * provided. + * + * @return the builder + */ + public Builder targetLanguage(String targetLanguage) { + this.targetLanguage = targetLanguage; + return self(); + } + + @Override + public TranslateOptions build() { + // Auth credentials are not used by Translate + authCredentials(AuthCredentials.noAuth()); + return new TranslateOptions(this); + } + } + + private TranslateOptions(Builder builder) { + super(TranslateFactory.class, TranslateRpcFactory.class, builder); + this.apiKey = builder.apiKey != null ? builder.apiKey : defaultApiKey(); + 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()); + } + + @Override + protected TranslateFactory defaultServiceFactory() { + return DefaultTranslateFactory.INSTANCE; + } + + @Override + protected TranslateRpcFactory defaultRpcFactory() { + return DefaultTranslateRpcFactory.INSTANCE; + } + + @Override + protected boolean projectIdRequired() { + return false; + } + + @Override + protected Set scopes() { + return SCOPES; + } + + protected String defaultApiKey() { + return System.getProperty(API_KEY_ENV_NAME, System.getenv(API_KEY_ENV_NAME)); + } + + /** + * Returns the API key, to be used used to send requests. + */ + public String apiKey() { + return apiKey; + } + + /** + * Returns the code for the default target language. + */ + public String targetLanguage() { + return targetLanguage; + } + + @SuppressWarnings("unchecked") + @Override + public Builder toBuilder() { + return new Builder(this); + } + + @Override + public int hashCode() { + return baseHashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof TranslateOptions)) { + return false; + } + TranslateOptions options = (TranslateOptions) obj; + return baseEquals(options) + && apiKey.equals(options.apiKey) + && targetLanguage.equals(options.targetLanguage); + } + + /** + * Returns a default {@code TranslateOptions} instance. + */ + public static TranslateOptions defaultInstance() { + return builder().build(); + } + + /** + * Returns a builder for {@code TranslateOptions} objects. + */ + public static Builder builder() { + return new Builder(); + } +} diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/Translation.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/Translation.java new file mode 100644 index 000000000000..ebf9db4835a2 --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/Translation.java @@ -0,0 +1,97 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import com.google.api.services.translate.model.TranslationsResource; +import com.google.common.base.Function; +import com.google.common.base.MoreObjects; + +import java.io.Serializable; +import java.util.Objects; + +/** + * Information about a translation. Objects of this class contain the translated text and the source + * language's code. Source language's code can be the one provided by the user (if any) or the one + * detected by the Google Translate service. + * + * Translating Text + */ +public class Translation implements Serializable { + + private static final long serialVersionUID = 2556017420486245581L; + static final Function FROM_PB_FUNCTION = + new Function() { + @Override + public Translation apply(TranslationsResource translationPb) { + return Translation.fromPb(translationPb); + } + }; + + private final String translatedText; + private final String sourceLanguage; + + private Translation(String translatedText, String sourceLanguage) { + this.translatedText = translatedText; + this.sourceLanguage = sourceLanguage; + } + + /** + * Returns the translated text. + */ + public String translatedText() { + return translatedText; + } + + /** + * Returns the language code of the source text. If no source language was provided this value is + * the source language as detected by the Google Translate service. + */ + public String sourceLanguage() { + return sourceLanguage; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("translatedText", translatedText) + .add("sourceLanguage", sourceLanguage) + .toString(); + } + + @Override + public final int hashCode() { + return Objects.hash(translatedText, sourceLanguage); + } + + @Override + public final boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj == null || !obj.getClass().equals(Translation.class)) { + return false; + } + Translation other = (Translation) obj; + return Objects.equals(translatedText, other.translatedText) + && Objects.equals(sourceLanguage, other.sourceLanguage); + } + + static Translation fromPb(TranslationsResource translationPb) { + return new Translation(translationPb.getTranslatedText(), + translationPb.getDetectedSourceLanguage()); + } +} diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/package-info.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/package-info.java new file mode 100644 index 000000000000..80a4732a53de --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/package-info.java @@ -0,0 +1,41 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A client to Google Translate. + * + *

Here's a simple usage example for using gcloud-java. This example shows how to detect the + * language of some text and how to translate some text. The example assumes that the + * {@code GOOGLE_API_KEY} is set and contains a valid API key. Alternatively, you can use + * {@link com.google.cloud.translate.TranslateOptions.Builder#apiKey(java.lang.String)} to set the + * API key. For the complete source code see + * + * DetectLanguageAndTranslate.java. + *

 {@code
+ * Translate translate = TranslateOptions.defaultInstance().service();
+ *
+ * Detection detection = translate.detect("Hola");
+ * String detectedLanguage = detection.language();
+ *
+ * Translation translation = translate.translate(
+ *     "World",
+ *     TranslateOption.sourceLanguage("en"),
+ *     TranslateOption.targetLanguage(detectedLanguage));
+ *
+ * System.out.printf("Hola %s%n", translation.translatedText());
+ * }
+ */ +package com.google.cloud.translate; diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/spi/DefaultTranslateRpc.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/spi/DefaultTranslateRpc.java new file mode 100644 index 000000000000..1af329a0be47 --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/spi/DefaultTranslateRpc.java @@ -0,0 +1,112 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate.spi; + +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.HttpRequestInitializer; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.json.jackson.JacksonFactory; +import com.google.api.services.translate.Translate; +import com.google.api.services.translate.model.DetectionsResourceItems; +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.Lists; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public class DefaultTranslateRpc implements TranslateRpc { + + private final TranslateOptions options; + private final Translate translate; + + public DefaultTranslateRpc(TranslateOptions options) { + HttpTransport transport = options.httpTransportFactory().create(); + HttpRequestInitializer initializer = options.httpRequestInitializer(); + this.options = options; + translate = new Translate.Builder(transport, new JacksonFactory(), initializer) + .setRootUrl(options.host()) + .setApplicationName(options.applicationName()) + .build(); + } + + private static TranslateException translate(IOException exception) { + return new TranslateException(exception); + } + + @Override + public List> detect(List texts) { + try { + List> detections = + translate.detections().list(texts).setKey(options.apiKey()).execute().getDetections(); + return detections != null ? detections : ImmutableList.>of(); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public List listSupportedLanguages(Map optionMap) { + try { + List languages = translate.languages() + .list() + .setKey(options.apiKey()) + .setTarget(firstNonNull(TARGET_LANGUAGE.getString(optionMap), options.targetLanguage())) + .execute().getLanguages(); + return languages != null ? languages : ImmutableList.of(); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public List translate(List texts, Map optionMap) { + try { + String targetLanguage = + firstNonNull(TARGET_LANGUAGE.getString(optionMap), options.targetLanguage()); + final String sourceLanguage = SOURCE_LANGUAGE.getString(optionMap); + List translations = + translate.translations() + .list(texts, targetLanguage) + .setSource(sourceLanguage) + .setKey(options.apiKey()) + .execute() + .getTranslations(); + return Lists.transform( + translations != null ? translations : ImmutableList.of(), + new Function() { + @Override + public TranslationsResource apply(TranslationsResource translationsResource) { + if (translationsResource.getDetectedSourceLanguage() == null) { + translationsResource.setDetectedSourceLanguage(sourceLanguage); + } + return translationsResource; + } + }); + } catch (IOException ex) { + throw translate(ex); + } + } +} diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/spi/TranslateRpc.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/spi/TranslateRpc.java new file mode 100644 index 000000000000..5156bb7f1ac1 --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/spi/TranslateRpc.java @@ -0,0 +1,76 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate.spi; + +import com.google.api.services.translate.model.DetectionsResourceItems; +import com.google.api.services.translate.model.LanguagesResource; +import com.google.api.services.translate.model.TranslationsResource; + +import java.util.List; +import java.util.Map; + +public interface TranslateRpc { + + enum Option { + SOURCE_LANGUAGE("source"), + TARGET_LANGUAGE("target"); + + private final String value; + + Option(String value) { + this.value = value; + } + + public String value() { + return value; + } + + @SuppressWarnings("unchecked") + T get(Map options) { + return (T) options.get(this); + } + + String getString(Map options) { + return get(options); + } + } + + /** + * Returns a list of the languages supported by Google Translate. + * + * @param optionMap options to listing language translations + */ + List listSupportedLanguages(Map optionMap); + + /** + * Detects the language of the provided texts. + * + * @param texts the texts to translate + * @return a list of lists of detections, one list of detections for each provided text, in order + */ + List> detect(List texts); + + /** + * Translates the provided texts. + * + * @param texts the texts to translate + * @param optionMap options to text translation + * @return a list of resources containing translation information, in the same order of the + * provided texts + */ + List translate(List texts, Map optionMap); +} diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/spi/TranslateRpcFactory.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/spi/TranslateRpcFactory.java new file mode 100644 index 000000000000..5ecf502e5306 --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/spi/TranslateRpcFactory.java @@ -0,0 +1,27 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate.spi; + +import com.google.cloud.spi.ServiceRpcFactory; +import com.google.cloud.translate.TranslateOptions; + +/** + * An interface for Translate RPC factory. + * Implementation will be loaded via {@link java.util.ServiceLoader}. + */ +public interface TranslateRpcFactory extends ServiceRpcFactory { +} diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/testing/RemoteTranslateHelper.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/testing/RemoteTranslateHelper.java new file mode 100644 index 000000000000..a903d08ddb9b --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/testing/RemoteTranslateHelper.java @@ -0,0 +1,83 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate.testing; + +import com.google.cloud.RetryParams; +import com.google.cloud.translate.TranslateOptions; + +/** + * Utility to create a remote translate configuration for testing. Translate options can be obtained + * via the {@link #options()} method. Returned options have custom + * {@link TranslateOptions#retryParams()}: {@link RetryParams#retryMaxAttempts()} is {@code 10}, + * {@link RetryParams#retryMinAttempts()} is {@code 6}, {@link RetryParams#maxRetryDelayMillis()} + * is {@code 30000}, {@link RetryParams#totalRetryPeriodMillis()} is {@code 120000} and + * {@link RetryParams#initialRetryDelayMillis()} is {@code 250}. + * {@link TranslateOptions#connectTimeout()} and {@link TranslateOptions#readTimeout()} are both set + * to {@code 60000}. + */ +public class RemoteTranslateHelper { + + private final TranslateOptions options; + + private RemoteTranslateHelper(TranslateOptions options) { + this.options = options; + } + + /** + * Returns a {@link TranslateOptions} object to be used for testing. + */ + public TranslateOptions options() { + return options; + } + + /** + * Creates a {@code RemoteTranslateHelper} object for the given API key. + * + * @param apiKey API key used to issue requests to Google Translate. + */ + public static RemoteTranslateHelper create(String apiKey) { + TranslateOptions translateOptions = TranslateOptions.builder() + .apiKey(apiKey) + .retryParams(retryParams()) + .connectTimeout(60000) + .readTimeout(60000) + .build(); + return new RemoteTranslateHelper(translateOptions); + } + + /** + * Creates a {@code RemoteStorageHelper} object. + */ + public static RemoteTranslateHelper create() { + TranslateOptions translateOption = TranslateOptions.builder() + .retryParams(retryParams()) + .connectTimeout(60000) + .readTimeout(60000) + .build(); + return new RemoteTranslateHelper(translateOption); + } + + private static RetryParams retryParams() { + return RetryParams.builder() + .retryMaxAttempts(10) + .retryMinAttempts(6) + .maxRetryDelayMillis(30000) + .totalRetryPeriodMillis(120000) + .initialRetryDelayMillis(250) + .build(); + } +} diff --git a/gcloud-java-translate/src/main/java/com/google/cloud/translate/testing/package-info.java b/gcloud-java-translate/src/main/java/com/google/cloud/translate/testing/package-info.java new file mode 100644 index 000000000000..02f64ebeb689 --- /dev/null +++ b/gcloud-java-translate/src/main/java/com/google/cloud/translate/testing/package-info.java @@ -0,0 +1,30 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A testing helper for Google Translate. + * + *

A simple usage example: + *

Before the test: + *

 {@code
+ * RemoteTranslateHelper helper = RemoteTranslateHelper.create();
+ * Translate translate = helper.options().service();
+ * } 
+ * + * @see + * gcloud-java tools for testing + */ +package com.google.cloud.translate.testing; diff --git a/gcloud-java-translate/src/test/java/com/google/cloud/translate/DetectionTest.java b/gcloud-java-translate/src/test/java/com/google/cloud/translate/DetectionTest.java new file mode 100644 index 000000000000..9300fae3e85d --- /dev/null +++ b/gcloud-java-translate/src/test/java/com/google/cloud/translate/DetectionTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import static org.junit.Assert.assertEquals; + +import com.google.api.services.translate.model.DetectionsResourceItems; + +import org.junit.Test; + +public class DetectionTest { + + private static final String LANGUAGE = "en"; + private static final float CONFIDENCE = 0.42F; + private static final DetectionsResourceItems DETECTION_PB = + new DetectionsResourceItems().setLanguage(LANGUAGE).setConfidence(CONFIDENCE); + private static final Detection DETECTION = Detection.fromPb(DETECTION_PB); + + @Test + public void testFromPb() { + assertEquals(LANGUAGE, DETECTION.language()); + assertEquals(CONFIDENCE, DETECTION.confidence(), 0); + compareDetection(DETECTION, Detection.fromPb(DETECTION_PB)); + } + + private void compareDetection(Detection expected, Detection value) { + assertEquals(expected, value); + assertEquals(expected.language(), value.language()); + assertEquals(expected.confidence(), value.confidence(), 0); + assertEquals(expected.hashCode(), value.hashCode()); + assertEquals(expected.toString(), value.toString()); + } +} diff --git a/gcloud-java-translate/src/test/java/com/google/cloud/translate/LanguageTest.java b/gcloud-java-translate/src/test/java/com/google/cloud/translate/LanguageTest.java new file mode 100644 index 000000000000..4f6849270de0 --- /dev/null +++ b/gcloud-java-translate/src/test/java/com/google/cloud/translate/LanguageTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import com.google.api.services.translate.model.LanguagesResource; + +import org.junit.Test; + +public class LanguageTest { + + private static final String CODE = "en"; + private static final String NAME = "English"; + private static final LanguagesResource LANGUAGE_PB = + new LanguagesResource().setLanguage(CODE).setName(NAME); + private static final Language LANGUAGE = Language.fromPb(LANGUAGE_PB); + + @Test + public void testFromPb() { + assertEquals(CODE, LANGUAGE.code()); + assertEquals(NAME, LANGUAGE.name()); + Language language = Language.fromPb(new LanguagesResource().setLanguage(CODE)); + assertEquals(CODE, language.code()); + assertNull(language.name()); + compareLanguage(LANGUAGE, Language.fromPb(LANGUAGE_PB)); + } + + private void compareLanguage(Language expected, Language value) { + assertEquals(expected, value); + assertEquals(expected.name(), value.name()); + assertEquals(expected.code(), value.code()); + assertEquals(expected.hashCode(), value.hashCode()); + assertEquals(expected.toString(), value.toString()); + } +} diff --git a/gcloud-java-translate/src/test/java/com/google/cloud/translate/OptionTest.java b/gcloud-java-translate/src/test/java/com/google/cloud/translate/OptionTest.java new file mode 100644 index 000000000000..152e5c10c455 --- /dev/null +++ b/gcloud-java-translate/src/test/java/com/google/cloud/translate/OptionTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; + +import com.google.cloud.translate.spi.TranslateRpc; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class OptionTest { + + private static final TranslateRpc.Option RPC_OPTION = TranslateRpc.Option.SOURCE_LANGUAGE; + private static final String VALUE = "some value"; + private static final String OTHER_VALUE = "another value"; + private static final Option OPTION = new Option(RPC_OPTION, VALUE) {}; + private static final Option OPTION_EQUALS = new Option(RPC_OPTION, VALUE) {}; + private static final Option OPTION_NOT_EQUALS = new Option(RPC_OPTION, OTHER_VALUE) {}; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testEquals() { + assertEquals(OPTION, OPTION_EQUALS); + assertNotEquals(OPTION, OPTION_NOT_EQUALS); + } + + @Test + public void testHashCode() { + assertEquals(OPTION.hashCode(), OPTION_EQUALS.hashCode()); + } + + @Test + public void testConstructor() { + assertEquals(RPC_OPTION, OPTION.rpcOption()); + assertEquals(VALUE, OPTION.value()); + Option option = new Option(RPC_OPTION, null) {}; + assertEquals(RPC_OPTION, option.rpcOption()); + assertNull(option.value()); + thrown.expect(NullPointerException.class); + new Option(null, VALUE) {}; + } +} diff --git a/gcloud-java-translate/src/test/java/com/google/cloud/translate/SerializationTest.java b/gcloud-java-translate/src/test/java/com/google/cloud/translate/SerializationTest.java new file mode 100644 index 000000000000..adc597a56301 --- /dev/null +++ b/gcloud-java-translate/src/test/java/com/google/cloud/translate/SerializationTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import com.google.api.services.translate.model.DetectionsResourceItems; +import com.google.api.services.translate.model.TranslationsResource; +import com.google.cloud.AuthCredentials; +import com.google.cloud.BaseSerializationTest; +import com.google.cloud.Restorable; + +import java.io.Serializable; + +public class SerializationTest extends BaseSerializationTest { + + private static final String API_KEY = "apiKey"; + private static final String LANGUAGE = "en"; + private static final float CONFIDENCE = 0.42F; + private static final DetectionsResourceItems DETECTION_PB = + new DetectionsResourceItems().setLanguage(LANGUAGE).setConfidence(CONFIDENCE); + private static final Detection DETECTION = Detection.fromPb(DETECTION_PB); + private static final String TRANSLATED_TEXT = "Hello world"; + private static final TranslationsResource TRANSLATION_PB = new TranslationsResource() + .setTranslatedText(TRANSLATED_TEXT) + .setDetectedSourceLanguage(LANGUAGE); + private static final Translation TRANSLATION = Translation.fromPb(TRANSLATION_PB); + private static final TranslateException TRANSLATE_EXCEPTION = + new TranslateException(42, "message"); + private static final Translate.LanguageListOption LANGUAGE_LIST_OPTION = + Translate.LanguageListOption.targetLanguage(LANGUAGE); + private static final Translate.TranslateOption TRANSLATE_OPTION = + Translate.TranslateOption.sourceLanguage(LANGUAGE); + + @Override + protected Serializable[] serializableObjects() { + TranslateOptions options = TranslateOptions.builder() + .apiKey(API_KEY) + .authCredentials(AuthCredentials.createForAppEngine()) + .build(); + TranslateOptions otherOptions = options.toBuilder() + .authCredentials(null) + .build(); + return new Serializable[]{DETECTION, TRANSLATION, TRANSLATE_EXCEPTION, LANGUAGE_LIST_OPTION, + TRANSLATE_OPTION, options, otherOptions}; + } + + @Override + protected Restorable[] restorableObjects() { + return null; + } +} diff --git a/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateExceptionTest.java b/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateExceptionTest.java new file mode 100644 index 000000000000..13e2786ffe92 --- /dev/null +++ b/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateExceptionTest.java @@ -0,0 +1,105 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import com.google.cloud.BaseServiceException; +import com.google.cloud.RetryHelper.RetryHelperException; + +import org.junit.Test; + +import java.io.IOException; +import java.net.SocketTimeoutException; + +public class TranslateExceptionTest { + + @Test + public void testTranslateException() { + TranslateException exception = new TranslateException(500, "message"); + assertEquals(500, exception.code()); + assertEquals("message", exception.getMessage()); + assertNull(exception.reason()); + assertTrue(exception.retryable()); + assertTrue(exception.idempotent()); + + exception = new TranslateException(400, "message"); + assertEquals(400, exception.code()); + assertEquals("message", exception.getMessage()); + assertNull(exception.reason()); + assertFalse(exception.retryable()); + assertTrue(exception.idempotent()); + + IOException cause = new SocketTimeoutException(); + exception = new TranslateException(cause); + assertNull(exception.reason()); + assertNull(exception.getMessage()); + assertTrue(exception.retryable()); + assertTrue(exception.idempotent()); + assertSame(cause, exception.getCause()); + + exception = new TranslateException(400, "message", cause); + assertEquals(400, exception.code()); + assertEquals("message", exception.getMessage()); + assertNull(exception.reason()); + assertFalse(exception.retryable()); + assertTrue(exception.idempotent()); + assertSame(cause, exception.getCause()); + } + + @Test + public void testTranslateAndThrow() throws Exception { + Exception cause = new TranslateException(500, "message"); + RetryHelperException exceptionMock = createMock(RetryHelperException.class); + expect(exceptionMock.getCause()).andReturn(cause).times(2); + replay(exceptionMock); + try { + TranslateException.translateAndThrow(exceptionMock); + } catch (BaseServiceException ex) { + assertEquals(500, ex.code()); + assertEquals("message", ex.getMessage()); + assertTrue(ex.retryable()); + assertTrue(ex.idempotent()); + } finally { + verify(exceptionMock); + } + cause = new IllegalArgumentException("message"); + exceptionMock = createMock(RetryHelperException.class); + expect(exceptionMock.getMessage()).andReturn("message").times(1); + expect(exceptionMock.getCause()).andReturn(cause).times(2); + replay(exceptionMock); + try { + TranslateException.translateAndThrow(exceptionMock); + } catch (BaseServiceException ex) { + assertEquals(TranslateException.UNKNOWN_CODE, ex.code()); + assertEquals("message", ex.getMessage()); + assertFalse(ex.retryable()); + assertTrue(ex.idempotent()); + assertSame(cause, ex.getCause()); + } finally { + verify(exceptionMock); + } + } +} diff --git a/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateImplTest.java b/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateImplTest.java new file mode 100644 index 000000000000..5c98c2c0cd23 --- /dev/null +++ b/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateImplTest.java @@ -0,0 +1,348 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; + +import com.google.api.services.translate.model.DetectionsResourceItems; +import com.google.api.services.translate.model.LanguagesResource; +import com.google.api.services.translate.model.TranslationsResource; +import com.google.cloud.RetryParams; +import com.google.cloud.translate.Translate.LanguageListOption; +import com.google.cloud.translate.Translate.TranslateOption; +import com.google.cloud.translate.spi.TranslateRpc; +import com.google.cloud.translate.spi.TranslateRpcFactory; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +import org.easymock.EasyMock; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.util.List; +import java.util.Map; + +public class TranslateImplTest { + + private static final String API_KEY = "api_key"; + private static final String TARGET_LANGUAGE = "es"; + + private static final LanguagesResource LANGUAGE1_PB = + new LanguagesResource().setLanguage("en").setName("english"); + private static final LanguagesResource LANGUAGE2_PB = + new LanguagesResource().setLanguage("es").setName("spanish"); + private static final LanguagesResource LANGUAGE3_PB = + new LanguagesResource().setLanguage("en").setName("inglés"); + private static final LanguagesResource LANGUAGE4_PB = + new LanguagesResource().setLanguage("es").setName("español"); + private static final Language LANGUAGE1 = Language.fromPb(LANGUAGE1_PB); + private static final Language LANGUAGE2 = Language.fromPb(LANGUAGE2_PB); + private static final Language LANGUAGE3 = Language.fromPb(LANGUAGE3_PB); + private static final Language LANGUAGE4 = Language.fromPb(LANGUAGE4_PB); + private static final List LANGUAGES1 = ImmutableList.of(LANGUAGE1, LANGUAGE2); + private static final List LANGUAGES2 = ImmutableList.of(LANGUAGE3, LANGUAGE4); + private static final DetectionsResourceItems DETECTION1_PB = + new DetectionsResourceItems().setLanguage("en").setConfidence(0.9F); + private static final DetectionsResourceItems DETECTION2_PB = + new DetectionsResourceItems().setLanguage("en").setConfidence(0.8F); + private static final Detection DETECTION1 = Detection.fromPb(DETECTION1_PB); + private static final Detection DETECTION2 = Detection.fromPb(DETECTION2_PB); + private static final TranslationsResource TRANSLATION1_PB = + new TranslationsResource().setTranslatedText("Hello World!").setDetectedSourceLanguage("es"); + private static final TranslationsResource TRANSLATION2_PB = + new TranslationsResource().setTranslatedText("Hello World!").setDetectedSourceLanguage("de"); + private static final Translation TRANSLATION1 = Translation.fromPb(TRANSLATION1_PB); + private static final Translation TRANSLATION2 = Translation.fromPb(TRANSLATION2_PB); + + // Empty TranslateRpc options + private static final Map EMPTY_RPC_OPTIONS = ImmutableMap.of(); + + // Language list options + private static final LanguageListOption LANGUAGE_LIST_OPTION = + LanguageListOption.targetLanguage(TARGET_LANGUAGE); + private static final Map LANGUAGE_LIST_OPTIONS = ImmutableMap.of( + TranslateRpc.Option.TARGET_LANGUAGE, LANGUAGE_LIST_OPTION.value()); + + // Translate options + private static final TranslateOption TARGET_LANGUAGE_OPTION = + TranslateOption.targetLanguage("en"); + private static final TranslateOption SOURCE_LANGUAGE_OPTION = + TranslateOption.sourceLanguage("de"); + private static final Map TRANSLATE_OPTIONS = ImmutableMap.of( + TranslateRpc.Option.TARGET_LANGUAGE, TARGET_LANGUAGE_OPTION.value(), + TranslateRpc.Option.SOURCE_LANGUAGE, SOURCE_LANGUAGE_OPTION.value()); + + private TranslateOptions options; + private TranslateRpcFactory rpcFactoryMock; + private TranslateRpc translateRpcMock; + private Translate translate; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Before + public void setUp() { + rpcFactoryMock = EasyMock.createMock(TranslateRpcFactory.class); + translateRpcMock = EasyMock.createMock(TranslateRpc.class); + EasyMock.expect(rpcFactoryMock.create(EasyMock.anyObject(TranslateOptions.class))) + .andReturn(translateRpcMock); + EasyMock.replay(rpcFactoryMock); + options = TranslateOptions.builder() + .apiKey(API_KEY) + .serviceRpcFactory(rpcFactoryMock) + .retryParams(RetryParams.noRetries()) + .build(); + } + + @After + public void tearDown() throws Exception { + EasyMock.verify(rpcFactoryMock, translateRpcMock); + } + + private void initializeService() { + translate = options.service(); + } + + @Test + public void testGetOptions() { + EasyMock.replay(translateRpcMock); + initializeService(); + assertSame(options, translate.options()); + } + + @Test + public void testListSupportedLanguages() { + EasyMock.expect(translateRpcMock.listSupportedLanguages(EMPTY_RPC_OPTIONS)) + .andReturn(ImmutableList.of(LANGUAGE1_PB, LANGUAGE2_PB)); + EasyMock.replay(translateRpcMock); + initializeService(); + assertEquals(LANGUAGES1, translate.listSupportedLanguages()); + } + + @Test + public void testListSupportedLanguagesWithOptions() { + EasyMock.expect(translateRpcMock.listSupportedLanguages(LANGUAGE_LIST_OPTIONS)) + .andReturn(ImmutableList.of(LANGUAGE3_PB, LANGUAGE4_PB)); + EasyMock.replay(translateRpcMock); + initializeService(); + assertEquals(LANGUAGES2, translate.listSupportedLanguages( + LanguageListOption.targetLanguage(TARGET_LANGUAGE))); + } + + @Test + public void testDetect() { + String text = "text"; + EasyMock.expect(translateRpcMock.detect(ImmutableList.of(text))) + .andReturn( + ImmutableList.>of(ImmutableList.of(DETECTION1_PB))); + EasyMock.replay(translateRpcMock); + initializeService(); + assertEquals(DETECTION1, translate.detect(text)); + } + + @Test + public void testDetectMultipleDetections() { + String text = "text"; + EasyMock.expect(translateRpcMock.detect(ImmutableList.of(text))) + .andReturn(ImmutableList.>of( + ImmutableList.of(DETECTION1_PB, DETECTION2_PB))); + EasyMock.replay(translateRpcMock); + initializeService(); + thrown.expect(IllegalStateException.class); + thrown.expectMessage("Multiple detections found for text: text"); + translate.detect(text); + } + + @Test + public void testDetectNoDetection() { + String text = "text"; + EasyMock.expect(translateRpcMock.detect(ImmutableList.of(text))) + .andReturn(ImmutableList.>of( + ImmutableList.of())); + EasyMock.replay(translateRpcMock); + initializeService(); + thrown.expect(IllegalStateException.class); + thrown.expectMessage("No detection found for text: text"); + translate.detect(text); + } + + @Test + public void testDetectList() { + String text1 = "text"; + String text2 = "other text"; + List texts = ImmutableList.of(text1, text2); + EasyMock.expect(translateRpcMock.detect(texts)) + .andReturn(ImmutableList.>of( + ImmutableList.of(DETECTION1_PB), ImmutableList.of(DETECTION2_PB))); + EasyMock.replay(translateRpcMock); + initializeService(); + assertEquals(ImmutableList.of(DETECTION1, DETECTION2), translate.detect(texts)); + } + + @Test + public void testDetectListMultipleDetections() { + String text1 = "text"; + String text2 = "other text"; + List texts = ImmutableList.of(text1, text2); + EasyMock.expect(translateRpcMock.detect(texts)) + .andReturn(ImmutableList.>of( + ImmutableList.of(DETECTION1_PB, DETECTION2_PB), ImmutableList.of(DETECTION1_PB))); + EasyMock.replay(translateRpcMock); + initializeService(); + thrown.expect(IllegalStateException.class); + thrown.expectMessage("Multiple detections found for text: text"); + translate.detect(texts); + } + + @Test + public void testDetectListNoDetection() { + String text1 = "text"; + String text2 = "other text"; + List texts = ImmutableList.of(text1, text2); + EasyMock.expect(translateRpcMock.detect(texts)) + .andReturn(ImmutableList.>of( + ImmutableList.of(DETECTION1_PB), ImmutableList.of())); + EasyMock.replay(translateRpcMock); + initializeService(); + thrown.expect(IllegalStateException.class); + thrown.expectMessage("No detection found for text: other text"); + translate.detect(texts); + } + + @Test + public void testDetectVararg() { + String text1 = "text"; + String text2 = "other text"; + EasyMock.expect(translateRpcMock.detect(ImmutableList.of(text1, text2))) + .andReturn(ImmutableList.>of( + ImmutableList.of(DETECTION1_PB), ImmutableList.of(DETECTION2_PB))); + EasyMock.replay(translateRpcMock); + initializeService(); + assertEquals(ImmutableList.of(DETECTION1, DETECTION2), translate.detect(text1, text2)); + } + + @Test + public void testDetectVarargMultipleDetections() { + String text1 = "text"; + String text2 = "other text"; + EasyMock.expect(translateRpcMock.detect(ImmutableList.of(text1, text2))) + .andReturn(ImmutableList.>of( + ImmutableList.of(DETECTION1_PB, DETECTION2_PB), ImmutableList.of(DETECTION1_PB))); + EasyMock.replay(translateRpcMock); + initializeService(); + thrown.expect(IllegalStateException.class); + thrown.expectMessage("Multiple detections found for text: text"); + translate.detect(text1, text2); + } + + @Test + public void testDetectVarargNoDetection() { + String text1 = "text"; + String text2 = "other text"; + EasyMock.expect(translateRpcMock.detect(ImmutableList.of(text1, text2))) + .andReturn(ImmutableList.>of( + ImmutableList.of(DETECTION1_PB), ImmutableList.of())); + EasyMock.replay(translateRpcMock); + initializeService(); + thrown.expect(IllegalStateException.class); + thrown.expectMessage("No detection found for text: other text"); + translate.detect(text1, text2); + } + + @Test + public void testTranslate() { + String text = "¡Hola Mundo!"; + EasyMock.expect(translateRpcMock.translate(ImmutableList.of(text), EMPTY_RPC_OPTIONS)) + .andReturn(ImmutableList.of(TRANSLATION1_PB)); + EasyMock.replay(translateRpcMock); + initializeService(); + assertEquals(TRANSLATION1, translate.translate(text)); + } + + @Test + public void testTranslateWithOptions() { + String text = "Hallo Welt!"; + EasyMock.expect(translateRpcMock.translate(ImmutableList.of(text), TRANSLATE_OPTIONS)) + .andReturn(ImmutableList.of(TRANSLATION2_PB)); + EasyMock.replay(translateRpcMock); + initializeService(); + assertEquals(TRANSLATION2, + translate.translate(text, TARGET_LANGUAGE_OPTION, SOURCE_LANGUAGE_OPTION)); + } + + @Test + public void testTranslateList() { + String text1 = "¡Hola Mundo!"; + String text2 = "Hallo Welt!"; + List texts = ImmutableList.of(text1, text2); + EasyMock.expect(translateRpcMock.translate(texts, EMPTY_RPC_OPTIONS)) + .andReturn(ImmutableList.of(TRANSLATION1_PB, TRANSLATION2_PB)); + EasyMock.replay(translateRpcMock); + initializeService(); + assertEquals(ImmutableList.of(TRANSLATION1, TRANSLATION2), translate.translate(texts)); + } + + @Test + public void testTranslateListWithOptions() { + String text = "Hallo Welt!"; + List texts = ImmutableList.of(text); + EasyMock.expect(translateRpcMock.translate(texts, TRANSLATE_OPTIONS)) + .andReturn(ImmutableList.of(TRANSLATION2_PB)); + EasyMock.replay(translateRpcMock); + initializeService(); + assertEquals(ImmutableList.of(TRANSLATION2), + translate.translate(texts, TARGET_LANGUAGE_OPTION, SOURCE_LANGUAGE_OPTION)); + } + + @Test + public void testRetryableException() { + EasyMock.expect(translateRpcMock.listSupportedLanguages(EMPTY_RPC_OPTIONS)) + .andThrow(new TranslateException(500, "internalError")) + .andReturn(ImmutableList.of(LANGUAGE1_PB, LANGUAGE2_PB)); + EasyMock.replay(translateRpcMock); + translate = options.toBuilder().retryParams(RetryParams.defaultInstance()).build().service(); + assertEquals(LANGUAGES1, translate.listSupportedLanguages()); + } + + @Test + public void testNonRetryableException() { + String exceptionMessage = "Not Implemented"; + EasyMock.expect(translateRpcMock.listSupportedLanguages(EMPTY_RPC_OPTIONS)) + .andThrow(new TranslateException(501, exceptionMessage)); + EasyMock.replay(translateRpcMock); + translate = options.toBuilder().retryParams(RetryParams.defaultInstance()).build().service(); + thrown.expect(TranslateException.class); + thrown.expectMessage(exceptionMessage); + translate.listSupportedLanguages(); + } + + @Test + public void testRuntimeException() { + String exceptionMessage = "Artificial runtime exception"; + EasyMock.expect(translateRpcMock.listSupportedLanguages(EMPTY_RPC_OPTIONS)) + .andThrow(new RuntimeException(exceptionMessage)); + EasyMock.replay(translateRpcMock); + translate = options.toBuilder().retryParams(RetryParams.defaultInstance()).build().service(); + thrown.expect(TranslateException.class); + thrown.expectMessage(exceptionMessage); + translate.listSupportedLanguages(); + } +} diff --git a/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateTest.java b/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateTest.java new file mode 100644 index 000000000000..899ee32a7109 --- /dev/null +++ b/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslateTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import static org.junit.Assert.assertEquals; + +import com.google.cloud.translate.Translate.LanguageListOption; +import com.google.cloud.translate.Translate.TranslateOption; +import com.google.cloud.translate.spi.TranslateRpc; + +import org.junit.Test; + +public class TranslateTest { + + private static final String LANGUAGE = "en"; + + @Test + public void testListOptions() { + // target language + LanguageListOption listOption = LanguageListOption.targetLanguage(LANGUAGE); + assertEquals(TranslateRpc.Option.TARGET_LANGUAGE, listOption.rpcOption()); + assertEquals(LANGUAGE, listOption.value()); + } + + @Test + public void testTranslateOptions() { + // target language + TranslateOption translateOption = TranslateOption.targetLanguage(LANGUAGE); + assertEquals(TranslateRpc.Option.TARGET_LANGUAGE, translateOption.rpcOption()); + assertEquals(LANGUAGE, translateOption.value()); + // source language + translateOption = TranslateOption.sourceLanguage(LANGUAGE); + assertEquals(TranslateRpc.Option.SOURCE_LANGUAGE, translateOption.rpcOption()); + assertEquals(LANGUAGE, translateOption.value()); + } +} diff --git a/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslationTest.java b/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslationTest.java new file mode 100644 index 000000000000..efb819f81362 --- /dev/null +++ b/gcloud-java-translate/src/test/java/com/google/cloud/translate/TranslationTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate; + +import static org.junit.Assert.assertEquals; + +import com.google.api.services.translate.model.TranslationsResource; + +import org.junit.Test; + +public class TranslationTest { + + private static final String TRANSLATED_TEXT = "Hello world"; + private static final String SOURCE_LANGUAGE = "en"; + private static final TranslationsResource TRANSLATION_PB = new TranslationsResource() + .setTranslatedText(TRANSLATED_TEXT) + .setDetectedSourceLanguage(SOURCE_LANGUAGE); + private static final Translation TRANSLATION = Translation.fromPb(TRANSLATION_PB); + + @Test + public void testFromPb() { + assertEquals(TRANSLATED_TEXT, TRANSLATION.translatedText()); + assertEquals(SOURCE_LANGUAGE, TRANSLATION.sourceLanguage()); + compareTranslation(TRANSLATION, Translation.fromPb(TRANSLATION_PB)); + } + + private void compareTranslation(Translation expected, Translation value) { + assertEquals(expected, value); + assertEquals(expected.translatedText(), value.translatedText()); + assertEquals(expected.sourceLanguage(), value.sourceLanguage()); + assertEquals(expected.hashCode(), value.hashCode()); + assertEquals(expected.toString(), value.toString()); + } +} diff --git a/gcloud-java-translate/src/test/java/com/google/cloud/translate/it/ITTranslateTest.java b/gcloud-java-translate/src/test/java/com/google/cloud/translate/it/ITTranslateTest.java new file mode 100644 index 000000000000..c92c09b5ac14 --- /dev/null +++ b/gcloud-java-translate/src/test/java/com/google/cloud/translate/it/ITTranslateTest.java @@ -0,0 +1,125 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.translate.it; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.google.cloud.translate.Detection; +import com.google.cloud.translate.Language; +import com.google.cloud.translate.Translate; +import com.google.cloud.translate.Translate.LanguageListOption; +import com.google.cloud.translate.Translate.TranslateOption; +import com.google.cloud.translate.Translation; +import com.google.cloud.translate.testing.RemoteTranslateHelper; +import com.google.common.collect.ImmutableList; + +import org.junit.Test; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class ITTranslateTest { + + private static final Translate TRANSLATE = RemoteTranslateHelper.create().options().service(); + private static final String[] LANGUAGES = {"af", "sq", "ar", "hy", "az", "eu", "be", "bn", "bs", + "bg", "ca", "ceb", "ny", "zh-TW", "hr", "cs", "da", "nl", "en", "eo", "et", "tl", "fi", "fr", + "gl", "ka", "de", "el", "gu", "ht", "ha", "iw", "hi", "hmn", "hu", "is", "ig", "id", "ga", + "it", "ja", "jw", "kn", "kk", "km", "ko", "lo", "la", "lv", "lt", "mk", "mg", "ms", "ml", + "mt", "mi", "mr", "mn", "my", "ne", "no", "fa", "pl", "pt", "ro", "ru", "sr", "st", "si", + "sk", "sl", "so", "es", "su", "sw", "sv", "tg", "ta", "te", "th", "tr", "uk", "ur", "uz", + "vi", "cy", "yi", "yo", "zu"}; + + @Test + public void testListSupportedLanguages() { + Set supportedLanguages = new HashSet<>(); + List languages = TRANSLATE.listSupportedLanguages(); + for (Language language : languages) { + supportedLanguages.add(language.code()); + assertNotNull(language.name()); + } + for (String code : LANGUAGES) { + assertTrue(supportedLanguages.contains(code)); + } + } + + @Test + public void testListSupportedLanguagesWithOptions() { + Set supportedLanguages = new HashSet<>(); + List languages = TRANSLATE.listSupportedLanguages( + LanguageListOption.targetLanguage("es")); + for (Language language : languages) { + supportedLanguages.add(language.code()); + assertNotNull(language.name()); + } + for (String code : LANGUAGES) { + assertTrue(supportedLanguages.contains(code)); + } + } + + @Test + public void testDetectLanguageOfTexts() { + List detections = TRANSLATE.detect("Hello", "Hallo"); + Detection detection = detections.get(0); + assertEquals("en", detection.language()); + detection = detections.get(1); + assertEquals("de", detection.language()); + } + + @Test + public void testDetectLanguageOfTextList() { + List detections = TRANSLATE.detect(ImmutableList.of("Hello", "Hallo")); + Detection detection = detections.get(0); + assertEquals("en", detection.language()); + detection = detections.get(1); + assertEquals("de", detection.language()); + } + + @Test + public void testDetectLanguageOfText() { + Detection detection = TRANSLATE.detect("Hello"); + assertEquals("en", detection.language()); + } + + @Test + public void testTranslateTextList() { + List translations = TRANSLATE.translate(ImmutableList.of("Hola", "Hallo")); + Translation translation = translations.get(0); + assertEquals("Hello", translation.translatedText()); + assertEquals("es", translation.sourceLanguage()); + translation = translations.get(1); + assertEquals("Hello", translation.translatedText()); + assertEquals("de", translation.sourceLanguage()); + } + + @Test + public void testTranslateText() { + Translation translation = TRANSLATE.translate("Hola"); + assertEquals("Hello", translation.translatedText()); + assertEquals("es", translation.sourceLanguage()); + } + + @Test + public void testTranslateTextWithOptions() { + Translation translation = TRANSLATE.translate("Hola", + TranslateOption.sourceLanguage("es"), TranslateOption.targetLanguage("de")); + assertEquals("Hallo", translation.translatedText()); + assertEquals("es", translation.sourceLanguage()); + } +} diff --git a/gcloud-java/pom.xml b/gcloud-java/pom.xml index a28494e028fa..4ae17bff1d37 100644 --- a/gcloud-java/pom.xml +++ b/gcloud-java/pom.xml @@ -59,5 +59,10 @@ gcloud-java-storage ${project.version} + + ${project.groupId} + gcloud-java-translate + ${project.version} + diff --git a/pom.xml b/pom.xml index eab6f035481e..d83d7398e6a1 100644 --- a/pom.xml +++ b/pom.xml @@ -105,6 +105,7 @@ gcloud-java-pubsub gcloud-java-resourcemanager gcloud-java-storage + gcloud-java-translate @@ -401,7 +402,7 @@ Test helpers packages - com.google.cloud.bigquery.testing:com.google.cloud.compute.testing:com.google.cloud.datastore.testing:com.google.cloud.dns.testing:com.google.cloud.logging.testing:com.google.cloud.pubsub.testing:com.google.cloud.resourcemanager.testing:com.google.cloud.storage.testing + com.google.cloud.bigquery.testing:com.google.cloud.compute.testing:com.google.cloud.datastore.testing:com.google.cloud.dns.testing:com.google.cloud.logging.testing:com.google.cloud.pubsub.testing:com.google.cloud.resourcemanager.testing:com.google.cloud.storage.testing:com.google.cloud.translate.testing Example packages @@ -409,7 +410,7 @@ SPI packages - com.google.cloud.spi:com.google.cloud.bigquery.spi:com.google.cloud.compute.spi:com.google.cloud.datastore.spi:com.google.cloud.dns.spi:com.google.cloud.logging.spi:com.google.cloud.logging.spi.*:com.google.cloud.pubsub.spi:com.google.cloud.pubsub.spi.*:com.google.cloud.resourcemanager.spi:com.google.cloud.storage.spi + com.google.cloud.spi:com.google.cloud.bigquery.spi:com.google.cloud.compute.spi:com.google.cloud.datastore.spi:com.google.cloud.dns.spi:com.google.cloud.logging.spi:com.google.cloud.logging.spi.*:com.google.cloud.pubsub.spi:com.google.cloud.pubsub.spi.*:com.google.cloud.resourcemanager.spi:com.google.cloud.storage.spi:com.google.cloud.translate.spi