classlib: implement String.to__Case with locale parameter in JS BE (#766)

This commit is contained in:
Ivan Hetman 2023-11-14 17:57:09 +02:00 committed by GitHub
parent e877cc86e4
commit 5336fc9b3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 94 additions and 14 deletions

View File

@ -195,15 +195,39 @@ public class JSStringInjector implements Injector, Function<ProviderContext, Inj
} }
private void toLowerCaseJS(InjectorContext context) { private void toLowerCaseJS(InjectorContext context) {
if (context.argumentCount() == 1) {
var writer = context.getWriter(); var writer = context.getWriter();
context.writeExpr(context.getArgument(0)); context.writeExpr(context.getArgument(0));
writer.append(".toLowerCase()"); writer.append(".toLowerCase()");
return;
}
if (context.argumentCount() == 2) {
var writer = context.getWriter();
context.writeExpr(context.getArgument(0));
writer.append(".toLocaleLowerCase(");
context.writeExpr(context.getArgument(1));
writer.append(")");
return;
}
throw new IllegalArgumentException();
} }
private void toUpperCaseJS(InjectorContext context) { private void toUpperCaseJS(InjectorContext context) {
if (context.argumentCount() == 1) {
var writer = context.getWriter(); var writer = context.getWriter();
context.writeExpr(context.getArgument(0)); context.writeExpr(context.getArgument(0));
writer.append(".toUpperCase()"); writer.append(".toUpperCase()");
return;
}
if (context.argumentCount() == 2) {
var writer = context.getWriter();
context.writeExpr(context.getArgument(0));
writer.append(".toLocaleUpperCase(");
context.writeExpr(context.getArgument(1));
writer.append(")");
return;
}
throw new IllegalArgumentException();
} }
private void intern(InjectorContext context) { private void intern(InjectorContext context) {

View File

@ -740,6 +740,9 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
@NoSideEffects @NoSideEffects
private static native Object toLowerCaseJS(Object nativeString); private static native Object toLowerCaseJS(Object nativeString);
@NoSideEffects
private static native Object toLowerCaseJS(Object nativeString, Object languageTag);
private TString toLowerCaseChars() { private TString toLowerCaseChars() {
var chars = new char[charactersLength()]; var chars = new char[charactersLength()];
for (int i = 0; i < charactersLength(); ++i) { for (int i = 0; i < charactersLength(); ++i) {
@ -766,6 +769,10 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
} }
public TString toLowerCase(TLocale locale) { public TString toLowerCase(TLocale locale) {
if (PlatformDetector.isJavaScript()) {
var upperCase = toLowerCaseJS(nativeString(), locale.toLanguageTag().nativeString());
return upperCase != nativeString() ? new TString(upperCase) : this;
}
return toLowerCase(); return toLowerCase();
} }
@ -800,6 +807,9 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
@NoSideEffects @NoSideEffects
private static native Object toUpperCaseJS(Object nativeString); private static native Object toUpperCaseJS(Object nativeString);
@NoSideEffects
private static native Object toUpperCaseJS(Object nativeString, Object languageTag);
private TString toUpperCaseChars() { private TString toUpperCaseChars() {
var chars = new char[charactersLength()]; var chars = new char[charactersLength()];
for (int i = 0; i < charactersLength(); ++i) { for (int i = 0; i < charactersLength(); ++i) {
@ -825,6 +835,10 @@ public class TString extends TObject implements TSerializable, TComparable<TStri
} }
public TString toUpperCase(TLocale locale) { public TString toUpperCase(TLocale locale) {
if (PlatformDetector.isJavaScript()) {
var upperCase = toUpperCaseJS(nativeString(), locale.toLanguageTag().nativeString());
return upperCase != nativeString() ? new TString(upperCase) : this;
}
return toUpperCase(); return toUpperCase();
} }

View File

@ -36,6 +36,7 @@ import java.util.Arrays;
import org.teavm.classlib.impl.unicode.CLDRHelper; import org.teavm.classlib.impl.unicode.CLDRHelper;
import org.teavm.classlib.java.io.TSerializable; import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.lang.TCloneable; import org.teavm.classlib.java.lang.TCloneable;
import org.teavm.classlib.java.lang.TString;
import org.teavm.platform.metadata.ResourceArray; import org.teavm.platform.metadata.ResourceArray;
import org.teavm.platform.metadata.ResourceMap; import org.teavm.platform.metadata.ResourceMap;
import org.teavm.platform.metadata.StringResource; import org.teavm.platform.metadata.StringResource;
@ -88,7 +89,7 @@ public final class TLocale implements TCloneable, TSerializable {
if (language == null || country == null || variant == null) { if (language == null || country == null || variant == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
if (language.length() == 0 && country.length() == 0) { if (language.isEmpty() && country.isEmpty()) {
languageCode = ""; languageCode = "";
countryCode = ""; countryCode = "";
variantCode = variant; variantCode = variant;
@ -200,18 +201,18 @@ public final class TLocale implements TCloneable, TSerializable {
public String getDisplayName(TLocale locale) { public String getDisplayName(TLocale locale) {
int count = 0; int count = 0;
StringBuilder buffer = new StringBuilder(); StringBuilder buffer = new StringBuilder();
if (languageCode.length() > 0) { if (!languageCode.isEmpty()) {
buffer.append(getDisplayLanguage(locale)); buffer.append(getDisplayLanguage(locale));
count++; count++;
} }
if (countryCode.length() > 0) { if (!countryCode.isEmpty()) {
if (count == 1) { if (count == 1) {
buffer.append(" ("); buffer.append(" (");
} }
buffer.append(getDisplayCountry(locale)); buffer.append(getDisplayCountry(locale));
count++; count++;
} }
if (variantCode.length() > 0) { if (!variantCode.isEmpty()) {
if (count == 1) { if (count == 1) {
buffer.append(" ("); buffer.append(" (");
} else if (count == 2) { } else if (count == 2) {
@ -260,12 +261,12 @@ public final class TLocale implements TCloneable, TSerializable {
public String toString() { public String toString() {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
result.append(languageCode); result.append(languageCode);
if (countryCode.length() > 0) { if (!countryCode.isEmpty()) {
result.append('_'); result.append('_');
result.append(countryCode); result.append(countryCode);
} }
if (variantCode.length() > 0 && result.length() > 0) { if (!variantCode.isEmpty() && result.length() > 0) {
if (0 == countryCode.length()) { if (countryCode.isEmpty()) {
result.append("__"); result.append("__");
} else { } else {
result.append('_'); result.append('_');
@ -274,4 +275,18 @@ public final class TLocale implements TCloneable, TSerializable {
} }
return result.toString(); return result.toString();
} }
public TString toLanguageTag() {
StringBuilder result = new StringBuilder();
result.append(languageCode);
if (!countryCode.isEmpty()) {
result.append('-');
result.append(countryCode);
}
if (!variantCode.isEmpty() && result.length() > 0) {
result.append('-');
result.append(variantCode);
}
return new TString(result.toString().toCharArray());
}
} }

View File

@ -22,6 +22,7 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.Locale;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.teavm.junit.EachTestCompiledSeparately; import org.teavm.junit.EachTestCompiledSeparately;
@ -309,8 +310,24 @@ public class StringTest {
} }
@Test @Test
public void makesLowerCase() { public void convertsCase() {
assertEquals("foo bar", "FoO bAr".toLowerCase()); assertEquals("foo bar", "FoO bAr".toLowerCase());
assertEquals("FOO BAR", "FoO bAr".toUpperCase());
}
private String common = "i̇stanbul";
private String turkish = "istanbul";
@Test
@SkipPlatform({ TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI })
public void convertsCaseLocaled() {
assertEquals(turkish, "İstanbul".toLowerCase(new Locale("tr", "TR")));
assertEquals(common, "İstanbul".toLowerCase(Locale.US));
assertNotEquals(turkish, common);
assertEquals("İSTANBUL", common.toUpperCase(Locale.US));
assertEquals("İSTANBUL", turkish.toUpperCase(new Locale("tr", "TR")));
assertNotEquals(common.toUpperCase(Locale.US), turkish.toUpperCase(new Locale("tr", "TR")));
assertEquals(common.toUpperCase(Locale.US), common.toUpperCase(Locale.CANADA));
} }
@Test @Test

View File

@ -61,4 +61,14 @@ public class LocaleTest {
assertEquals("Соединенные Штаты", usEnglish.getDisplayCountry(russian)); assertEquals("Соединенные Штаты", usEnglish.getDisplayCountry(russian));
assertEquals("Россия", russian.getDisplayCountry(russian)); assertEquals("Россия", russian.getDisplayCountry(russian));
} }
@Test
public void testLanguageTag() {
assertEquals("fr-CA", Locale.CANADA_FRENCH.toLanguageTag());
assertEquals("zh", Locale.CHINESE.toLanguageTag());
assertEquals("zh-TW", Locale.TRADITIONAL_CHINESE.toLanguageTag());
assertEquals("zh-CN", Locale.SIMPLIFIED_CHINESE.toLanguageTag());
assertEquals("en-GB", Locale.UK.toLanguageTag());
assertEquals("en-US", Locale.US.toLanguageTag());
}
} }