diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/hermes/unicode/AndroidUnicodeUtils.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/hermes/unicode/AndroidUnicodeUtils.java deleted file mode 100644 index 6a8796e3491..00000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/hermes/unicode/AndroidUnicodeUtils.java +++ /dev/null @@ -1,84 +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.hermes.unicode; - -import com.facebook.infer.annotation.Nullsafe; -import com.facebook.proguard.annotations.DoNotStrip; -import java.text.Collator; -import java.text.DateFormat; -import java.text.Normalizer; -import java.util.Locale; - -// TODO: use com.facebook.common.locale.Locales.getApplicationLocale() as the current locale, -// rather than the device locale. This is challenging because getApplicationLocale() is only -// available via DI. -@Nullsafe(Nullsafe.Mode.LOCAL) -@DoNotStrip -public class AndroidUnicodeUtils { - @DoNotStrip - public static int localeCompare(String left, String right) { - Collator collator = Collator.getInstance(); - return collator.compare(left, right); - } - - @DoNotStrip - public static String dateFormat(double unixtimeMs, boolean formatDate, boolean formatTime) { - DateFormat format; - if (formatDate && formatTime) { - format = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); - } else if (formatDate) { - format = DateFormat.getDateInstance(DateFormat.MEDIUM); - } else if (formatTime) { - format = DateFormat.getTimeInstance(DateFormat.MEDIUM); - } else { - throw new RuntimeException("Bad dateFormat configuration"); - } - return format.format((long) unixtimeMs).toString(); - } - - @DoNotStrip - public static String convertToCase(String input, int targetCase, boolean useCurrentLocale) { - // These values must match CaseConversion in PlatformUnicode.h - final int targetUppercase = 0; - final int targetLowercase = 1; - // Note Java's case conversions use the user's locale. For example "I".toLowerCase() - // will produce a dotless i. From Java's docs: "To obtain correct results for locale - // insensitive strings, use toLowerCase(Locale.ENGLISH)." - Locale locale = useCurrentLocale ? Locale.getDefault() : Locale.ENGLISH; - switch (targetCase) { - case targetLowercase: - return input.toLowerCase(locale); - case targetUppercase: - return input.toUpperCase(locale); - default: - throw new RuntimeException("Invalid target case"); - } - } - - @DoNotStrip - public static String normalize(String input, int form) { - // Values must match NormalizationForm in PlatformUnicode.h. - final int formC = 0; - final int formD = 1; - final int formKC = 2; - final int formKD = 3; - - switch (form) { - case formC: - return Normalizer.normalize(input, Normalizer.Form.NFC); - case formD: - return Normalizer.normalize(input, Normalizer.Form.NFD); - case formKC: - return Normalizer.normalize(input, Normalizer.Form.NFKC); - case formKD: - return Normalizer.normalize(input, Normalizer.Form.NFKD); - default: - throw new RuntimeException("Invalid form"); - } - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/hermes/unicode/AndroidUnicodeUtils.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/hermes/unicode/AndroidUnicodeUtils.kt new file mode 100644 index 00000000000..09d844461e4 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/hermes/unicode/AndroidUnicodeUtils.kt @@ -0,0 +1,73 @@ +/* + * 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.hermes.unicode + +import com.facebook.proguard.annotations.DoNotStrip +import java.text.Collator +import java.text.DateFormat +import java.text.Normalizer +import java.util.Locale + +// TODO: use com.facebook.common.locale.Locales.getApplicationLocale() as the current locale, +// rather than the device locale. This is challenging because getApplicationLocale() is only +// available via DI. +@DoNotStrip +public object AndroidUnicodeUtils { + + @DoNotStrip + public fun localeCompare(left: String?, right: String?): Int { + val collator = Collator.getInstance() + return collator.compare(left, right) + } + + @DoNotStrip + public fun dateFormat(unixtimeMs: Double, formatDate: Boolean, formatTime: Boolean): String { + val format = + when { + formatDate && formatTime -> + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM) + formatDate -> DateFormat.getDateInstance(DateFormat.MEDIUM) + formatTime -> DateFormat.getTimeInstance(DateFormat.MEDIUM) + else -> error("Bad dateFormat configuration") + } + return format.format(unixtimeMs.toLong()).toString() + } + + @DoNotStrip + public fun convertToCase(input: String, targetCase: Int, useCurrentLocale: Boolean): String { + // Note Java's case conversions use the user's locale. For example "I".toLowerCase() + // will produce a dotless i. From Java's docs: "To obtain correct results for locale + // insensitive strings, use toLowerCase(Locale.ENGLISH)." + val locale = if (useCurrentLocale) Locale.getDefault() else Locale.ENGLISH + return when (targetCase) { + TARGET_LOWERCASE -> input.lowercase(locale) + TARGET_UPPERCASE -> input.uppercase(locale) + else -> error("Invalid target case") + } + } + + @DoNotStrip + public fun normalize(input: String?, form: Int): String = + when (form) { + FORM_C -> Normalizer.normalize(input, Normalizer.Form.NFC) + FORM_D -> Normalizer.normalize(input, Normalizer.Form.NFD) + FORM_KC -> Normalizer.normalize(input, Normalizer.Form.NFKC) + FORM_KD -> Normalizer.normalize(input, Normalizer.Form.NFKD) + else -> error("Invalid form") + } + + // These values must match CaseConversion in PlatformUnicode.h + private const val TARGET_UPPERCASE = 0 + private const val TARGET_LOWERCASE = 1 + + // Values must match NormalizationForm in PlatformUnicode.h. + private const val FORM_C = 0 + private const val FORM_D = 1 + private const val FORM_KC = 2 + private const val FORM_KD = 3 +}