7015500: Locale.toLanguageTag() uses "und" as lang subtag for private use only Locale
authornaoto
Tue, 08 Feb 2011 09:04:30 -0800
changeset 8149 768769e3cddd
parent 8148 ff3d90bb0503
child 8150 0a3a7198c1c8
child 8371 6201af876de8
7015500: Locale.toLanguageTag() uses "und" as lang subtag for private use only Locale Reviewed-by: srl
jdk/src/share/classes/java/util/Locale.java
jdk/src/share/classes/sun/util/locale/LanguageTag.java
jdk/test/java/util/Locale/LocaleEnhanceTest.java
--- a/jdk/src/share/classes/java/util/Locale.java	Mon Feb 07 21:34:31 2011 +0300
+++ b/jdk/src/share/classes/java/util/Locale.java	Tue Feb 08 09:04:30 2011 -0800
@@ -1265,7 +1265,9 @@
         StringBuilder buf = new StringBuilder();
 
         String subtag = tag.getLanguage();
-        buf.append(LanguageTag.canonicalizeLanguage(subtag));
+        if (subtag.length() > 0) {
+            buf.append(LanguageTag.canonicalizeLanguage(subtag));
+        }
 
         subtag = tag.getScript();
         if (subtag.length() > 0) {
@@ -1294,7 +1296,10 @@
 
         subtag = tag.getPrivateuse();
         if (subtag.length() > 0) {
-            buf.append(LanguageTag.SEP).append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
+            if (buf.length() > 0) {
+                buf.append(LanguageTag.SEP);
+            }
+            buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
             // preserve casing
             buf.append(subtag);
         }
--- a/jdk/src/share/classes/sun/util/locale/LanguageTag.java	Mon Feb 07 21:34:31 2011 +0300
+++ b/jdk/src/share/classes/sun/util/locale/LanguageTag.java	Tue Feb 08 09:04:30 2011 -0800
@@ -421,11 +421,11 @@
         String region = baseLocale.getRegion();
         String variant = baseLocale.getVariant();
 
+        boolean hasSubtag = false;
+
         String privuseVar = null;   // store ill-formed variant subtags
 
-        if (language.length() == 0 || !isLanguage(language)) {
-            tag._language = UNDETERMINED;
-        } else {
+        if (language.length() > 0 && isLanguage(language)) {
             // Convert a deprecated language code used by Java to
             // a new code
             if (language.equals("iw")) {
@@ -440,10 +440,12 @@
 
         if (script.length() > 0 && isScript(script)) {
             tag._script = canonicalizeScript(script);
+            hasSubtag = true;
         }
 
         if (region.length() > 0 && isRegion(region)) {
             tag._region = canonicalizeRegion(region);
+            hasSubtag = true;
         }
 
         // Special handling for no_NO_NY - use nn_NO for language tag
@@ -468,6 +470,7 @@
             }
             if (variants != null) {
                 tag._variants = variants;
+                hasSubtag = true;
             }
             if (!varitr.isDone()) {
                 // ill-formed variant subtags
@@ -508,6 +511,7 @@
 
         if (extensions != null) {
             tag._extensions = extensions;
+            hasSubtag = true;
         }
 
         // append ill-formed variant subtags to private use
@@ -521,8 +525,12 @@
 
         if (privateuse != null) {
             tag._privateuse = privateuse;
-        } else if (tag._language.length() == 0) {
-            // use "und" if neither language nor privateuse is available
+        }
+
+        if (tag._language.length() == 0 && (hasSubtag || privateuse == null)) {
+            // use lang "und" when 1) no language is available AND
+            // 2) any of other subtags other than private use are available or
+            // no private use tag is available
             tag._language = UNDETERMINED;
         }
 
--- a/jdk/test/java/util/Locale/LocaleEnhanceTest.java	Mon Feb 07 21:34:31 2011 +0300
+++ b/jdk/test/java/util/Locale/LocaleEnhanceTest.java	Tue Feb 08 09:04:30 2011 -0800
@@ -478,6 +478,23 @@
             Locale locale = new Locale(test[0], test[1], test[2]);
             assertEquals("case " + i, test[3], locale.toLanguageTag());
         }
+
+        // test locales created from forLanguageTag
+        String[][] tests1 = {
+            // case is normalized during the round trip
+            { "EN-us", "en-US" },
+            { "en-Latn-US", "en-Latn-US" },
+            // reordering Unicode locale extensions
+            { "de-u-co-phonebk-ca-gregory", "de-u-ca-gregory-co-phonebk" },
+            // private use only language tag is preserved (no extra "und")
+            { "x-elmer", "x-elmer" },
+            { "x-lvariant-JP", "x-lvariant-JP" },
+        };
+        for (String[] test : tests1) {
+            Locale locale = Locale.forLanguageTag(test[0]);
+            assertEquals("case " + test[0], test[1], locale.toLanguageTag());
+        }
+
     }
 
     public void testForLanguageTag() {
@@ -488,9 +505,9 @@
 
         String[][] tests = {
             // private use tags only
-            { "x-abc", "und-x-abc" },
-            { "x-a-b-c", "und-x-a-b-c" },
-            { "x-a-12345678", "und-x-a-12345678" },
+            { "x-abc", "x-abc" },
+            { "x-a-b-c", "x-a-b-c" },
+            { "x-a-12345678", "x-a-12345678" },
 
             // grandfathered tags with preferred mappings
             { "i-ami", "ami" },
@@ -517,7 +534,7 @@
             // grandfathered irregular tags, no preferred mappings, drop illegal fields
             // from end.  If no subtag is mappable, fallback to 'und'
             { "i-default", "en-x-i-default" },
-            { "i-enochian", "und-x-i-enochian" },
+            { "i-enochian", "x-i-enochian" },
             { "i-mingo", "see-x-i-mingo" },
             { "en-GB-oed", "en-GB-x-oed" },
             { "zh-min", "nan-x-zh-min" },