From 652f4ecee0187982cb91c74a5ede979786806675 Mon Sep 17 00:00:00 2001 From: Petros Douvantzis Date: Fri, 7 Nov 2025 14:32:31 +0200 Subject: [PATCH 1/5] Update repository links in readme The links used to point to the old "search.maven.org". Now they point to "central.sonatype.com". --- README.md | 2 +- TransifexNativeSDK/doc/readme.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index be8e950..8379f36 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Include the dependency: implementation 'com.transifex.txnative:txsdk:x.y.z' ``` -Please replace `x`, `y` and `z` with the latest version numbers: [![Maven Central](https://img.shields.io/maven-central/v/com.transifex.txnative/txsdk?color=32c955)](https://maven-badges.herokuapp.com/maven-central/com.transifex.txnative/txsdk) +Please replace `x`, `y` and `z` with the latest version numbers: [![Maven Central](https://img.shields.io/maven-central/v/com.transifex.txnative/txsdk?color=32c955)](https://central.sonatype.com/artifact/com.transifex.txnative/txsdk) The library's minimum supported SDK is 18 (Android 4.3). diff --git a/TransifexNativeSDK/doc/readme.html b/TransifexNativeSDK/doc/readme.html index a971bd1..2f0eab1 100644 --- a/TransifexNativeSDK/doc/readme.html +++ b/TransifexNativeSDK/doc/readme.html @@ -17,7 +17,7 @@

Include the dependency:

implementation 'com.transifex.txnative:txsdk:x.y.z'
 
-

Please replace x, y and z with the latest version numbers: Maven Central

+

Please replace x, y and z with the latest version numbers: Maven Central

The library’s minimum supported SDK is 18 (Android 4.3).

The SDK requires Appcompat and automatically adds it as a dependency.

SDK configuration

From 73f5c6d608c445cb6727243ca0b7ed72a3e26449 Mon Sep 17 00:00:00 2001 From: Petros Douvantzis Date: Fri, 12 Dec 2025 12:21:58 +0200 Subject: [PATCH 2/5] Replace TimeLimitExceededException with TimeoutException Replaced TimeLimitExceededException with java.util.concurrent.TimeoutException, which is supported on both Java SE and Android and preserves the intended "time limit exceeded" semantics. --- .../main/java/com/transifex/clitool/MainClass.java | 9 ++++----- .../main/java/com/transifex/common/CDSHandler.java | 13 ++++++------- .../java/com/transifex/common/CDSHandlerTest.java | 11 +++++------ 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/TransifexNativeSDK/clitool/src/main/java/com/transifex/clitool/MainClass.java b/TransifexNativeSDK/clitool/src/main/java/com/transifex/clitool/MainClass.java index 426cadd..ec58eb8 100644 --- a/TransifexNativeSDK/clitool/src/main/java/com/transifex/clitool/MainClass.java +++ b/TransifexNativeSDK/clitool/src/main/java/com/transifex/clitool/MainClass.java @@ -18,10 +18,9 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; +import java.util.concurrent.TimeoutException; import java.util.logging.Logger; -import javax.naming.TimeLimitExceededException; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import picocli.CommandLine; @@ -216,7 +215,7 @@ public Integer call() throws Exception { LocaleData.TxJobStatus jobStatus = null; try { jobStatus = cdsHandler.pushSourceStrings(postData); - } catch (TimeLimitExceededException e) { + } catch (TimeoutException e) { System.out.println("Strings are queued for processing"); return 0; } @@ -270,7 +269,7 @@ public Integer call() throws Exception { LocaleData.TxJobStatus jobStatus = null; try { jobStatus = cdsHandler.pushSourceStrings(postData); - } catch (TimeLimitExceededException e) { + } catch (TimeoutException e) { System.out.println("Source string clearing is queued for processing"); return 0; } @@ -446,4 +445,4 @@ String getErrorString(@NonNull LocaleData.TxJobStatus jobStatus) { private static @NonNull String getNonDownloadedLocalesString(@NonNull HashSet nonDownloadedLocales) { return "The translations for the following locales were not downloaded: " + Arrays.toString(nonDownloadedLocales.toArray()); } -} +} \ No newline at end of file diff --git a/TransifexNativeSDK/common/src/main/java/com/transifex/common/CDSHandler.java b/TransifexNativeSDK/common/src/main/java/com/transifex/common/CDSHandler.java index b39f11b..4e15563 100644 --- a/TransifexNativeSDK/common/src/main/java/com/transifex/common/CDSHandler.java +++ b/TransifexNativeSDK/common/src/main/java/com/transifex/common/CDSHandler.java @@ -21,11 +21,10 @@ import java.net.URISyntaxException; import java.net.URL; import java.util.Set; +import java.util.concurrent.TimeoutException; import java.util.logging.Level; import java.util.logging.Logger; -import javax.naming.TimeLimitExceededException; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -345,11 +344,11 @@ public LocaleData.TranslationMap fetchTranslations(@Nullable String localeCode, * The job status can be either "completed" or "failed". * If everything fails, null is returned. * - * @throws TimeLimitExceededException When the server takes longer than 20 seconds to complete + * @throws TimeoutException When the server takes longer than 20 seconds to complete * processing the job. */ public @Nullable - LocaleData.TxJobStatus pushSourceStrings(@NonNull LocaleData.TxPostData postData) throws TimeLimitExceededException { + LocaleData.TxJobStatus pushSourceStrings(@NonNull LocaleData.TxPostData postData) throws TimeoutException { LocaleData.TxPostResponseData response = pushSourceStringsInternal(postData); if (response == null) { return null; @@ -462,13 +461,13 @@ LocaleData.TxJobStatus pushSourceStrings(@NonNull LocaleData.TxPostData postData * @return The job status object or null if everything failed. The job status can * be either "completed" or "failed". * - * @throws TimeLimitExceededException When the server takes longer than 20 seconds to complete + * @throws TimeoutException When the server takes longer than 20 seconds to complete * processing the job. * * @see * https://github.com/transifex/transifex-delivery/#job-status */ - private @Nullable LocaleData.TxJobStatus getJobStatus(@NonNull LocaleData.TxPostResponseData responseData) throws TimeLimitExceededException { + private @Nullable LocaleData.TxJobStatus getJobStatus(@NonNull LocaleData.TxPostResponseData responseData) throws TimeoutException { URL url = null; try { URI cdsContentURI = new URI(mCdsHost); @@ -531,7 +530,7 @@ LocaleData.TxJobStatus pushSourceStrings(@NonNull LocaleData.TxPostData postData } } - throw new TimeLimitExceededException("Server is still processing the pushed strings"); + throw new TimeoutException("Server is still processing the pushed strings"); } /** diff --git a/TransifexNativeSDK/common/src/test/java/com/transifex/common/CDSHandlerTest.java b/TransifexNativeSDK/common/src/test/java/com/transifex/common/CDSHandlerTest.java index 2156424..5900abf 100644 --- a/TransifexNativeSDK/common/src/test/java/com/transifex/common/CDSHandlerTest.java +++ b/TransifexNativeSDK/common/src/test/java/com/transifex/common/CDSHandlerTest.java @@ -11,8 +11,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashMap; - -import javax.naming.TimeLimitExceededException; +import java.util.concurrent.TimeoutException; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -354,7 +353,7 @@ public void testPushSourceStrings_badURL() { LocaleData.TxJobStatus jobStatus = null; try { jobStatus = cdsHandler.pushSourceStrings(postData); - } catch (TimeLimitExceededException ignored) {} + } catch (TimeoutException ignored) {} assertThat(jobStatus).isNull(); } @@ -369,7 +368,7 @@ public void testPushSourceStrings_normal() { LocaleData.TxJobStatus jobStatus = null; try { jobStatus = cdsHandler.pushSourceStrings(postData); - } catch (TimeLimitExceededException ignored) {} + } catch (TimeoutException ignored) {} assertThat(jobStatus).isNotNull(); @@ -405,7 +404,7 @@ public void testPushSourceStrings_CDSRespondsWith409_returnNull() { LocaleData.TxJobStatus jobStatus = null; try { jobStatus = cdsHandler.pushSourceStrings(postData); - } catch (TimeLimitExceededException ignored) {} + } catch (TimeoutException ignored) {} assertThat(jobStatus).isNull(); @@ -421,7 +420,7 @@ public void testPushSourceStrings_CDSRespondsWithFailedJob_returnErrorInResponse LocaleData.TxJobStatus jobStatus = null; try { jobStatus = cdsHandler.pushSourceStrings(postData); - } catch (TimeLimitExceededException ignored) {} + } catch (TimeoutException ignored) {} assertThat(jobStatus).isNotNull(); From c1c4ef13bd953f18c6e7d9835481ac230f9d3321 Mon Sep 17 00:00:00 2001 From: Petros Douvantzis Date: Fri, 12 Dec 2025 12:32:55 +0200 Subject: [PATCH 3/5] Update Gradle Android unit test deployment was broken at some point. Updating Gradle and some other changed helped. Updated to Gradle 8.2 and AGP 8.2.2 --- TransifexNativeSDK/app/build.gradle | 5 ++++- TransifexNativeSDK/build.gradle | 2 +- TransifexNativeSDK/gradle.properties | 2 -- TransifexNativeSDK/gradle/wrapper/gradle-wrapper.properties | 6 +++--- TransifexNativeSDK/txsdk/build.gradle | 5 ++++- .../com/transifex/txnative/cache/TxStandardCacheTest.java | 2 +- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/TransifexNativeSDK/app/build.gradle b/TransifexNativeSDK/app/build.gradle index 33e24dc..d72766d 100644 --- a/TransifexNativeSDK/app/build.gradle +++ b/TransifexNativeSDK/app/build.gradle @@ -39,6 +39,10 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } + + buildFeatures { + buildConfig = true + } } // Uncomment in combination with "setCompatVectorFromResourcesEnabled()" in "MyApplication" to @@ -50,7 +54,6 @@ android { //} dependencies { - implementation fileTree(dir: "libs", include: ["*.jar"]) implementation "androidx.appcompat:appcompat:$versions.appcompat" implementation "com.google.android.material:material:$versions.material" implementation 'androidx.constraintlayout:constraintlayout:2.1.4' diff --git a/TransifexNativeSDK/build.gradle b/TransifexNativeSDK/build.gradle index 657096d..2ca24e1 100644 --- a/TransifexNativeSDK/build.gradle +++ b/TransifexNativeSDK/build.gradle @@ -33,7 +33,7 @@ buildscript { plugins { id "io.github.gradle-nexus.publish-plugin" version "2.0.0" - id 'com.android.application' version '8.1.0' apply false + id 'com.android.application' version '8.2.2' apply false id 'com.android.library' version '8.1.0' apply false id 'org.jetbrains.kotlin.android' version '1.9.20' apply false } diff --git a/TransifexNativeSDK/gradle.properties b/TransifexNativeSDK/gradle.properties index 99bd2ad..8cd4f06 100644 --- a/TransifexNativeSDK/gradle.properties +++ b/TransifexNativeSDK/gradle.properties @@ -18,7 +18,5 @@ android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX android.enableJetifier=true -# https://developer.android.com/build/releases/past-releases/agp-8-0-0-release-notes#default-changes -android.defaults.buildfeatures.buildconfig=true android.nonTransitiveRClass=false android.nonFinalResIds=false \ No newline at end of file diff --git a/TransifexNativeSDK/gradle/wrapper/gradle-wrapper.properties b/TransifexNativeSDK/gradle/wrapper/gradle-wrapper.properties index a9b6427..243d0cf 100644 --- a/TransifexNativeSDK/gradle/wrapper/gradle-wrapper.properties +++ b/TransifexNativeSDK/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Sep 20 14:45:43 EEST 2021 +#Fri Dec 12 11:57:17 EET 2025 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip distributionPath=wrapper/dists -zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/TransifexNativeSDK/txsdk/build.gradle b/TransifexNativeSDK/txsdk/build.gradle index 2855e0c..bdcc9f3 100644 --- a/TransifexNativeSDK/txsdk/build.gradle +++ b/TransifexNativeSDK/txsdk/build.gradle @@ -50,6 +50,10 @@ android { withSourcesJar() } } + + buildFeatures { + buildConfig = true + } } tasks.withType(Test).configureEach { @@ -63,7 +67,6 @@ configurations.configureEach { } dependencies { - implementation fileTree(dir: "libs", include: ["*.jar"]) compileOnly "androidx.annotation:annotation:$versions.androidXAnnotation" implementation "androidx.appcompat:appcompat:$versions.appcompat" compileOnly "com.google.android.material:material:$versions.material" diff --git a/TransifexNativeSDK/txsdk/src/androidTest/java/com/transifex/txnative/cache/TxStandardCacheTest.java b/TransifexNativeSDK/txsdk/src/androidTest/java/com/transifex/txnative/cache/TxStandardCacheTest.java index 2544c98..dea54bf 100644 --- a/TransifexNativeSDK/txsdk/src/androidTest/java/com/transifex/txnative/cache/TxStandardCacheTest.java +++ b/TransifexNativeSDK/txsdk/src/androidTest/java/com/transifex/txnative/cache/TxStandardCacheTest.java @@ -14,7 +14,7 @@ import java.io.File; import java.lang.reflect.Field; -import androidx.test.espresso.core.internal.deps.guava.util.concurrent.MoreExecutors; +import com.google.common.util.concurrent.MoreExecutors; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; From 98866f179e4c1c34b789c1993650d9f2edb80311 Mon Sep 17 00:00:00 2001 From: Petros Douvantzis Date: Fri, 12 Dec 2025 15:57:23 +0200 Subject: [PATCH 4/5] Initialization via builder-style Initializer A new `TxNative.Initializer` class has been introduced to simplify SDK initialization. Users can now configure optional parameters through fluent methods before calling `init()`. The old `TxNative#init()` method is still available but has been deprecated. Support for specifying a custom authorization header key has also been added. --- README.md | 18 +- .../myapplication/MyApplication.java | 15 +- .../java/com/transifex/clitool/MainClass.java | 6 +- .../java/com/transifex/common/CDSHandler.java | 24 +- .../com/transifex/common/CDSHandlerTest.java | 56 +++- .../common/TranslationsDownloaderTest.java | 14 +- TransifexNativeSDK/doc/readme.html | 290 +++++++++--------- .../transifex/txnative/CDSHandlerAndroid.java | 2 +- .../com/transifex/txnative/NativeCore.java | 24 +- .../java/com/transifex/txnative/TxNative.java | 135 +++++++- .../transifex/txnative/NativeCoreTest.java | 50 +-- .../transifex/txnative/TxResourcesTest.java | 24 +- 12 files changed, 396 insertions(+), 262 deletions(-) diff --git a/README.md b/README.md index 8379f36..6fc7ccd 100644 --- a/README.md +++ b/README.md @@ -57,19 +57,11 @@ public void onCreate() { new String[]{"en", "el", "de", "fr", "ar", "sl", "es_ES", "es_MX"}, null); - TxNative.init( - // application context - getApplicationContext(), - // a LocaleState instance - localeState, - // token - token, - // cdsHost URL - null, - // a TxCache implementation - null, - // a MissingPolicy implementation - null); + TxNative.initializer(base, localeState, token) + .withCdsHost(null) // cdsHost URL + .withCache(null) // a TxCache implementation + .withMissingPolicy(null) // a MissingPolicy implementation + .init(); // Fetch all translations from CDS TxNative.fetchTranslations(null, null); diff --git a/TransifexNativeSDK/app/src/main/java/com/transifex/myapplication/MyApplication.java b/TransifexNativeSDK/app/src/main/java/com/transifex/myapplication/MyApplication.java index 37d9730..4a0ee41 100644 --- a/TransifexNativeSDK/app/src/main/java/com/transifex/myapplication/MyApplication.java +++ b/TransifexNativeSDK/app/src/main/java/com/transifex/myapplication/MyApplication.java @@ -48,13 +48,11 @@ protected void attachBaseContext(Context base) { new String[]{"en", "el", "de", "fr", "ar", "sl"}, null); - TxNative.init( - base, // application context - localeState, // a LocaleState instance - token, // token - null, // cdsHost URL - null, // a TxCache implementation - null); // a MissingPolicy implementation + TxNative.initializer(base, localeState, token) + .withCdsHost(null) // cdsHost URL + .withCache(null) // a TxCache implementation + .withMissingPolicy(null) // a MissingPolicy implementation + .init(); // OPTIONAL: // Wrap the application's base context to allow TxNative to intercept all string resource @@ -64,7 +62,8 @@ protected void attachBaseContext(Context base) { // strings translated. super.attachBaseContext(TxNative.wrap(base)); - // SAFER: Do not wrap the application's base context. + // SAFER: Do not wrap the application's base context. Just pass the base context as you + // would normally do. // super.attachBaseContext(base); } } diff --git a/TransifexNativeSDK/clitool/src/main/java/com/transifex/clitool/MainClass.java b/TransifexNativeSDK/clitool/src/main/java/com/transifex/clitool/MainClass.java index ec58eb8..8d67fcb 100644 --- a/TransifexNativeSDK/clitool/src/main/java/com/transifex/clitool/MainClass.java +++ b/TransifexNativeSDK/clitool/src/main/java/com/transifex/clitool/MainClass.java @@ -211,7 +211,7 @@ public Integer call() throws Exception { // Push to CDS CDSHandler cdsHandler = new CDSHandler(null, token, secret, - mainClass.hostURL); + mainClass.hostURL, null); LocaleData.TxJobStatus jobStatus = null; try { jobStatus = cdsHandler.pushSourceStrings(postData); @@ -265,7 +265,7 @@ public Integer call() throws Exception { // Push to CDS CDSHandler cdsHandler = new CDSHandler(null, token, secret, - mainClass.hostURL); + mainClass.hostURL, null); LocaleData.TxJobStatus jobStatus = null; try { jobStatus = cdsHandler.pushSourceStrings(postData); @@ -358,7 +358,7 @@ public Integer call() throws Exception { // Pull from CDS CDSHandler cdsHandler = new CDSHandler(translatedLocales, token, null, - mainClass.hostURL); + mainClass.hostURL, null); TranslationsDownloader downloader = new TranslationsDownloader(cdsHandler); HashMap downloadedFiles = downloader.downloadTranslations(null, tags, outDir, OUT_FILE_NAME); diff --git a/TransifexNativeSDK/common/src/main/java/com/transifex/common/CDSHandler.java b/TransifexNativeSDK/common/src/main/java/com/transifex/common/CDSHandler.java index 4e15563..ff01892 100644 --- a/TransifexNativeSDK/common/src/main/java/com/transifex/common/CDSHandler.java +++ b/TransifexNativeSDK/common/src/main/java/com/transifex/common/CDSHandler.java @@ -52,6 +52,9 @@ public class CDSHandler { // The host of the Content Delivery Service private final String mCdsHost; + // A custom authorization header key + private final String mCustomAuthorizationHeaderKey; + private final Gson mGson; /** @@ -99,18 +102,21 @@ void onTranslationFetched(@Nullable InputStream inputStream, @NonNull String loc /** * Creates a CDSHandler instance. * - * @param localeCodes An array of locale codes that can be downloaded from CDS. The source - * locale can also be included. - * @param token The API token to use for connecting to the CDS. - * @param secret The API secret to use for connecting to the CDS. - * @param csdHost The host of the Content Delivery Service. + * @param localeCodes An array of locale codes that can be downloaded from CDS. The source + * locale can also be included. + * @param token The API token to use for connecting to the CDS. + * @param secret The API secret to use for connecting to the CDS. + * @param csdHost The host of the Content Delivery Service. + * @param customAuthorizationHeaderKey A custom HTTP header name used to pass the token to CDS. */ public CDSHandler(@Nullable String[] localeCodes, - @NonNull String token, @Nullable String secret, @NonNull String csdHost) { + @NonNull String token, @Nullable String secret, @NonNull String csdHost, + String customAuthorizationHeaderKey) { mLocaleCodes = localeCodes; mToken = token; mSecret = secret; mCdsHost = csdHost; + mCustomAuthorizationHeaderKey = customAuthorizationHeaderKey; mGson = new Gson(); } @@ -547,11 +553,13 @@ private void addHeaders(@NonNull HttpURLConnection connection, boolean withSecre connection.addRequestProperty("Content-type", "application/json; charset=utf-8"); + String authorizationKey = (mCustomAuthorizationHeaderKey != null) ? + mCustomAuthorizationHeaderKey : "Authorization"; if (withSecret) { - connection.addRequestProperty("Authorization", "Bearer " + mToken + ":" + mSecret); + connection.addRequestProperty(authorizationKey, "Bearer " + mToken + ":" + mSecret); } else { - connection.addRequestProperty("Authorization", "Bearer " + mToken); + connection.addRequestProperty(authorizationKey, "Bearer " + mToken); } connection.addRequestProperty("x-native-sdk", "mobile/android/" + BuildProperties.getSDKVersion()); diff --git a/TransifexNativeSDK/common/src/test/java/com/transifex/common/CDSHandlerTest.java b/TransifexNativeSDK/common/src/test/java/com/transifex/common/CDSHandlerTest.java index 5900abf..091bdec 100644 --- a/TransifexNativeSDK/common/src/test/java/com/transifex/common/CDSHandlerTest.java +++ b/TransifexNativeSDK/common/src/test/java/com/transifex/common/CDSHandlerTest.java @@ -72,7 +72,7 @@ public void onFailure(@NonNull Exception exception) { @Test public void testFetchTranslationsCallback_badURL() { String[] localeCodes = new String[]{"el", "es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, "invalidHostURL"); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, "invalidHostURL", null); DummyFetchCallback callback = new DummyFetchCallback(); @@ -88,7 +88,7 @@ public void testFetchTranslationsCallback_normalResponse() { cdsMock.getServer().setDispatcher(CDSMockHelper.getElEsDispatcher()); String[] localeCodes = new String[]{"el", "es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); DummyFetchCallback callback = new DummyFetchCallback() { @@ -136,12 +136,38 @@ public void onTranslationFetched(@Nullable InputStream inputStream, @NonNull Str assertThat(recordedRequest.getHeader("Accept-version")).isEqualTo("v2"); } + @Test + public void testFetchTranslationsCallback_customAuthorizationHeaderKey() { + cdsMock.getServer().setDispatcher(CDSMockHelper.getElEsDispatcher()); + + String[] localeCodes = new String[]{"el", "es"}; + String customAuthorizationHeaderKey = "CustomKey"; + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), customAuthorizationHeaderKey); + + DummyFetchCallback callback = new DummyFetchCallback(); + + cdsHandler.fetchTranslations(null, null, callback); + + assertThat(callback.onFetchingTranslationsCalled).isTrue(); + assertThat(callback.onFetchingTranslationsCalled).isTrue(); + assertThat(callback.onFailureCalled).isFalse(); + + RecordedRequest recordedRequest = null; + try { + recordedRequest = cdsMock.getServer().takeRequest(); + } catch (InterruptedException ignored) { + } + assertThat(recordedRequest).isNotNull(); + assertThat(recordedRequest.getMethod()).isEqualTo("GET"); + assertThat(recordedRequest.getHeader(customAuthorizationHeaderKey)).isEqualTo("Bearer token"); + } + @Test public void testFetchTranslationsCallback_onlyElInResponse() { cdsMock.getServer().setDispatcher(CDSMockHelper.getElDispatcher()); String[] localeCodes = new String[]{"el", "es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); DummyFetchCallback callback = new DummyFetchCallback() { @@ -193,7 +219,7 @@ public void onTranslationFetched(@Nullable InputStream inputStream, @NonNull Str @Test public void testFetchTranslations_badURL() { String[] localeCodes = new String[]{"el", "es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, "invalidHostURL"); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, "invalidHostURL", null); LocaleData.TranslationMap map = cdsHandler.fetchTranslations(null, null); assertThat(map).isNotNull(); @@ -205,7 +231,7 @@ public void testFetchTranslations_normalResponse() { cdsMock.getServer().setDispatcher(CDSMockHelper.getElEsDispatcher()); String[] localeCodes = new String[]{"el", "es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); LocaleData.TranslationMap map = cdsHandler.fetchTranslations(null, null); @@ -241,7 +267,7 @@ public void testFetchTranslations_onlyElInResponse() { cdsMock.getServer().setDispatcher(CDSMockHelper.getElDispatcher()); String[] localeCodes = new String[]{"el", "es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); LocaleData.TranslationMap map = cdsHandler.fetchTranslations(null, null); assertThat(map).isNotNull(); @@ -259,7 +285,7 @@ public void testFetchTranslations_specifyLocale_normalResponse() { cdsMock.getServer().setDispatcher(CDSMockHelper.getElEsDispatcher()); String[] localeCodes = new String[]{"el", "es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); LocaleData.TranslationMap map = cdsHandler.fetchTranslations("el", null); assertThat(map).isNotNull(); @@ -277,7 +303,7 @@ public void testFetchTranslations_specifyTags_normalResponse() { cdsMock.getServer().setDispatcher(CDSMockHelper.getElEsWithTagsDispatcher()); String[] localeCodes = new String[]{"el", "es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); HashSet tags = new HashSet<>(Arrays.asList("tag a", "tag b")); LocaleData.TranslationMap map = cdsHandler.fetchTranslations(null, tags); @@ -302,7 +328,7 @@ public void testFetchTranslations_first202_thenNormalResponse() { cdsMock.getServer().setDispatcher(CDSMockHelper.getElEs202OnceDispatcher(10)); String[] localeCodes = new String[]{"el", "es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); LocaleData.TranslationMap map = cdsHandler.fetchTranslations(null, null); assertThat(map).isNotNull(); @@ -326,7 +352,7 @@ public void testFetchTranslations_only202() { cdsMock.getServer().setDispatcher(CDSMockHelper.getElEs202OnceDispatcher(30)); String[] localeCodes = new String[]{"el", "es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); LocaleData.TranslationMap map = cdsHandler.fetchTranslations(null, null); assertThat(map).isNotNull(); @@ -338,7 +364,7 @@ public void testFetchTranslations_onlyElInResponse_badJSONFormatting() { cdsMock.getServer().setDispatcher(CDSMockHelper.getElDispatcherBadJsonFormatting()); String[] localeCodes = new String[]{"el"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); LocaleData.TranslationMap map = cdsHandler.fetchTranslations(null, null); assertThat(map).isNotNull(); @@ -347,7 +373,7 @@ public void testFetchTranslations_onlyElInResponse_badJSONFormatting() { @Test public void testPushSourceStrings_badURL() { - CDSHandler cdsHandler = new CDSHandler(null, "token", "secret", "invalidHostURL"); + CDSHandler cdsHandler = new CDSHandler(null, "token", "secret", "invalidHostURL", null); LocaleData.TxPostData postData = getPostData(); LocaleData.TxJobStatus jobStatus = null; @@ -362,7 +388,7 @@ public void testPushSourceStrings_badURL() { public void testPushSourceStrings_normal() { cdsMock.getServer().setDispatcher(CDSMockHelper.getPostDispatcher()); - CDSHandler cdsHandler = new CDSHandler(null, "token", "secret", cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(null, "token", "secret", cdsMock.getBaseUrl(), null); LocaleData.TxPostData postData = getPostData(); LocaleData.TxJobStatus jobStatus = null; @@ -398,7 +424,7 @@ public void testPushSourceStrings_normal() { public void testPushSourceStrings_CDSRespondsWith409_returnNull() { cdsMock.getServer().setDispatcher(CDSMockHelper.getPostWith409Dispatcher()); - CDSHandler cdsHandler = new CDSHandler(null, "token", "secret", cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(null, "token", "secret", cdsMock.getBaseUrl(), null); LocaleData.TxPostData postData = getPostData(); LocaleData.TxJobStatus jobStatus = null; @@ -414,7 +440,7 @@ public void testPushSourceStrings_CDSRespondsWith409_returnNull() { public void testPushSourceStrings_CDSRespondsWithFailedJob_returnErrorInResponse() { cdsMock.getServer().setDispatcher(CDSMockHelper.getPostWithFailedJobDispatcher()); - CDSHandler cdsHandler = new CDSHandler(null, "token", "secret", cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(null, "token", "secret", cdsMock.getBaseUrl(), null); LocaleData.TxPostData postData = getPostData(); LocaleData.TxJobStatus jobStatus = null; diff --git a/TransifexNativeSDK/common/src/test/java/com/transifex/common/TranslationsDownloaderTest.java b/TransifexNativeSDK/common/src/test/java/com/transifex/common/TranslationsDownloaderTest.java index 755bc04..3f88032 100644 --- a/TransifexNativeSDK/common/src/test/java/com/transifex/common/TranslationsDownloaderTest.java +++ b/TransifexNativeSDK/common/src/test/java/com/transifex/common/TranslationsDownloaderTest.java @@ -46,7 +46,7 @@ public void Teardown() { @Test public void testSaveTranslations_dirDoesNotExist() { String[] localeCodes = new String[]{"el", "es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); TranslationsDownloader downloader = new TranslationsDownloader(cdsHandler); HashMap translationFiles = downloader.downloadTranslations(null, null, tempDir.getFile(), "strings.txt"); @@ -63,7 +63,7 @@ public void testSaveTranslations_normalResponse() { assertThat(tempDirCreated).isTrue(); String[] localeCodes = new String[]{"el", "es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); TranslationsDownloader downloader = new TranslationsDownloader(cdsHandler); HashMap translationFiles = downloader.downloadTranslations(null, null, tempDir.getFile(), "strings.txt"); @@ -108,7 +108,7 @@ public void testSaveTranslations_onlyElInResponse() { assertThat(tempDirCreated).isTrue(); String[] localeCodes = new String[]{"el", "es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); TranslationsDownloader downloader = new TranslationsDownloader(cdsHandler); HashMap translationFiles = downloader.downloadTranslations(null, null, tempDir.getFile(), "strings.txt"); @@ -132,7 +132,7 @@ public void testSaveTranslations_specifyLocale_normalResponse() { assertThat(tempDirCreated).isTrue(); String[] localeCodes = new String[]{"el", "es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); TranslationsDownloader downloader = new TranslationsDownloader(cdsHandler); HashMap translationFiles = downloader.downloadTranslations("el", null, tempDir.getFile(), "strings.txt"); @@ -156,7 +156,7 @@ public void testSaveTranslations_specifyTags_normalResponse() { assertThat(tempDirCreated).isTrue(); String[] localeCodes = new String[]{"el", "es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); TranslationsDownloader downloader = new TranslationsDownloader(cdsHandler); Set tags = new HashSet<>(Arrays.asList("tag a", "tag b")); @@ -198,7 +198,7 @@ public void testSaveTranslations_overwriteExistingFile() { } catch (IOException ignored) {} String[] localeCodes = new String[]{"el"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); TranslationsDownloader downloader = new TranslationsDownloader(cdsHandler); HashMap translationFiles = downloader.downloadTranslations(null, null, tempDir.getFile(), "strings.txt"); @@ -231,7 +231,7 @@ public void testSaveTranslations_skipExistingFileIfError() { } catch (IOException ignored) {} String[] localeCodes = new String[]{"es"}; - CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl()); + CDSHandler cdsHandler = new CDSHandler(localeCodes, "token", null, cdsMock.getBaseUrl(), null); TranslationsDownloader downloader = new TranslationsDownloader(cdsHandler); HashMap translationFiles = downloader.downloadTranslations(null, null, tempDir.getFile(), "strings.txt"); diff --git a/TransifexNativeSDK/doc/readme.html b/TransifexNativeSDK/doc/readme.html index 2f0eab1..8cbb7ba 100644 --- a/TransifexNativeSDK/doc/readme.html +++ b/TransifexNativeSDK/doc/readme.html @@ -15,7 +15,7 @@

advantage of the features that Transifex Native offers, such as OTA translations.

SDK installation

Include the dependency:

-
implementation 'com.transifex.txnative:txsdk:x.y.z'
+
implementation 'com.transifex.txnative:txsdk:x.y.z'
 

Please replace x, y and z with the latest version numbers: Maven Central

The library’s minimum supported SDK is 18 (Android 4.3).

@@ -23,89 +23,81 @@

SDK configuration

Configure the SDK in your Application class.

The language codes supported by Transifex can be found here. They can either use 2 characters, such as es, or specify the regional code as well, such as es_ES. Keep in mind that in the sample code below you will have to replace <transifex_token> with the actual token that is associated with your Transifex project and resource.

-
@Override
+
@Override
 public void onCreate() {
     super.onCreate();
 
     // Initialize TxNative
-    String token = "<transifex_token>";
+    String token = "<transifex_token>";
 
     LocaleState localeState = new LocaleState(getApplicationContext(),
         // source locale
-        "en",
+        "en",
         // supported locales
-        new String[]{"en", "el", "de", "fr", "ar", "sl", "es_ES", "es_MX"},
+        new String[]{"en", "el", "de", "fr", "ar", "sl", "es_ES", "es_MX"},
         null);
 
-    TxNative.init(
-        // application context
-        getApplicationContext(),
-        // a LocaleState instance
-        localeState,
-        // token
-        token,
-        // cdsHost URL
-        null,
-        // a TxCache implementation
-        null,
-        // a MissingPolicy implementation
-        null);
+    TxNative.initializer(base, localeState, token)
+                .withCdsHost(null)           // cdsHost URL
+                .withCache(null)             // a TxCache implementation
+                .withMissingPolicy(null)     // a MissingPolicy implementation
+                .init();
 
     // Fetch all translations from CDS
     TxNative.fetchTranslations(null, null);
 }
 
-

In this example, the SDK uses its default cache, TxStandardCache, and default missing policy, SourceStringPolicy. However, you can choose between different cache and missing policy implementations or even provide your own. For example, if you want to fallback to translations provided via strings.xml files, use the AndroidMissingPolicy. You can read more about cache implementations later on.

-

In this example, we fetch the translations for all locales. If you want, you can target specific locales or strings that have specific tags.

-

App configuration

-

Starting from Android N, Android has multilingual support: users can select more that one locale in Android’s settings and the OS will try to pick the topmost locale that is supported by the app. Place the supported app languages in your app’s gradle file:

-
android {
+

In this example, the SDK uses its default cache, TxStandardCache, and default missing policy, SourceStringPolicy. However, you can choose between different cache and missing policy implementations or even provide your own. For example, if you want to fallback to translations provided via strings.xml files, use the AndroidMissingPolicy. You can read more about cache implementations later on.

+

In this example, we fetch the translations for all locales. If you want, you can target specific locales or strings that have specific tags.

+

App configuration

+

Starting from Android N, Android has multilingual support: users can select more that one locale in Android’s settings and the OS will try to pick the topmost locale that is supported by the app. Place the supported app languages in your app’s gradle file:

+
android {
     ...
     defaultConfig {
-        resourceConfigurations += ['en', 'el', 'de', 'fr', 'ar', 'sl', 'es_ES', 'es_MX']
+        resourceConfigurations += ['en', 'el', 'de', 'fr', 'ar', 'sl', 'es_ES', 'es_MX']
     }
 }
 
-

This will let Android know which locales your app supports and help it choose the correct one in case of a multilingual user.

-

For some languages such as Kinyarwanda, you will need to do some more work. You should define a dummy string in your default, unlocalized strings.xml file and place a strings.xml file for that locale and define the same string there. For example:

-
<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <string name="dummy">dummy</string>
-</resources>
+

This will let Android know which locales your app supports and help it choose the correct one in case of a multilingual user.

+

For some languages such as Kinyarwanda, you will need to do some more work. You should define a dummy string in your default, unlocalized strings.xml file and place a strings.xml file for that locale and define the same string there. For example:

+
<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="dummy">dummy</string>
+</resources>
 
-

If you don’t do that, Android will never choose that language.

-

Context Wrapping

-

The SDK’s functionality is enabled by wrapping the context, so that all string resource related methods, such a getString(), getText(), flow through the SDK.

-

To enable context wrapping in your AppCompatActivity, extend the SDK’s TxBaseAppcompatActivity or copy its implementation to your own base class.
+

If you don’t do that, Android will never choose that language.

+

Context Wrapping

+

The SDK’s functionality is enabled by wrapping the context, so that all string resource related methods, such a getString(), getText(), flow through the SDK.

+

To enable context wrapping in your AppCompatActivity, extend the SDK’s TxBaseAppcompatActivity or copy its implementation to your own base class.
If you are using an older AppCompat version, please read the class’s implementation as you may need to uncomment some code.

-

If you want to use the SDK outside an activity’s context, such as a service context, make sure that you wrap the context:

-
public class SimpleIntentService extends JobIntentService {
+

If you want to use the SDK outside an activity’s context, such as a service context, make sure that you wrap the context:

+
public class SimpleIntentService extends JobIntentService {
 
-    @Override
+    @Override
     protected void attachBaseContext(Context newBase) {
         super.attachBaseContext(TxNative.wrap(newBase));
     }
 }
 
-

If you want to use the SDK in some arbitrary place where you can get your application’s context, please do the following:

-
...
+

If you want to use the SDK in some arbitrary place where you can get your application’s context, please do the following:

+
...
 // Wrap the context
 Context wrappedContext = TxNative.wrap(getApplicationContext());
 // Use the wrapped context for getting a string
 wrappedContext.getString();
 
-

If you want to wrap the application context itself, you need to move the SDK’s initialization from the application’s onCreate() to attachBaseContext():

-
 @Override
+

If you want to wrap the application context itself, you need to move the SDK’s initialization from the application’s onCreate() to attachBaseContext():

+
 @Override
  protected void attachBaseContext(Context base) {
     // Initialize TxNative
-    String token = "<transifex_token>";
+    String token = "<transifex_token>";
 
     LocaleState localeState = new LocaleState(
         base,   // Use the base context instead of getApplicationContext()
         // source locale
-        "en",
+        "en",
         // supported locales
-        new String[]{"en", "el", "de", "fr", "ar", "sl", "es_ES", "es_MX"},
+        new String[]{"en", "el", "de", "fr", "ar", "sl", "es_ES", "es_MX"},
         null);
 
     TxNative.init(
@@ -126,25 +118,25 @@ 

super.attachBaseContext(TxNative.wrap(base)); }

-

Note though that this global wrapper can interfere with third-party libraries that use their own string resources. In that case, use “AndroidMissingPolicy” so that these libraries have their strings translated.

-

If you want to disable the SDK functionality, don’t initialize it and don’t call any TxNative methods. TxNative.wrap() will be a no-op and the context will not be wrapped. Thus, all getString() etc methods, won’t flow through the SDK.

-

Cache

-

The SDK relies on a cache mechanism to return source strings and translations for the supported locales. If the cache is empty, the SDK will return a string based on the current missing policy.

-

The cache is updated when fetchTranslations() is called. You can read more on that later.

-

The cache can be prepopulated by the developer, using the command-line tool’s pull command.

-

Standard Cache

-

The default cache strategy used by the SDK, if no other cache is provided by the developer, is returned by TxStandardCache.getCache(). The standard cache operates by making use of the publicly exposed classes and interfaces from the com.transifex.txnative.cache package of the SDK, so it’s easy to construct another cache strategy if that’s desired.

-

The standard cache is initialized with a memory cache that manages all cached entries in memory. When the memory cache gets initialized, it tries to look up if there are any already stored translations in the file system:

+

Note though that this global wrapper can interfere with third-party libraries that use their own string resources. In that case, use “AndroidMissingPolicy” so that these libraries have their strings translated.

+

If you want to disable the SDK functionality, don’t initialize it and don’t call any TxNative methods. TxNative.wrap() will be a no-op and the context will not be wrapped. Thus, all getString() etc methods, won’t flow through the SDK.

+

Cache

+

The SDK relies on a cache mechanism to return source strings and translations for the supported locales. If the cache is empty, the SDK will return a string based on the current missing policy.

+

The cache is updated when fetchTranslations() is called. You can read more on that later.

+

The cache can be prepopulated by the developer, using the command-line tool’s pull command.

+

Standard Cache

+

The default cache strategy used by the SDK, if no other cache is provided by the developer, is returned by TxStandardCache.getCache(). The standard cache operates by making use of the publicly exposed classes and interfaces from the com.transifex.txnative.cache package of the SDK, so it’s easy to construct another cache strategy if that’s desired.

+

The standard cache is initialized with a memory cache that manages all cached entries in memory. When the memory cache gets initialized, it tries to look up if there are any already stored translations in the file system:

    -
  • First, it looks for translations saved in the app’s Assets directory that may have been offered by the developer, using the command-line tool when building the app.
  • -
  • Secondly, it looks for translations in the app’s internal cache directory, in case the app had already downloaded the translations from the server from a previous launch. These translations take precedence over the previous ones, if found.
  • +
  • First, it looks for translations saved in the app’s Assets directory that may have been offered by the developer, using the command-line tool when building the app.
  • +
  • Secondly, it looks for translations in the app’s internal cache directory, in case the app had already downloaded the translations from the server from a previous launch. These translations take precedence over the previous ones, if found.
-

Whenever new translations are fetched from the server using the fetchTranslations() method, the standard cache is updated and those translations are stored as-is in the app’s cache directory, in the same directory used previsouly during initialization. The in-memory cache though is not affected by the update. An app restart is required to read the newly saved translations.

-

Under the SDK’s default configuration, the first time the app is launched, the source strings are displayed, unless the developer has bundled translations via the command-line tool.

-

Alternative cache strategy

-

The SDK allows you to implement your own cache from scratch by implementing the TxCache interface. Alternatively, you may change the standard cache strategy by implementing your own using the SDK’s publicly exposed classes.

-

In order to achieve that, you can create a a method that returns an object that implements TxCache. For example, the standard cache is created as follows (you can see the full source code here):

-
return new TxFileOutputCacheDecorator(
+

Whenever new translations are fetched from the server using the fetchTranslations() method, the standard cache is updated and those translations are stored as-is in the app’s cache directory, in the same directory used previsouly during initialization. The in-memory cache though is not affected by the update. An app restart is required to read the newly saved translations.

+

Under the SDK’s default configuration, the first time the app is launched, the source strings are displayed, unless the developer has bundled translations via the command-line tool.

+

Alternative cache strategy

+

The SDK allows you to implement your own cache from scratch by implementing the TxCache interface. Alternatively, you may change the standard cache strategy by implementing your own using the SDK’s publicly exposed classes.

+

In order to achieve that, you can create a a method that returns an object that implements TxCache. For example, the standard cache is created as follows (you can see the full source code here):

+
return new TxFileOutputCacheDecorator(
     <cached Translations Directory>,
     new TXReadonlyCacheDecorator(
         new TxProviderBasedCache(
@@ -157,130 +149,130 @@ 

If you want to have your memory cache updated with the new translations when fetchTranslations() is called, you can remove the TXReadonlyCacheDecorator.

-

Fetching translations

-

As soon as fetchTranslations() is called, the SDK will attempt to download both the source locale strings
+

If you want to have your memory cache updated with the new translations when fetchTranslations() is called, you can remove the TXReadonlyCacheDecorator.

+

Fetching translations

+

As soon as fetchTranslations() is called, the SDK will attempt to download both the source locale strings
and the translations for the supported locales. If successful, it will update the cache.

-

The fetchTranslations() method in the SDK configuration example is called as soon as the application launches, but that’s not required. Depending on the application, the developer might choose to call that method whenever it is most appropriate (for example, each time the application is brought to the foreground or when the internet connectivity is established).

-

Transifex Command Line Tool

-

Transifex Command Line Tool is a command line tool that can assist developers in pushing the source strings of an Android app to Transifex.

-

Building

-

You can get the cli tool pre-built from the release page.

-

If you want to build the tool yourself, enter the TransifexNativeSDK directory and run from the command line:

-
gradlew :clitool:assemble
+

The fetchTranslations() method in the SDK configuration example is called as soon as the application launches, but that’s not required. Depending on the application, the developer might choose to call that method whenever it is most appropriate (for example, each time the application is brought to the foreground or when the internet connectivity is established).

+

Transifex Command Line Tool

+

Transifex Command Line Tool is a command line tool that can assist developers in pushing the source strings of an Android app to Transifex.

+

Building

+

You can get the cli tool pre-built from the release page.

+

If you want to build the tool yourself, enter the TransifexNativeSDK directory and run from the command line:

+
gradlew :clitool:assemble
 
-

You will find the built .jar file at clitool/build/libs/transifex.jar. You can copy it wherever you want.

-

Running

-

To run the tool, type:

-
java -jar /path/to/transifex.jar
+

You will find the built .jar file at clitool/build/libs/transifex.jar. You can copy it wherever you want.

+

Running

+

To run the tool, type:

+
java -jar /path/to/transifex.jar
 
-

where /path/to/ is the path to the directory you placed “transifex.jar”.

-

Note that even though the tool uses UTF-8 internally, it’s recommended to have your JVM’s default character encoding set to UTF-8. If this isn’t the case for your system, you can use:

-
java -jar -Dfile.encoding=UTF8 /path/to/transifex.jar
+

where /path/to/ is the path to the directory you placed “transifex.jar”.

+

Note that even though the tool uses UTF-8 internally, it’s recommended to have your JVM’s default character encoding set to UTF-8. If this isn’t the case for your system, you can use:

+
java -jar -Dfile.encoding=UTF8 /path/to/transifex.jar
 
-

For simplicity, the following commands will not include the java -jar part required to run the file.

-

Usage

-

To use the tool on your app’s Android Studio project, enter the root directory of your project from the command line.

-

Help

-

transifex, transifex -h, transifex --help
+

For simplicity, the following commands will not include the java -jar part required to run the file.

+

Usage

+

To use the tool on your app’s Android Studio project, enter the root directory of your project from the command line.

+

Help

+

transifex, transifex -h, transifex --help
Displays a help dialog with all the options and commands.

-

transifex help <command>
+

transifex help <command>
Get help for a particular command.

-

Pushing

-

transifex push -t <transifex_token> -s <transifex_secret> -m <app_module_name>
+

Pushing

+

transifex push -t <transifex_token> -s <transifex_secret> -m <app_module_name>
Pushes the source strings of your app found in a module named “app_module_name”. The tool reads the strings.xml resource file found in the main source set of the specified module: app_module_name/src/main/res/values/strings.xml. It processes it and pushes the result to the Transifex CDS.

-

transifex push -t <transifex_token> -s <transifex_secret> -f path/to/strings1.xml path2/to/strings2.xml ...
+

transifex push -t <transifex_token> -s <transifex_secret> -f path/to/strings1.xml path2/to/strings2.xml ...
If your app has a more complex string setup, you can specify one or more string resource files.

-

transifex push -t <transifex_token> -s <transifex_secret> -m <app_module_name> --dry-run -v
+

transifex push -t <transifex_token> -s <transifex_secret> -m <app_module_name> --dry-run -v
Append --dry-run -v to display the source strings that will be pushed without actually pushing them.

-

transifex clear -t <transifex_token> -s <transifex_secret>
+

transifex clear -t <transifex_token> -s <transifex_secret>
Clears all existing resource content from CDS. This action will also remove existing localizations.

-

Pulling

-

transifex pull -t <transifex_token> -m <app_module_name> -l <locale>...
+

Pulling

+

transifex pull -t <transifex_token> -m <app_module_name> -l <locale>...
Downloads the translations from Transifex CDS for the specified locales and stores them in txstrings.json files under the “assets” directory of the main source set of the specified app module: app_module_name/src/main/assets/txnative. The directory is created if needed. These files will be bundled inside your app and accessed by TxNative.

-

transifex pull -t <transifex_token> -d <directory> -l <locale>...
+

transifex pull -t <transifex_token> -d <directory> -l <locale>...
If you have a different setup, you can enter the path to your app’s assets directory.

-

Note that cache of CDS has a TTL of 30 minutes. If you update some translations on Transifex
+

Note that cache of CDS has a TTL of 30 minutes. If you update some translations on Transifex
and you need to see them on your app immediately or pull them using the above command, you need to make an HTTP request
to the invalidation endpoint of CDS.

-

Advanced topics

-

Disable TxNative for specific strings

-

There are cases where you don’t want TxNative to interfere with string loading. For example, many apps have API keys or some configuration saved in non-translatable strings in their strings.xml file. A method like getString() is used to retrieve the strings. If you are using the SDK’s default missing policy, SourceStringPolicy, the expected string will be returned. If, however, you are using some other policy, the string may be altered and your app will not behave as expected. In such a case, make sure that you are using a non-wrapped context when loading such a string:

-
getApplicationContext().getString(<string_ID>);
+

Advanced topics

+

Disable TxNative for specific strings

+

There are cases where you don’t want TxNative to interfere with string loading. For example, many apps have API keys or some configuration saved in non-translatable strings in their strings.xml file. A method like getString() is used to retrieve the strings. If you are using the SDK’s default missing policy, SourceStringPolicy, the expected string will be returned. If, however, you are using some other policy, the string may be altered and your app will not behave as expected. In such a case, make sure that you are using a non-wrapped context when loading such a string:

+
getApplicationContext().getString(<string_ID>);
 
-

String styling

-

As explained in Android’s documentation, strings can have styling applied to them if they contain HTML markup. There are two ways to accomplish that.

-

Write a string with HTML markup. For example:

-
<string name="styled_text">A <font color="#FF7700">localization</font> platform</string>
+

String styling

+

As explained in Android’s documentation, strings can have styling applied to them if they contain HTML markup. There are two ways to accomplish that.

+

Write a string with HTML markup. For example:

+
<string name="styled_text">A <font color="#FF7700">localization</font> platform</string>
 
-

The SDK will parse the tags into spans so that styling is applied. You can reference such a string in a layout XML file or use getText() (not getString()) and set it programmatically to the desired view. To disable this behavior and treat tags as plain text, you can disable span support by calling TxNative.setSupportSpannable(false).
+

The SDK will parse the tags into spans so that styling is applied. You can reference such a string in a layout XML file or use getText() (not getString()) and set it programmatically to the desired view. To disable this behavior and treat tags as plain text, you can disable span support by calling TxNative.setSupportSpannable(false).
Note that when span support is enabled and tags are detected in a string, the SDK uses fromHTML(). This has the side-effect of new lines being converted to spaces and sequences of whitespace characters being collapsed into a single space.

-

Alternatively, you can write a string with the opening brackets escaped (using &lt; instead of <):

-
<string name="styled_text">A &lt;font color="#FF7700">localization&lt;/font> platform</string>
+

Alternatively, you can write a string with the opening brackets escaped (using &lt; instead of <):

+
<string name="styled_text">A &lt;font color="#FF7700">localization&lt;/font> platform</string>
 
-

Then, you can use fromHTML() to get styled text as shown below:

-
String string = getResources().getString(R.string.styled_text);
+

Then, you can use fromHTML() to get styled text as shown below:

+
String string = getResources().getString(R.string.styled_text);
 Spanned styledTest = HtmlCompat.fromHtml(string, HtmlCompat.FROM_HTML_MODE_COMPACT);
 someView.setText(styledText);
 
-

Stylable attributes

-

Android lets you define attributes that can point to different string resources, according to the current theme. For example you can create an attr.xml file that declares a stylable:

-
<declare-styleable name="custom_view">
-    <attr name="label" format="string|reference"/>
-</declare-styleable>
+

Stylable attributes

+

Android lets you define attributes that can point to different string resources, according to the current theme. For example you can create an attr.xml file that declares a stylable:

+
<declare-styleable name="custom_view">
+    <attr name="label" format="string|reference"/>
+</declare-styleable>
 
-

You can set the string value of this attribute to a TextView the following way:

-
TypedValue typedValue = new TypedValue();
+

You can set the string value of this attribute to a TextView the following way:

+
TypedValue typedValue = new TypedValue();
 getTheme().resolveAttribute(R.attr.label, typedValue, true);
 textView.setText(typedValue.resourceId);
-// textView.setText(typedValue.string); // DON'T DO THAT!!!
+// textView.setText(typedValue.string); // DON'T DO THAT!!!
 
-

or the following way:

-
TypedArray typedArray  = getTheme().obtainStyledAttributes(set, R.styleable.custom_view, defStyleAttr, defStyleRes);
+

or the following way:

+
TypedArray typedArray  = getTheme().obtainStyledAttributes(set, R.styleable.custom_view, defStyleAttr, defStyleRes);
 textView.setText(typedArray.getResourceId(R.styleable.custom_view_label, -1)); // Get the resource id of the stylable attribute under the current theme
-// textView.setText(typedArray.getString(R.styleable.custom_view_label, -1)); // DON'T DO THAT!!!
+// textView.setText(typedArray.getString(R.styleable.custom_view_label, -1)); // DON'T DO THAT!!!
 typedArray.recycle();
 
-

Note that if you try to resolve the string value directly from the theme methods, the call will not pass through the SDK. The trick here is to resolve the resource id from the theme methods.

-

TxNative and 3rd party libraries

-

Some libs may contain their own localized strings, views or activities. In such as case, you don’t want TxNative to interfere with string loading. To accomplish that, make sure that you pass a non-wrapped context to the library’s initialization method:

-
SomeSDK.init(getApplicationContext());
+

Note that if you try to resolve the string value directly from the theme methods, the call will not pass through the SDK. The trick here is to resolve the resource id from the theme methods.

+

TxNative and 3rd party libraries

+

Some libs may contain their own localized strings, views or activities. In such as case, you don’t want TxNative to interfere with string loading. To accomplish that, make sure that you pass a non-wrapped context to the library’s initialization method:

+
SomeSDK.init(getApplicationContext());
 
-

Note however that if a View provided by the library is used inside your app’s activity, TxNative will be used during that view’s inflation (if your activity is set up correctly). In that case, any library strings will not be found in TxNative translations and the result will depend on the missing policy used. SourceStringPolicy will return the source string provided by the library, which will probably be in English. Using, AndroidMissingPolicy will return the localized string using the library’s localized string resources, as expected.

-

Multiple private libraries

-

If your app is split into libraries that contain localized strings, views or activities, you need to set up your project in the following way to take advantage of TxNatve in said libs.

-

The strings included in the libraries have to be pushed to the CDS. You can push all of them at once using the push CLI command, e.g.
+

Note however that if a View provided by the library is used inside your app’s activity, TxNative will be used during that view’s inflation (if your activity is set up correctly). In that case, any library strings will not be found in TxNative translations and the result will depend on the missing policy used. SourceStringPolicy will return the source string provided by the library, which will probably be in English. Using, AndroidMissingPolicy will return the localized string using the library’s localized string resources, as expected.

+

Multiple private libraries

+

If your app is split into libraries that contain localized strings, views or activities, you need to set up your project in the following way to take advantage of TxNatve in said libs.

+

The strings included in the libraries have to be pushed to the CDS. You can push all of them at once using the push CLI command, e.g.
transifex push -t <transifex_token> -s <transifex_secret> -f path/to/strings1.xml path2/to/strings2.xml. Alternatively, you can push each one separately as long as all strings reach the CDS resource used by the main app.

-

If your lib has an initialization method, make sure that your main app passes the wrapped context:

-
YourLib.init(TxNative.wrap(getApplicationContext()));
+

If your lib has an initialization method, make sure that your main app passes the wrapped context:

+
YourLib.init(TxNative.wrap(getApplicationContext()));
 
-

The following string operations will result in string rendering through TxNative:

+

The following string operations will result in string rendering through TxNative:

    -
  • The main app uses, in a layout or programmatically, the strings that the lib provides.
  • -
  • The lib calls string resource methods such as getString(), e.g. for logging or something else, using the context that the main app passes through initialization.
  • -
  • The lib has views that reference strings via layout or code and the main app displays these views in its activities.
  • +
  • The main app uses, in a layout or programmatically, the strings that the lib provides.
  • +
  • The lib calls string resource methods such as getString(), e.g. for logging or something else, using the context that the main app passes through initialization.
  • +
  • The lib has views that reference strings via layout or code and the main app displays these views in its activities.
-

Note that if the main app starts any activity provided by the lib, string rendering won’t go through TxNative. If you want to achieve this, you will have to integrate TxNative in the lib by following these steps:

+

Note that if the main app starts any activity provided by the lib, string rendering won’t go through TxNative. If you want to achieve this, you will have to integrate TxNative in the lib by following these steps:

    -
  1. Use TxNative as a dependency in the lib.
  2. -
  3. Implement TxNative in the lib’s activities.
  4. -
  5. Note that TxNative should not be initialized inside the lib. The main app is responsible for this.
  6. +
  7. Use TxNative as a dependency in the lib.
  8. +
  9. Implement TxNative in the lib’s activities.
  10. +
  11. Note that TxNative should not be initialized inside the lib. The main app is responsible for this.
-

Limitations

-

The SDK has some limitations, which most of the time can be overcome with workarouds.

-

String Arrrays

-

Currently, the SDK does not support String arrays. The command line tool will not upload them to Transifex and the SDK will not override the respective methods. String arrays presentation will work as normal using Android’s localization system, which will require that you have them translated in the respective strings.xml files.

-

Menu XML files

-

Strings that are referenced in menu layout files will not be handled by the SDK. They will use Android’s localization system as normal.

-

ActionBar

-

Even though the SDK handles the strings referenced in a Toolbar, it won’t handle strings referenced in an ActionBar. You will have to set them programmatically (e.g. by calling setTitle()) to take advantage of the SDK. Otherwise, Android’s localization system will be used.

-

Video resources

+

Limitations

+

The SDK has some limitations, which most of the time can be overcome with workarouds.

+

String Arrrays

+

Currently, the SDK does not support String arrays. The command line tool will not upload them to Transifex and the SDK will not override the respective methods. String arrays presentation will work as normal using Android’s localization system, which will require that you have them translated in the respective strings.xml files.

+

Menu XML files

+

Strings that are referenced in menu layout files will not be handled by the SDK. They will use Android’s localization system as normal.

+

ActionBar

+

Even though the SDK handles the strings referenced in a Toolbar, it won’t handle strings referenced in an ActionBar. You will have to set them programmatically (e.g. by calling setTitle()) to take advantage of the SDK. Otherwise, Android’s localization system will be used.

+

Video resources

-

License

-

Licensed under Apache License 2.0, see LICENSE file.

+

License

+

Licensed under Apache License 2.0, see LICENSE file.

\ No newline at end of file diff --git a/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/CDSHandlerAndroid.java b/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/CDSHandlerAndroid.java index b227df6..b8ab7e9 100644 --- a/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/CDSHandlerAndroid.java +++ b/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/CDSHandlerAndroid.java @@ -54,7 +54,7 @@ interface FetchTranslationsCallback { * @param csdHost The host of the Content Delivery Service. */ public CDSHandlerAndroid(@Nullable String[] localeCodes, @NonNull String token, @Nullable String secret, @NonNull String csdHost) { - super(localeCodes, token, secret, csdHost); + super(localeCodes, token, secret, csdHost, null); mExecutor = Executors.newSingleThreadExecutor(); } diff --git a/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/NativeCore.java b/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/NativeCore.java index 9b83516..dd5de67 100644 --- a/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/NativeCore.java +++ b/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/NativeCore.java @@ -47,22 +47,24 @@ public class NativeCore { *

* We initialize and set-up the rest of the SDK classes and enable ViewPump interception. * - * @param applicationContext The application context. - * @param localeState Keeps track of the available and current locales. - * @param token The Transifex token that can be used for retrieving translations from CDS. - * @param cdsHost An optional host for the Content Delivery Service; defaults to the production - * host provided by Transifex. - * @param cache The translation cache that holds the translations from the CDS; - * {@link com.transifex.txnative.cache.TxStandardCache TxStandardCache} is used if set to - * null. - * @param missingPolicy Determines how to handle translations that are not available; - * {@link com.transifex.txnative.missingpolicy.SourceStringPolicy SourceStringPolicy} is used - * if set to null. + * @param applicationContext The application context. + * @param localeState Keeps track of the available and current locales. + * @param token The Transifex token that can be used for retrieving translations from CDS. + * @param cdsHost An optional host for the Content Delivery Service; defaults to the production + * host provided by Transifex. + * @param customAuthorizationHeaderKey + * @param cache The translation cache that holds the translations from the CDS; + * {@link TxStandardCache TxStandardCache} is used if set to + * null. + * @param missingPolicy Determines how to handle translations that are not available; + * {@link SourceStringPolicy SourceStringPolicy} is used + * if set to null. */ public NativeCore(@NonNull Context applicationContext, @NonNull LocaleState localeState, @NonNull String token, @Nullable String cdsHost, + String customAuthorizationHeaderKey, @Nullable TxCache cache, @Nullable MissingPolicy missingPolicy) { mContext = applicationContext; diff --git a/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/TxNative.java b/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/TxNative.java index 1accb88..41b2c8f 100644 --- a/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/TxNative.java +++ b/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/TxNative.java @@ -14,7 +14,6 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatDelegate; -import androidx.appcompat.app.TxContextWrappingDelegateJava2; import androidx.appcompat.app.ViewPumpAppCompatDelegate; import dev.b3nedikt.viewpump.ViewPump; @@ -46,6 +45,8 @@ public class TxNative { * @param missingPolicy Determines how to handle translations that are not available; * {@link com.transifex.txnative.missingpolicy.SourceStringPolicy SourceStringPolicy} is used * if set to null. + * @deprecated Use {@link #initializer(Context, LocaleState, String)} to initialize the SDK with a builder pattern. + * For example: {@code TxNative.builder(applicationContext, locales, token).init();} */ public static void init(@NonNull Context applicationContext, @NonNull LocaleState locales, @@ -54,19 +55,133 @@ public static void init(@NonNull Context applicationContext, @Nullable TxCache cache, @Nullable MissingPolicy missingPolicy) { - if (sNativeCore != null) { - throw new RuntimeException("TxNative is already initialized"); + TxNative.initializer(applicationContext, locales, token) + .withCdsHost(cdsHost) + .withCache(cache) + .withMissingPolicy(missingPolicy) + .init(); + } + + // region Builder pattern for Initialization + + /** + * Entry point for initializing the SDK. You need to call {@link Initializer#init()} to complete + * initialization. + *

+ * Should be called in {@link Application#onCreate()} or + * {@link Application#attachBaseContext(Context)}. + *

+ * + * @param applicationContext The application context. + * @param locales Configures the locales supported by the SDK. + * @param token The Transifex token that can be used for retrieving translations from CDS. + * + * @return An Initializer instance to configure optional parameters and finally call + * {@code init()}. + */ + public static Initializer initializer(@NonNull Context applicationContext, + @NonNull LocaleState locales, + @NonNull String token) { + return new Initializer(applicationContext, locales, token); + } + + + /** + * Builder class for initializing the SDK. + */ + public static class Initializer { + private final Context applicationContext; + private final LocaleState locales; + private final String token; + private String cdsHost = null; + private TxCache cache = null; + private MissingPolicy missingPolicy = null; + private String customAuthorizationHeaderKey = null; + + /** + * Creates an Initializer with mandatory parameters. + * + * @param applicationContext The application context. + * @param locales Configures the locales supported by the SDK. + * @param token The Transifex token that can be used for retrieving translations from CDS. + */ + public Initializer(@NonNull Context applicationContext, + @NonNull LocaleState locales, + @NonNull String token) { + this.applicationContext = applicationContext; + this.locales = locales; + this.token = token; } - sNativeCore = new NativeCore(applicationContext, locales, token, cdsHost, cache, missingPolicy); + /** + * Initializes the TransifexNative SDK with the configured parameters. + * + * @throws RuntimeException if the SDK has already been initialized. + */ + public void init() { + if (TxNative.isInitialized()) { + throw new RuntimeException("TxNative is already initialized"); + } - // Initialize ViewPump with our interceptor - ViewPump.init(new TxInterceptor()); + sNativeCore = new NativeCore(applicationContext, locales, token, cdsHost, customAuthorizationHeaderKey, cache, missingPolicy); + + // Initialize ViewPump with our interceptor + ViewPump.init(new TxInterceptor()); + } + + /** + * Sets an optional host for the Content Delivery Service. + * If set to {@code null}, the production host provided by Transifex is used. + * + * @param cdsHost The CDS host. + * @return The Initializer instance for chaining. + */ + public Initializer withCdsHost(@Nullable String cdsHost) { + this.cdsHost = cdsHost; + return this; + } + + /** + * Sets a custom key for the HTTP Header used for passing the token to the Content Delivery + * Service. If set to {@code null}, the default key is used. + * + * @param customAuthorizationHeaderKey The custom authorization key. + * @return The Initializer instance for chaining. + */ + public Initializer withCustomAuthorizationHeaderKey(@Nullable String customAuthorizationHeaderKey) { + this.customAuthorizationHeaderKey = customAuthorizationHeaderKey; + return this; + } + + /** + * Sets the translation cache that holds the translations from the CDS. + * If set to {@code null}, {@link com.transifex.txnative.cache.TxStandardCache TxStandardCache} is used. + * + * @param cache The translation cache. + * @return The Initializer instance for chaining. + */ + public Initializer withCache(@Nullable TxCache cache) { + this.cache = cache; + return this; + } + + /** + * Sets the missing policy that determines how to handle translations that are not available. + * If set to {@code null}, {@link com.transifex.txnative.missingpolicy.SourceStringPolicy SourceStringPolicy} is used. + * + * @param missingPolicy The missing policy. + * @return The Initializer instance for chaining. + */ + public Initializer withMissingPolicy(@Nullable MissingPolicy missingPolicy) { + this.missingPolicy = missingPolicy; + return this; + } } + // endregion /** * Checks if the SDK has been initialized by a previous call to - * {@link #init(Context, LocaleState, String, String, TxCache, MissingPolicy)}. + * {@link #initializer(Context, LocaleState, String) TxNative.builder().init()}. * * @return true if the SDK has been initialized, false otherwise. */ @@ -149,8 +264,8 @@ public static void fetchTranslations(@Nullable String localeCode, @Nullable Set< /** * Fetches the translations from CDS and updates the cache. - * - * @see #fetchTranslations(String, Set) + * + * @see #fetchTranslations(String, Set) */ public static void fetchTranslations(@Nullable String localeCode) { if (sNativeCore == null) { @@ -217,4 +332,4 @@ public static Context generalWrap(@NonNull Context context) { public static @NonNull AppCompatDelegate wrapAppCompatDelegate(@NonNull AppCompatDelegate delegate, @NonNull Context baseContext) { return new ViewPumpAppCompatDelegate(delegate, baseContext, TxNative::wrap); } -} +} \ No newline at end of file diff --git a/TransifexNativeSDK/txsdk/src/test/java/com/transifex/txnative/NativeCoreTest.java b/TransifexNativeSDK/txsdk/src/test/java/com/transifex/txnative/NativeCoreTest.java index 1eff8e5..a2c713d 100644 --- a/TransifexNativeSDK/txsdk/src/test/java/com/transifex/txnative/NativeCoreTest.java +++ b/TransifexNativeSDK/txsdk/src/test/java/com/transifex/txnative/NativeCoreTest.java @@ -130,7 +130,7 @@ public void testTranslate_androidUsesSourceLocale() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence string = nativeCore.translate(txResources, R.string.tx_test_key); @@ -146,7 +146,7 @@ public void testTranslate_androidUsesSourceLocale_sourceStringsProvided_returnSo new String[]{"en", "el"}, null); TxMemoryCache memoryCache = getEnElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, memoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, memoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence string = nativeCore.translate(txResources, R.string.tx_test_key); @@ -163,7 +163,7 @@ public void testTranslate_androidUsesSupportedLocale() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence string = nativeCore.translate(txResources, R.string.tx_test_key); @@ -179,7 +179,7 @@ public void testTranslateWithDefaultMissingPolicy_androidUsesUnsupportedLocale_r new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence string = nativeCore.translate(txResources, R.string.tx_test_key); @@ -195,7 +195,7 @@ public void testTranslateWithDefaultMissingPolicy_androidUsesUnsupportedLocale_s new String[]{"en", "el"}, null); TxMemoryCache memoryCache = getEnElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, memoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, memoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence string = nativeCore.translate(txResources, R.string.tx_test_key); @@ -210,7 +210,7 @@ public void testTranslate_idDoesNotExist_exceptionIsThrown() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - final NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + final NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); final TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); assertThrows(Resources.NotFoundException.class, new ThrowingRunnable() { @@ -228,7 +228,7 @@ public void testTranslateWithDefaultString_idDoesNotExist_defaultStringIsReturne new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - final NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + final NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); final TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence string = nativeCore.translate(txResources, 0, "default"); @@ -244,7 +244,7 @@ public void testTranslate_testMode_returnPrefixedString() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - final NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + final NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); nativeCore.setTestMode(true); final TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); @@ -261,7 +261,7 @@ public void testTranslate_testModeAndUseAndroidResourceString_returnedStringNotP new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); nativeCore.setTestMode(true); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); @@ -285,7 +285,7 @@ public void testGetSpannedString_spanSupportEnabled_returnSpannedString() { new String[]{"en", "el"}, null); TxMemoryCache dummyCache = getEmptyMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, dummyCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, dummyCache, null); nativeCore.setSupportSpannable(true); CharSequence string = nativeCore.getSpannedString(STRING_WITH_TAGS); @@ -317,7 +317,7 @@ public void testGetSpannedString_spanSupportEnabledWithHTMLEscapedString_returnS new String[]{"en", "el"}, null); TxMemoryCache dummyCache = getEmptyMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, dummyCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, dummyCache, null); nativeCore.setSupportSpannable(true); CharSequence string = nativeCore.getSpannedString(STRING_WITH_TAGS_HTML_ESCAPED); @@ -351,7 +351,7 @@ public void testGetSpannedString_spanSupportEnabledWithSimpleString_returnString new String[]{"en", "el"}, null); TxMemoryCache dummyCache = getEmptyMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, dummyCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, dummyCache, null); nativeCore.setSupportSpannable(true); CharSequence string = nativeCore.getSpannedString(STRING_WITHOUT_TAGS); @@ -370,7 +370,7 @@ public void testGetSpannedString_spanSupportEnabledWithSimpleStringWithHTMLEntit new String[]{"en", "el"}, null); TxMemoryCache dummyCache = getEmptyMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, dummyCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, dummyCache, null); nativeCore.setSupportSpannable(true); CharSequence string = nativeCore.getSpannedString(STRING_WITHOUT_TAGS_AND_HTML_ENTITIES); @@ -390,7 +390,7 @@ public void testGetSpannedString_spanSupportDisabled_returnStringWithTags() { new String[]{"en", "el"}, null); TxMemoryCache dummyCache = getEmptyMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, dummyCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, dummyCache, null); nativeCore.setSupportSpannable(false); CharSequence string = nativeCore.getSpannedString(STRING_WITH_TAGS); @@ -425,7 +425,7 @@ public void testGetSpannedString_spanSupportDisabledWithHTMLEscapedString_return new String[]{"en", "el"}, null); TxMemoryCache dummyCache = getEmptyMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, dummyCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, dummyCache, null); nativeCore.setSupportSpannable(false); CharSequence string = nativeCore.getSpannedString(STRING_WITH_TAGS_HTML_ESCAPED); @@ -464,7 +464,7 @@ public void testGetSpannedString_spanSupportDisabledWithSimpleStringWithHTMLEnti new String[]{"en", "el"}, null); TxMemoryCache dummyCache = getEmptyMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, dummyCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, dummyCache, null); nativeCore.setSupportSpannable(false); CharSequence string = nativeCore.getSpannedString(STRING_WITHOUT_TAGS_AND_HTML_ENTITIES); @@ -611,7 +611,7 @@ public void testTranslateQuantityString_androidUsesSourceLocale() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence stringOne = nativeCore.translateQuantityString(txResources, R.plurals.tx_plural_test_key, 1); @@ -629,7 +629,7 @@ public void testTranslateQuantityString_androidUsesSourceLocale_sourceStringsPro new String[]{"en", "el"}, null); TxMemoryCache memoryCache = getEnElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, memoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, memoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence stringOne = nativeCore.translateQuantityString(txResources, R.plurals.tx_plural_test_key, 1); @@ -647,7 +647,7 @@ public void testTranslateQuantityString_androidUsesSupportedLocale() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence stringOne = nativeCore.translateQuantityString(txResources, R.plurals.tx_plural_test_key, 1); @@ -668,7 +668,7 @@ public void testTranslateQuantityStringWithDefaultMissingPolicy_ENSourceLocaleAn new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence stringOne = nativeCore.translateQuantityString(txResources, R.plurals.tx_plural_test_key, 1); @@ -689,7 +689,7 @@ public void testTranslateQuantityStringWithDefaultMissingPolicy_SLSourceLocaleAn new String[]{"sl", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence stringOne = nativeCore.translateQuantityString(txResources, R.plurals.tx_plural_test_key, 1); @@ -710,7 +710,7 @@ public void testTranslateQuantityStringWithDefaultMissingPolicy_ENSourceLocaleAn new String[]{"en", "el"}, null); TxMemoryCache memoryCache = getEnElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, memoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, memoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence stringOne = nativeCore.translateQuantityString(txResources, R.plurals.tx_plural_test_key, 1); @@ -731,7 +731,7 @@ public void testTranslateQuantityStringWithDefaultMissingPolicy_SLSourceLocaleAn new String[]{"sl", "el"}, null); TxMemoryCache memoryCache = getSLElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, memoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, memoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence stringOne = nativeCore.translateQuantityString(txResources, R.plurals.tx_plural_test_key, 1); @@ -748,7 +748,7 @@ public void testTranslateQuantityString_idDoesNotExist_exceptionIsThrown() { new String[]{"sl", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - final NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + final NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); final TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); assertThrows(Resources.NotFoundException.class, new ThrowingRunnable() { @@ -767,7 +767,7 @@ public void testTranslateQuantityString_testMode_returnPrefixedString() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); nativeCore.setTestMode(true); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); diff --git a/TransifexNativeSDK/txsdk/src/test/java/com/transifex/txnative/TxResourcesTest.java b/TransifexNativeSDK/txsdk/src/test/java/com/transifex/txnative/TxResourcesTest.java index e96b568..1834a2c 100644 --- a/TransifexNativeSDK/txsdk/src/test/java/com/transifex/txnative/TxResourcesTest.java +++ b/TransifexNativeSDK/txsdk/src/test/java/com/transifex/txnative/TxResourcesTest.java @@ -64,7 +64,7 @@ public void testIsAndroidStringResource() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); assertThat(txResources.isAndroidStringResource(android.R.string.cancel)).isTrue(); @@ -79,7 +79,7 @@ public void testGetOriginalText() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence string = txResources.getOriginalText(R.string.tx_test_key); @@ -95,7 +95,7 @@ public void testGetOriginalQuantityText() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence string = txResources.getOriginalQuantityText(R.plurals.tx_plural_test_key, 2); @@ -116,7 +116,7 @@ public void testGetText_androidUsesSupportedLocale() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence string = txResources.getText(R.string.tx_test_key); @@ -132,7 +132,7 @@ public void testGetText_androidUsesSupportedLocaleAndIdDoesNotExist_exceptionIsT new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); final TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); assertThrows(Resources.NotFoundException.class, new ThrowingRunnable() { @@ -151,7 +151,7 @@ public void testGetTextDef_androidUsesSupportedLocaleAndIdDoesNotExist_defaultSt new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence string = txResources.getText(0, "default string"); @@ -167,7 +167,7 @@ public void testGetString_androidUsesSupportedLocale() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence string = txResources.getString(R.string.tx_test_key); @@ -183,7 +183,7 @@ public void testGetStringFormat_androidUsesSupportedLocale() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence string = txResources.getString(R.string.tx_test_key, 9); @@ -199,7 +199,7 @@ public void testGetQuantityText_androidUsesSupportedLocale() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence stringOne = txResources.getQuantityText(R.plurals.tx_plural_test_key, 1); @@ -217,7 +217,7 @@ public void testGetQuantityText_androidUsesSupportedLocaleAndIdDoesNotExist_exce new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); final TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); assertThrows(Resources.NotFoundException.class, new ThrowingRunnable() { @@ -236,7 +236,7 @@ public void testGetQuantityString_androidUsesSupportedLocale() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence stringOne = txResources.getQuantityString(R.plurals.tx_plural_test_key, 1); @@ -254,7 +254,7 @@ public void testGetQuantityStringFormat_androidUsesSupportedLocale() { new String[]{"en", "el"}, null); TxMemoryCache elMemoryCache = getElMemoryCache(); - NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, elMemoryCache, null); + NativeCore nativeCore = new NativeCore(mockContext, localeState, "token", null, null, elMemoryCache, null); TxResources txResources = new TxResources(mockContext.getResources(), nativeCore); CharSequence stringOne = txResources.getQuantityString(R.plurals.tx_plural_test_key, 1, 1); From 43fe5a5c659f83b8e44f8a81c6a9bbe0053bd9a9 Mon Sep 17 00:00:00 2001 From: Petros Douvantzis Date: Fri, 12 Dec 2025 16:22:01 +0200 Subject: [PATCH 5/5] Bump version to 1.4.1 --- TransifexNativeSDK/build.gradle | 4 ++-- .../src/main/java/com/transifex/common/CDSHandler.java | 2 +- .../main/java/com/transifex/txnative/CDSHandlerAndroid.java | 6 ++++-- .../src/main/java/com/transifex/txnative/NativeCore.java | 5 +++-- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/TransifexNativeSDK/build.gradle b/TransifexNativeSDK/build.gradle index 2ca24e1..207af6b 100644 --- a/TransifexNativeSDK/build.gradle +++ b/TransifexNativeSDK/build.gradle @@ -16,10 +16,10 @@ buildscript { ] ext { sdkVersionCode = 11 // version code for txsdk - sdkVersion = '1.4.0' // version for txsdk and common + sdkVersion = '1.4.1' // version for txsdk and common pomGroupID = "com.transifex.txnative" // pom group id for txsdk and common - cliVersion = '1.4.0' // clitool version + cliVersion = '1.4.1' // clitool version } repositories { google() diff --git a/TransifexNativeSDK/common/src/main/java/com/transifex/common/CDSHandler.java b/TransifexNativeSDK/common/src/main/java/com/transifex/common/CDSHandler.java index ff01892..a574543 100644 --- a/TransifexNativeSDK/common/src/main/java/com/transifex/common/CDSHandler.java +++ b/TransifexNativeSDK/common/src/main/java/com/transifex/common/CDSHandler.java @@ -111,7 +111,7 @@ void onTranslationFetched(@Nullable InputStream inputStream, @NonNull String loc */ public CDSHandler(@Nullable String[] localeCodes, @NonNull String token, @Nullable String secret, @NonNull String csdHost, - String customAuthorizationHeaderKey) { + @Nullable String customAuthorizationHeaderKey) { mLocaleCodes = localeCodes; mToken = token; mSecret = secret; diff --git a/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/CDSHandlerAndroid.java b/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/CDSHandlerAndroid.java index b8ab7e9..3e1b426 100644 --- a/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/CDSHandlerAndroid.java +++ b/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/CDSHandlerAndroid.java @@ -53,8 +53,10 @@ interface FetchTranslationsCallback { * @param secret The API secret to use for connecting to the CDS. * @param csdHost The host of the Content Delivery Service. */ - public CDSHandlerAndroid(@Nullable String[] localeCodes, @NonNull String token, @Nullable String secret, @NonNull String csdHost) { - super(localeCodes, token, secret, csdHost, null); + public CDSHandlerAndroid(@Nullable String[] localeCodes, @NonNull String token, + @Nullable String secret, @NonNull String csdHost, + @Nullable String customAuthorizationHeaderKey) { + super(localeCodes, token, secret, csdHost, customAuthorizationHeaderKey); mExecutor = Executors.newSingleThreadExecutor(); } diff --git a/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/NativeCore.java b/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/NativeCore.java index dd5de67..352f8a0 100644 --- a/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/NativeCore.java +++ b/TransifexNativeSDK/txsdk/src/main/java/com/transifex/txnative/NativeCore.java @@ -64,7 +64,7 @@ public NativeCore(@NonNull Context applicationContext, @NonNull LocaleState localeState, @NonNull String token, @Nullable String cdsHost, - String customAuthorizationHeaderKey, + @Nullable String customAuthorizationHeaderKey, @Nullable TxCache cache, @Nullable MissingPolicy missingPolicy) { mContext = applicationContext; @@ -77,7 +77,8 @@ public NativeCore(@NonNull Context applicationContext, if (cdsHost == null) { cdsHost = CDSHandlerAndroid.CDS_HOST; } - mCDSHandler = new CDSHandlerAndroid(mLocaleState.getAppLocales(), token, null, cdsHost); + mCDSHandler = new CDSHandlerAndroid(mLocaleState.getAppLocales(), token, null, + cdsHost, customAuthorizationHeaderKey); mSourceLocaleResources = Utils.getLocalizedResources(mContext, new Locale(mLocaleState.getSourceLocale()));