Skip to content

Commit c4cdb11

Browse files
loicottetjovanstevanovic
authored andcommitted
[GR-52096] Set default locale at run-time.
PullRequest: graal/16807
2 parents 0df39c8 + 9f1ae94 commit c4cdb11

File tree

15 files changed

+1075
-91
lines changed

15 files changed

+1075
-91
lines changed

substratevm/mx.substratevm/suite.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@
291291
"sun.security.util",
292292
"sun.text.spi",
293293
"sun.util",
294+
"sun.util.locale",
294295
"sun.util.calendar",
295296
"sun.util.locale.provider",
296297
"sun.util.resources",

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/LibCHelper.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import org.graalvm.nativeimage.c.type.CCharPointer;
3131
import org.graalvm.nativeimage.c.type.CCharPointerPointer;
3232

33+
import com.oracle.svm.core.util.BasedOnJDKFile;
34+
3335
@CLibrary(value = "libchelper", requireStatic = true, dependsOn = "java")
3436
public class LibCHelper {
3537
@CFunction(transition = Transition.NO_TRANSITION)
@@ -39,4 +41,18 @@ public class LibCHelper {
3941
// Checkstyle: stop
4042
public static native CCharPointer SVM_FindJavaTZmd(CCharPointer tzMappings, int length);
4143
// Checkstyle: start
44+
45+
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+13/src/java.base/unix/native/libjava/locale_str.h")
46+
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+13/src/java.base/windows/native/libjava/locale_str.h")
47+
public static class Locale {
48+
@CFunction(transition = Transition.TO_NATIVE)
49+
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+13/src/java.base/unix/native/libjava/java_props_md.c#L93-L540")
50+
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+13/src/java.base/windows/native/libjava/java_props_md.c#L257-L713")
51+
public static native CCharPointerPointer parseDisplayLocale();
52+
53+
@CFunction(transition = Transition.TO_NATIVE)
54+
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+13/src/java.base/unix/native/libjava/java_props_md.c#L93-L540")
55+
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+13/src/java.base/windows/native/libjava/java_props_md.c#L257-L713")
56+
public static native CCharPointerPointer parseFormatLocale();
57+
}
4258
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemPropertiesSupport.java

Lines changed: 130 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
*/
2525
package com.oracle.svm.core.jdk;
2626

27+
import static java.util.Locale.Category.DISPLAY;
28+
import static java.util.Locale.Category.FORMAT;
29+
2730
import java.util.Collections;
2831
import java.util.HashMap;
2932
import java.util.Locale;
@@ -35,13 +38,18 @@
3538
import org.graalvm.nativeimage.ImageSingletons;
3639
import org.graalvm.nativeimage.Platform;
3740
import org.graalvm.nativeimage.Platforms;
41+
import org.graalvm.nativeimage.c.type.CCharPointerPointer;
42+
import org.graalvm.nativeimage.c.type.CTypeConversion;
3843
import org.graalvm.nativeimage.impl.RuntimeSystemPropertiesSupport;
3944

45+
import com.oracle.svm.core.LibCHelper;
4046
import com.oracle.svm.core.VM;
4147
import com.oracle.svm.core.config.ConfigurationValues;
48+
import com.oracle.svm.core.headers.LibCSupport;
4249
import com.oracle.svm.core.util.VMError;
4350

4451
import jdk.graal.compiler.api.replacements.Fold;
52+
import jdk.graal.compiler.debug.GraalError;
4553

4654
/**
4755
* This class maintains the system properties at run time.
@@ -76,6 +84,13 @@ public abstract class SystemPropertiesSupport implements RuntimeSystemProperties
7684
"java.vm.specification.version"
7785
};
7886

87+
/* The list of field positions in locale_props_t (see locale_str.h). */
88+
private static final int LANGUAGE_POSITION = 0;
89+
private static final int SCRIPT_POSITION = LANGUAGE_POSITION + 1;
90+
private static final int COUNTRY_POSITION = SCRIPT_POSITION + 1;
91+
private static final int VARIANT_POSITION = COUNTRY_POSITION + 1;
92+
private static final int EXTENSION_POSITION = VARIANT_POSITION + 1;
93+
7994
/** System properties that are lazily computed at run time on first access. */
8095
private final Map<String, Supplier<String>> lazyRuntimeValues;
8196

@@ -139,6 +154,21 @@ protected SystemPropertiesSupport() {
139154
lazyRuntimeValues.put("java.io.tmpdir", this::javaIoTmpDir);
140155
lazyRuntimeValues.put("java.library.path", this::javaLibraryPath);
141156
lazyRuntimeValues.put("os.version", this::osVersionValue);
157+
lazyRuntimeValues.put(UserSystemProperty.USER_LANGUAGE, () -> postProcessLocale(UserSystemProperty.USER_LANGUAGE, parseLocale(DISPLAY).language(), null));
158+
lazyRuntimeValues.put(UserSystemProperty.USER_LANGUAGE_DISPLAY, () -> postProcessLocale(UserSystemProperty.USER_LANGUAGE, parseLocale(DISPLAY).language(), DISPLAY));
159+
lazyRuntimeValues.put(UserSystemProperty.USER_LANGUAGE_FORMAT, () -> postProcessLocale(UserSystemProperty.USER_LANGUAGE, parseLocale(FORMAT).language(), FORMAT));
160+
lazyRuntimeValues.put(UserSystemProperty.USER_SCRIPT, () -> postProcessLocale(UserSystemProperty.USER_SCRIPT, parseLocale(DISPLAY).script(), null));
161+
lazyRuntimeValues.put(UserSystemProperty.USER_SCRIPT_DISPLAY, () -> postProcessLocale(UserSystemProperty.USER_SCRIPT, parseLocale(DISPLAY).script(), DISPLAY));
162+
lazyRuntimeValues.put(UserSystemProperty.USER_SCRIPT_FORMAT, () -> postProcessLocale(UserSystemProperty.USER_SCRIPT, parseLocale(FORMAT).script(), FORMAT));
163+
lazyRuntimeValues.put(UserSystemProperty.USER_COUNTRY, () -> postProcessLocale(UserSystemProperty.USER_COUNTRY, parseLocale(DISPLAY).country(), null));
164+
lazyRuntimeValues.put(UserSystemProperty.USER_COUNTRY_DISPLAY, () -> postProcessLocale(UserSystemProperty.USER_COUNTRY, parseLocale(DISPLAY).country(), DISPLAY));
165+
lazyRuntimeValues.put(UserSystemProperty.USER_COUNTRY_FORMAT, () -> postProcessLocale(UserSystemProperty.USER_COUNTRY, parseLocale(FORMAT).country(), FORMAT));
166+
lazyRuntimeValues.put(UserSystemProperty.USER_VARIANT, () -> postProcessLocale(UserSystemProperty.USER_VARIANT, parseLocale(DISPLAY).variant(), null));
167+
lazyRuntimeValues.put(UserSystemProperty.USER_VARIANT_DISPLAY, () -> postProcessLocale(UserSystemProperty.USER_VARIANT, parseLocale(DISPLAY).variant(), DISPLAY));
168+
lazyRuntimeValues.put(UserSystemProperty.USER_VARIANT_FORMAT, () -> postProcessLocale(UserSystemProperty.USER_VARIANT, parseLocale(FORMAT).variant(), FORMAT));
169+
lazyRuntimeValues.put(UserSystemProperty.USER_EXTENSIONS, () -> postProcessLocale(UserSystemProperty.USER_EXTENSIONS, parseLocale(DISPLAY).extensions(), null));
170+
lazyRuntimeValues.put(UserSystemProperty.USER_EXTENSIONS_DISPLAY, () -> postProcessLocale(UserSystemProperty.USER_EXTENSIONS, parseLocale(DISPLAY).extensions(), DISPLAY));
171+
lazyRuntimeValues.put(UserSystemProperty.USER_EXTENSIONS_FORMAT, () -> postProcessLocale(UserSystemProperty.USER_EXTENSIONS, parseLocale(FORMAT).extensions(), FORMAT));
142172

143173
String targetName = System.getProperty("svm.targetName");
144174
if (targetName != null) {
@@ -183,6 +213,12 @@ protected String getProperty(String key) {
183213
return properties.getProperty(key);
184214
}
185215

216+
protected String getSavedProperty(String key, String defaultValue) {
217+
initializeLazyValue(key);
218+
String value = savedProperties.get(key);
219+
return value != null ? value : defaultValue;
220+
}
221+
186222
public void setProperties(Properties props) {
187223
// Flush lazy values into savedProperties
188224
ensureFullyInitialized();
@@ -235,10 +271,14 @@ private void initializeLazyValue(String key) {
235271
* manual updates of the same property key.
236272
*/
237273
String value = lazyRuntimeValues.get(key).get();
238-
if (properties.putIfAbsent(key, value) == null) {
239-
synchronized (savedProperties) {
240-
savedProperties.put(key, value);
241-
}
274+
setRawProperty(key, value);
275+
}
276+
}
277+
278+
private void setRawProperty(String key, String value) {
279+
if (value != null && properties.putIfAbsent(key, value) == null) {
280+
synchronized (savedProperties) {
281+
savedProperties.put(key, value);
242282
}
243283
}
244284
}
@@ -318,4 +358,90 @@ protected String osNameValue() {
318358
}
319359

320360
protected abstract String osVersionValue();
361+
362+
public record LocaleEncoding(String language, String script, String country, String variant, String extensions) {
363+
private LocaleEncoding(CCharPointerPointer properties) {
364+
this(fromCStringArray(properties, LANGUAGE_POSITION),
365+
fromCStringArray(properties, SCRIPT_POSITION),
366+
fromCStringArray(properties, COUNTRY_POSITION),
367+
fromCStringArray(properties, VARIANT_POSITION),
368+
fromCStringArray(properties, EXTENSION_POSITION));
369+
}
370+
371+
private static String fromCStringArray(CCharPointerPointer cString, int index) {
372+
if (cString.isNull()) {
373+
return null;
374+
}
375+
return CTypeConversion.toJavaString(cString.read(index));
376+
}
377+
}
378+
379+
private LocaleEncoding displayLocale;
380+
381+
private LocaleEncoding formatLocale;
382+
383+
protected LocaleEncoding parseLocale(Locale.Category category) {
384+
if (!ImageSingletons.contains(LibCSupport.class)) {
385+
/* If native calls are not supported, just return fixed values. */
386+
return new LocaleEncoding("en", "", "US", "", "");
387+
}
388+
switch (category) {
389+
case DISPLAY -> {
390+
if (displayLocale == null) {
391+
displayLocale = new LocaleEncoding(LibCHelper.Locale.parseDisplayLocale());
392+
}
393+
return displayLocale;
394+
}
395+
case FORMAT -> {
396+
if (formatLocale == null) {
397+
formatLocale = new LocaleEncoding(LibCHelper.Locale.parseFormatLocale());
398+
}
399+
return formatLocale;
400+
}
401+
default -> throw new GraalError("Unknown locale category: " + category + ".");
402+
}
403+
}
404+
405+
private String postProcessLocale(String base, String value, Locale.Category category) {
406+
if (category == null) {
407+
/* user.xxx property */
408+
String baseValue = null;
409+
if (value != null) {
410+
setRawProperty(base, value);
411+
baseValue = value;
412+
}
413+
return baseValue;
414+
}
415+
switch (category) {
416+
case DISPLAY, FORMAT -> {
417+
/* user.xxx.(display|format) property */
418+
String baseValue = getProperty(base);
419+
if (baseValue == null && value != null) {
420+
setRawProperty(base + '.' + category.name().toLowerCase(Locale.ROOT), value);
421+
return value;
422+
}
423+
return null;
424+
}
425+
default -> throw new GraalError("Unknown locale category: " + category + ".");
426+
}
427+
}
428+
429+
public static class UserSystemProperty {
430+
public static final String USER_LANGUAGE = "user.language";
431+
public static final String USER_LANGUAGE_DISPLAY = USER_LANGUAGE + ".display";
432+
public static final String USER_LANGUAGE_FORMAT = USER_LANGUAGE + ".format";
433+
public static final String USER_SCRIPT = "user.script";
434+
public static final String USER_SCRIPT_DISPLAY = USER_SCRIPT + ".display";
435+
public static final String USER_SCRIPT_FORMAT = USER_SCRIPT + ".format";
436+
public static final String USER_COUNTRY = "user.country";
437+
public static final String USER_COUNTRY_DISPLAY = USER_COUNTRY + ".display";
438+
public static final String USER_COUNTRY_FORMAT = USER_COUNTRY + ".format";
439+
public static final String USER_VARIANT = "user.variant";
440+
public static final String USER_VARIANT_DISPLAY = USER_VARIANT + ".display";
441+
public static final String USER_VARIANT_FORMAT = USER_VARIANT + ".format";
442+
public static final String USER_EXTENSIONS = "user.extensions";
443+
public static final String USER_EXTENSIONS_DISPLAY = USER_EXTENSIONS + ".display";
444+
public static final String USER_EXTENSIONS_FORMAT = USER_EXTENSIONS + ".format";
445+
public static final String USER_REGION = "user.region";
446+
}
321447
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_util_StaticProperty.java

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626

2727
import java.util.function.BooleanSupplier;
2828

29+
import com.oracle.svm.core.SubstrateUtil;
30+
import com.oracle.svm.core.annotate.Alias;
31+
import com.oracle.svm.core.annotate.RecomputeFieldValue;
2932
import com.oracle.svm.core.annotate.Substitute;
3033
import com.oracle.svm.core.annotate.TargetClass;
3134
import com.oracle.svm.core.annotate.TargetElement;
@@ -44,6 +47,93 @@
4447
@SuppressWarnings("unused")
4548
final class Target_jdk_internal_util_StaticProperty {
4649

50+
// Checkstyle: stop
51+
@Alias//
52+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
53+
public static String USER_LANGUAGE;
54+
55+
@Alias//
56+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
57+
public static String USER_LANGUAGE_DISPLAY;
58+
59+
@Alias//
60+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
61+
public static String USER_LANGUAGE_FORMAT;
62+
63+
@Alias//
64+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
65+
public static String USER_SCRIPT;
66+
67+
@Alias//
68+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
69+
public static String USER_SCRIPT_DISPLAY;
70+
71+
@Alias//
72+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
73+
public static String USER_SCRIPT_FORMAT;
74+
75+
@Alias//
76+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
77+
public static String USER_COUNTRY;
78+
79+
@Alias//
80+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
81+
public static String USER_COUNTRY_DISPLAY;
82+
83+
@Alias//
84+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
85+
public static String USER_COUNTRY_FORMAT;
86+
87+
@Alias//
88+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
89+
public static String USER_VARIANT;
90+
91+
@Alias//
92+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
93+
public static String USER_VARIANT_DISPLAY;
94+
95+
@Alias//
96+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
97+
public static String USER_VARIANT_FORMAT;
98+
99+
@Alias//
100+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
101+
public static String USER_EXTENSIONS;
102+
103+
@Alias//
104+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
105+
public static String USER_EXTENSIONS_DISPLAY;
106+
107+
@Alias//
108+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
109+
public static String USER_EXTENSIONS_FORMAT;
110+
111+
@Alias//
112+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)//
113+
public static String USER_REGION;
114+
// Checkstyle: resume
115+
116+
static {
117+
if (!SubstrateUtil.HOSTED) {
118+
USER_LANGUAGE = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_LANGUAGE, "en");
119+
USER_LANGUAGE_DISPLAY = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_LANGUAGE_DISPLAY, USER_LANGUAGE);
120+
USER_LANGUAGE_FORMAT = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_SCRIPT_FORMAT, USER_LANGUAGE);
121+
USER_SCRIPT = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_SCRIPT, "");
122+
USER_SCRIPT_DISPLAY = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_SCRIPT_DISPLAY, USER_SCRIPT);
123+
USER_SCRIPT_FORMAT = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_SCRIPT_FORMAT, USER_SCRIPT);
124+
USER_COUNTRY = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_COUNTRY, "");
125+
USER_COUNTRY_DISPLAY = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_COUNTRY_DISPLAY, USER_COUNTRY);
126+
USER_COUNTRY_FORMAT = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_COUNTRY_FORMAT, USER_COUNTRY);
127+
USER_VARIANT = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_VARIANT, "");
128+
USER_VARIANT_DISPLAY = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_VARIANT_DISPLAY, USER_VARIANT);
129+
USER_VARIANT_FORMAT = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_VARIANT_FORMAT, USER_VARIANT);
130+
USER_EXTENSIONS = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_EXTENSIONS, "");
131+
USER_EXTENSIONS_DISPLAY = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_EXTENSIONS_DISPLAY, USER_EXTENSIONS);
132+
USER_EXTENSIONS_FORMAT = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_EXTENSIONS_FORMAT, USER_EXTENSIONS);
133+
USER_REGION = SystemPropertiesSupport.singleton().getSavedProperty(SystemPropertiesSupport.UserSystemProperty.USER_REGION, "");
134+
}
135+
}
136+
47137
@Substitute
48138
private static String javaHome() {
49139
/* Native images do not have a Java home directory. */

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/BundleContentSubstitutedLocalizationSupport.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ public class BundleContentSubstitutedLocalizationSupport extends LocalizationSup
6969

7070
private final Set<String> existingBundles = ConcurrentHashMap.newKeySet();
7171

72-
public BundleContentSubstitutedLocalizationSupport(Locale defaultLocale, Set<Locale> locales, Charset defaultCharset, List<String> requestedPatterns, ForkJoinPool pool) {
73-
super(defaultLocale, locales, defaultCharset);
72+
public BundleContentSubstitutedLocalizationSupport(Set<Locale> locales, Charset defaultCharset, List<String> requestedPatterns, ForkJoinPool pool) {
73+
super(locales, defaultCharset);
7474
this.pool = pool;
7575
this.compressBundlesPatterns = parseCompressBundlePatterns(requestedPatterns);
7676
}
@@ -112,8 +112,7 @@ private void storeBundleContentOf(ResourceBundle bundle) {
112112

113113
@Platforms(Platform.HOSTED_ONLY.class)
114114
private StoredBundle processBundle(ResourceBundle bundle) {
115-
boolean isInDefaultLocale = bundle.getLocale().equals(defaultLocale);
116-
if (!isInDefaultLocale && shouldCompressBundle(bundle) && GzipBundleCompression.canCompress(bundle)) {
115+
if (shouldCompressBundle(bundle) && GzipBundleCompression.canCompress(bundle)) {
117116
return GzipBundleCompression.compress(bundle);
118117
}
119118
Map<String, Object> content = BundleSerializationUtils.extractContent(bundle);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,6 @@ public class LocalizationSupport {
7777

7878
public final Map<String, Charset> charsets = new HashMap<>();
7979

80-
public final Locale defaultLocale;
81-
8280
public final Locale[] allLocales;
8381

8482
public final Set<String> supportedLanguageTags;
@@ -91,8 +89,7 @@ public class LocalizationSupport {
9189

9290
private final EconomicMap<String, RuntimeConditionSet> registeredBundles = ImageHeapMap.create();
9391

94-
public LocalizationSupport(Locale defaultLocale, Set<Locale> locales, Charset defaultCharset) {
95-
this.defaultLocale = defaultLocale;
92+
public LocalizationSupport(Set<Locale> locales, Charset defaultCharset) {
9693
this.allLocales = locales.toArray(new Locale[0]);
9794
this.defaultCharset = defaultCharset;
9895
this.supportedLanguageTags = locales.stream().map(Locale::toString).collect(Collectors.toSet());

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/OptimizedLocalizationSupport.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ private record BundleCacheKey(String bundleName, Locale locale) {
5858

5959
final Map<BundleCacheKey, ResourceBundle> resourceBundles = new HashMap<>();
6060

61-
public OptimizedLocalizationSupport(Locale defaultLocale, Set<Locale> locales, Charset defaultCharset) {
62-
super(defaultLocale, locales, defaultCharset);
61+
public OptimizedLocalizationSupport(Set<Locale> locales, Charset defaultCharset) {
62+
super(locales, defaultCharset);
6363
}
6464

6565
@Override

0 commit comments

Comments
 (0)