View Javadoc
1   /*
2    * ===========================================================================
3    * Copyright (C) 2011-2025 by the Okapi Framework contributors
4    * -----------------------------------------------------------------------------
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    * 
9    * http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   * ===========================================================================
17   */
18  
19  package net.sf.okapi.connectors.google.v3;
20  
21  import java.util.ArrayList;
22  import java.util.List;
23  
24  import com.acumenvelocity.ath.common.AthUtil;
25  import com.acumenvelocity.ath.common.ControllerUtil;
26  import com.acumenvelocity.ath.common.Log;
27  import com.acumenvelocity.ath.gct.v3.AthTranslation;
28  import com.google.api.gax.rpc.ApiException;
29  import com.google.cloud.translate.v3.GetSupportedLanguagesRequest;
30  import com.google.cloud.translate.v3.GlossaryName;
31  import com.google.cloud.translate.v3.LocationName;
32  import com.google.cloud.translate.v3.SupportedLanguage;
33  import com.google.cloud.translate.v3.TranslateTextGlossaryConfig;
34  import com.google.cloud.translate.v3.TranslateTextRequest;
35  import com.google.cloud.translate.v3.TranslateTextResponse;
36  import com.google.cloud.translate.v3.Translation;
37  import com.google.cloud.translate.v3.TranslationServiceClient;
38  
39  import net.sf.okapi.common.Util;
40  
41  /**
42   * Implementation of Google Cloud Translation API v3 using the official Google Cloud Java Client.
43   */
44  public class GoogleMTv3APIImpl implements GoogleMTv3API {
45  
46    private final GoogleMTv3Parameters params;
47    private TranslationServiceClient client;
48  
49    public GoogleMTv3APIImpl(GoogleMTv3Parameters params) {
50      this.params = params;
51      this.client = AthTranslation.getClient();
52    }
53  
54    @Override
55    public <T> List<TranslationResponse> translate(GoogleQueryBuilder<T> qb)
56        throws GoogleMTv3ErrorException {
57      try {
58        LocationName parent = LocationName.of(ControllerUtil.getProjectId(),
59            params.getProjectLocation());
60  
61        TranslateTextRequest.Builder requestBuilder = TranslateTextRequest.newBuilder()
62            .setParent(parent.toString())
63            .setMimeType(params.getMimeType())
64            .setSourceLanguageCode(qb.getSourceLanguage())
65            .setTargetLanguageCode(qb.getTargetLanguage())
66            .addAllContents(qb.getQueries());
67  
68        // Add Model
69        if (!Util.isEmpty(params.getModelId())) {
70          // requestBuilder.setModel(String.format("projects/%s/locations/%s/models/%s",
71          // params.getModelProjectId(), params.getModelProjectLocation(), params.getModelId()));
72  
73          String modelProjectId = AthUtil.fallback(params.getModelProjectId(),
74              ControllerUtil.getProjectId());
75  
76          String modelProjectLocation = AthUtil.fallback(params.getModelProjectLocation(),
77              params.getProjectLocation());
78  
79          // ModelName modelName = ModelName.of(modelProjectId, modelProjectLocation,
80          // params.getModelId());
81  
82          String modelName = Log.format("projects/{}/locations/{}/models/{}", modelProjectId,
83              modelProjectLocation, params.getModelId());
84  
85          requestBuilder.setModel(modelName);
86        }
87  
88        // Add Glossary
89        if (!Util.isEmpty(params.getGlossaryId())) {
90          String glossaryProjectId = AthUtil.fallback(params.getGlossaryProjectId(),
91              ControllerUtil.getProjectId());
92  
93          String glossaryProjectLocation = AthUtil.fallback(params.getGlossaryProjectLocation(),
94              params.getProjectLocation());
95  
96          GlossaryName glossaryName = GlossaryName.of(glossaryProjectId, glossaryProjectLocation,
97              params.getGlossaryId());
98  
99          TranslateTextGlossaryConfig glossaryConfig = TranslateTextGlossaryConfig.newBuilder()
100             // .setGlossary(String.format("projects/%s/locations/%s/glossaries/%s",
101             // params.getGlossaryProjectId(), params.getGlossaryProjectLocation(),
102             // params.getGlossaryId()))
103             .setGlossary(glossaryName.toString())
104             .build();
105 
106         requestBuilder.setGlossaryConfig(glossaryConfig);
107       }
108 
109       TranslateTextResponse response = client.translateText(requestBuilder.build());
110       return parseTranslations(response);
111 
112     } catch (ApiException e) {
113       throw new GoogleMTv3ErrorException(e.getStatusCode().getCode().getHttpStatusCode(),
114           e.getMessage(), qb.getQuery());
115 
116     } catch (Exception e) {
117       throw new GoogleMTv3ErrorException(500, e.getMessage(), qb.getQuery());
118     }
119   }
120 
121   @Override
122   public <T> TranslationResponse translateSingleSegment(GoogleQueryBuilder<T> qb, String sourceText)
123       throws GoogleMTv3ErrorException {
124     // Updated: Explicitly specify <T> and remove 'params' to match the updated GoogleQueryBuilder
125     // constructor
126     GoogleQueryBuilder<T> singleQb = new GoogleQueryBuilder<T>(qb.getSourceLanguage(),
127         qb.getTargetLanguage());
128 
129     singleQb.addQuery(sourceText, null);
130 
131     List<TranslationResponse> responses = translate(singleQb);
132 
133     if (responses != null && !responses.isEmpty()) {
134       return responses.get(0);
135     }
136 
137     return null;
138   }
139 
140   @Override
141   public List<String> getLanguages() throws GoogleMTv3ErrorException {
142     try {
143       LocationName parent = LocationName.of(ControllerUtil.getProjectId(),
144           params.getProjectLocation());
145 
146       GetSupportedLanguagesRequest request = GetSupportedLanguagesRequest.newBuilder()
147           .setParent(parent.toString())
148           .build();
149 
150       List<SupportedLanguage> languages = client.getSupportedLanguages(request)
151           .getLanguagesList();
152 
153       List<String> codes = new ArrayList<>();
154 
155       for (SupportedLanguage lang : languages) {
156         codes.add(lang.getLanguageCode());
157       }
158 
159       return codes;
160 
161     } catch (ApiException e) {
162       throw new GoogleMTv3ErrorException(e.getStatusCode().getCode().getHttpStatusCode(),
163           e.getMessage(), "getLanguages");
164     }
165   }
166 
167   private List<TranslationResponse> parseTranslations(TranslateTextResponse response) {
168     List<TranslationResponse> results = new ArrayList<>();
169 
170     for (Translation translation : response.getTranslationsList()) {
171       String translatedText = translation.getTranslatedText();
172       String detectedLanguage = translation.getDetectedLanguageCode();
173 
174       String finalTranslation = translatedText;
175 
176       // Check for glossary specific translation info if available in the response object
177       if (translation.hasGlossaryConfig()) {
178         // The V3 java client handles glossary application within the translated text usually,
179         // but specific glossary metadata handling would go here if needed.
180       }
181 
182       results.add(new TranslationResponse(finalTranslation, detectedLanguage));
183     }
184 
185     return results;
186   }
187 
188   @Override
189   public void close() {
190     // The GCT v3 client is closed in AthTranslation#done()
191   }
192 }