Giter VIP home page Giter VIP logo

mobile-sdk-android's People

Contributors

alxgord avatar andrii-bodnar avatar anton-yurkiv avatar billhoo avatar dependabot[bot] avatar mykhailonester avatar nazar-1 avatar rohalskyy avatar shyshka avatar tolot27 avatar twoeightnine avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mobile-sdk-android's Issues

Target API 31 support

Describe the bug
In version 1.4.7 the old work manager version is used (v2.5.0), which causes:

java.lang.IllegalArgumentException: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
    Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.
        at android.app.PendingIntent.checkFlags(PendingIntent.java:375)
        at android.app.PendingIntent.getBroadcastAsUser(PendingIntent.java:645)
        at android.app.PendingIntent.getBroadcast(PendingIntent.java:632)
        at androidx.work.impl.utils.ForceStopRunnable.getPendingIntent(ForceStopRunnable.java:273)
        at androidx.work.impl.utils.ForceStopRunnable.isForceStopped(ForceStopRunnable.java:151)
        at androidx.work.impl.utils.ForceStopRunnable.forceStopRunnable(ForceStopRunnable.java:171)
        at androidx.work.impl.utils.ForceStopRunnable.run(ForceStopRunnable.java:102)
        at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:91)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:920)

See https://issuetracker.google.com/issues/194108978#comment13

To Reproduce
Steps to reproduce the behavior:

  1. Create a project with target API 31
  2. Integrate SDK v1.4.7
  3. Launch an app

Expected behavior
Application will not crash.

Improve first time UX when using SDK if only screenshot feature is needed

Is your feature request related to a problem? Please describe.
I'm only interested in using the SDK because of the screenshot upload feature, but if I follow the readme description I don't see that it is required to have the real time feature enabled in order to get the first time authorisation flow running. This is the sample code in the screenshot section:

    Crowdin.init(applicationContext,
        CrowdinConfig.Builder()
            .withDistributionHash(your_distribution_hash)
            .withScreenshotEnabled()
            .withSourceLanguage(source_language)
            .withAuthConfig(AuthConfig(client_id, client_secret, organization_name))
            .withNetworkType(network_type)                                           // optional
            .withUpdateInterval(interval_in_millisec)                                // optional
            .build())

but looking at the following code in Crowdin.kt it becomes apparent why the flow is not executed since both features must be enabled, which is a pitfall for spending time wondering why the screenshot uploading isn't working.

fun authorize(activity: Activity) {
        if (!FeatureFlags.isRealTimeUpdateEnabled || !FeatureFlags.isScreenshotEnabled) {
            return
        }
        if (isAuthorized()) {
            tryCreateRealTimeConnection()
        } else {
            createAuthDialog(activity) { AuthActivity.launchActivity(activity) }
        }
    }

Describe the solution you'd like
Possible solutions

  1. Update the readme and sample code
  2. Don't require that both feature flags must be enabled

exported field error when targeting Android >=12

Describe the bug
The exported field is missing in the manifest, which is required when targeting Android 12, throwing the following error:
android:exported needs to be explicitly specified for element <activity#com.crowdin.platform.auth.AuthActivity>

To Reproduce
Steps to reproduce the behavior:

  1. Create a Jetpack Compose Android project that targets API 33
  2. Set up the Android SDK integration
  3. Build and see error

Expected behavior
The crash shouldn't happen.

Screenshots
image

Smartphone (please complete the following information):

  • Device: Pixel 6 (emulator)
  • OS: Android 12

Attributes from the theme of the parent view are lost to the view from SupportedCustomViews.

Describe the bug

After adding the BaseContextWrappingDelegate to inflate from the MaterialAutoCompleteTextView xml, it is not the context from Activity that is used (the style set in the parent view theme is lost).

To Reproduce

BaseActivity

override fun getDelegate() = BaseContextWrappingDelegate(super.getDelegate())

style.xml

<style name="ThemeOverlay.AutoCompleteTextView" parent="">
    <item name="autoCompleteTextViewStyle">@style/AutoCompleteTextView</item>
</style>

<style name="AutoCompleteTextView" parent="Widget.MaterialComponents.AutoCompleteTextView.FilledBox.Dense">
    <item name="android:background">@color/black</item>
</style>

layout.xml

<com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:materialThemeOverlay="@style/ThemeOverlay.AutoCompleteTextView">

<com.google.android.material.textfield.MaterialAutoCompleteTextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

</com.google.android.material.textfield.TextInputLayout>

Expected behavior

MaterialAutoCompleteTextView uses the AutoCompleteTextView style from the parent view's theme.

Additional context

The problem lies with the CrowdinLayoutInflater. supportedCustomViews contains the string "TextView" without a package, so any view containing "TextView" in the name (and hence MaterialAutoCompleteTextView) falls under the supportedCustomViews rules.

private val supportedCustomViews = listOf(
        "com.google.android.material.bottomnavigation.BottomNavigationView",
        "com.google.android.material.navigation.NavigationView",
        "com.google.android.material.button.MaterialButton",
        "androidx.appcompat.widget.AppCompatButton",
        "TextView"
)

Such views are created through the LayoutInflater.createView(String, String, AttributeSet) function, which is not passed the context from Factory2, so the LayoutInflater uses the base context instead of the context of the parent view.

Screenshot 2023-07-27 at 22 15 52 Screenshot 2023-07-27 at 22 09 48

The following points raise questions:

  1. Many views can contain the string "TextView", isn't this a too general rule and is it necessary to add a package?
  2. Why is the context passed to Factory2 ignored? Is losing the theme of the parent view the expected behavior?

Version

SDK 1.5.9

HTML select tag crash on WebView

Describe the bug
Clicking on a website that contains a select, the app crash instead of showing the select options.

To Reproduce
A sample project has been created: https://github.com/walter-juan/crowdin_sdk_webview_crash

Expected behavior
It should be the default behavior on Android, showing a dialog with all options from the select

Screenshots
Crash
https://user-images.githubusercontent.com/4141614/225893490-299c884c-b6f6-4680-91d7-fac9bae4d72b.mp4
Expected behavior (using Google Chrome)
https://user-images.githubusercontent.com/4141614/225893403-7f198b15-b13d-46c0-811d-ef34ad9a4035.mp4

Smartphone (please complete the following information):

  • Samsung Galaxy A53 5G, Android 13
  • Emulator, Pixel 4 API 29

Additional context
Bug already reported some time ago (HERE the Issue) and closed because it was not possible to reproduce

Zz

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context about the feature request here.

Handle newlines ("\n") in source strings

Is your feature request related to a problem? Please describe.
If source string contains newlines they are handled correctly by Android (by aapt I guess) but rendered as is by Crowdin sdk:
2020-11-27_14-36-20

Describe the solution you'd like
It'll be great if newlines handled correctly both in distributions and real time
2020-11-27_14-40-14

Describe alternatives you've considered
I was able to achieve that with such quick hack:

--- a/crowdin/src/main/java/com/crowdin/platform/CrowdinResources.kt
+++ b/crowdin/src/main/java/com/crowdin/platform/CrowdinResources.kt
@@ -175,4 +175,4 @@ fun String.fromHtml(): CharSequence =
         Html.fromHtml(this)
     } else {
         Html.fromHtml(this, Html.FROM_HTML_MODE_COMPACT)
-    }
+    }.replace(Regex.fromLiteral("\\n"), "\n")
diff --git a/crowdin/src/main/java/com/crowdin/platform/util/TextUtils.kt b/crowdin/src/main/java/com/crowdin/platform/util/TextUtils.kt
index 2cccca2..338fa92 100644
--- a/crowdin/src/main/java/com/crowdin/platform/util/TextUtils.kt
+++ b/crowdin/src/main/java/com/crowdin/platform/util/TextUtils.kt
@@ -18,7 +18,7 @@ internal object TextUtils {
             }
         }

-        return text
+        return text?.replace(Regex.fromLiteral("\\n"), "\n")
     }

     fun getTextAttributeKey(res: Resources, attrs: AttributeSet, index: Int): String? {

No translations for regional variation of language

I'm trying to implement Crowdin SDK and I found out that regional variation of language is ignored.

Case 1: device is using French french (fr_FR)
Everything is going OK. I see correct translations in my app.

Case 2.1: device is using Canadian french (fr_CA)
I expect to see correct french translation, but actually translations are ignored, SDK uses default string.

Case 2.2: device is using Canadian french (fr_CA) but trying to remove locale country
I tried to fix this issue like this
Locale.setDefault(Locale(Locale.getDefault().language))
The same as in case 2.1.

In Crowdin admin panel only default french is used:
image

By the way, the SDK has mentioned limitations:

Currently, Custom Languages, Dialects, and Language Mapping are not supported for Android SDK

So my questions: are these cases currently not supported as mentioned above? if it is supported, what should i do to fix it?

Crowdin over-the-air not working with default variant of spanish language

Describe the bug
We are using crowdin over-the-air for real time text changes in our app. We are using default spanish language and over the air translations are not working. If we try to set for example "Spanish, Costa rica" variant of spanish language and we have this language also set in android system settings, everything works. If we try the same with default Spanish language, translations are not downloaded & updated.

To Reproduce
Steps to reproduce the behavior:

  1. Create over-the-air content delivery and add spanish language to crowdin (default spanish + for example costa rica variant of spanish language)
  2. Set default spanish as system language in android system settings
  3. Try over-the-air content delivery -> not working
  4. Set "Spanish, Costa rica" (or any other spanish variant) as system language in android system settings
  5. Try over-the-air content delivery -> working

Expected behavior
If default spanish language is set in android system settings, and this language is also in crowdin - I would expect it to be working. If I try some other variant of spanish language, or any other language (for example Slovenian), it works.

Smartphone (please complete the following information):

  • Device: Pixel 6
  • OS: Android 13

Annotated tags are missing attributes

Describe the bug

We use Android's annotations to style to style a few of our strings.

Specifically, we're using the annotations to denote urls that we later underline in our code. Our strings.xml file has entries such as:

<string name="login_legal_links"><annotation url="https://example.com">View Terms of Use</annotation> and <annotation url="https://example.com">Privacy Policy</annotation></string>

When we the Crowdin SDK to download the translations at run-time, the annotation tag is missing all of its properties. The SDK is changing the string into this after its downloaded - note the missing url="https://example.com" properties:

<string name="login_legal_links"><annotation>View Terms of Use</annotation> and <annotation>Privacy Policy</annotation></string>

I verified that when I download the translated files from the Crowdin web portal or CLI, the annotation are correct with the url property. It's specifically the SDK that is not working.

I got as far as seeing that it's like the parser that assumes any inner tag in a <string> has no properties - https://github.com/crowdin/mobile-sdk-android/blob/master/crowdin/src/main/java/com/crowdin/platform/data/parser/StringResourceParser.kt#L74

Expected behavior
I would expect the SDK to fully populate the inner tags' properties.

Additional context
We're using v1.5.7 of the SDK.

Unable to authorize through Google: disallowed_useragent (403)

Describe the bug
When you try to log in using Google on auth page, Google says '403: disallowed_useragent'

To Reproduce

  1. Implement crowdin SDK with screenshot and real-time update features enabled
  2. Open your app
  3. When crowdin suggests you to sign in, click 'OK'
  4. On Crowdin auth page click 'Google'

Expected behavior
I expect to have an ability to continue logging in using Google

Screenshots
image

Smartphones:
Reproducible on several devices:

  • Xiaomi Mi A3 (Android 10)
  • Huawei P20 Lite (Android 8.0)

{ "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJS...ZjFkMWI4OWFlIiwiaWF", "token_type":"bearer", "expires_in": 7200, "refresh_token": "ea506ea4c37aa152f0a91ed2482...4a0c567" }

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Smartphone (please complete the following information):

  • Device: [e.g. Pixel 3]
  • OS: [e.g. Android X]

Additional context
Add any other context about the problem here.

AppCompatDelegate.setApplicationLocales not working due to crowdin need of overriding getDelegate in activities

Describe the bug
I need to implement in app language switch. Based on android documentation https://developer.android.com/guide/topics/resources/app-languages#androidx-impl - this is recommended to use. I am already using crowdin over the air and based on example app, I need to do this in all activities :
override fun getDelegate(): AppCompatDelegate = BaseContextWrappingDelegate(super.getDelegate())

  • if I remove this getDelegate() override, setApplicationLocales() method is changing app language as expected
    I need to make it work together somehow.

To Reproduce
Steps to reproduce the behavior:

  1. Try to change app language via AppCompatDelegate.setApplicationLocales in your example app https://github.com/crowdin/mobile-sdk-android/tree/master/example
  2. language is not changed
  3. try to remove getDelegateOverride
  4. language is changed

Expected behavior
I think I should be able to change app language via AppCompatDelegate.setApplicationLocales and also use crowdin sdk for over-the-air translations.

Smartphone (please complete the following information):

  • Device: Pixel 6
  • OS: Android 13

permission denied for window type 2038

If I add the SDK to take screenshorts, my app crashes with the following exception:

2021-01-02 03:11:09.091 2475-2475/com.eveningoutpost.dexdrip E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.eveningoutpost.dexdrip, PID: 2475
    java.lang.RuntimeException: Unable to resume activity {com.eveningoutpost.dexdrip/com.eveningoutpost.dexdrip.Home}: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@ef03a02 -- permission denied for window type 2038
        at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3581)
        at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3621)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2862)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
     Caused by: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@ef03a02 -- permission denied for window type 2038
        at android.view.ViewRootImpl.setView(ViewRootImpl.java:789)
        at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:356)
        at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
        at com.crowdin.platform.util.UiUtilKt.createAuthDialog(UiUtil.kt:39)
        at com.crowdin.platform.Crowdin.authorize(Crowdin.kt:338)
        at com.eveningoutpost.dexdrip.Home.onResume(Home.java:1916)
        at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1355)
        at android.app.Activity.performResume(Activity.java:7117)
        at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3556)
        at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3621) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2862) 
        at android.app.ActivityThread.-wrap11(Unknown Source:0) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6494) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 

I've tested it with a Samsung Galaxy S7 running Android 8.0 as well as with a Pixel 2 API 27 emulator on Win 10 x64.

I know that the app/Crowdin SDK should request ACTION_MANAGE_OVERLAY_PERMISSION but it did not. On the Pixel, it is also not listed in the list of apps having overlay permission.

NPE thrown when preffered language is changed while fetching data

Describe the bug
When fetchData is called, and eventually onManifestDataReceived is called, then the checks for nullable preferredLanguageCode fail when it's called a 2nd time somewhere else with different values

To Reproduce
Not sure, just seen a lot of crashes in production

Expected behavior
proper null handling

Additional context
Exception java.lang.NullPointerException:
at com.crowdin.platform.data.remote.StringDataRemoteRepository.onManifestDataReceived (StringDataRemoteRepository.kt:80)
at com.crowdin.platform.data.remote.StringDataRemoteRepository$fetchData$1.invoke (StringDataRemoteRepository.kt:40)
at com.crowdin.platform.data.remote.StringDataRemoteRepository$fetchData$1.invoke (StringDataRemoteRepository.kt:39)
at com.crowdin.platform.data.remote.CrowdingRepository$getManifest$1.onResponse$lambda-1 (CrowdingRepository.kt:52)
at com.crowdin.platform.data.remote.CrowdingRepository$getManifest$1.$r8$lambda$jN6aXm_D5EaTWkTx0UZyomZJoDw (CrowdingRepository.kt)
at com.crowdin.platform.data.remote.CrowdingRepository$getManifest$1$$InternalSyntheticLambda$1$0d3d2449efe6166aad19bf5ef586b77cec4b102b62ab7598b0a8656be0cf009a$0.run (CrowdingRepository.java)
at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:641)
at java.lang.Thread.run (Thread.java:764)

If `wrapContext` is called in the background before Crowdin is initialized it throws `UninitializedPropertyAccessException`

Describe the bug
If the Crowdin initialization isn't finished when an activity is being created, wrap context will fail and crash the app.

We don't have Crowdin initialization in our application onCreate so it's not called on push message received and we defer it until the first activity on create.

Expected behavior
Calls to wrapContext should not crash an instead just fail gracefully.

Unable to sign in via Google: nothing happens after entering e-mail

Describe the bug
On Google Sign In page when I enter e-mail and click 'Next', e-mail disappears (sometimes partially) and nothing more happens.

To Reproduce

  1. Implement crowdin SDK with real-time update features enabled
  2. Open your app
  3. When crowdin suggests you to sign in, click 'OK'
  4. On Crowdin auth page click 'Google'
  5. On Google Sign In page enter e-mail and click 'Next'

Expected behavior
Google consumes my e-mail and prompts to enter my password

Smartphone:

  • Xiaomi Mi A3 (Android 10)
  • Android Studio Emulator (Android 10)
  • Huawei P20 Lite (Android 8.0)

Crowdin SDK v1.2.1

拉取請求

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Smartphone (please complete the following information):

  • Device: [e.g. Pixel 3]
  • OS: [e.g. Android X]

Additional context
Add any other context about the problem here.

Issue: Bug report

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Smartphone (please complete the following information):

  • Device: [e.g. Pixel 3]
  • OS: [e.g. Android X]

Additional context
Add any other context about the problem here.

Behaviour improvement in case when there is no `countryCode` in Locale

Is your feature request related to a problem? Please describe.
My feature request is related to a problem when application has installed locale without country code. Just imagine the situation when application relies for Locale.getDefault().language. Such case can be when developer sets locale as Locale.setDefault(Locale("uk")). In this way application with installed Crowdin with two localizations (maybe Russian as default and Ukrainian) will work in a wrong way, Crowdin will provide no localization strings.
Why? CauseCrowdinResources.getStringFromRepository() will return something like uk- instead of uk-UA that Crowdin library assumes to get. With this uk- string Crowdin go to MemoryLocalRepository.getString(language, key). Mehtod will return null due to stringsData["uk-"] provides no matches in the map.

Describe the solution you'd like

  1. Improve Locale.getDefault().getFormattedCode() method, add additional check for countryCode. If it's empty return only it's code (without - symbol).
  2. Improve MemoryLocalRepository.getString(language, key), add possibility to find appropriate translation based only on language in case when no countryCode provided. It will be better than app took default app locale.

Crowdin SDK: Crash while implementing Real-time updates

Describe the bug
A clear and concise description of what the bug is.

Expected behavior
This occurred while implementing Real-Time Preview and Screenshots features. After logging in, the app crashes and returns the error below.

Smartphone (please complete the following information):

  • Device: [Samsung A30]
  • OS: [e.g. Android 11]
  • Crowdin SDK version: 1.4.8

Error log

FATAL EXCEPTION: OkHttp Dispatcher
    java.lang.IllegalStateException: cannot make a new request because the previous response is still open: please call response.close()
        at okhttp3.internal.connection.RealCall.enterNetworkInterceptorExchange(RealCall.kt:229)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:66)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
        at com.crowdin.platform.data.remote.interceptor.HeaderInterceptor.intercept(HeaderInterceptor.kt:19)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
        at com.crowdin.platform.data.remote.interceptor.SessionInterceptor.intercept(SessionInterceptor.kt:36)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
        at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
        at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:517)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:923)

Sevgi.hrnt

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Smartphone (please complete the following information):

  • Device: [e.g. Pixel 3]
  • OS: [e.g. Android X]

Additional context
Add any other context about the problem here.

Unity SDK

When will you add SDK for unity?

UnknownFormatConversionException when trying to set text with `%` at the end

Describe the bug
Crowdin SDK crashes when trying to set text with % at the end:

myTextView.text = "10%"

On the other hand, when trying to set %%, the SDK is not crashing but it is not what I expect to see in UI.

To Reproduce

  1. Implement and initialize Crowdin SDK
  2. Try to set text with % at the end

Expected behavior
Crowdin SDK doesn't crash and shows text correctly.

Smartphone (please complete the following information):

  • Xiaomi Mi A3 (Android 10)
  • Huawei P20 Lite (Android 8.0)

Stacktrace

java.util.UnknownFormatConversionException: Conversion = 'End of String'
        at java.util.Formatter$FormatSpecifierParser.peek(Formatter.java:2641)
        at java.util.Formatter$FormatSpecifierParser.<init>(Formatter.java:2602)
        at java.util.Formatter.parse(Formatter.java:2557)
        at java.util.Formatter.format(Formatter.java:2504)
        at java.util.Formatter.format(Formatter.java:2458)
        at java.lang.String.format(String.java:2770)
        at com.crowdin.platform.data.local.MemoryLocalRepository.searchInPlurals(MemoryLocalRepository.kt:160)
        at com.crowdin.platform.data.local.MemoryLocalRepository.searchInResources(MemoryLocalRepository.kt:147)
        at com.crowdin.platform.data.local.MemoryLocalRepository.getTextData(MemoryLocalRepository.kt:129)
        at com.crowdin.platform.data.local.SharedPrefLocalRepository.getTextData(SharedPrefLocalRepository.kt:77)
        at com.crowdin.platform.data.DataManager.provideTextMetaData(DataManager.kt:47)
        at com.crowdin.platform.transformer.TextViewTransformer$Watcher.afterTextChanged(TextViewTransformer.kt:104)
        at android.widget.TextView.sendAfterTextChanged(TextView.java:9605)
        at android.widget.TextView.setText(TextView.java:5496)
        at android.widget.TextView.setText(TextView.java:5343)
        at android.widget.TextView.setText(TextView.java:5300)

Strings not updated correctly

For some reason I can't see and use the updated strings.

I'm forcing the update from Crowdin using the following command:

I have the following configuration in my application:

Crowdin.init(
            context = applicationContext,
            config = CrowdinConfig.Builder()
                .withDistributionHash("aaa")
                .build()
        )

And I force the update of Crowdin string to get the new ones:

val bundleString = getString(R.string.abc)

Crowdin.forceUpdate(this) {
    val updatedString = getString(R.string.abc)
}

The value of bundleString is the one that I have in my strings.xml file.

When doing the force update, I see that Crowdin update is working as expected and the DataManager.updateData enters in the onDataLoaded callback. On this callback I can see the string "abc" with a different value than the one I have in my app bundle.

I understand that after this forceUpdate if I get the resource I should see the updated value from Crowdin, but this is not the case, bundleString and updatedString both have the same value.

Is there something that I'm missing, or I have misunderstood?

Thanks

Flutter SDK

I love your OTA and Real-time updates feature for Android/iOS. Would be great to have Crowdin SDK for Flutter.
Thanks for the great work!

Memory leak

Describe the bug
I found a memory leak that was caused by your library.

Additional context

HEAP ANALYSIS RESULT
1 APPLICATION LEAKS

References underlined with "~~~" are likely causes.
Learn more at https://squ.re/leaks.

166721 bytes retained by leaking objects
Signature: c7ebbd5543e08693dce2ed523688ad1f1e7c24b7

┬───
│ GC Root: Thread object
│
├─ android.net.ConnectivityThread instance
│    Leaking: NO (PathClassLoader↓ is not leaking)
│    Thread name: 'ConnectivityThread'
│    ↓ Thread.contextClassLoader
├─ dalvik.system.PathClassLoader instance
│    Leaking: NO (InternalLeakCanary↓ is not leaking and A ClassLoader is never
│    leaking)
│    ↓ ClassLoader.runtimeInternalObjects
├─ java.lang.Object[] array
│    Leaking: NO (InternalLeakCanary↓ is not leaking)
│    ↓ Object[1893]
├─ leakcanary.internal.InternalLeakCanary class
│    Leaking: NO (WelcomeActivity↓ is not leaking and a class is never leaking)
│    ↓ static InternalLeakCanary.resumedActivity
├─ com.example.presenters.welcome.WelcomeActivity instance
│    Leaking: NO (WandToolbar↓ is not leaking and Activity#mDestroyed is false)
│    mApplication instance of com.example.DebugApp
│    mBase instance of com.crowdin.platform.CrowdinContextWrapper
│    ↓ BaseActivity.toolbar
├─ com.exampleapp.wand.toolbar.WandToolbar instance
│    Leaking: NO (View attached)
│    View is part of a window view hierarchy
│    View.mAttachInfo is not null (view attached)
│    View.mID = R.id.toolbar
│    View.mWindowAttachCount = 1
│    mPopupContext instance of android.view.ContextThemeWrapper, wrapping
│    activity com.example.presenters.welcome.WelcomeActivity with mDestroyed =
│    false
│    mContext instance of androidx.appcompat.view.ContextThemeWrapper, wrapping
│    activity com.example.presenters.welcome.WelcomeActivity with mDestroyed =
│    false
│    ↓ ViewGroup.mOnHierarchyChangeListener
│                ~~~~~~~~~~~~~~~~~~~~~~~~~~
├─ com.crowdin.platform.transformer.
│  BaseToolbarTransformer$addHierarchyChangeListener$1 instance
│    Leaking: UNKNOWN
│    Retaining 12 B in 1 objects
│    Anonymous class implementing android.view.
│    ViewGroup$OnHierarchyChangeListener
│    ↓ BaseToolbarTransformer$addHierarchyChangeListener$1.this$0
│                                                          ~~~~~~
├─ com.crowdin.platform.transformer.SupportToolbarTransformer instance
│    Leaking: UNKNOWN
│    Retaining 167.0 kB in 2043 objects
│    ↓ BaseTransformer.createdViews
│                      ~~~~~~~~~~~~
├─ java.util.concurrent.ConcurrentHashMap instance
│    Leaking: UNKNOWN
│    Retaining 166.9 kB in 2042 objects
│    ↓ ConcurrentHashMap[key()]
│                       ~~~~~~~
├─ androidx.appcompat.widget.AppCompatTextView instance
│    Leaking: YES (View.mContext references a destroyed activity)
│    Retaining 166.7 kB in 2036 objects
│    View is part of a window view hierarchy
│    View.mAttachInfo is null (view detached)
│    View.mWindowAttachCount = 1
│    mContext instance of androidx.appcompat.view.ContextThemeWrapper, wrapping
│    activity com.example.presenters.splash.view.SplashActivity with mDestroyed =
│    true
│    ↓ View.mContext
├─ androidx.appcompat.view.ContextThemeWrapper instance
│    Leaking: YES (AppCompatTextView↑ is leaking and ContextThemeWrapper wraps
│    an Activity with Activity.mDestroyed true)
│    Retaining 376 B in 16 objects
│    mBase instance of android.view.ContextThemeWrapper, wrapping activity com.
│    wirex.presenters.splash.view.SplashActivity with mDestroyed = true
│    ↓ ContextThemeWrapper.mInflater
├─ com.crowdin.platform.CrowdinLayoutInflater instance
│    Leaking: YES (ContextThemeWrapper↑ is leaking)
│    Retaining 120 B in 6 objects
│    mContext instance of androidx.appcompat.view.ContextThemeWrapper, wrapping
│    activity com.example.presenters.splash.view.SplashActivity with mDestroyed =
│    true
│    mPrivateFactory instance of com.example.presenters.splash.view.
│    SplashActivity with mDestroyed = true
│    ↓ LayoutInflater.mPrivateFactory
╰→ com.example.presenters.splash.view.SplashActivity instance
​     Leaking: YES (ObjectWatcher was watching this because com.example.
​     presenters.splash.view.SplashActivity received Activity#onDestroy()
​     callback and Activity#mDestroyed is true)
​     Retaining 15.1 kB in 575 objects
​     key = b40686a4-c6d5-40ce-ae59-716b318424e9
​     watchDurationMillis = 9164
​     retainedDurationMillis = 4163
​     mApplication instance of com.example.DebugApp
​     mBase instance of com.crowdin.platform.CrowdinContextWrapper

0 LIBRARY LEAKS

A Library Leak is a leak caused by a known bug in 3rd party code that you do
not have control over.
See https://square.github.
io/leakcanary/fundamentals-how-leakcanary-works/#4-categorizing-leaks


0 UNREACHABLE OBJECTS

An unreachable object is still in memory but LeakCanary could not find a strong
reference path
from GC roots.


METADATA

Please include this in bug reports and Stack Overflow questions.

Build.VERSION.SDK_INT: 28
Build.MANUFACTURER: unknown
LeakCanary version: 2.8.1
App process name: com.example.dev
Stats: LruCache[maxSize=3000,hits=66638,misses=209457,hitRate=24%]
RandomAccess[bytes=9676219,reads=209457,travel=77382097279,range=39571154,size=4
6888561]
Analysis duration: 3751 ms
Heap dump file path: /data/user/0/com.example.
dev/cache/leakcanary/2022-04-29_13-23-54_521.hprof
Heap dump timestamp: 1651231440461
Heap dump duration: Unknown

User's privacy

This is certainly an interesting addition to Crowdin, but how about the privacy of the app users?

Should there be a privacy policy? What should the policy contain? How can users opt-in (not opt-out!).

IMHO this should be documented on the main page, also to take away any concerns developers may have.

Crowdin screenshots not working on Android 13

Crowdin screenshot is not compatible with Android 13.

Indeed, 3 new permission are introduced with Android 13:

  • READ_MEDIA_IMAGES,
  • READ_MEDIA_VIDEO
  • READ_MEDIA_AUDIO.

If you were using READ_EXTERNAL_STORAGE for accessing files, then you need to use one of these new permissions.

For the compatibility with Android 13, you need to support READ_MEDIA_IMAGES here.

Dexter.withContext(context)
            .withPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
            .withListener(object : PermissionListener {
                override fun onPermissionGranted(p0: PermissionGrantedResponse?) {
                    searchAndUploadScreenshot()
                }

                override fun onPermissionDenied(p0: PermissionDeniedResponse?) {
                    onErrorListener?.invoke(context.getString(R.string.required_permission_read_storage))
                }

                override fun onPermissionRationaleShouldBeShown(p0: PermissionRequest?, p1: PermissionToken?) {
                    p1?.continuePermissionRequest()
                }
            })
            .check()

TextView marquee is not working

After using the Crowdin Android sdk for a few month, I found a bug that a textview can't marquee correctly while set a long text to it in java code or koltin code, just like that

myTextView.text = "123456789987654321123456789987654321"

And It can be marquee correctly while init in xml:

<TextView
        android:id="@+id/tv_marquee"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/long_str"
        android:textColor="#333333"
        android:singleLine="true"
        android:ellipsize="marquee"
        android:marqueeRepeatLimit="marquee_forever"
        android:scrollHorizontally="true"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:freezesText="true"
        android:textSize="22sp"/>

the long_str is

<string name="long_str">123456789987654321123456789987654321</string>

minSdkVersion 29 too high

In SDK version 1.6.0 minSdkVersion was raised which makes it impossible to use it in our project (and many others). The 16 -> 29 step is too big. API 29 only covers 72.2% of android users (according to google statistics) which is too low for production apps.

Might need to be revisited solving the problem of using Context in LayoutInflator to avoid using the new API. #207

Screenshot 2023-08-09 at 14 20 04

Duplicate class androidx.appcompat.app.BaseContextWrappingDelegate

Describe the bug
Duplicate class androidx.appcompat.app.BaseContextWrappingDelegate found in modules onfido-capture-sdk-core-10.3.5-runtime (com.onfido.sdk.capture:onfido-capture-sdk-core:10.3.5) and sdk-1.5.1-runtime (com.github.crowdin.mobile-sdk-android:sdk:1.5.1)

Expected behavior
Maybe you should name it with "CrowdIn" prefix to avoid duplicates. Looks like other developers use the same technique and even the same naming. Probably all of you read the same StackOverflow question https://stackoverflow.com/questions/55265834/change-locale-not-work-after-migrate-to-androidx 🙂

Inflating Views using Contexts wrapped by CrowdIn result in Resources$NotFoundExceptions

Describe the bug
When using CrowdIn in our app, we've found hundreds of mysterious android.content.res.Resources$NotFoundException coming from our WebView and ExoPlayer views we're inflating in our app (our only non-composable views in our app). We tried several approaches to figure out the root cause of these crashes, and were able to determine that CrowdIn's wrapping of our base context that we were then using to inflate these views was the root cause of these crashes.

To Reproduce
Steps to reproduce the behavior:

  1. Set up a project using CrowdIn that wraps the base context when an activity starts up in attachBaseContext
  2. Inflate a WebView instance programmatically, ie WebView(context)
  3. Select text on a web page or text input field in order to trigger the system inflating a contextual window pop up (ie, Copy, Paste, etc) via long clicking, or double-tapping text.
  4. Observe the web view crash, with a Resources$NotFoundException. Exception thrown will be some permutation of this message:

android.content.res.Resources$NotFoundException - Unable to find resource ID #

  1. Comment out lines that wrap the base context attachBaseContext
  2. Select text in a webview, you should see no crash.

Expected behavior
A view's non-string resources should not be impacted or obstructed by crowd in in any way

Screenshots
N/A

Smartphone (please complete the following information):

  • All Android versions we support (Android 8-14), dozens of different models

Additional context
We were able to add a work around for this issue by preserving our activity's base context before it gets wrapped by CrowdIn, keep a reference to it, and use that context to inflate our views. Since doing that, our crash rates have reduced dramatically.

See additional context/thread in this WebView Issue Tracker issue.

http://updates-http.cdn-apple.com/2021WinterFCS/fullrestores/071-22599/73CFA24E-F391-4E77-8CAF-36207D7BE02A/iPhone12,8_14.4.2_18D70_Restore.ipsw

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Smartphone (please complete the following information):

  • Device: [e.g. Pixel 3]
  • OS: [e.g. Android X]

Additional context
Add any other context about the problem here.

Crowdin.authorize() keep crashing: Channel is unrecoverably broken and will be disposed!

Describe the bug
Every time when logged into Crowdin from Crowdin.authorize(), App crashes.

To Reproduce
Steps to reproduce the behavior:

  1. Follow the official instructions to setup Crowdin SDK, confirm that Crowdin.init() works good.
  2. Add Crowdin.authorize() to MainActivity's onCreate() method
  3. Open my App and there will be a Crowdin prompt said need authorize, click OK to jump to Crowdin page and input correct password, click login
  4. An "In progress ..." page is shown.
  5. After 3~4 seconds, App crashed.

Expected behavior
After step #4 above, it should be back to MainActivity and no crash.

Smartphone (please complete the following information):

  • Device: Huawei P20
  • OS: Android 10

Additional context

  • The App is our own working product, just added Crowdin.authorize() to MainActivity's onCreate() method.
  • If I press Cancel when prompt, no crash will happen.
  • If I press OK, then get into the login page, and input nothing, just click back button, i could get back to MainActivity normaly.
  • When get into the login page, onPause() of MainActivity was triggered, but after successful login, the App was crashed and onResume() was never triggered.

Based on contexts above, i guess there's something wrong when authorize succeed and Crowdin trying to resume MainActivity.

Logs listed below:

 E/InputDispatcher: Window handle Window{b240f29 u0 com.myapp.activity/com.myapp.activity.main.MainActivity} has no registered input channel
 E/WindowManager: win=Window{b240f29 u0 com.myapp.activity/com.myapp.activity.main.MainActivity EXITING} destroySurfaces: appStopped=false win.mWindowRemovalAllowed=true win.mRemoveOnExit=true
 ...
 E/WindowManager: win=Window{b1905b9 u0 com.myapp.activity/com.myapp.activity.main.MainActivity} destroySurfaces: appStopped=true win.mWindowRemovalAllowed=false win.mRemoveOnExit=false
 E/WindowManager: win=Window{b296b29 u0 Splash Screen com.myapp.activity EXITING} destroySurfaces: appStopped=false win.mWindowRemovalAllowed=true win.mRemoveOnExit=true
 ...
 E/InputDispatcher: channel 'b27bee1 com.myapp.activity/com.crowdin.platform.auth.AuthActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
 E/InputDispatcher: channel 'b1905b9 com.myapp.activity/com.myapp.activity.main.MainActivity (server)' ~ Channel is unrecoverably broken and will be disposed!

HTML select tag crash on WebView

Describe the bug
Clicking on a website that contains a select, the app crash instead of showing the select options.

To Reproduce
Sample project has been created: https://github.com/walterjuanp/crowdin_sdk_webview_crash

Expected behaviour
It should be the default behaviour on Android, showing a dialog with all options from the select

Smartphone (please complete the following information):

  • Emulator, Pixel 4 API 29

Translations from Crowdin are not shown in the app

Describe the bug
Translations are not shown in the app

To Reproduce
Steps to reproduce the behavior:

  1. Install Crowdin (config below)
  2. Translate and approve a string in the Crowdin web interface
  3. Click Content Delivery -> Distribution -> Release
  4. Wait fo 15 minutes

Expected behavior
The string displayed is the one that comes from Crowdin

Actual behavior
The string displayed is the one that was built in

Smartphone (please complete the following information):

  • Huawei Honor 9, Android 9.0
  • Nexus 5X (emulator), Android 9.0

The built-in string has this warning:

"fragmentPrivateSetupCodeInUse" is not translated in "de" (German), ...

Via debugging I see that the strings are being sent from Crowdin and stored in local and persistent repos, but getString is never called

My config:

// App.kt

    override fun attachBaseContext(base: Context?) {
        val newBase = base?.run { Crowdin.wrapContext(this) }
        super.attachBaseContext(newBase)
    }

    private fun initCrowdin() {
        Crowdin.init(applicationContext,
            CrowdinConfig.Builder()
                .withDistributionHash(applicationContext.getString(R.string.crowdin_distribution_hash))
                .withNetworkType(NetworkType.ALL)
                .withAuthConfig(
                    AuthConfig(
                        applicationContext.getString(R.string.crowdin_client_id),
                        applicationContext.getString(R.string.crowdin_client_secret),
                        null
                    )
                )
                .build())


        Crowdin.registerDataLoadingObserver(object: LoadingStateListener {
            override fun onDataChanged() {
                Log.d("***", "success")
            }

            override fun onFailure(throwable: Throwable) {
                Log.d("***", "fail", throwable)
            }

        })


        Crowdin.forceUpdate(applicationContext)
    }

// in code:
    ui.showError(R.string.fragmentPrivateSetupCodeInUse)

Over the air content delivery not working for Preference & PreferenceCategory views

Describe the bug
Over the air content delivery is not working with preferences & preference categories. Strings are not updated - defaults are used instead.

To Reproduce
Steps to reproduce the behavior:
Try to add this view to your layout
<PreferenceCategory android:layout="@layout/layout_preference_category" android:summary="@string/second" android:title="@string/first">

Expected behavior
If string 'first' or 'second' is changed in crowdin and translations are released, I would expect these strings to be changed in the app. If I use these strings in standard TextView, it works. If I use Preference or PreferenceCategory view, it doesnt.

Smartphone (please complete the following information):

  • Device: Pixel 6
  • OS: Android 13

Realtime preview crash

Crash happened on every app start if realtime preview enabled.
crowdin versions: 1.5.4 - 1.5.5

 E/AndroidRuntime: FATAL EXCEPTION: LocalWorkThreadPool-23
    java.util.ConcurrentModificationException
        at java.util.WeakHashMap$HashIterator.nextEntry(WeakHashMap.java:807)
        at java.util.WeakHashMap$EntryIterator.next(WeakHashMap.java:846)
        at java.util.WeakHashMap$EntryIterator.next(WeakHashMap.java:844)
        at java.util.WeakHashMap.putAll(WeakHashMap.java:566)
        at java.util.Collections$SynchronizedMap.putAll(Collections.java:2645)
        at com.crowdin.platform.transformer.ViewTransformerManager.getVisibleViewsWithData(ViewTransformerManager.kt:70)
        at com.crowdin.platform.realtimeupdate.EchoWebSocketListener.saveMatchedTextViewWithMappingId(EchoWebSocketListener.kt:86)
        at com.crowdin.platform.realtimeupdate.EchoWebSocketListener.resubscribeView(EchoWebSocketListener.kt:60)
        at com.crowdin.platform.realtimeupdate.EchoWebSocketListener.access$resubscribeView(EchoWebSocketListener.kt:26)
        at com.crowdin.platform.realtimeupdate.EchoWebSocketListener$onOpen$1.onChange$lambda-0(EchoWebSocketListener.kt:47)
        at com.crowdin.platform.realtimeupdate.EchoWebSocketListener$onOpen$1.$r8$lambda$4ex4arbJg14-n4M0d3eoz8P9RjE(Unknown Source:0)
        at com.crowdin.platform.realtimeupdate.EchoWebSocketListener$onOpen$1$$ExternalSyntheticLambda0.run(Unknown Source:10)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
        at java.lang.Thread.run(Thread.java:1012)

feature request

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context about the feature request here.

SDK escapes already escaped symbols

I use SDK in its simplest implementation just to receive translations updates over-the-air.
I'm using latest available version:

implementation ('com.crowdin.platform:mobile-sdk:1.1.6') {
    exclude group: 'com.google.code.gson', module: 'gson'
}

And here is my configuration:

val crowdinConfig = CrowdinConfig.Builder()
        .withDistributionHash(BuildConfig.CROWDIN_HASH)
        .withNetworkType(NetworkType.ALL)
        .build()
Crowdin.init(applicationContext, crowdinConfig)

But there is a problem with symbols escaping.

  1. To test implementation I've added new string res to default strings.xml file.
  2. Then I "translated" it to the Spanish language using Crowdin web interface, but added symbols that should be escaped to it to test this behavior: https://prnt.sc/u3dj4i
  3. I've released new translations through Settings->Content Delivery->"Release" button to the distribution that I've created.
  4. To debug I'm logging current resources to the console using Crowdin.getResources() and after translation updates, my new string res appeared there, but with a strange escaping update as you can see on screenshot: https://prnt.sc/u3djpt
  5. And on UI this string looks like this: https://prnt.sc/u3dk0g

It looks like the Crowdin web already escapes these special symbols at the "release" stage before send them over-the-air. And SDK then escapes them at the receiving stage.
I've checked and didn't find anything about escaping in the docs, CrowdinConfiguration or Crowdin class public methods.

Is there any possible way to disable special symbols escaping at the SDK level cause it breaks my new and already existing resources with special symbols in it?

"LOAD NEW RESOURCES" button won't work for the second time

Describe the bug

A Distribution Hash could only work once, when i click the "LOAD NEW RESOURCES" button for the second time (i did click the Release button on the Crowdin side), it won't update my strings any more.

To Reproduce

  1. Compile and install Android Examples with correct Distribution Hash.
  2. Upload strings.xml from the example project to Crowdin, and translate some of the strings.
  3. Add a new dist-hash to Crowdin page and click Release button.
  4. Open the Example App, it shows the original texts.
  5. Click LOAD NEW RESOURCES button, and translations made in step 2 is shown, work like a charm!
  6. Get back to Crowdin page, translate more strings, make sure they are approved, and go to Distribution to click Release button again
  7. Get back to example App, click LOAD NEW RESOURCES again, but new translations are not shown, and when debugging, the strings are empty {"arrays":{},"language":"zh-CN","plurals":{},"strings":{}}

Expected behavior
Once i released new strings from Crowdin page, and clicked the LOAD button, the example App should show the latest strings.

Additional context
Interest thing is, keep all the things not changed, and just add another New Distribution Hash, then Release it, and recompile the example App with the new hash, the latest strings will show. But this is not the solution, I want to just use one hash for one App, i don't want to re-compile my App.

SDK breaks styles

Describe the bug

After adding the SDK to the application, the dialog styles (AlertDialog, BottomSheetDialog, etc.) broke.

This is how I implemeted base activity for my app.

abstract class CrowdInActivity: AppCompatActivity() {
    override fun attachBaseContext(base: Context) {
        super.attachBaseContext(Crowdin.wrapContext(base))
    }
}

I'm using the latest version of SDK (1.2.0)

Screenshots

SDK EnabledSDK Disabled

Smartphone:

  • Device: Samsung Galaxy S10
  • OS: Android X

Gradle Transitive dependency exclusion

Some libraries have guava dependency, this is a reason a problem with the Gradle Transitive dependency exclusion.

./gradlew crowdin:dependencies

Describe the solution you'd like
Can exclude guava for each dependency do you have in the project, or exclude all project.

Describe alternatives you've considered
Only add this lines in build.gradle (crowdin)

configurations {
    all*.exclude group: 'com.google.guava', module: 'listenablefuture'
}

Additional context
This change dont affect anything, just ensure that guava will not cause conflicts

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.