--- url: /at4j/guide/introduction.md --- # Introduction {#introduction} Welcome to the AT4J docs! 👋 This documentation will help you to get started with your first Azure Translator implementation as fast as possible. ## What is the purpose of the AT4J library? {#purpose} The AT4J library is a Java wrapper for the Azure Translator API Using Java classes for its API like CompletableFuture for async requests and Optional for return types which may be `null`. It provides a simple and easy-to-use interface to interact with the Azure Translator API, allowing you to translate text between languages. ## What is the Azure Translator? {#azure-translator} The Azure Translator, provided by Microsoft, is a cloud-based machine translation service that is part of the Microsoft Azure cloud services. It offers a set of APIs that allow for text translation between languages and language detection of a given text, among other features. --- --- url: /at4j/guide/installation.md --- # Download/Installation {#install} The recommended way to get AT4J is to use a build manager, like Gradle or Maven. If you are not familiar with build managers, you can follow one of the beginner ide setup guides (see navigation) or download AT4J directly from [GitHub](https://github.com/brenoepics/at4j). ## AT4J Dependency {#at4j-dependency} ::: code-group ```groovy [Gradle] implementation group: 'io.github.brenoepics', name: 'at4j', version: 'AT4J-VERSION' ``` ```xml [Maven] io.github.brenoepics at4j AT4J-VERSION ``` ```scala [Sbt] libraryDependencies += "io.github.brenoepics" % "at4j" % "AT4J-VERSION" ``` ::: --- --- url: /at4j/guide/basic-usage.md --- # Basic Usage {#basic-usage} This section will guide you through the basic usage of AT4J. ## Simple Hello World Translation {#hello-world} ```java import io.github.brenoepics.at4j.AzureApi; import io.github.brenoepics.at4j.AzureApiBuilder; import io.github.brenoepics.at4j.data.request.TranslateParams; import io.github.brenoepics.at4j.data.response.TranslationResponse; import java.util.List; import java.util.Optional; public class ExampleApi { private static AzureApi azureApi; public static void main(String[] args) { // Insert your Azure key and region here String azureKey = ""; String azureRegion = ""; azureApi = new AzureApiBuilder().setKey(azureKey).region(azureRegion).build(); translate(args.join(" "), List.of("pt", "es", "fr")); } private static void translate(String inputText, List targetLanguages) { TranslateParams params = new TranslateParams(inputText, targetLanguages); Optional result = azureApi.translate(params).join(); result.ifPresent(response -> response.getFirstResult().getTranslations().forEach(ExampleApi::log)); } public static void log(Translation translation) { System.out.println(translation.getLanguageCode() + ": " + translation.getText()); } } ``` **Input** ```console Hello, World! ``` **Result** ```console pt: Olá, Mundo! es: ¡Hola mundo! fr: Salut tout le monde! ``` The above example demonstrates the core feature of AT4J: * **AzureApi**: Serves as the primary entry point for interacting with the Azure Translator API. It provides a set of methods to perform various translation-related tasks. You may already have questions—don't worry. We will cover every little detail in the rest of the documentation. For now, please read along, so you can have a high-level understanding of what AT4J offers. :::tip Prerequisites The rest of the documentation assumes basic familiarity with Java and Azure Portal. If you are totally new to backend development, it's recommended to familiarize yourself with Java programming and the Azure Portal before proceeding with the rest of the documentation. Here are some brief pointers to help you get started: [Java](https://www.tutorialspoint.com/java/index.htm) and [Azure](https://azure.microsoft.com/en-us/get-started) if needed. ::: ## Still Got Questions? {#still-got-questions} Check out our [GitHub Discussions](https://github.com/brenoepics/at4j/discussions) page for more information and to ask questions. --- --- url: /at4j/essential/completable-futures.md --- # What is the `CompletableFuture` API? {#completable-future} > \[!WARNING] > > This tutorial assumes that you are familiar with [lambda expressions](https://www.w3schools.com/java/java_lambda.asp). Take a look at the lambda introduction first if > you are not! AT4J uses Futures for asynchronous requests. To understand how AT4J works, you must understand the concept of [Futures](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html) in general, as well as their most common implementation, the [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html). `CompletableFuture` is a class introduced in Java 8 that represents a future result of an asynchronous computation. It is a part of the `java.util.concurrent` package and is used for asynchronous programming in Java. This little introduction gives you a quick overview of the basics you need to know to work with Futures. ## What is a `Future`? A `Future` is a placeholder for a result that is not yet available. It represents the result of an asynchronous computation. This is useful if a method call requires some time and should not block the execution of your current code. You can see the difference with a primitive speed comparison: ```java long currentTime = System.currentTimeMillis(); TranslateParams params = new TranslateParams("Hello World!", List.of("pt", "es", "fr")); azureApi.translate(params); azureApi.translate(params); azureApi.translate(params); azureApi.translate(params); azureApi.translate(params); System.out.println((System.currentTimeMillis() - currentTime) + " ms"); ``` ```java long currentTime = System.currentTimeMillis(); TranslateParams params = new TranslateParams("Hello World!", List.of("pt", "es", "fr")); azureApi.translate(params).join(); azureApi.translate(params).join(); azureApi.translate(params).join(); azureApi.translate(params).join(); azureApi.translate(params).join(); System.out.println((System.currentTimeMillis() - currentTime) + " ms"); ``` The first example will take a few milliseconds to execute, while the second example will take a few seconds to execute. This is because the first example does not wait for the result of the `translate` method, while the second example waits for the result of each `translate` method call. ## `CompletableFuture` Methods ### `join()` > \[!CAUTION] > The `join` method is a blocking operation, which means that it will wait for the result of the `CompletableFuture` to > be > available. If the computation fails, a `CompletionException` will be thrown. > It is recommended to use the `join` method only when you are sure that the computation will succeed. > Avoid using the `join` method in production code, and methods which will be called by other methods, as it can lead to > deadlocks. The `join` method is used to wait for the result of the `CompletableFuture`. It returns the result of the computation when it is done or throws a `CompletionException` if anything failed. The following example demonstrates how to use the `join` method: ```java TranslateParams params = new TranslateParams("Hello World!", List.of("pt", "es", "fr")); Optional translationResult = azureApi.translate(params).join(); translationResult.ifPresent( response -> response.getFirstResult().getTranslations().forEach(System.out::println)); ``` This example translates the text "Hello World!" into Portuguese, Spanish, and French. The `join` method waits for the result of the translation and prints the translations to the console. > \[!TIP] > While join() can become a performance issue when you call it very frequently, it is very convenient to use and easy to > understand. If you are new to programming and just want to get your first application working, this is a good method to start > with. > Once you gathered more experience, we highly advise against using `join()` as it negatively impacts the performance > of your application. ### `thenAccept()` The `thenAccept` method is used to perform an action when the `CompletableFuture` completes. It takes a `Consumer` as a parameter, which is called with the result of the computation when it is done. The following example demonstrates how to use the `thenAccept` method: ```java TranslateParams params = new TranslateParams("Hello World!", List.of("pt", "es", "fr")); azureApi.translate(params).thenAccept( response -> response.getFirstResult().getTranslations().forEach(System.out::println)); ``` > \[!CAUTION] > The example above does not handle exceptions. If the translation fails, the exception will be thrown and not caught. > This can lead to unexpected behavior in your application and make it harder to debug. > It is recommended to use the `exceptionally` method to handle exceptions. ### `exceptionally(...)` The `exceptionally` method is used to handle exceptions that occur during the computation of the `CompletableFuture`. It takes a `Function` as a parameter, which is called with the exception when it occurs. The following example demonstrates how to use the `exceptionally` method: ```java TranslateParams params = new TranslateParams("Hello World!", List.of("pt", "es", "fr")); azureApi.translate(params).exceptionally( exception -> { System.err.println("An error occurred: " + exception.getMessage()); return null; }).thenAccept( response -> response.getFirstResult().getTranslations().forEach(System.out::println)); ``` ### `thenCompose()` The `thenCompose` method is used to chain multiple `CompletableFuture` instances together. It takes a `Function` as a parameter, which is called with the result of the computation when it is done. The following example demonstrates how to use the `thenCompose` method: ```java TranslateParams params = new TranslateParams("Hello World!", List.of("pt", "es", "fr")); azureApi.translate(params).thenCompose( response -> azureApi.translate(params)).thenAccept( response -> response.getFirstResult().getTranslations().forEach(System.out::println)); ``` ## Further Reading To learn more about `CompletableFuture`, check out the following resources: * [Java 8 CompletableFuture Tutorial](https://www.baeldung.com/java-completablefuture) * [Java 8 CompletableFuture API](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) * [Java 8 CompletableFuture Javadoc](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) * [Java 8 CompletableFuture Tutorial](https://www.callicoder.com/java-8-completablefuture-tutorial/) --- --- url: /at4j/essential/optionals.md --- # What are `Optional` types? {#optional} Basically, every method that might return a `null` value will return an Optional in AT4J. This is a way to avoid `NullPointerException`s in your code. This type was introduced in Java 8 and is a container object that may or may not contain a non-null value. If a value is present, `isPresent()` will return `true`, and `get()` will return the value. Old code: ```java TranslationResponse translation = azureApi.translate(text).join(); if (translation != null) { translation.getFirstResult().getTranslations().forEach(ExampleApi::log); } ``` New code: ```java azureApi.translate(text).ifPresent(response -> response.getFirstResult().getTranslations().forEach(ExampleApi::log)); ``` You can imagine an Optional like a box that may or may not contain a value. Before accessing this value, you have to unpack this box first. ## Methods ### `get()` > \[!CAUTION] > You should avoid using the `get` method as it can throw a `NoSuchElementException` if the value is not present. > It is recommended to use the `isPresent` method to check if the value is present before calling the `get` method. > If you are sure that the value is present, you can use the `orElse` method to provide a default value if the value is > not present. The `get` method returns the value if present, otherwise throws a `NoSuchElementException`. ```java TranslationResponse translation = azureApi.translate(text).get(); translation.getFirstResult().getTranslations().forEach(ExampleApi::log); ``` ### `isPresent()` The `isPresent` method returns `true` if the `Optional` contains a non-null value, otherwise `false`. ```java Optional translation = azureApi.translate(text); if (translation.isPresent()) { translation.get().getFirstResult().getTranslations().forEach(ExampleApi::log); } ``` ### `ifPresent(Consumer consumer)` The `ifPresent` method takes a `Consumer` as an argument and executes the consumer if the `Optional` contains a non-null value. ```java azureApi.translate(text).ifPresent(response -> response.getFirstResult().getTranslations().forEach(ExampleApi::log)); ``` ### `orElse(T other)` The `orElse` method returns the value if present, otherwise returns the specified value. ```java TranslationResponse translation = azureApi.translate(text).orElse(new TranslationResponse()); translation.getFirstResult().getTranslations().forEach(ExampleApi::log); ``` ### `orElseGet(Supplier other)` The `orElseGet` method returns the value if present, otherwise returns the result of the specified `Supplier`. ```java TranslationResponse translation = azureApi.translate(text).orElseGet(() -> new TranslationResponse()); translation.getFirstResult().getTranslations().forEach(ExampleApi::log); ``` ### `orElseThrow()` The `orElseThrow` method returns the value if present, otherwise throws an exception. ```java TranslationResponse translation = azureApi.translate(text).orElseThrow(); translation.getFirstResult().getTranslations().forEach(ExampleApi::log); ``` ### `map(Function mapper)` The `map` method applies the given function to the value if present, otherwise returns an empty `Optional`. ```java Optional translation = azureApi.translate(text).map(response -> response.getFirstResult().getTranslations().getFirst().getText()); translation.ifPresent(System.out::println); ``` ### `filter(Predicate predicate)` The `filter` method returns an `Optional` containing the value if present and the value matches the given predicate, ```java Optional translation = azureApi.translate(text).flatMap(response -> response.getFirstResult().getTranslations().stream().findFirst()); translation.filter(t -> t.getLanguageCode().equals("en")).ifPresent(ExampleApi::log); ``` ### `flatMap(Function> mapper)` The `flatMap` method applies the given function to the value if present, otherwise returns an empty `Optional`. ```java Optional translation = azureApi.translate(text).flatMap(response -> response.getFirstResult().getTranslations().stream().findFirst()); translation.ifPresent(ExampleApi::log); ``` ## Further Reading * [Optional (Java Platform SE 8 )](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html) * [Java 8 Optional Tutorial](https://www.baeldung.com/java-optional) * [Java 8 Optional API](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html) --- --- url: /at4j/essential/error-handling.md --- # Error Handling > \[!WARNING] > TODO: Add more information about error handling in AT4J. --- --- url: /at4j/essential/logging.md --- # Logging AT4J uses the [SLF4J](http://www.slf4j.org/) logging facade. This allows you to use your favorite logging framework with AT4J. By default, AT4J uses the `org.slf4j.Logger` interface to log messages. > \[!WARNING] > TODO: Add more information about logging in AT4J. --- --- url: /at4j/advanced/threading.md --- # Creating an AzureApi with a Custom ExecutorService This guide will walk you through the process of creating an `AzureApiBuilder` with a custom `ExecutorService`. ## Steps 1. **Create a custom ExecutorService** For this example, we'll create a custom `ExecutorService` using the Virtual Threads API introduced in Java 21: ```java ExecutorService customExecutorService = Executors.newVirtualThreadPerTaskExecutor(); ``` 2. **Create an AzureApiBuilder** You can create an `AzureApi` by using the `AzureApiBuilder` class. Here's an example: ```java String azureKey = ""; String azureRegion = ""; AzureApi azureApi = new AzureApiBuilder() .setKey(azureKey) .region(azureRegion) .executorService(customExecutorService).build(); ``` This will create an `AzureApi` with the settings you specified in the `AzureApiBuilder`. That's it! You've successfully created an `AzureApi` with a custom `ExecutorService`. You can now use this `AzureApi` to make requests to the Azure API. --- --- url: /at4j/advanced/caching.md --- # Caching > \[!WARNING] > TODO: Add more information about caching in AT4J. --- --- url: /at4j/guide/azure-subscription.md --- # Getting an Azure Subscription {#azure-subscription} :::warning Azure Keys Remember to **keep your keys secure and do not share them publicly**. If you believe that a key has been compromised, you must regenerate it in Azure's Panel. For more information, visit the [Azure portal](https://portal.azure.com/). ::: Azure Text Translation is able to translate text instantly or in batches across [more than 100 languages](https://go.microsoft.com/fwlink/?linkid=2216841), Support a wide range of use cases, such as translation for call centers, multilingual conversational agents, or in-app communication. ## Free Tier {#azure-free-tier} Azure offers a free tier for its services, which is a great way to get started with Azure Translator for Java. The free tier includes a monthly allowance of two million characters for Translator Text. This is sufficient for testing and small projects. Please note that the free tier usage limits are subject to change by Azure, and it's recommended to check the current details on the [Azure Pricing](https://azure.microsoft.com/en-us/pricing/details/cognitive-services/translator/) page. ## How to generate an Azure Translation Subscription {#generate-azure-subscription} > \[!TIP] > Generate your > keys [Here](https://portal.azure.com/#view/Microsoft_Azure_ProjectOxford/CognitiveServicesHub/~/TextTranslation). 1. Sign in to the [Azure portal](https://portal.azure.com/). 2. In the left-hand menu, click on "Create a resource." 3. In the "Search the Marketplace" box, type "Translator Text" and select it from the dropdown list. 4. Click on the "Create" button. 5. Fill in the required details: * **Name:** Enter a unique name for your resource. * **Subscription:** Select the Azure subscription that you want to use. * **Resource Group:** You can create a new resource group or select an existing one. * **Pricing tier:** Select the pricing tier that suits your needs. 6. Click on the "Review + create" button. 7. Review your settings and click on the "Create" button. 8. After the deployment is complete, go to the resource you just created. 9. In the left-hand menu, click on "Keys and Endpoint." 10. You will see two keys and an endpoint. You can use either of the keys in your application. --- --- url: /at4j/azure-reference/languages.md --- # Azure Available Languages The Azure Translator API supports a wide range of languages for translation. This guide provides a list of languages that are supported by the Azure Translator API. ## Supported Languages > \[!TIP] > You can find the full list of supported languages in the [Azure Translator API documentation](https://docs.microsoft.com/en-us/azure/cognitive-services/translator/language-support). --- --- url: /at4j/azure-reference/datacenter-list.md --- # Datacenter List This page contains a list of Azure datacenters and their locations. ## Azure Datacenter Locations --- --- url: /at4j/error-reference.md --- # Azure Error Code Reference {#azure-errors} The following table maps the codes to their original full information strings. --- --- url: /at4j/examples.md --- # Examples {#examples} This section contains examples of how to use AT4J in different scenarios. ## Translate Hello World {#translator} ```java public class ExampleTranslator { public static void main(String[] args) { // Insert your Azure key and region here String azureKey = ""; String azureRegion = ""; AzureApi api = new AzureApiBuilder().setKey(azureKey).region(azureRegion).build(); // Set up translation parameters List targetLanguages = List.of("pt", "es", "fr"); TranslateParams params = new TranslateParams("Hello World!", targetLanguages).setSourceLanguage("en"); // Translate the text Optional translationResult = api.translate(params).join(); // Print the translations translationResult.ifPresent( response -> response.getFirstResult().getTranslations().forEach(ExampleTranslator::logLanguage)); } public static void logLanguage(Translation translation) { System.out.println(translation.getLanguageCode() + ": " + translation.getText()); } } ``` ## Language Detector {#detect} ```java public class ExampleDetector { public static void main(String[] args) { // Insert your Azure key and region here String azureKey = ""; String azureRegion = ""; AzureApi api = new AzureApiBuilder().setKey(azureKey).region(azureRegion).build(); DetectLanguageParams params = new DetectLanguageParams("Hello World!").addText("Bonjour le monde!"); // Translate the text Optional result = api.detectLanguage(params).join(); // Print the translations result.ifPresent( response -> response.getDetectedLanguages().forEach(ExampleDetector::logLanguage)); } public static void logLanguage(DetectedLanguage detectedLanguage) { System.out.println(detectedLanguage.getLanguageCode() + ": " + detectedLanguage.getScore()); } } ``` ## JSON Translator {#json} Azure Translator API does not support JSON translation. However, you can use AT4J to translate JSON objects. [kt-json-i18n](https://github.com/brenoepics/kt-json-i18n) is a library that allows you to translate JSON objects using AT4J. You can use it as an example to translate JSON objects.