Skip to content

Commit 4bc43bf

Browse files
committed
Parse Locales with scripts properly in LocaleTypeDescriptor.fromString
Locales with scripts (e.g. zh-Hant-HK) were not parsed properly by LocaleTypeDescriptor, causing the script part to get lost.
1 parent b40d125 commit 4bc43bf

File tree

2 files changed

+52
-45
lines changed

2 files changed

+52
-45
lines changed

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/LocaleTypeDescriptor.java

+37-36
Original file line numberDiff line numberDiff line change
@@ -41,53 +41,54 @@ public String toString(Locale value) {
4141
}
4242

4343
public Locale fromString(String string) {
44-
// TODO : Ultimately switch to Locale.Builder for this. However, Locale.Builder is Java 7
45-
4644
if ( string == null ) {
4745
return null;
4846
}
4947

50-
if( string.isEmpty() ) {
48+
if ( string.isEmpty() ) {
5149
return Locale.ROOT;
5250
}
5351

54-
boolean separatorFound = false;
55-
int position = 0;
56-
char[] chars = string.toCharArray();
57-
58-
for ( int i = 0; i < chars.length; i++ ) {
59-
// We just look for separators
60-
if ( chars[i] == '_' ) {
61-
if ( !separatorFound ) {
62-
// On the first separator we know that we have at least a language
63-
string = new String( chars, position, i - position );
64-
position = i + 1;
65-
}
66-
else {
67-
// On the second separator we have to check whether there are more chars available for variant
68-
if ( chars.length > i + 1 ) {
69-
// There is a variant so add it to the constructor
70-
return new Locale( string, new String( chars, position, i - position ), new String( chars,
71-
i + 1, chars.length - i - 1 ) );
72-
}
73-
else {
74-
// No variant given, we just have language and country
75-
return new Locale( string, new String( chars, position, i - position ), "" );
76-
}
77-
}
78-
79-
separatorFound = true;
80-
}
52+
// Locale.toString returns a String representation matching the following pattern:
53+
// language + "_" + country + "_" + (variant + "_#" | "#") + script + "_" + extensions
54+
final Locale.Builder builder = new Locale.Builder();
55+
final String[] parts = string.split("#");
56+
final String[] langCountryVariant = parts[0].split("_");
57+
58+
if ( !langCountryVariant[0].isEmpty() ) {
59+
builder.setLanguage( langCountryVariant[0] );
8160
}
8261

83-
if ( !separatorFound ) {
84-
// No separator found, there is only a language
85-
return new Locale( string );
62+
if ( langCountryVariant.length > 1 && !langCountryVariant[1].isEmpty() ) {
63+
builder.setRegion( langCountryVariant[1] );
8664
}
87-
else {
88-
// Only one separator found, there is a language and a country
89-
return new Locale( string, new String( chars, position, chars.length - position ) );
65+
66+
if ( langCountryVariant.length > 2 && !langCountryVariant[2].isEmpty() ) {
67+
builder.setVariant( langCountryVariant[2] );
9068
}
69+
70+
if ( parts.length > 1 ) {
71+
final String scriptExtension = parts[1];
72+
final String maybeScript;
73+
if ( scriptExtension.contains( "_" ) ) {
74+
maybeScript = scriptExtension.substring( 0, scriptExtension.indexOf( "_" ) );
75+
}
76+
else {
77+
maybeScript = scriptExtension;
78+
}
79+
80+
if ( !isExtension(maybeScript) ) {
81+
builder.setScript(maybeScript);
82+
}
83+
}
84+
85+
return builder.build();
86+
}
87+
88+
private static boolean isExtension(String token) {
89+
return token.length() >= 3
90+
&& ( Character.isAlphabetic( token.charAt(0) ) || Character.isDigit( token.charAt(0) ) )
91+
&& token.charAt( 1 ) == '-';
9192
}
9293

9394
@SuppressWarnings({ "unchecked" })

hibernate-core/src/test/java/org/hibernate/test/type/descriptor/java/LocaleTypeDescriptorTest.java

+15-9
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,21 @@ public class LocaleTypeDescriptorTest extends BaseUnitTestCase {
2525

2626
@Test
2727
public void testConversionFromString() {
28-
assertEquals( toLocale( "de", null, null ), LocaleTypeDescriptor.INSTANCE.fromString( "de" ) );
29-
assertEquals( toLocale( "de", "DE", null ), LocaleTypeDescriptor.INSTANCE.fromString( "de_DE" ) );
30-
assertEquals( toLocale( null, "DE", null ), LocaleTypeDescriptor.INSTANCE.fromString( "_DE" ) );
31-
assertEquals( toLocale( null, null, "ch123" ), LocaleTypeDescriptor.INSTANCE.fromString( "__ch123" ) );
32-
assertEquals( toLocale( null, "DE", "ch123" ), LocaleTypeDescriptor.INSTANCE.fromString( "_DE_ch123" ) );
33-
assertEquals( toLocale( "de", null, "ch123" ), LocaleTypeDescriptor.INSTANCE.fromString( "de__ch123" ) );
34-
assertEquals( toLocale( "de", "DE", "ch123" ), LocaleTypeDescriptor.INSTANCE.fromString( "de_DE_ch123" ) );
35-
assertEquals( toLocale( "", "", "" ), LocaleTypeDescriptor.INSTANCE.fromString( "" ) );
28+
assertEquals( toLocale( "de", null, null, null ), LocaleTypeDescriptor.INSTANCE.fromString( "de" ) );
29+
assertEquals( toLocale( "de", "DE", null, null ), LocaleTypeDescriptor.INSTANCE.fromString( "de_DE" ) );
30+
assertEquals( toLocale( null, "DE", null, null ), LocaleTypeDescriptor.INSTANCE.fromString( "_DE" ) );
31+
assertEquals( toLocale( null, null, "ch123", null ), LocaleTypeDescriptor.INSTANCE.fromString( "__ch123" ) );
32+
assertEquals( toLocale( null, "DE", "ch123", null ), LocaleTypeDescriptor.INSTANCE.fromString( "_DE_ch123" ) );
33+
assertEquals( toLocale( "de", null, "ch123", null ), LocaleTypeDescriptor.INSTANCE.fromString( "de__ch123" ) );
34+
assertEquals( toLocale( "de", "DE", "ch123", null ), LocaleTypeDescriptor.INSTANCE.fromString( "de_DE_ch123" ) );
35+
assertEquals( toLocale( "zh", "HK", null, "Hant" ), LocaleTypeDescriptor.INSTANCE.fromString( "zh_HK_#Hant" ) );
36+
assertEquals( toLocale( "zh", "TW", null, "Hant" ), LocaleTypeDescriptor.INSTANCE.fromString( "zh_TW_#Hant_x-java" ) );
37+
assertEquals( toLocale( "de", "DE", "1996", null ), LocaleTypeDescriptor.INSTANCE.fromString( "de_DE_1996_#u-co-phonebk-ka-shifted" ) );
38+
3639
assertEquals( Locale.ROOT, LocaleTypeDescriptor.INSTANCE.fromString( "" ) );
3740
}
3841

39-
public Locale toLocale(String lang, String region, String variant) {
42+
public Locale toLocale(String lang, String region, String variant, String script) {
4043
final Locale.Builder builder = new Locale.Builder();
4144
if ( StringHelper.isNotEmpty( lang ) ) {
4245
builder.setLanguage( lang );
@@ -47,6 +50,9 @@ public Locale toLocale(String lang, String region, String variant) {
4750
if ( StringHelper.isNotEmpty( variant ) ) {
4851
builder.setVariant( variant );
4952
}
53+
if ( StringHelper.isNotEmpty( script ) ) {
54+
builder.setScript( script );
55+
}
5056
return builder.build();
5157
}
5258
}

0 commit comments

Comments
 (0)