Kotlinify I18nManagerModule (#44537)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/44537

# Changelog:
[Internal] -

As in the title.

Reviewed By: NickGerleman

Differential Revision: D57248159

fbshipit-source-id: 800de0454e4ac1bbb95679eaad6c24dc4d48ad22
This commit is contained in:
Ruslan Shestopalyuk
2024-05-13 22:45:04 -07:00
committed by Facebook GitHub Bot
parent 44f9371f24
commit 8593eee9fe
6 changed files with 138 additions and 168 deletions
@@ -3329,7 +3329,7 @@ public class com/facebook/react/modules/fresco/SystraceRequestListener : com/fac
public fun requiresExtraMap (Ljava/lang/String;)Z
}
public class com/facebook/react/modules/i18nmanager/I18nManagerModule : com/facebook/fbreact/specs/NativeI18nManagerSpec {
public final class com/facebook/react/modules/i18nmanager/I18nManagerModule : com/facebook/fbreact/specs/NativeI18nManagerSpec {
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;)V
public fun allowRTL (Z)V
public fun forceRTL (Z)V
@@ -3337,13 +3337,18 @@ public class com/facebook/react/modules/i18nmanager/I18nManagerModule : com/face
public fun swapLeftAndRightInRTL (Z)V
}
public class com/facebook/react/modules/i18nmanager/I18nUtil {
public fun allowRTL (Landroid/content/Context;Z)V
public fun doLeftAndRightSwapInRTL (Landroid/content/Context;)Z
public fun forceRTL (Landroid/content/Context;Z)V
public static fun getInstance ()Lcom/facebook/react/modules/i18nmanager/I18nUtil;
public fun isRTL (Landroid/content/Context;)Z
public fun swapLeftAndRightInRTL (Landroid/content/Context;Z)V
public final class com/facebook/react/modules/i18nmanager/I18nUtil {
public static final field Companion Lcom/facebook/react/modules/i18nmanager/I18nUtil$Companion;
public final fun allowRTL (Landroid/content/Context;Z)V
public final fun doLeftAndRightSwapInRTL (Landroid/content/Context;)Z
public final fun forceRTL (Landroid/content/Context;Z)V
public static final fun getInstance ()Lcom/facebook/react/modules/i18nmanager/I18nUtil;
public final fun isRTL (Landroid/content/Context;)Z
public final fun swapLeftAndRightInRTL (Landroid/content/Context;Z)V
}
public final class com/facebook/react/modules/i18nmanager/I18nUtil$Companion {
public final fun getInstance ()Lcom/facebook/react/modules/i18nmanager/I18nUtil;
}
public final class com/facebook/react/modules/image/ImageLoaderModule : com/facebook/fbreact/specs/NativeImageLoaderAndroidSpec, com/facebook/react/bridge/LifecycleEventListener {
@@ -1,61 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.modules.i18nmanager;
import android.content.Context;
import android.os.Build;
import com.facebook.fbreact.specs.NativeI18nManagerSpec;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.module.annotations.ReactModule;
import java.util.Locale;
import java.util.Map;
/** {@link NativeModule} that allows JS to set allowRTL and get isRTL status. */
@ReactModule(name = NativeI18nManagerSpec.NAME)
public class I18nManagerModule extends NativeI18nManagerSpec {
private final I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
public I18nManagerModule(ReactApplicationContext context) {
super(context);
}
@Override
public Map<String, Object> getTypedExportedConstants() {
final Context context = getReactApplicationContext();
final Locale locale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
locale = context.getResources().getConfiguration().getLocales().get(0);
} else {
locale = context.getResources().getConfiguration().locale;
}
final Map<String, Object> constants = MapBuilder.newHashMap();
constants.put("isRTL", sharedI18nUtilInstance.isRTL(context));
constants.put(
"doLeftAndRightSwapInRTL", sharedI18nUtilInstance.doLeftAndRightSwapInRTL(context));
constants.put("localeIdentifier", locale.toString());
return constants;
}
@Override
public void allowRTL(boolean value) {
sharedI18nUtilInstance.allowRTL(getReactApplicationContext(), value);
}
@Override
public void forceRTL(boolean value) {
sharedI18nUtilInstance.forceRTL(getReactApplicationContext(), value);
}
@Override
public void swapLeftAndRightInRTL(boolean value) {
sharedI18nUtilInstance.swapLeftAndRightInRTL(getReactApplicationContext(), value);
}
}
@@ -0,0 +1,43 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.modules.i18nmanager
import android.os.Build
import com.facebook.fbreact.specs.NativeI18nManagerSpec
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.module.annotations.ReactModule
/** [NativeModule] that allows JS to set allowRTL and get isRTL status. */
@ReactModule(name = NativeI18nManagerSpec.NAME)
public class I18nManagerModule(context: ReactApplicationContext?) : NativeI18nManagerSpec(context) {
override public fun getTypedExportedConstants(): Map<String, Any> {
val context = getReactApplicationContext()
val locale =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
context.resources.configuration.locales[0]
} else {
@Suppress("DEPRECATION") context.resources.configuration.locale
}
return mapOf(
"isRTL" to I18nUtil.instance.isRTL(context),
"doLeftAndRightSwapInRTL" to I18nUtil.instance.doLeftAndRightSwapInRTL(context),
"localeIdentifier" to locale.toString())
}
override fun allowRTL(value: Boolean) {
I18nUtil.instance.allowRTL(getReactApplicationContext(), value)
}
override fun forceRTL(value: Boolean) {
I18nUtil.instance.forceRTL(getReactApplicationContext(), value)
}
override fun swapLeftAndRightInRTL(value: Boolean) {
I18nUtil.instance.swapLeftAndRightInRTL(getReactApplicationContext(), value)
}
}
@@ -1,98 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.modules.i18nmanager;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.core.text.TextUtilsCompat;
import androidx.core.view.ViewCompat;
import java.util.Locale;
public class I18nUtil {
private static I18nUtil sharedI18nUtilInstance = null;
private static final String SHARED_PREFS_NAME = "com.facebook.react.modules.i18nmanager.I18nUtil";
private static final String KEY_FOR_PREFS_ALLOWRTL = "RCTI18nUtil_allowRTL";
private static final String KEY_FOR_PREFS_FORCERTL = "RCTI18nUtil_forceRTL";
private static final String KEY_FOR_PERFS_MAKE_RTL_FLIP_LEFT_AND_RIGHT_STYLES =
"RCTI18nUtil_makeRTLFlipLeftAndRightStyles";
private I18nUtil() {
// Exists only to defeat instantiation.
}
public static I18nUtil getInstance() {
if (sharedI18nUtilInstance == null) {
sharedI18nUtilInstance = new I18nUtil();
}
return sharedI18nUtilInstance;
}
/**
* Check if the device is currently running on an RTL locale. This only happens when the app:
*
* <ul>
* <li>is forcing RTL layout, regardless of the active language (for development purpose)
* <li>allows RTL layout when using RTL locale
* </ul>
*/
public boolean isRTL(Context context) {
if (isRTLForced(context)) {
return true;
}
return isRTLAllowed(context) && isDevicePreferredLanguageRTL();
}
/**
* Should be used very early during app start up Before the bridge is initialized
*
* @return whether the app allows RTL layout, default is true
*/
private boolean isRTLAllowed(Context context) {
return isPrefSet(context, KEY_FOR_PREFS_ALLOWRTL, true);
}
public void allowRTL(Context context, boolean allowRTL) {
setPref(context, KEY_FOR_PREFS_ALLOWRTL, allowRTL);
}
public boolean doLeftAndRightSwapInRTL(Context context) {
return isPrefSet(context, KEY_FOR_PERFS_MAKE_RTL_FLIP_LEFT_AND_RIGHT_STYLES, true);
}
public void swapLeftAndRightInRTL(Context context, boolean flip) {
setPref(context, KEY_FOR_PERFS_MAKE_RTL_FLIP_LEFT_AND_RIGHT_STYLES, flip);
}
/** Could be used to test RTL layout with English Used for development and testing purpose */
private boolean isRTLForced(Context context) {
return isPrefSet(context, KEY_FOR_PREFS_FORCERTL, false);
}
public void forceRTL(Context context, boolean forceRTL) {
setPref(context, KEY_FOR_PREFS_FORCERTL, forceRTL);
}
// Check if the current device language is RTL
private boolean isDevicePreferredLanguageRTL() {
final int directionality = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault());
return directionality == ViewCompat.LAYOUT_DIRECTION_RTL;
}
private boolean isPrefSet(Context context, String key, boolean defaultValue) {
SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
return prefs.getBoolean(key, defaultValue);
}
private void setPref(Context context, String key, boolean value) {
SharedPreferences.Editor editor =
context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE).edit();
editor.putBoolean(key, value);
editor.apply();
}
}
@@ -0,0 +1,81 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.modules.i18nmanager
import android.content.Context
import androidx.core.text.TextUtilsCompat
import androidx.core.view.ViewCompat
import java.util.Locale
public class I18nUtil private constructor() {
/**
* Check if the device is currently running on an RTL locale. This only happens when the app:
* * is forcing RTL layout, regardless of the active language (for development purpose)
* * allows RTL layout when using RTL locale
*/
public fun isRTL(context: Context): Boolean =
if (isRTLForced(context)) {
true
} else isRTLAllowed(context) && isDevicePreferredLanguageRTL
/**
* Should be used very early during app start up Before the bridge is initialized
*
* @return whether the app allows RTL layout, default is true
*/
private fun isRTLAllowed(context: Context): Boolean =
isPrefSet(context, KEY_FOR_PREFS_ALLOWRTL, true)
public fun allowRTL(context: Context, allowRTL: Boolean) {
setPref(context, KEY_FOR_PREFS_ALLOWRTL, allowRTL)
}
public fun doLeftAndRightSwapInRTL(context: Context): Boolean =
isPrefSet(context, KEY_FOR_PERFS_MAKE_RTL_FLIP_LEFT_AND_RIGHT_STYLES, true)
public fun swapLeftAndRightInRTL(context: Context, flip: Boolean) {
setPref(context, KEY_FOR_PERFS_MAKE_RTL_FLIP_LEFT_AND_RIGHT_STYLES, flip)
}
/** Could be used to test RTL layout with English Used for development and testing purpose */
private fun isRTLForced(context: Context): Boolean =
isPrefSet(context, KEY_FOR_PREFS_FORCERTL, false)
public fun forceRTL(context: Context, forceRTL: Boolean) {
setPref(context, KEY_FOR_PREFS_FORCERTL, forceRTL)
}
private val isDevicePreferredLanguageRTL: Boolean
// Check if the current device language is RTL
get() {
val directionality = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault())
return directionality == ViewCompat.LAYOUT_DIRECTION_RTL
}
private fun isPrefSet(context: Context, key: String, defaultValue: Boolean): Boolean =
context
.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE)
.getBoolean(key, defaultValue)
private fun setPref(context: Context, key: String, value: Boolean) {
val editor = context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE).edit()
editor.putBoolean(key, value)
editor.apply()
}
public companion object {
public val instance: I18nUtil = I18nUtil()
@JvmStatic get() = field
private const val SHARED_PREFS_NAME = "com.facebook.react.modules.i18nmanager.I18nUtil"
private const val KEY_FOR_PREFS_ALLOWRTL = "RCTI18nUtil_allowRTL"
private const val KEY_FOR_PREFS_FORCERTL = "RCTI18nUtil_forceRTL"
private const val KEY_FOR_PERFS_MAKE_RTL_FLIP_LEFT_AND_RIGHT_STYLES =
"RCTI18nUtil_makeRTLFlipLeftAndRightStyles"
}
}
@@ -121,7 +121,7 @@ public data class BorderRadiusStyle(
bottomRight = bottomRight?.resolve(width, height) ?: 0f,
)
LayoutDirection.RTL ->
if (I18nUtil.getInstance().doLeftAndRightSwapInRTL(context)) {
if (I18nUtil.instance.doLeftAndRightSwapInRTL(context)) {
ComputedBorderRadius(
topLeft = topRight?.resolve(width, height) ?: 0f,
topRight = topLeft?.resolve(width, height) ?: 0f,