Skip to content

Commit b2c2f0d

Browse files
committed
feat: create and expose android API to react-native thread
1 parent a14067c commit b2c2f0d

File tree

3 files changed

+105
-6
lines changed

3 files changed

+105
-6
lines changed

android/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ dependencies {
8787
//noinspection GradleDynamicVersion
8888
implementation "com.facebook.react:react-native:+"
8989
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
90+
91+
implementation "androidx.appcompat:appcompat:1.6.0-rc01"
92+
implementation "androidx.appcompat:appcompat-resources:1.6.0-rc01"
9093
}
9194

9295
if (isNewArchitectureEnabled()) {

android/src/main/java/com/localizationsettings/LocalizationSettingsModule.kt

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
package com.localizationsettings
22

3+
import android.content.Context
4+
import android.content.SharedPreferences
5+
import android.os.Build
6+
import androidx.appcompat.app.AppCompatDelegate
7+
import androidx.core.os.LocaleListCompat
8+
import com.facebook.react.bridge.Promise
39
import com.facebook.react.bridge.ReactApplicationContext
410
import com.facebook.react.bridge.ReactMethod
5-
import com.facebook.react.bridge.Promise
11+
import java.util.*
12+
613

714
class LocalizationSettingsModule internal constructor(context: ReactApplicationContext) :
815
LocalizationSettingsSpec(context) {
@@ -11,11 +18,99 @@ class LocalizationSettingsModule internal constructor(context: ReactApplicationC
1118
return NAME
1219
}
1320

14-
// Example method
15-
// See https://reactnative.dev/docs/native-modules-android
21+
/**
22+
* Get IETF BCP 47 (language-COUNTRY "pl-PL")
23+
* if country is not available in locale, then use system defaults (even if it's not 100% correct, like "pl-US")
24+
**/
25+
private fun getLanguageTag(language: String): String {
26+
// if language have format language_COUNTRY, then return it
27+
if (Locale(language).country != "") return Locale(language).toLanguageTag()
28+
// fallback for system country
29+
return "$language-${Locale.getDefault().country}"
30+
}
31+
32+
33+
/**
34+
* Get current language
35+
* returns string in IETF BCP 47 (language-COUNTRY "pl-PL")
36+
* If API version >= 33, use native per-app language feature
37+
* else, fallback to SharedPreferences
38+
**/
39+
private fun getCurrentLanguage(): String? {
40+
// If API version is >= 33, then use per-app language settings
41+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
42+
val currentLocaleName = if (!AppCompatDelegate.getApplicationLocales().isEmpty) {
43+
// get per-app language
44+
AppCompatDelegate.getApplicationLocales()[0]?.toLanguageTag()
45+
} else {
46+
// Fallback to the default System Locale
47+
Locale.getDefault().toLanguageTag()
48+
}
49+
return currentLocaleName
50+
}
51+
// if API is < 33, then use SharedPreferences with fallback to default System Locale
52+
if (getPreferences().getString("languageFrom", null) == Locale.getDefault().language) {
53+
return getPreferences().getString("language", Locale.getDefault().toLanguageTag())
54+
}
55+
return Locale.getDefault().toLanguageTag()
56+
}
57+
58+
59+
/**
60+
* Set current language
61+
* passed language can be in ISO 639-1 (language "pl")
62+
* or IETF BCP 47 (language-COUNTRY "pl-PL")
63+
* If API version >= 33, use native per-app language feature
64+
* else, fallback to SharedPreferences
65+
**/
66+
private fun setCurrentLanguage(language: String) {
67+
// If API version is >= 33, then use per-app language settings
68+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
69+
val localeList = LocaleListCompat.forLanguageTags(getLanguageTag(language))
70+
AppCompatDelegate.setApplicationLocales(localeList)
71+
} else {
72+
// if API is < 33, then set SharedPreferences language
73+
val editor = getEditor();
74+
editor.putString("languageFrom", Locale.getDefault().language)
75+
editor.putString("language", getLanguageTag(language))
76+
editor.apply()
77+
}
78+
}
79+
80+
81+
/**
82+
* Expose functions to react-native
83+
**/
1684
@ReactMethod
17-
override fun multiply(a: Double, b: Double, promise: Promise) {
18-
promise.resolve(a * b)
85+
override fun getLanguage(promise: Promise) {
86+
promise.resolve(getCurrentLanguage())
87+
}
88+
89+
@ReactMethod
90+
override fun setLanguage(language: String) {
91+
setCurrentLanguage(language)
92+
}
93+
94+
/**
95+
* Expose constants to react-native
96+
**/
97+
override fun getConstants(): MutableMap<String, String?>? {
98+
val constants: MutableMap<String, String?> = HashMap()
99+
constants["language"] = getCurrentLanguage()
100+
return constants
101+
}
102+
103+
/**
104+
* SharedPreferences (only used when API version is below 33)
105+
**/
106+
private fun getPreferences(): SharedPreferences {
107+
return reactApplicationContext.getSharedPreferences(
108+
"LocalizationSettings", Context.MODE_PRIVATE
109+
)
110+
}
111+
112+
private fun getEditor(): SharedPreferences.Editor {
113+
return getPreferences().edit()
19114
}
20115

21116
companion object {

android/src/oldarch/LocalizationSettingsSpec.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ import com.facebook.react.bridge.Promise
77
abstract class LocalizationSettingsSpec internal constructor(context: ReactApplicationContext) :
88
ReactContextBaseJavaModule(context) {
99

10-
abstract fun multiply(a: Double, b: Double, promise: Promise)
10+
abstract fun getLanguage(promise: Promise)
11+
abstract fun setLanguage(language: String)
1112
}

0 commit comments

Comments
 (0)