]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/test/cintltst/cloctst.c
ICU-551.51.4.tar.gz
[apple/icu.git] / icuSources / test / cintltst / cloctst.c
index 2569eb23aab4de29ac487a716e47185e93a84f0c..5a90cb67ed3ab2cf91e002286390bf74d0caf3ef 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT:
- * Copyright (c) 1997-2013, International Business Machines Corporation and
+ * Copyright (c) 1997-2016, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 /*****************************************************************************
@@ -20,6 +20,7 @@
 #include "cstring.h"
 #include "uparse.h"
 #include "uresimp.h"
+#include "cmemory.h"
 
 #include "unicode/putil.h"
 #include "unicode/ubrk.h"
 #include "unicode/ustring.h"
 #include "unicode/utypes.h"
 #include "unicode/ulocdata.h"
+#include "unicode/uldnames.h"
 #include "unicode/parseerr.h" /* may not be included with some uconfig switches */
 #include "udbgutil.h"
-#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+#include "unicode/ualoc.h" /* Apple-specific */
 
 static void TestNullDefault(void);
 static void TestNonexistentLanguageExemplars(void);
 static void TestLocDataErrorCodeChaining(void);
 static void TestLanguageExemplarsFallbacks(void);
+static void TestDisplayNameBrackets(void);
 
 static void TestUnicodeDefines(void);
 
+static void TestIsRightToLeft(void);
+
+static void TestGetLanguagesForRegion(void);
+static void TestGetAppleParent(void);
+static void TestAppleLocalizationsToUse(void);
+
 void PrintDataTable();
 
 /*---------------------------------------------------
@@ -88,7 +97,7 @@ static const char* const rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = {
     /* display language (French) */
     {   "anglais",  "fran\\u00E7ais",   "catalan", "grec",    "norv\\u00E9gien",    "chinois", "allemand", "espagnol", "japonais"     },
     /* display script code (French) */
-    {   "",     "",     "",     "",     "",     "chinois simplifi\\u00e9", "", "", ""         },
+    {   "",     "",     "",     "",     "",     "sinogrammes simplifi\\u00e9s", "", "", ""         },
     /* display country (French) */
     {   "\\u00C9tats-Unis",    "France",   "Espagne",  "Gr\\u00E8ce",   "Norv\\u00E8ge",    "Chine", "Allemagne", "", "Japon"       },
     /* display variant (French) */
@@ -96,12 +105,12 @@ static const char* const rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = {
     /* display name (French) */
     {   "anglais (\\u00C9tats-Unis)", "fran\\u00E7ais (France)", "catalan (Espagne)", 
         "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, NY)",  "chinois (simplifi\\u00e9, Chine)", 
-        "allemand (Allemagne, ordonnancement=Ordre de l\\u2019annuaire)", "espagnol (ordonnancement=Ordre traditionnel)", "japonais (Japon, calendrier=Calendrier japonais)" },
+        "allemand (Allemagne, ordre de tri=ordre de l\\u2019annuaire)", "espagnol (ordre de tri=ordre traditionnel)", "japonais (Japon, calendrier=calendrier japonais)" },
 
     /* display language (Catalan) */
     {   "angl\\u00E8s", "franc\\u00E8s", "catal\\u00E0", "grec",  "noruec", "xin\\u00E8s", "alemany", "espanyol", "japon\\u00E8s"    },
     /* display script code (Catalan) */
-    {   "",     "",     "",     "",     "",     "xin\\u00E8s simplificat", "", "", ""         },
+    {   "",     "",     "",     "",     "",     "han simplificat", "", "", ""         },
     /* display country (Catalan) */
     {   "Estats Units", "Fran\\u00E7a", "Espanya",  "Gr\\u00E8cia", "Noruega",  "Xina", "Alemanya", "", "Jap\\u00F3"    },
     /* display variant (Catalan) */
@@ -109,7 +118,7 @@ static const char* const rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = {
     /* display name (Catalan) */
     {   "angl\\u00E8s (Estats Units)", "franc\\u00E8s (Fran\\u00E7a)", "catal\\u00E0 (Espanya)", 
     "grec (Gr\\u00E8cia)", "noruec (Noruega, NY)", "xin\\u00E8s (simplificat, Xina)", 
-    "alemany (Alemanya, ordre alfab\\u00e8tic=ordre de la guia telef\\u00F2nica)", "espanyol (ordre alfab\\u00e8tic=ordre tradicional)", "japon\\u00E8s (Jap\\u00F3, calendari=calendari japon\\u00e8s)" },
+    "alemany (Alemanya, ordenaci\\u00F3=ordre de la guia telef\\u00F2nica)", "espanyol (ordenaci\\u00F3=ordre tradicional)", "japon\\u00E8s (Jap\\u00F3, calendari=calendari japon\\u00e8s)" },
 
     /* display language (Greek) */
     {
@@ -125,10 +134,10 @@ static const char* const rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = {
     },
     /* display script code (Greek) */
 
-    {   "",     "",     "",     "",     "", "\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03b1 \\u03a7\\u03b1\\u03bd", "", "", "" },
+    {   "",     "",     "",     "",     "", "\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf \\u03a7\\u03b1\\u03bd", "", "", "" },
     /* display country (Greek) */
     {
-        "\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2 \\u03C4\\u03B7\\u03C2 \\u0391\\u03BC\\u03B5\\u03C1\\u03B9\\u03BA\\u03AE\\u03C2",
+        "\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2",
         "\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1",
         "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1",
         "\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1",
@@ -142,15 +151,15 @@ static const char* const rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = {
     {   "", "", "", "", "NY", "", "", "", ""    }, /* TODO: currently there is no translation for NY in Greek fix this test when we have it */
     /* display name (Greek) */
     {
-        "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac (\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2 \\u03C4\\u03B7\\u03C2 \\u0391\\u03BC\\u03B5\\u03C1\\u03B9\\u03BA\\u03AE\\u03C2)",
+        "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac (\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2)",
         "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac (\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1)",
         "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1)",
         "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac (\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1)",
-        "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac (\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1,NY)",
-        "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC (\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf \\u039a\\u03b9\\u03bd\\u03b5\\u03b6\\u03b9\\u03ba\\u03cc,\\u039A\\u03AF\\u03BD\\u03B1)",
-        "\\u0393\\u03b5\\u03c1\\u03bc\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0393\\u03b5\\u03c1\\u03bc\\u03b1\\u03bd\\u03af\\u03b1,\\u03a3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2=\\u03a3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2 \\u03c4\\u03b7\\u03bb\\u03b5\\u03c6\\u03c9\\u03bd\\u03b9\\u03ba\\u03bf\\u03cd \\u03ba\\u03b1\\u03c4\\u03b1\\u03bb\\u03cc\\u03b3\\u03bf\\u03c5)",
+        "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac (\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1, NY)",
+        "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC (\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf\\u039A\\u03AF\\u03BD\\u03B1)",
+        "\\u0393\\u03b5\\u03c1\\u03bc\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0393\\u03b5\\u03c1\\u03bc\\u03b1\\u03bd\\u03af\\u03b1, \\u03a3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2=\\u03a3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2 \\u03c4\\u03b7\\u03bb\\u03b5\\u03c6\\u03c9\\u03bd\\u03b9\\u03ba\\u03bf\\u03cd \\u03ba\\u03b1\\u03c4\\u03b1\\u03bb\\u03cc\\u03b3\\u03bf\\u03c5)",
         "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u03a3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2=\\u03a0\\u03b1\\u03c1\\u03b1\\u03b4\\u03bf\\u03c3\\u03b9\\u03b1\\u03ba\\u03ae \\u03c3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2)",
-        "\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03b9\\u03ba\\u03ac (\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03af\\u03b1,\\u0397\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf=\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03b9\\u03ba\\u03cc \\u03b7\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf)"
+        "\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03b9\\u03ba\\u03ac (\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03af\\u03b1, \\u0397\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf=\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03b9\\u03ba\\u03cc \\u03b7\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf)"
     }
 };
 
@@ -245,6 +254,15 @@ void addLocaleTest(TestNode** root)
     TESTCASE(TestTrailingNull);
     TESTCASE(TestUnicodeDefines);
     TESTCASE(TestEnglishExemplarCharacters);
+    TESTCASE(TestDisplayNameBrackets);
+    TESTCASE(TestIsRightToLeft);
+    TESTCASE(TestToUnicodeLocaleKey);
+    TESTCASE(TestToLegacyKey);
+    TESTCASE(TestToUnicodeLocaleType);
+    TESTCASE(TestToLegacyType);
+    TESTCASE(TestGetLanguagesForRegion);
+    TESTCASE(TestGetAppleParent);
+    TESTCASE(TestAppleLocalizationsToUse);
 }
 
 
@@ -662,7 +680,7 @@ static void TestDisplayNames()
 
     /* test that the default locale has a display name for its own language */
     errorCode=U_ZERO_ERROR;
-    length=uloc_getDisplayLanguage(NULL, NULL, buffer, LENGTHOF(buffer), &errorCode);
+    length=uloc_getDisplayLanguage(NULL, NULL, buffer, UPRV_LENGTHOF(buffer), &errorCode);
     if(U_FAILURE(errorCode) || (length<=3 && buffer[0]<=0x7f)) {
         /* check <=3 to reject getting the language code as a display name */
         log_data_err("unable to get a display string for the language of the default locale - %s (Are you missing data?)\n", u_errorName(errorCode));
@@ -670,14 +688,14 @@ static void TestDisplayNames()
 
     /* test that we get the language code itself for an unknown language, and a default warning */
     errorCode=U_ZERO_ERROR;
-    length=uloc_getDisplayLanguage("qq", "rr", buffer, LENGTHOF(buffer), &errorCode);
+    length=uloc_getDisplayLanguage("qq", "rr", buffer, UPRV_LENGTHOF(buffer), &errorCode);
     if(errorCode!=U_USING_DEFAULT_WARNING || length!=2 || buffer[0]!=0x71 || buffer[1]!=0x71) {
         log_err("error getting the display string for an unknown language - %s\n", u_errorName(errorCode));
     }
     
     /* test that we get a default warning for a display name where one component is unknown (4255) */
     errorCode=U_ZERO_ERROR;
-    length=uloc_getDisplayName("qq_US_POSIX", "en_US", buffer, LENGTHOF(buffer), &errorCode);
+    length=uloc_getDisplayName("qq_US_POSIX", "en_US", buffer, UPRV_LENGTHOF(buffer), &errorCode);
     if(errorCode!=U_USING_DEFAULT_WARNING) {
         log_err("error getting the display name for a locale with an unknown language - %s\n", u_errorName(errorCode));
     }
@@ -690,14 +708,14 @@ static void TestDisplayNames()
             "ca_ES",
             "el_GR" };
         static const char *expect[] = { "Spanish (Calendar=Japanese Calendar, Sort Order=Traditional Sort Order)", /* note sorted order of keywords */
-            "espagnol (calendrier=Calendrier japonais, ordonnancement=Ordre traditionnel)",
-            "espanyol (calendari=calendari japon\\u00e8s, ordre alfab\\u00e8tic=ordre tradicional)",
-            "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0397\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf=\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03b9\\u03ba\\u03cc \\u03b7\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf,\\u03a3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2=\\u03a0\\u03b1\\u03c1\\u03b1\\u03b4\\u03bf\\u03c3\\u03b9\\u03b1\\u03ba\\u03ae \\u03c3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2)" };
+            "espagnol (calendrier=calendrier japonais, ordre de tri=ordre traditionnel)",
+            "espanyol (calendari=calendari japon\\u00e8s, ordenaci\\u00f3=ordre tradicional)",
+            "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0397\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf=\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03b9\\u03ba\\u03cc \\u03b7\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf, \\u03a3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2=\\u03a0\\u03b1\\u03c1\\u03b1\\u03b4\\u03bf\\u03c3\\u03b9\\u03b1\\u03ba\\u03ae \\u03c3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2)" };
         UChar *expectBuffer;
 
-        for(i=0;i<LENGTHOF(testL);i++) {
+        for(i=0;i<UPRV_LENGTHOF(testL);i++) {
             errorCode = U_ZERO_ERROR;
-            uloc_getDisplayName(aLocale, testL[i], buffer, LENGTHOF(buffer), &errorCode);
+            uloc_getDisplayName(aLocale, testL[i], buffer, UPRV_LENGTHOF(buffer), &errorCode);
             if(U_FAILURE(errorCode)) {
                 log_err("FAIL in uloc_getDisplayName(%s,%s,..) -> %s\n", aLocale, testL[i], u_errorName(errorCode));
             } else {
@@ -719,7 +737,7 @@ static void TestDisplayNames()
         static const char *locale="az_Cyrl";
         static const char *displayLocale="ja";
         static const char *expectedChars =
-                "\\u30a2\\u30bc\\u30eb\\u30d0\\u30a4\\u30b8\\u30e3\\u30f3\\u8a9e"
+                "\\u30a2\\u30bc\\u30eb\\u30d0\\u30a4\\u30b8\\u30e3\\u30f3\\u8a9e "
                 "(\\u30ad\\u30ea\\u30eb\\u6587\\u5b57)";
         UErrorCode ec=U_ZERO_ERROR;
         UChar result[256];
@@ -729,7 +747,7 @@ static void TestDisplayNames()
         if(ec==U_BUFFER_OVERFLOW_ERROR) {
             ec=U_ZERO_ERROR;
         }
-        len=uloc_getDisplayName(locale, displayLocale, result, LENGTHOF(result), &ec);
+        len=uloc_getDisplayName(locale, displayLocale, result, UPRV_LENGTHOF(result), &ec);
         if(U_FAILURE(ec)) {
             log_err("uloc_getDisplayName(%s, %s...) returned error: %s",
                     locale, displayLocale, u_errorName(ec));
@@ -1021,6 +1039,102 @@ setUpDataTable();
 cleanUpDataTable();
 }
 
+/*------------------------------
+ * TestDisplayNameBrackets
+ */
+
+typedef struct {
+    const char * displayLocale;
+    const char * namedRegion;
+    const char * namedLocale;
+    const char * regionName;
+    const char * ulocLocaleName;
+    const char * uldnLocaleName;
+} DisplayNameBracketsItem;
+
+static const DisplayNameBracketsItem displayNameBracketsItems[] = {
+    { "en", "CC", "en_CC",      "Cocos (Keeling) Islands",  "English (Cocos [Keeling] Islands)",  "English (Cocos [Keeling] Islands)" },
+    { "en", "MM", "my_MM",      "Myanmar (Burma)",          "Burmese (Myanmar [Burma])",          "Burmese (Myanmar)"                 },
+    { "en", "MM", "my_Mymr_MM", "Myanmar (Burma)",          "Burmese (Myanmar, Myanmar [Burma])", "Burmese (Myanmar, Myanmar)"        },
+    { "zh", "CC", "en_CC",      "\\u79D1\\u79D1\\u65AF\\uFF08\\u57FA\\u6797\\uFF09\\u7FA4\\u5C9B",
+                                "\\u82F1\\u6587\\uFF08\\u79D1\\u79D1\\u65AF\\uFF3B\\u57FA\\u6797\\uFF3D\\u7FA4\\u5C9B\\uFF09",
+                                "\\u82F1\\u6587\\uFF08\\u79D1\\u79D1\\u65AF\\uFF3B\\u57FA\\u6797\\uFF3D\\u7FA4\\u5C9B\\uFF09"         },
+    { "zh", "CG", "fr_CG",      "\\u521A\\u679C\\uFF08\\u5E03\\uFF09",
+                                "\\u6CD5\\u6587\\uFF08\\u521A\\u679C\\uFF3B\\u5E03\\uFF3D\\uFF09",
+                                "\\u6CD5\\u6587\\uFF08\\u521A\\u679C\\uFF3B\\u5E03\\uFF3D\\uFF09"                                     },
+    { NULL, NULL, NULL,         NULL,                       NULL,                                  NULL                               }
+};
+
+enum { kDisplayNameBracketsMax = 128 };
+
+static void TestDisplayNameBrackets()
+{
+    const DisplayNameBracketsItem * itemPtr = displayNameBracketsItems;
+    for (; itemPtr->displayLocale != NULL; itemPtr++) {
+        ULocaleDisplayNames * uldn;
+        UErrorCode status;
+        UChar expectRegionName[kDisplayNameBracketsMax];
+        UChar expectUlocLocaleName[kDisplayNameBracketsMax];
+        UChar expectUldnLocaleName[kDisplayNameBracketsMax];
+        UChar getName[kDisplayNameBracketsMax];
+        int32_t ulen;
+        
+        (void) u_unescape(itemPtr->regionName, expectRegionName, kDisplayNameBracketsMax);
+        (void) u_unescape(itemPtr->ulocLocaleName, expectUlocLocaleName, kDisplayNameBracketsMax);
+        (void) u_unescape(itemPtr->uldnLocaleName, expectUldnLocaleName, kDisplayNameBracketsMax);
+
+        status = U_ZERO_ERROR;
+        ulen = uloc_getDisplayCountry(itemPtr->namedLocale, itemPtr->displayLocale, getName, kDisplayNameBracketsMax, &status);
+        if ( U_FAILURE(status) || u_strcmp(getName, expectRegionName) != 0 ) {
+            log_data_err("uloc_getDisplayCountry for displayLocale %s and namedLocale %s returns unexpected name or status %s\n", itemPtr->displayLocale, itemPtr->namedLocale, myErrorName(status));
+        }
+
+        status = U_ZERO_ERROR;
+        ulen = uloc_getDisplayName(itemPtr->namedLocale, itemPtr->displayLocale, getName, kDisplayNameBracketsMax, &status);
+        if ( U_FAILURE(status) || u_strcmp(getName, expectUlocLocaleName) != 0 ) {
+            log_data_err("uloc_getDisplayName for displayLocale %s and namedLocale %s returns unexpected name or status %s\n", itemPtr->displayLocale, itemPtr->namedLocale, myErrorName(status));
+        }
+        if ( U_FAILURE(status) ) {
+            log_data_err("uloc_getDisplayName for displayLocale %s and namedLocale %-10s returns unexpected status %s\n", itemPtr->displayLocale, itemPtr->namedLocale, myErrorName(status));
+        } else if ( u_strcmp(getName, expectUlocLocaleName) != 0 ) {
+            char bbuf[128];
+            u_strToUTF8(bbuf, 128, NULL, getName, ulen, &status);
+            log_data_err("uloc_getDisplayName for displayLocale %s and namedLocale %-10s returns unexpected name (len %d): \"%s\"\n", itemPtr->displayLocale, itemPtr->namedLocale, ulen, bbuf);
+        }
+
+#if !UCONFIG_NO_FORMATTING
+        status = U_ZERO_ERROR;
+        uldn = uldn_open(itemPtr->displayLocale, ULDN_STANDARD_NAMES, &status);
+        if (U_SUCCESS(status)) {
+            status = U_ZERO_ERROR;
+            ulen = uldn_regionDisplayName(uldn, itemPtr->namedRegion, getName, kDisplayNameBracketsMax, &status);
+            if ( U_FAILURE(status) || u_strcmp(getName, expectRegionName) != 0 ) {
+                log_data_err("uldn_regionDisplayName for displayLocale %s and namedRegion %s returns unexpected name or status %s\n", itemPtr->displayLocale, itemPtr->namedRegion, myErrorName(status));
+            }
+
+            status = U_ZERO_ERROR;
+            ulen = uldn_localeDisplayName(uldn, itemPtr->namedLocale, getName, kDisplayNameBracketsMax, &status);
+            if ( U_FAILURE(status) ) {
+                log_data_err("uldn_localeDisplayName for displayLocale %s and namedLocale %-10s returns unexpected status %s\n", itemPtr->displayLocale, itemPtr->namedLocale, myErrorName(status));
+            } else if ( u_strcmp(getName, expectUldnLocaleName) != 0 ) {
+                char bbuf[128];
+                u_strToUTF8(bbuf, 128, NULL, getName, ulen, &status);
+                log_data_err("uldn_localeDisplayName for displayLocale %s and namedLocale %-10s returns unexpected name (len %d): \"%s\"\n", itemPtr->displayLocale, itemPtr->namedLocale, ulen, bbuf);
+            }
+
+            uldn_close(uldn);
+        } else {
+            log_data_err("uldn_open fails for displayLocale %s, status=%s\n", itemPtr->displayLocale, u_errorName(status));
+        }
+#endif
+    (void)ulen;   /* Suppress variable not used warning */
+    }
+}
+
+/*------------------------------
+ * TestISOFunctions
+ */
+
 #if !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION
 /* test for uloc_getISOLanguages, uloc_getISOCountries */
 static void TestISOFunctions()
@@ -1667,6 +1781,7 @@ static void TestKeywordVariants(void)
             uenum_close(keywords);
         }
         resultLen = uloc_getName(testCases[i].localeID, buffer, 256, &status);
+        (void)resultLen;    /* Suppress set but not used warning. */
         if (uprv_strcmp(testCases[i].expectedLocaleID, buffer) != 0) {
             log_err("Expected uloc_getName(\"%s\") => \"%s\"; got \"%s\"\n",
                     testCases[i].localeID, testCases[i].expectedLocaleID, buffer);
@@ -1702,6 +1817,7 @@ static void TestKeywordVariantParsing(void)
     for(i = 0; i < sizeof(testCases)/sizeof(testCases[0]); i++) {
         *buffer = 0;
         resultLen = uloc_getKeywordValue(testCases[i].localeID, testCases[i].keyword, buffer, 256, &status);
+        (void)resultLen;    /* Suppress set but not used warning. */
         if(uprv_strcmp(testCases[i].expectedValue, buffer) != 0) {
             log_err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Got \"%s\" instead\n",
                 testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, buffer);
@@ -2112,14 +2228,14 @@ static void TestDisplayKeywordValues(void){
         {   "de_AT@currency=ATS",         "fr_FR", 
             {0x0073, 0x0063, 0x0068, 0x0069, 0x006c, 0x006c, 0x0069, 0x006e, 0x0067, 0x0020, 0x0061, 0x0075, 0x0074, 0x0072, 0x0069, 0x0063, 0x0068, 0x0069, 0x0065, 0x006e, 0x0000}
         },
-        { "de_DE@currency=DEM",         "it", 
-            {0x004d, 0x0061, 0x0072, 0x0063, 0x006f, 0x0020, 0x0054, 0x0065, 0x0064, 0x0065, 0x0073, 0x0063, 0x006f, 0x0000}
+        {   "de_DE@currency=DEM",         "it", 
+            {0x006d, 0x0061, 0x0072, 0x0063, 0x006f, 0x0020, 0x0074, 0x0065, 0x0064, 0x0065, 0x0073, 0x0063, 0x006f, 0x0000}
         },
         {   "el_GR@currency=GRD",         "en",    
             {0x0047, 0x0072, 0x0065, 0x0065, 0x006b, 0x0020, 0x0044, 0x0072, 0x0061, 0x0063, 0x0068, 0x006d, 0x0061, 0x0000}
         },
         {   "eu_ES@currency=ESP",         "it_IT", 
-            {0x0050, 0x0065, 0x0073, 0x0065, 0x0074, 0x0061, 0x0020, 0x0053, 0x0070, 0x0061, 0x0067, 0x006e, 0x006f, 0x006c, 0x0061, 0x0000}
+            {0x0070, 0x0065, 0x0073, 0x0065, 0x0074, 0x0061, 0x0020, 0x0073, 0x0070, 0x0061, 0x0067, 0x006e, 0x006f, 0x006c, 0x0061, 0x0000}
         },
         {   "de@collation=phonebook",     "es",    
             {0x006F, 0x0072, 0x0064, 0x0065, 0x006E, 0x0020, 0x0064, 0x0065, 0x0020, 0x006C, 0x0069, 0x0073, 0x0074, 0x00ED, 0x006E, 0x0020, 0x0074, 0x0065, 0x006C, 0x0065, 0x0066, 0x00F3, 0x006E, 0x0069, 0x0063, 0x006F, 0x0000}
@@ -2266,6 +2382,7 @@ static void TestGetBaseName(void) {
 
     for(i = 0; i < sizeof(testCases)/sizeof(testCases[0]); i++) {
         baseNameLen = uloc_getBaseName(testCases[i].localeID, baseName, 256, &status);
+        (void)baseNameLen;    /* Suppress set but not used warning. */
         if(strcmp(testCases[i].baseName, baseName)) {
             log_err("For locale \"%s\" expected baseName \"%s\", but got \"%s\"\n",
                 testCases[i].localeID, testCases[i].baseName, baseName);
@@ -2302,6 +2419,7 @@ static void TestDisplayNameWarning(void) {
     UErrorCode status = U_ZERO_ERROR;
     
     size = uloc_getDisplayLanguage("qqq", "kl", name, sizeof(name)/sizeof(name[0]), &status);
+    (void)size;    /* Suppress set but not used warning. */
     if (status != U_USING_DEFAULT_WARNING) {
         log_err("For language \"qqq\" in locale \"kl\", expecting U_USING_DEFAULT_WARNING, but got %s\n",
             u_errorName(status));
@@ -2643,6 +2761,7 @@ static void TestAcceptLanguage(void) {
         available = ures_openAvailableLocales(tests[i].icuSet, &status);
         tmp[0]=0;
         rc = uloc_acceptLanguageFromHTTP(tmp, 199, &outResult, http[tests[i].httpSet], available, &status);
+        (void)rc;    /* Suppress set but not used warning. */
         uenum_close(available);
         log_verbose(" got %s, %s [%s]\n", tmp[0]?tmp:"(EMPTY)", acceptResult(outResult), u_errorName(status));
         if(outResult != tests[i].res) {
@@ -2693,7 +2812,7 @@ static void TestCalendar() {
         log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
         return;
     }
-    for (i=0; i<LENGTHOF(LOCALE_ALIAS); i++) {
+    for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
         const char* oldLoc = LOCALE_ALIAS[i][0];
         const char* newLoc = LOCALE_ALIAS[i][1];
         UCalendar* c1 = NULL;
@@ -2729,7 +2848,7 @@ static void TestDateFormat() {
         log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
         return;
     }
-    for (i=0; i<LENGTHOF(LOCALE_ALIAS); i++) {
+    for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
         const char* oldLoc = LOCALE_ALIAS[i][0];
         const char* newLoc = LOCALE_ALIAS[i][1];
         UDateFormat* df1 = NULL;
@@ -2772,7 +2891,7 @@ static void TestCollation() {
         log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
         return;
     }
-    for (i=0; i<LENGTHOF(LOCALE_ALIAS); i++) {
+    for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
         const char* oldLoc = LOCALE_ALIAS[i][0];
         const char* newLoc = LOCALE_ALIAS[i][1];
         UCollator* c1 = NULL;
@@ -2896,7 +3015,7 @@ static void  TestULocale() {
         log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
         return;
     }
-    for (i=0; i<LENGTHOF(LOCALE_ALIAS); i++) {
+    for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
         const char* oldLoc = LOCALE_ALIAS[i][0];
         const char* newLoc = LOCALE_ALIAS[i][1];
         UChar name1[256], name2[256];
@@ -2942,7 +3061,7 @@ static void TestUResourceBundle() {
         return;
     }
     resIndex = ures_open(NULL,"res_index", &status);
-    for (i=0; i<LENGTHOF(LOCALE_ALIAS); i++) {
+    for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
 
         const char* oldLoc = LOCALE_ALIAS[i][0];
         const char* newLoc = LOCALE_ALIAS[i][1];
@@ -2987,7 +3106,7 @@ static void TestDisplayName() {
     int32_t capacity = 256;
     int i =0;
     int j=0;
-    for (i=0; i<LENGTHOF(LOCALE_ALIAS); i++) {
+    for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
         const char* oldLoc = LOCALE_ALIAS[i][0];
         const char* newLoc = LOCALE_ALIAS[i][1];
         UErrorCode status = U_ZERO_ERROR;
@@ -3600,7 +3719,7 @@ const char* const full_data[][3] = {
     "pa_PK"
   }, {
     "pap",
-    "pap_Latn_BQ",
+    "pap_Latn_AW",
     "pap"
   }, {
     "pau",
@@ -3790,10 +3909,6 @@ const char* const full_data[][3] = {
     "und_AM",
     "hy_Armn_AM",
     "hy"
-  }, {
-    "und_AN",
-    "pap_Latn_AN",
-    "pap_AN"
   }, {
     "und_AO",
     "pt_Latn_AO",
@@ -4036,8 +4151,8 @@ const char* const full_data[][3] = {
     "fi"
   }, {
     "und_FM",
-    "chk_Latn_FM",
-    "chk"
+    "en_Latn_FM",
+    "en_FM"
   }, {
     "und_FO",
     "fo_Latn_FO",
@@ -4128,8 +4243,8 @@ const char* const full_data[][3] = {
     "hu"
   }, {
     "und_Hani",
-    "zh_Hans_CN",
-    "zh"
+    "zh_Hani_CN",
+    "zh_Hani"
   }, {
     "und_Hans",
     "zh_Hans_CN",
@@ -4632,12 +4747,12 @@ const char* const full_data[][3] = {
     "es_UY"
   }, {
     "und_UZ",
-    "uz_Cyrl_UZ",
+    "uz_Latn_UZ",
     "uz"
   }, {
     "und_VA",
-    "la_Latn_VA",
-    "la"
+    "it_Latn_VA",
+    "it_VA"
   }, {
     "und_VE",
     "es_Latn_VE",
@@ -4676,7 +4791,7 @@ const char* const full_data[][3] = {
     "ur"
   }, {
     "uz",
-    "uz_Cyrl_UZ",
+    "uz_Latn_UZ",
     "uz"
   }, {
     "uz_AF",
@@ -4720,8 +4835,8 @@ const char* const full_data[][3] = {
     "zh_HK"
   }, {
     "zh_Hani",
-    "zh_Hans_CN",
-    "zh"
+    "zh_Hani_CN", /* changed due to cldrbug 6204, may be an error */
+    "zh_Hani", /* changed due to cldrbug 6204, may be an error */
   }, {
     "zh_Hant",
     "zh_Hant_TW",
@@ -5589,7 +5704,6 @@ static void TestLikelySubtags()
 }
 
 const char* const locale_to_langtag[][3] = {
-    {"@x=elmer",    "x-elmer",      "x-elmer"},
     {"",            "und",          "und"},
     {"en",          "en",           "en"},
     {"en_US",       "en-US",        "en-US"},
@@ -5623,9 +5737,9 @@ const char* const locale_to_langtag[][3] = {
     {"en@timezone=America/New_York;calendar=japanese",    "en-u-ca-japanese-tz-usnyc",    "en-u-ca-japanese-tz-usnyc"},
     {"en@timezone=US/Eastern",  "en-u-tz-usnyc",    "en-u-tz-usnyc"},
     {"en@x=x-y-z;a=a-b-c",  "en-x-x-y-z",   NULL},
-    {"it@collation=badcollationtype;colStrength=identical;cu=usd-eur", "it-u-ks-identic",  NULL},
+    {"it@collation=badcollationtype;colStrength=identical;cu=usd-eur", "it-u-cu-usd-eur-ks-identic",  NULL},
     {"en_US_POSIX", "en-US-u-va-posix", "en-US-u-va-posix"},
-    {"en_US_POSIX@calendar=japanese;currency=EUR","en-US-u-ca-japanese-cu-EUR-va-posix", "en-US-u-ca-japanese-cu-EUR-va-posix"},
+    {"en_US_POSIX@calendar=japanese;currency=EUR","en-US-u-ca-japanese-cu-eur-va-posix", "en-US-u-ca-japanese-cu-eur-va-posix"},
     {"@x=elmer",    "x-elmer",      "x-elmer"},
     {"en@x=elmer",  "en-x-elmer",   "en-x-elmer"},
     {"@x=elmer;a=exta", "und-a-exta-x-elmer",   "und-a-exta-x-elmer"},
@@ -5650,6 +5764,7 @@ static void TestToLanguageTag(void) {
         expected = locale_to_langtag[i][1];
 
         len = uloc_toLanguageTag(inloc, langtag, sizeof(langtag), FALSE, &status);
+        (void)len;    /* Suppress set but not used warning. */
         if (U_FAILURE(status)) {
             if (expected != NULL) {
                 log_err("Error returned by uloc_toLanguageTag for locale id [%s] - error: %s\n",
@@ -5694,6 +5809,7 @@ static const struct {
     const char  *locID;
     int32_t     len;
 } langtag_to_locale[] = {
+    {"ja-u-ijkl-efgh-abcd-ca-japanese-xx-yyy-zzz-kn",   "ja@attribute=abcd-efgh-ijkl;calendar=japanese;colnumeric=yes;xx=yyy-zzz",  FULL_LENGTH},
     {"en",                  "en",                   FULL_LENGTH},
     {"en-us",               "en_US",                FULL_LENGTH},
     {"und-US",              "_US",                  FULL_LENGTH},
@@ -5763,7 +5879,7 @@ static void TestForLanguageTag(void) {
                 langtag_to_locale[i].bcpID, u_errorName(status));
         } else {
             if (uprv_strcmp(langtag_to_locale[i].locID, locale) != 0) {
-                log_err("uloc_forLanguageTag returned locale [%s] for input language tag [%s] - expected: [%s]\n",
+                log_data_err("uloc_forLanguageTag returned locale [%s] for input language tag [%s] - expected: [%s]\n",
                     locale, langtag_to_locale[i].bcpID, langtag_to_locale[i].locID);
             }
             if (parsedLen != expParsedLen) {
@@ -5774,6 +5890,187 @@ static void TestForLanguageTag(void) {
     }
 }
 
+static void TestToUnicodeLocaleKey(void)
+{
+    /* $IN specifies the result should be the input pointer itself */
+    static const char* DATA[][2] = {
+        {"calendar",    "ca"},
+        {"CALEndar",    "ca"},  /* difference casing */
+        {"ca",          "ca"},  /* bcp key itself */
+        {"kv",          "kv"},  /* no difference between legacy and bcp */
+        {"foo",         NULL},  /* unknown, bcp ill-formed */
+        {"ZZ",          "$IN"}, /* unknown, bcp well-formed -  */
+        {NULL,          NULL}
+    };
+
+    int32_t i;
+    for (i = 0; DATA[i][0] != NULL; i++) {
+        const char* keyword = DATA[i][0];
+        const char* expected = DATA[i][1];
+        const char* bcpKey = NULL;
+
+        bcpKey = uloc_toUnicodeLocaleKey(keyword);
+        if (expected == NULL) {
+            if (bcpKey != NULL) {
+                log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=NULL\n", keyword, bcpKey);
+            }
+        } else if (bcpKey == NULL) {
+            log_data_err("toUnicodeLocaleKey: keyword=%s => NULL, expected=%s\n", keyword, expected);
+        } else if (uprv_strcmp(expected, "$IN") == 0) {
+            if (bcpKey != keyword) {
+                log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=%s(input pointer)\n", keyword, bcpKey, keyword);
+            }
+        } else if (uprv_strcmp(bcpKey, expected) != 0) {
+            log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=%s\n", keyword, bcpKey, expected);
+        }
+    }
+}
+
+static void TestToLegacyKey(void)
+{
+    /* $IN specifies the result should be the input pointer itself */
+    static const char* DATA[][2] = {
+        {"kb",          "colbackwards"},
+        {"kB",          "colbackwards"},    /* different casing */
+        {"Collation",   "collation"},   /* keyword itself with different casing */
+        {"kv",          "kv"},  /* no difference between legacy and bcp */
+        {"foo",         "$IN"}, /* unknown, bcp ill-formed */
+        {"ZZ",          "$IN"}, /* unknown, bcp well-formed */
+        {"e=mc2",       NULL},  /* unknown, bcp/legacy ill-formed */
+        {NULL,          NULL}
+    };
+
+    int32_t i;
+    for (i = 0; DATA[i][0] != NULL; i++) {
+        const char* keyword = DATA[i][0];
+        const char* expected = DATA[i][1];
+        const char* legacyKey = NULL;
+
+        legacyKey = uloc_toLegacyKey(keyword);
+        if (expected == NULL) {
+            if (legacyKey != NULL) {
+                log_err("toLegacyKey: keyword=%s => %s, expected=NULL\n", keyword, legacyKey);
+            }
+        } else if (legacyKey == NULL) {
+            log_err("toLegacyKey: keyword=%s => NULL, expected=%s\n", keyword, expected);
+        } else if (uprv_strcmp(expected, "$IN") == 0) {
+            if (legacyKey != keyword) {
+                log_err("toLegacyKey: keyword=%s => %s, expected=%s(input pointer)\n", keyword, legacyKey, keyword);
+            }
+        } else if (uprv_strcmp(legacyKey, expected) != 0) {
+            log_data_err("toUnicodeLocaleKey: keyword=%s, %s, expected=%s\n", keyword, legacyKey, expected);
+        }
+    }
+}
+
+static void TestToUnicodeLocaleType(void)
+{
+    /* $IN specifies the result should be the input pointer itself */
+    static const char* DATA[][3] = {
+        {"tz",              "Asia/Kolkata",     "inccu"},
+        {"calendar",        "gregorian",        "gregory"},
+        {"ca",              "gregorian",        "gregory"},
+        {"ca",              "Gregorian",        "gregory"},
+        {"ca",              "buddhist",         "buddhist"},
+        {"Calendar",        "Japanese",         "japanese"},
+        {"calendar",        "Islamic-Civil",    "islamic-civil"},
+        {"calendar",        "islamicc",         "islamic-civil"},   /* bcp type alias */
+        {"colalternate",    "NON-IGNORABLE",    "noignore"},
+        {"colcaselevel",    "yes",              "true"},
+        {"tz",              "america/new_york", "usnyc"},
+        {"tz",              "Asia/Kolkata",     "inccu"},
+        {"timezone",        "navajo",           "usden"},
+        {"ca",              "aaaa",             "$IN"},     /* unknown type, well-formed type */
+        {"ca",              "gregory-japanese-islamic", "$IN"}, /* unknown type, well-formed type */
+        {"zz",              "gregorian",        NULL},      /* unknown key, ill-formed type */
+        {"co",              "foo-",             NULL},      /* unknown type, ill-formed type */
+        {"variableTop",     "00A0",             "$IN"},     /* valid codepoints type */
+        {"variableTop",     "wxyz",             "$IN"},     /* invalid codepoints type - return as is for now */
+        {"kr",              "space-punct",      "space-punct"}, /* valid reordercode type */
+        {"kr",              "digit-spacepunct", NULL},      /* invalid (bcp ill-formed) reordercode type */
+        {NULL,              NULL,               NULL}
+    };
+
+    int32_t i;
+    for (i = 0; DATA[i][0] != NULL; i++) {
+        const char* keyword = DATA[i][0];
+        const char* value = DATA[i][1];
+        const char* expected = DATA[i][2];
+        const char* bcpType = NULL;
+
+        bcpType = uloc_toUnicodeLocaleType(keyword, value);
+        if (expected == NULL) {
+            if (bcpType != NULL) {
+                log_err("toUnicodeLocaleType: keyword=%s, value=%s => %s, expected=NULL\n", keyword, value, bcpType);
+            }
+        } else if (bcpType == NULL) {
+            log_data_err("toUnicodeLocaleType: keyword=%s, value=%s => NULL, expected=%s\n", keyword, value, expected);
+        } else if (uprv_strcmp(expected, "$IN") == 0) {
+            if (bcpType != value) {
+                log_err("toUnicodeLocaleType: keyword=%s, value=%s => %s, expected=%s(input pointer)\n", keyword, value, bcpType, value);
+            }
+        } else if (uprv_strcmp(bcpType, expected) != 0) {
+            log_data_err("toUnicodeLocaleType: keyword=%s, value=%s => %s, expected=%s\n", keyword, value, bcpType, expected);
+        }
+    }
+}
+
+static void TestToLegacyType(void)
+{
+    /* $IN specifies the result should be the input pointer itself */
+    static const char* DATA[][3] = {
+        {"calendar",        "gregory",          "gregorian"},
+        {"ca",              "gregory",          "gregorian"},
+        {"ca",              "Gregory",          "gregorian"},
+        {"ca",              "buddhist",         "buddhist"},
+        {"Calendar",        "Japanese",         "japanese"},
+        {"calendar",        "Islamic-Civil",    "islamic-civil"},
+        {"calendar",        "islamicc",         "islamic-civil"},   /* bcp type alias */
+        {"colalternate",    "noignore",         "non-ignorable"},
+        {"colcaselevel",    "true",             "yes"},
+        {"tz",              "usnyc",            "America/New_York"},
+        {"tz",              "inccu",            "Asia/Calcutta"},
+        {"timezone",        "usden",            "America/Denver"},
+        {"timezone",        "usnavajo",         "America/Denver"},  /* bcp type alias */
+        {"colstrength",     "quarternary",      "quaternary"},  /* type alias */
+        {"ca",              "aaaa",             "$IN"}, /* unknown type */
+        {"calendar",        "gregory-japanese-islamic", "$IN"}, /* unknown type, well-formed type */
+        {"zz",              "gregorian",        "$IN"}, /* unknown key, bcp ill-formed type */
+        {"ca",              "gregorian-calendar",   "$IN"}, /* known key, bcp ill-formed type */
+        {"co",              "e=mc2",            NULL},  /* known key, ill-formed bcp/legacy type */
+        {"variableTop",     "00A0",             "$IN"},     /* valid codepoints type */
+        {"variableTop",     "wxyz",             "$IN"},    /* invalid codepoints type - return as is for now */
+        {"kr",              "space-punct",      "space-punct"}, /* valid reordercode type */
+        {"kr",              "digit-spacepunct", "digit-spacepunct"},    /* invalid reordercode type, but ok for legacy syntax */
+        {NULL,              NULL,               NULL}
+    };
+
+    int32_t i;
+    for (i = 0; DATA[i][0] != NULL; i++) {
+        const char* keyword = DATA[i][0];
+        const char* value = DATA[i][1];
+        const char* expected = DATA[i][2];
+        const char* legacyType = NULL;
+
+        legacyType = uloc_toLegacyType(keyword, value);
+        if (expected == NULL) {
+            if (legacyType != NULL) {
+                log_err("toLegacyType: keyword=%s, value=%s => %s, expected=NULL\n", keyword, value, legacyType);
+            }
+        } else if (legacyType == NULL) {
+            log_err("toLegacyType: keyword=%s, value=%s => NULL, expected=%s\n", keyword, value, expected);
+        } else if (uprv_strcmp(expected, "$IN") == 0) {
+            if (legacyType != value) {
+                log_err("toLegacyType: keyword=%s, value=%s => %s, expected=%s(input pointer)\n", keyword, value, legacyType, value);
+            }
+        } else if (uprv_strcmp(legacyType, expected) != 0) {
+            log_data_err("toLegacyType: keyword=%s, value=%s => %s, expected=%s\n", keyword, value, legacyType, expected);
+        }
+    }
+}
+
+
+
 static void test_unicode_define(const char *namech, char ch, const char *nameu, UChar uch)
 {
   UChar asUch[1];
@@ -5794,3 +6091,791 @@ static void TestUnicodeDefines(void) {
   TEST_UNICODE_DEFINE(ULOC_KEYWORD_ASSIGN, ULOC_KEYWORD_ASSIGN_UNICODE);
   TEST_UNICODE_DEFINE(ULOC_KEYWORD_ITEM_SEPARATOR, ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE);
 }
+
+static void TestIsRightToLeft() {
+    // API test only. More test cases in intltest/LocaleTest.
+    if(uloc_isRightToLeft("root") || !uloc_isRightToLeft("EN-HEBR")) {
+        log_err("uloc_isRightToLeft() failed");
+    }
+}
+
+/* Apple-specific, test for Apple-specific function ualoc_getAppleParent */
+static const char* localesAndAppleParent[] = {
+    "en",               "root",
+    "en-US",            "en",
+    "en-CA",            "en_001",
+    "en-001",           "en",
+    "en_001",           "en",
+    "en-150",           "en_GB",
+    "en-GB",            "en_001",
+    "en_GB",            "en_001",
+    "en-AU",            "en_GB",
+    "en-BE",            "en_150",
+    "en-DG",            "en_GB",
+    "en-FK",            "en_GB",
+    "en-GG",            "en_GB",
+    "en-GI",            "en_GB",
+    "en-HK",            "en_GB",
+    "en-IE",            "en_GB",
+    "en-IM",            "en_GB",
+    "en-IN",            "en_GB",
+    "en-IO",            "en_GB",
+    "en-JE",            "en_GB",
+    "en-MO",            "en_GB",
+    "en-MT",            "en_GB",
+    "en-NZ",            "en_GB",
+    "en-PK",            "en_GB",
+    "en-SG",            "en_GB",
+    "en-SH",            "en_GB",
+    "en-VG",            "en_GB",
+    "es",               "root",
+    "es-ES",            "es",
+    "es-419",           "es",
+    "es_419",           "es",
+    "es-MX",            "es_419",
+    "es-AR",            "es_419",
+    "fr",               "root",
+    "fr-CA",            "fr",
+    "fr-CH",            "fr",
+    "haw",              "root",
+    "nl",               "root",
+    "nl-BE",            "nl",
+    "pt",               "root",
+    "pt-BR",            "pt",
+    "pt-PT",            "pt",
+    "pt-MO",            "pt_PT",
+    "sr",               "root",
+    "sr-Cyrl",          "sr",
+    "sr-Latn",          "root",
+    "tlh",              "root",
+    "zh_CN",            "root",
+    "zh-CN",            "root",
+    "zh",               "zh_CN",
+    "zh-Hans",          "zh",
+    "zh_TW",            "root",
+    "zh-TW",            "root",
+    "zh-Hant",          "zh_TW",
+    "zh_HK",            "zh_Hant_HK",
+    "zh-HK",            "zh_Hant_HK",
+    "zh_Hant",          "zh_TW",
+    "zh-Hant-HK",       "zh_Hant",
+    "zh_Hant_HK",       "zh_Hant",
+    "zh-Hant-MO",       "zh_Hant_HK",
+    "zh-Hans-HK",       "zh_Hans",
+    "root",             "root",
+    "en-Latn",          "en",
+    "en-Latn-US",       "en_Latn",
+    "en_US_POSIX",      "en_US",
+    "en_Latn_US_POSIX", "en_Latn_US",
+    "en-u-ca-hebrew",   "root",
+    "en@calendar=hebrew", "root",
+    "en_@calendar=hebrew", "root",
+    "en-",              "root",
+    "en_",              "root",
+    "Default@2x",       "root",
+    "default",          "root",
+    NULL /* terminator */
+};
+
+static void TestGetAppleParent() {
+    const char **localesPtr = localesAndAppleParent;
+    const char * locale;
+    while ((locale = *localesPtr++) != NULL) {
+        const char * expectParent = *localesPtr++;
+        UErrorCode status = U_ZERO_ERROR;
+        char getParent[ULOC_FULLNAME_CAPACITY];
+        int32_t plen = ualoc_getAppleParent(locale, getParent, ULOC_FULLNAME_CAPACITY, &status);
+        if (U_FAILURE(status)) {
+            log_err("FAIL: ualoc_getAppleParent input \"%s\", status %s\n", locale, u_errorName(status));
+        } else if (uprv_strcmp(expectParent, getParent) != 0) {
+            log_err("FAIL: ualoc_getAppleParent input \"%s\", expected parent \"%s\", got parent \"%s\"\n", locale, expectParent, getParent);
+        }
+    }
+}
+
+/* Apple-specific, test for Apple-specific function ualoc_getLanguagesForRegion */
+enum { kUALanguageEntryMax = 10 };
+
+static void TestGetLanguagesForRegion() {
+    UALanguageEntry entries[kUALanguageEntryMax];
+    int32_t entryCount;
+    UErrorCode status;
+    const char * region;
+
+    status = U_ZERO_ERROR;
+    region = "CN";
+    entryCount = ualoc_getLanguagesForRegion(region, 0.001, entries, kUALanguageEntryMax, &status);
+    if (U_FAILURE(status)) {
+            log_err("FAIL: ualoc_getLanguagesForRegion %s, status %s\n", region, u_errorName(status));
+    } else {
+        // Expect approximately:
+        // zh_Hans 0.90 UALANGSTATUS_OFFICIAL
+        // wuu 0.06 Wu
+        // hsn 0.06 Xiang
+        // hak 0.023 Hakka
+        // nan 0.019 Minnan
+        // gan 0.017 Gan
+        // ii  0.006 Yi
+        // ug_Arab 0.0055 Uighur UALANGSTATUS_REGIONAL_OFFICIAL
+        // ...at least 4 more with fractions >= 0.001
+        if (entryCount < kUALanguageEntryMax) {
+            log_err("FAIL: ualoc_getLanguagesForRegion %s, entryCount %d is too small\n", region, entryCount);
+        } else {
+            UALanguageEntry* entryPtr = entries;
+            if (uprv_strcmp(entryPtr->languageCode, "zh_Hans") != 0 || entryPtr->userFraction < 0.8 || entryPtr->userFraction > 1.0 || entryPtr->status != UALANGSTATUS_OFFICIAL) {
+                log_err("FAIL: ualoc_getLanguagesForRegion %s, invalid entries[0] { %s, %.3f, %d }\n", region, entryPtr->languageCode, entryPtr->userFraction, (int)entryPtr->status);
+            }
+            for (entryPtr++; entryPtr < entries + kUALanguageEntryMax && uprv_strcmp(entryPtr->languageCode, "ug_Arab") != 0; entryPtr++)
+                ;
+            if (entryPtr < entries + kUALanguageEntryMax) {
+                // we found ug_Arab, make sure it has correct status
+                if (entryPtr->status != UALANGSTATUS_REGIONAL_OFFICIAL) {
+                    log_err("FAIL: ualoc_getLanguagesForRegion %s, ug_Arab had incorrect status %d\n", (int)entryPtr->status);
+                }
+            } else {
+                // did not find ug_Arab
+                log_err("FAIL: ualoc_getLanguagesForRegion %s, entries did not include ug_Arab\n", region);
+            }
+        }
+    }
+
+    status = U_ZERO_ERROR;
+    region = "CA";
+    entryCount = ualoc_getLanguagesForRegion(region, 0.001, entries, kUALanguageEntryMax, &status);
+    if (U_FAILURE(status)) {
+            log_err("FAIL: ualoc_getLanguagesForRegion %s, status %s\n", region, u_errorName(status));
+    } else {
+        // Expect approximately:
+        // en 0.85 UALANGSTATUS_OFFICIAL
+        // fr 0.22 UALANGSTATUS_OFFICIAL
+        // ...
+        if (entryCount < 2) {
+            log_err("FAIL: ualoc_getLanguagesForRegion %s, entryCount %d is too small\n", region, entryCount);
+        } else {
+            if (uprv_strcmp(entries[0].languageCode, "en") != 0 || entries[0].userFraction < 0.7 || entries[0].userFraction > 1.0 || entries[0].status != UALANGSTATUS_OFFICIAL) {
+                log_err("FAIL: ualoc_getLanguagesForRegion %s, invalid entries[0] { %s, %.3f, %d }\n", region, entries[0].languageCode, entries[0].userFraction, (int)entries[0].status);
+            }
+            if (uprv_strcmp(entries[1].languageCode, "fr") != 0 || entries[1].userFraction < 0.1 || entries[1].userFraction > 1.0 || entries[1].status != UALANGSTATUS_OFFICIAL) {
+                log_err("FAIL: ualoc_getLanguagesForRegion %s, invalid entries[1] { %s, %.3f, %d }\n", region, entries[1].languageCode, entries[1].userFraction, (int)entries[1].status);
+            }
+        }
+    }
+
+    status = U_ZERO_ERROR;
+    region = "IN";
+    entryCount = ualoc_getLanguagesForRegion(region, 0.001, NULL, 0, &status);
+    if (U_FAILURE(status)) {
+            log_err("FAIL: ualoc_getLanguagesForRegion %s, status %s\n", region, u_errorName(status));
+    } else {
+        if (entryCount < 40) {
+            log_err("FAIL: ualoc_getLanguagesForRegion %s, entryCount %d is too small\n", region, entryCount);
+        }
+    }
+}
+
+/* data for TestAppleLocalizationsToUse */
+
+typedef struct {
+    const char * const *locs;
+    int32_t             locCount;
+} AppleLocsAndCount;
+
+enum { kNumLocSets = 6 };
+
+typedef struct {
+    const char * language;
+    const char ** expLocsForSets[kNumLocSets];
+} LangAndExpLocs;
+
+
+static const char * appleLocs1[] = {
+    "Arabic",
+    "Danish",
+    "Dutch",
+    "English",
+    "Finnish",
+    "French",
+    "German",
+    "Italian",
+    "Japanese",
+    "Korean",
+    "Norwegian",
+    "Polish",
+    "Portuguese",
+    "Russian",
+    "Spanish",
+    "Swedish",
+    "Thai",
+    "Turkish",
+    "ca",
+    "cs",
+    "el",
+    "he",
+    "hr",
+    "hu",
+    "id",
+    "ms",
+    "ro",
+    "sk",
+    "uk",
+    "vi",
+    "zh_CN", "zh_TW",
+};
+
+static const char * appleLocs2[] = {
+    "ar",
+    "ca",
+    "cs",
+    "da",
+    "de",
+    "el",
+    "en", "en_AU", "en_GB",
+    "es", "es_MX",
+    "fi",
+    "fr", "fr_CA",
+    "he",
+    "hr",
+    "hu",
+    "id",
+    "it",
+    "ja",
+    "ko",
+    "ms",
+    "nl",
+    "no",
+    "pl",
+    "pt", "pt_PT",
+    "ro",
+    "ru",
+    "sk",
+    "sv",
+    "th",
+    "tr",
+    "uk",
+    "vi",
+    "zh_CN", "zh_HK", "zh_TW",
+};
+
+static const char * appleLocs3[] = {
+    "ar",
+    "ca",
+    "cs",
+    "da",
+    "de",
+    "el",
+    "en", "en_AU", "en_CA", "en_GB",
+    "es", "es_419",
+    "fi",
+    "fr", "fr_CA", "fr_FR",
+    "he",
+    "hr",
+    "hu",
+    "id",
+    "it",
+    "ja",
+    "ko",
+    "ms",
+    "nb",
+    "nl",
+    "pl",
+    "pt", "pt_BR", "pt_PT",
+    "ro",
+    "ru",
+    "sk",
+    "sv",
+    "th",
+    "tr",
+    "uk",
+    "vi",
+    "zh_CN", "zh_HK", "zh_MO", "zh_TW",
+};
+
+static const char * appleLocs4[] = {
+    "en", "en_AU", "en_CA", "en_GB", "en_IN", "en_US",
+    "es", "es_419", "es_MX",
+    "fr", "fr_CA", "fr_CH", "fr_FR",
+    "nl", "nl_BE", "nl_NL",
+    "pt", "pt_BR",
+    "ro", "ro_MD", "ro_RO",
+    "zh_Hans", "zh_Hant", "zh_Hant_HK",
+};
+
+static const char * appleLocs5[] = {
+    "en", "en_001", "en_AU", "en_GB",
+    "es", "es_ES", "es_MX",
+    "zh_CN", "zh_Hans", "zh_Hant", "zh_TW",
+    "yi",
+    "fil",
+    "haw",
+    "tlh",
+    "sr",
+    "sr-Latn",
+};
+
+// list 6
+static const char * appleLocs6[] = {
+    "en", "en_001", "en_150", "en_AU", "en_GB",
+    "es", "es_419", "es_ES", "es_MX",
+    "zh_CN", "zh_Hans", "zh_Hant", "zh_Hant_HK", "zh_HK", "zh_TW",
+    "iw",
+    "in",
+    "mo",
+    "tl",
+};
+
+static const AppleLocsAndCount locAndCountEntries[kNumLocSets] = {
+    { appleLocs1, UPRV_LENGTHOF(appleLocs1) },
+    { appleLocs2, UPRV_LENGTHOF(appleLocs2) },
+    { appleLocs3, UPRV_LENGTHOF(appleLocs3) },
+    { appleLocs4, UPRV_LENGTHOF(appleLocs4) },
+    { appleLocs5, UPRV_LENGTHOF(appleLocs5) },
+    { appleLocs6, UPRV_LENGTHOF(appleLocs6) },
+};
+
+
+static const char* l1_ar[]          = { "ar", NULL };
+static const char* l1_Ara[]         = { "Arabic", NULL };
+static const char* l1_ca[]          = { "ca", NULL };
+static const char* l1_cs[]          = { "cs", NULL };
+static const char* l1_da[]          = { "da", NULL };
+static const char* l1_Dan[]         = { "Danish", NULL };
+static const char* l1_de[]          = { "de", NULL };
+static const char* l1_Ger[]         = { "German", NULL };
+static const char* l1_el[]          = { "el", NULL };
+static const char* l1_en[]          = { "en", NULL };
+static const char* l1_Eng[]         = { "English", NULL };
+static const char* l2_en_001_[]     = { "en_001", "en", NULL };
+static const char* l2_en_CA_[]      = { "en_CA", "en", NULL };
+static const char* l2_en_GB_[]      = { "en_GB", "en", NULL };
+static const char* l2_en_US_[]      = { "en_US", "en", NULL };
+static const char* l2_en_GB_Eng[]   = { "en_GB", "English", NULL };
+static const char* l3_en_GB001_[]   = { "en_GB", "en_001", "en", NULL };
+static const char* l3_en_AUGB_[]    = { "en_AU", "en_GB", "en", NULL };
+static const char* l3_en_INGB_[]    = { "en_IN", "en_GB", "en", NULL };
+static const char* l4_en_150GB001_[] = { "en_150", "en_GB", "en_001", "en", NULL };
+static const char* l4_en_AUGB001_[] = { "en_AU", "en_GB", "en_001", "en", NULL };
+static const char* l1_es[]          = { "es", NULL };
+static const char* l1_Spa[]         = { "Spanish", NULL };
+static const char* l2_es_419_[]     = { "es_419", "es", NULL };
+static const char* l2_es_ES_[]      = { "es_ES", "es", NULL };
+static const char* l2_es_MX_[]      = { "es_MX", "es", NULL };
+static const char* l2_es_MX_Spa[]   = { "es_MX", "Spanish", NULL };
+static const char* l3_es_MX419_[]   = { "es_MX", "es_419", "es", NULL };
+static const char* l1_fi[]          = { "fi", NULL };
+static const char* l1_Fin[]         = { "Finnish", NULL };
+static const char* l1_fil[]         = { "fil", NULL };
+static const char* l1_tl[]          = { "tl", NULL };
+static const char* l1_fr[]          = { "fr", NULL };
+static const char* l1_Fre[]         = { "French", NULL };
+static const char* l2_fr_CA_[]      = { "fr_CA", "fr", NULL };
+static const char* l2_fr_CH_[]      = { "fr_CH", "fr", NULL };
+static const char* l2_fr_FR_[]      = { "fr_FR", "fr", NULL };
+static const char* l1_haw[]         = { "haw", NULL };
+static const char* l1_he[]          = { "he", NULL };
+static const char* l1_hr[]          = { "hr", NULL };
+static const char* l1_hu[]          = { "hu", NULL };
+static const char* l1_id[]          = { "id", NULL };
+static const char* l1_in[]          = { "in", NULL };
+static const char* l1_it[]          = { "it", NULL };
+static const char* l1_Ita[]         = { "Italian", NULL };
+static const char* l1_ja[]          = { "ja", NULL };
+static const char* l1_Japn[]        = { "Japanese", NULL };
+static const char* l1_ko[]          = { "ko", NULL };
+static const char* l1_Kor[]         = { "Korean", NULL };
+static const char* l1_ms[]          = { "ms", NULL };
+static const char* l1_nb[]          = { "nb", NULL };
+static const char* l1_no[]          = { "no", NULL };
+static const char* l1_Nor[]         = { "Norwegian", NULL };
+static const char* l2_no_NO_[]      = { "no_NO", "no", NULL };
+static const char* l1_nl[]          = { "nl", NULL };
+static const char* l1_Dut[]         = { "Dutch", NULL };
+static const char* l2_nl_BE_[]      = { "nl_BE", "nl", NULL };
+static const char* l1_pl[]          = { "pl", NULL };
+static const char* l1_Pol[]         = { "Polish", NULL };
+static const char* l1_pt[]          = { "pt", NULL };
+static const char* l1_pt_PT[]       = { "pt_PT", NULL };
+static const char* l1_Port[]        = { "Portuguese", NULL };
+static const char* l2_pt_BR_[]      = { "pt_BR", "pt", NULL };
+static const char* l2_pt_PT_[]      = { "pt_PT", "pt", NULL };
+static const char* l1_ro[]          = { "ro", NULL };
+static const char* l2_ro_MD_[]      = { "ro_MD", "ro", NULL };
+static const char* l1_mo[]          = { "mo", NULL };
+static const char* l1_ru[]          = { "ru", NULL };
+static const char* l1_Rus[]         = { "Russian", NULL };
+static const char* l1_sk[]          = { "sk", NULL };
+static const char* l1_sr[]          = { "sr", NULL };
+static const char* l1_srLatn[]      = { "sr-Latn", NULL };
+static const char* l1_sv[]          = { "sv", NULL };
+static const char* l1_Swe[]         = { "Swedish", NULL };
+static const char* l1_th[]          = { "th", NULL };
+static const char* l1_Thai[]        = { "Thai", NULL };
+static const char* l1_tlh[]         = { "tlh", NULL };
+static const char* l1_tr[]          = { "tr", NULL };
+static const char* l1_Tur[]         = { "Turkish", NULL };
+static const char* l1_uk[]          = { "uk", NULL };
+static const char* l1_vi[]          = { "vi", NULL };
+static const char* l1_yi[]          = { "yi", NULL };
+static const char* l1_iw[]          = { "iw", NULL };
+static const char* l1_zh_CN[]       = { "zh_CN", NULL };
+static const char* l1_zh_TW[]       = { "zh_TW", NULL };
+static const char* l1_zh_Hans[]     = { "zh_Hans", NULL };
+static const char* l1_zh_Hant[]     = { "zh_Hant", NULL };
+static const char* l1_zhHant[]      = { "zh-Hant", NULL };
+static const char* l2_zh_HKTW[]     = { "zh_HK", "zh_TW", NULL };
+static const char* l2_zh_Hant_HK_[] = { "zh_Hant_HK", "zh_Hant", NULL };
+static const char* l2_zh_CN_Hans[]  = { "zh_CN", "zh_Hans", NULL };
+static const char* l2_zh_TW_Hant[]  = { "zh_TW", "zh_Hant", NULL };
+static const char* l3_zh_MOHKTW[]   = { "zh_MO", "zh_HK", "zh_TW", NULL };
+static const char* l3_zh_HK_HantHK_Hant[] = { "zh_HK", "zh_Hant_HK", "zh_Hant", NULL };
+
+static const LangAndExpLocs appleLangAndLoc[] = {
+//    language\    result for appleLocs1      appleLocs2      appleLocs3      appleLocs4      appleLocs5      appleLocs6
+    { "zh",                 { l1_zh_CN,       l1_zh_CN,       l1_zh_CN,       l1_zh_Hans,     l1_zh_Hans,     l1_zh_Hans     } },
+    { "zh-Hans",            { l1_zh_CN,       l1_zh_CN,       l1_zh_CN,       l1_zh_Hans,     l1_zh_Hans,     l1_zh_Hans     } },
+    { "zh-Hant",            { l1_zh_TW,       l1_zh_TW,       l1_zh_TW,       l1_zh_Hant,     l1_zh_Hant,     l1_zh_Hant     } },
+    { "zh-Hans-CN",         { l1_zh_CN,       l1_zh_CN,       l1_zh_CN,       l1_zh_Hans,     l2_zh_CN_Hans,  l2_zh_CN_Hans  } },
+    { "zh-Hans-SG",         { l1_zh_CN,       l1_zh_CN,       l1_zh_CN,       l1_zh_Hans,     l1_zh_Hans,     l1_zh_Hans     } },
+    { "zh-Hant-TW",         { l1_zh_TW,       l1_zh_TW,       l1_zh_TW,       l1_zh_Hant,     l2_zh_TW_Hant,  l2_zh_TW_Hant  } },
+    { "zh-Hant-HK",         { l1_zh_TW,       l2_zh_HKTW,     l2_zh_HKTW,     l2_zh_Hant_HK_, l1_zh_Hant,     l2_zh_Hant_HK_ } },
+    { "zh-Hant-MO",         { l1_zh_TW,       l2_zh_HKTW,     l3_zh_MOHKTW,   l2_zh_Hant_HK_, l1_zh_Hant,     l2_zh_Hant_HK_ } },
+    { "zh-Hans-HK",         { l1_zh_CN,       l1_zh_CN,       l1_zh_CN,       l1_zh_Hans,     l1_zh_Hans,     l1_zh_Hans     } },
+    { "zh-CN",              { l1_zh_CN,       l1_zh_CN,       l1_zh_CN,       l1_zh_Hans,     l2_zh_CN_Hans,  l2_zh_CN_Hans  } },
+    { "zh-SG",              { l1_zh_CN,       l1_zh_CN,       l1_zh_CN,       l1_zh_Hans,     l1_zh_Hans,     l1_zh_Hans     } },
+    { "zh-TW",              { l1_zh_TW,       l1_zh_TW,       l1_zh_TW,       l1_zh_Hant,     l2_zh_TW_Hant,  l2_zh_TW_Hant  } },
+    { "zh-HK",              { l1_zh_TW,       l2_zh_HKTW,     l2_zh_HKTW,     l2_zh_Hant_HK_, l1_zh_Hant,     l3_zh_HK_HantHK_Hant } },
+    { "zh-MO",              { l1_zh_TW,       l2_zh_HKTW,     l3_zh_MOHKTW,   l2_zh_Hant_HK_, l1_zh_Hant,     l2_zh_Hant_HK_ } },
+    { "en",                 { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en-US",              { l1_Eng,         l1_en,          l1_en,          l2_en_US_,      l1_en,          l1_en          } },
+    { "en-AU",              { l1_Eng,         l3_en_AUGB_,    l3_en_AUGB_,    l3_en_AUGB_,    l4_en_AUGB001_, l4_en_AUGB001_ } },
+    { "en-CA",              { l1_Eng,         l1_en,          l2_en_CA_,      l2_en_CA_,      l2_en_001_,     l2_en_001_     } },
+    { "en-GB",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-IN",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l3_en_INGB_,    l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-US",              { l1_Eng,         l1_en,          l1_en,          l2_en_US_,      l1_en,          l1_en          } },
+    { "en_US",              { l1_Eng,         l1_en,          l1_en,          l2_en_US_,      l1_en,          l1_en          } },
+    { "en-FR",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l4_en_150GB001_ } },
+    { "en-BE",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l4_en_150GB001_ } },
+    { "en-GG",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-HK",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-IE",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-MO",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-MT",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-NZ",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-PK",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-SG",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-VG",              { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l3_en_GB001_   } },
+    { "en-IL",              { l1_Eng,         l1_en,          l1_en,          l1_en,          l2_en_001_,     l2_en_001_     } },
+    { "en-001",             { l1_Eng,         l1_en,          l1_en,          l1_en,          l2_en_001_,     l2_en_001_     } },
+    { "en-150",             { l1_Eng,         l2_en_GB_,      l2_en_GB_,      l2_en_GB_,      l3_en_GB001_,   l4_en_150GB001_ } },
+    { "en-Latn",            { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en-Latn-US",         { l1_Eng,         l1_en,          l1_en,          l1_en,/*TODO*/  l1_en,          l1_en          } },
+    { "en-US-POSIX",        { l1_Eng,         l1_en,          l1_en,          l2_en_US_,      l1_en,          l1_en          } },
+    { "en-Latn-US-POSIX",   { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en-u-ca-hebrew",     { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en@calendar=hebrew", { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en-",                { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "en_",                { l1_Eng,         l1_en,          l1_en,          l1_en,          l1_en,          l1_en          } },
+    { "es",                 { l1_Spa,         l1_es,          l1_es,          l1_es,          l1_es,          l1_es          } },
+    { "es-ES",              { l1_Spa,         l1_es,          l1_es,          l1_es,          l2_es_ES_,      l2_es_ES_      } },
+    { "es-419",             { l1_Spa,         l1_es,          l2_es_419_,     l2_es_419_,     l1_es,          l2_es_419_     } },
+    { "es-MX",              { l1_Spa,         l2_es_MX_,      l2_es_419_,     l3_es_MX419_,   l2_es_MX_,      l3_es_MX419_   } },
+    { "es-AR",              { l1_Spa,         l1_es,          l2_es_419_,     l2_es_419_,     l1_es,          l2_es_419_     } },
+    { "es-Latn",            { l1_Spa,         l1_es,          l1_es,          l1_es,          l1_es,          l1_es          } },
+    { "es-Latn-MX",         { l1_Spa,         l1_es,          l1_es,          l1_es,          l1_es,          l1_es          } },
+    { "pt",                 { l1_Port,        l1_pt,          l1_pt,          l1_pt,          NULL,           NULL  } },
+    { "pt-BR",              { l1_Port,        l1_pt,          l2_pt_BR_,      l2_pt_BR_,      NULL,           NULL  } },
+    { "pt-PT",              { l1_Port,        l2_pt_PT_,      l2_pt_PT_,      l1_pt,          NULL,           NULL  } },
+    { "pt-MO",              { l1_Port,        l2_pt_PT_,      l2_pt_PT_,      l1_pt,          NULL,           NULL  } },
+    { "fr",                 { l1_Fre,         l1_fr,          l1_fr,          l1_fr,          NULL,           NULL  } },
+    { "fr-FR",              { l1_Fre,         l1_fr,          l2_fr_FR_,      l2_fr_FR_,      NULL,           NULL  } },
+    { "fr-CA",              { l1_Fre,         l2_fr_CA_,      l2_fr_CA_,      l2_fr_CA_,      NULL,           NULL  } },
+    { "fr-CH",              { l1_Fre,         l1_fr,          l1_fr,          l2_fr_CH_,      NULL,           NULL  } },
+    { "ar",                 { l1_Ara,         l1_ar,          l1_ar,          NULL,           NULL,           NULL  } },
+    { "da",                 { l1_Dan,         l1_da,          l1_da,          NULL,           NULL,           NULL  } },
+    { "nl",                 { l1_Dut,         l1_nl,          l1_nl,          l1_nl,          NULL,           NULL  } },
+    { "nl-BE",              { l1_Dut,         l1_nl,          l1_nl,          l2_nl_BE_,      NULL,           NULL  } },
+    { "fi",                 { l1_Fin,         l1_fi,          l1_fi,          NULL,           NULL,           NULL  } },
+    { "de",                 { l1_Ger,         l1_de,          l1_de,          NULL,           NULL,           NULL  } },
+    { "it",                 { l1_Ita,         l1_it,          l1_it,          NULL,           NULL,           NULL  } },
+    { "ja",                 { l1_Japn,        l1_ja,          l1_ja,          NULL,           NULL,           NULL  } },
+    { "ko",                 { l1_Kor,         l1_ko,          l1_ko,          NULL,           NULL,           NULL  } },
+    { "nb",                 { l1_Nor,         l1_no,          l1_nb,          NULL,           NULL,           NULL  } },
+    { "no",                 { l1_Nor,         l1_no,          l1_nb,          NULL,           NULL,           NULL  } },
+    { "pl",                 { l1_Pol,         l1_pl,          l1_pl,          NULL,           NULL,           NULL  } },
+    { "ru",                 { l1_Rus,         l1_ru,          l1_ru,          NULL,           NULL,           NULL  } },
+    { "sv",                 { l1_Swe,         l1_sv,          l1_sv,          NULL,           NULL,           NULL  } },
+    { "th",                 { l1_Thai,        l1_th,          l1_th,          NULL,           NULL,           NULL  } },
+    { "tr",                 { l1_Tur,         l1_tr,          l1_tr,          NULL,           NULL,           NULL  } },
+    { "ca",                 { l1_ca,          l1_ca,          l1_ca,          NULL,           NULL,           NULL  } },
+    { "cs",                 { l1_cs,          l1_cs,          l1_cs,          NULL,           NULL,           NULL  } },
+    { "el",                 { l1_el,          l1_el,          l1_el,          NULL,           NULL,           NULL  } },
+    { "he",                 { l1_he,          l1_he,          l1_he,          NULL,           NULL,           l1_iw } },
+    { "iw",                 { l1_he,          l1_he,          l1_he,          NULL,           NULL,           l1_iw } },
+    { "hr",                 { l1_hr,          l1_hr,          l1_hr,          NULL,           NULL,           NULL  } },
+    { "hu",                 { l1_hu,          l1_hu,          l1_hu,          NULL,           NULL,           NULL  } },
+    { "id",                 { l1_id,          l1_id,          l1_id,          NULL,           NULL,           l1_in } },
+    { "in",                 { l1_id,          l1_id,          l1_id,          NULL,           NULL,           l1_in } },
+    { "ms",                 { l1_ms,          l1_ms,          l1_ms,          NULL,           NULL,           NULL  } },
+    { "ro",                 { l1_ro,          l1_ro,          l1_ro,          l1_ro,          NULL,           NULL  } },
+    { "mo",                 { l1_ro,          l1_ro,          l1_ro,          l2_ro_MD_,      NULL,           l1_mo } },
+    { "sk",                 { l1_sk,          l1_sk,          l1_sk,          NULL,           NULL,           NULL  } },
+    { "uk",                 { l1_uk,          l1_uk,          l1_uk,          NULL,           NULL,           NULL  } },
+    { "vi",                 { l1_vi,          l1_vi,          l1_vi,          NULL,           NULL,           NULL  } },
+    { "yi",                 { NULL,           NULL,           NULL,           NULL,           l1_yi,          NULL  } },
+    { "ji",                 { NULL,           NULL,           NULL,           NULL,           l1_yi,          NULL  } },
+    { "fil",                { NULL,           NULL,           NULL,           NULL,           l1_fil,         l1_tl } },
+    { "tl",                 { NULL,           NULL,           NULL,           NULL,           l1_fil,         l1_tl } },
+    { "haw",                { NULL,           NULL,           NULL,           NULL,           l1_haw,         NULL  } },
+    { "sr",                 { NULL,           NULL,           NULL,           NULL,           l1_sr,          NULL  } },
+    { "sr-Cyrl",            { NULL,           NULL,           NULL,           NULL,           l1_sr,          NULL  } },
+    { "sr-Latn",            { NULL,           NULL,           NULL,           NULL,           l1_srLatn,      NULL  } },
+    { "tlh",                { NULL,           NULL,           NULL,           NULL,           l1_tlh,         NULL  } },
+    { "Default@2x",         { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "default",            { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "root",               { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "",                   { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "_US",                { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "-US",                { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "-u-ca-hebrew",       { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "-u-ca-hebrew",       { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+    { "@calendar=hebrew",   { NULL,           NULL,           NULL,           NULL,           NULL,           NULL  } },
+};
+enum { kNumAppleLangAndLoc = UPRV_LENGTHOF(appleLangAndLoc) };
+
+/* tests from <rdar://problem/21518031> */
+
+static const char * appleLocsA1[] = { "en", "fr", "no", "zh-Hant" };
+static const char * appleLocsA2[] = { "en", "fr", "nb", "zh_TW", "zh_CN", "zh-Hant" };
+static const char * appleLocsA3[] = { "en", "en_IN", "en_GB", "fr", "de", "zh_TW" };
+static const char * appleLocsA4[] = { "Spanish", "es_MX", "English", "en_GB" };
+static const char * appleLocsA5[] = { "en", "fr", "de", "pt", "pt_PT" };
+static const char * appleLocsA6[] = { "en", "no", "no_NO", "pt_PT" };
+
+static const AppleLocsAndCount locAndCountEntriesA[kNumLocSets] = {
+    { appleLocsA1, UPRV_LENGTHOF(appleLocsA1) },
+    { appleLocsA2, UPRV_LENGTHOF(appleLocsA2) },
+    { appleLocsA3, UPRV_LENGTHOF(appleLocsA3) },
+    { appleLocsA4, UPRV_LENGTHOF(appleLocsA4) },
+    { appleLocsA5, UPRV_LENGTHOF(appleLocsA5) },
+    { appleLocsA6, UPRV_LENGTHOF(appleLocsA6) },
+};
+
+static const LangAndExpLocs appleLangAndLocA[] = {
+//    language\    result for appleLocsA1     appleLocsA2         appleLocsA3     appleLocsA4     appleLocsA5     appleLocsA6
+    { "zh-Hant",            { l1_zhHant,/*0*/ l1_zhHant,/*zh_TW*/ l1_zh_TW,       NULL,           NULL,           NULL        } },
+    { "zh_Hant",            { l1_zhHant,      l1_zhHant,/*zh_TW*/ l1_zh_TW,       NULL,           NULL,           NULL        } },
+    { "zh_HK",              { l1_zhHant,      l1_zhHant,/*zh_TW*/ l1_zh_TW,       NULL,           NULL,           NULL        } },
+    { "en_IN",              { l1_en,          l1_en,              l3_en_INGB_,    l2_en_GB_Eng,   l1_en,          l1_en       } },
+    { "es_MX",              { NULL,           NULL,               NULL,           l2_es_MX_Spa,   NULL,           NULL        } },
+    { "pt_PT",              { NULL,           NULL,               NULL,           NULL,           l2_pt_PT_,      l1_pt_PT    } },
+    { "pt",                 { NULL,           NULL,               NULL,           NULL,           l1_pt,          l1_pt_PT    } },
+    { "no",                 { l1_no,          l1_nb,              NULL,           NULL,           NULL,           l1_no       } },
+    { "no_NO",              { l1_no,          l1_nb,              NULL,           NULL,           NULL,           l2_no_NO_   } },
+    { "nb",                 { l1_no,          l1_nb,              NULL,           NULL,           NULL,           l1_no       } },
+    { "nb_NO",              { l1_no,          l1_nb,              NULL,           NULL,           NULL,           l2_no_NO_   } },
+};
+enum { kNumAppleLangAndLocA = UPRV_LENGTHOF(appleLangAndLocA) };
+
+/* tests from log attached to 21682790 */
+
+static const char * appleLocsB1[] = {
+    "ar",       "Base",     "ca",       "cs",
+    "da",       "Dutch",    "el",       "English",
+    "es_MX",    "fi",       "French",   "German",
+    "he",       "hr",       "hu",       "id",
+    "Italian",  "Japanese", "ko",       "ms",
+    "no",       "pl",       "pt",       "pt_PT",
+    "ro",       "ru",       "sk",       "Spanish",
+    "sv",       "th",       "tr",       "uk",
+    "vi",       "zh_CN",    "zh_TW"
+};
+
+static const char * appleLocsB2[] = {
+    "ar",                   "ca",       "cs",
+    "da",       "Dutch",    "el",       "English",
+    "es_MX",    "fi",       "French",   "German",
+    "he",       "hr",       "hu",       "id",
+    "Italian",  "Japanese", "ko",       "ms",
+    "no",       "pl",       "pt",       "pt_PT",
+    "ro",       "ru",       "sk",       "Spanish",
+    "sv",       "th",       "tr",       "uk",
+    "vi",       "zh_CN",    "zh_TW"
+};
+
+static const char * appleLocsB3[] = {
+    "ar",       "ca",       "cs",       "da",
+    "de",       "el",       "en",       "es",
+    "es_MX",    "fi",       "French",   "he",
+    "hr",       "hu",       "id",       "Italian",
+    "ja",       "ko",       "ms",       "nl",
+    "no",       "pl",       "pt",       "pt_PT",
+    "ro",       "ru",       "sk",       "sv",
+    "th",       "tr",       "uk",       "vi",
+    "zh_CN",    "zh_TW"
+};
+
+static const char * appleLocsB4[] = {
+    "ar",       "ca",       "cs",       "da",
+    "de",       "el",       "en",       "es",
+    "es_MX",    "fi",       "fr",       "he",
+    "hr",       "hu",       "id",       "it",
+    "ja",       "ko",       "ms",       "nl",
+    "no",       "pl",       "pt",       "pt_PT",
+    "ro",       "ru",       "sk",       "sv",
+    "th",       "tr",       "uk",       "vi",
+    "zh_CN",     "zh_TW"
+};
+
+static const char * appleLocsB5[] = { "en" };
+
+static const char * appleLocsB6[] = { "English" };
+
+static const AppleLocsAndCount locAndCountEntriesB[kNumLocSets] = {
+    { appleLocsB1, UPRV_LENGTHOF(appleLocsB1) },
+    { appleLocsB2, UPRV_LENGTHOF(appleLocsB2) },
+    { appleLocsB3, UPRV_LENGTHOF(appleLocsB3) },
+    { appleLocsB4, UPRV_LENGTHOF(appleLocsB4) },
+    { appleLocsB5, UPRV_LENGTHOF(appleLocsB5) },
+    { appleLocsB6, UPRV_LENGTHOF(appleLocsB6) },
+};
+
+static const LangAndExpLocs appleLangAndLocB[] = {
+//    language\    result for appleLocsB1     appleLocsB2         appleLocsB3     appleLocsB4     appleLocsB5     appleLocsB6
+// Prefs 1, logged with sets B1-B3
+    { "en",                 { l1_Eng,         l1_Eng,             l1_en,          l1_en,          l1_en,          l1_Eng      } },
+    { "es",                 { l1_Spa,         l1_Spa,             l1_es,          l1_es,          NULL,           NULL        } },
+// Prefs 2, logged with sets B1-B6
+    { "English",            { l1_Eng,         l1_Eng,             l1_en,          l1_en,          l1_en,          l1_Eng      } },
+    { "Spanish",            { l1_Spa,         l1_Spa,             l1_es,          l1_es,          NULL,           NULL        } },
+};
+enum { kNumAppleLangAndLocB = UPRV_LENGTHOF(appleLangAndLocB) };
+
+typedef struct {
+    const AppleLocsAndCount * locAndCountEntriesPtr;
+    const LangAndExpLocs *    appleLangAndLocPtr;
+    int32_t                   appleLangAndLocCount;
+} AppleLocToUseTestSet;
+
+static const AppleLocToUseTestSet altuTestSets[] = {
+    { locAndCountEntries,  appleLangAndLoc,  kNumAppleLangAndLoc },
+    { locAndCountEntriesA, appleLangAndLocA, kNumAppleLangAndLocA },
+    { locAndCountEntriesB, appleLangAndLocB, kNumAppleLangAndLocB },
+    { NULL, NULL, 0 }
+};
+
+/* tests for multiple prefs sets */
+
+static const char * appleLocsM[] = { "en", "en_GB", "pt", "pt_PT", "zh_CN", "zh_Hant" };
+static const char * prefLangsM[] = { "tlh", "zh_HK", "zh_SG", "zh_Hans", "pt_BR", "pt_PT", "en_IN", "en" };
+static const char * locsToUseM[] = { "zh_Hant" };
+enum {
+    kNumAppleLocsM = UPRV_LENGTHOF(appleLocsM),
+    kNumPrefLangsM = UPRV_LENGTHOF(prefLangsM),
+    kNumLocsToUseM = UPRV_LENGTHOF(locsToUseM),
+};
+
+/* general enums */
+
+enum { kMaxLocalizationsToUse = 8, kPrintArrayBufSize = 128 };
+
+// array, array of pointers to strings to print
+// count, count of array elements, may be -1 if array is terminated by a NULL entry
+// buf, buffer into which to put concatenated strings
+// bufSize, length of buf
+static void printStringArray(const char **array, int32_t count, char *buf, int32_t bufSize) {
+    char * bufPtr = buf;
+    const char * curEntry;
+    int32_t idx, countMax = bufSize/16;
+    if (count < 0 || count > countMax) {
+        count = countMax;
+    }
+    for (idx = 0; idx < count && (curEntry = *array++) != NULL; idx++) {
+        int32_t len = sprintf(bufPtr, "%s\"%.12s\"", (idx > 0)? ", ": "", curEntry);
+        if (len <= 0) {
+            break;
+        }
+        bufPtr += len;
+    }
+    *bufPtr = 0; /* ensure termination */
+}
+
+static UBool equalStringArrays(const char **array1, int32_t count1, const char **array2, int32_t count2) {
+    const char ** array1Ptr = array1;
+    const char ** array2Ptr = array2;
+    if (count1 < 0) {
+        count1 = 0;
+        while (*array1Ptr++ != NULL) {
+            count1++;
+        }
+    }
+    if (count2 < 0) {
+        count2 = 0;
+        while (*array2Ptr++ != NULL) {
+            count2++;
+        }
+    }
+    if (count1 != count2) {
+        return FALSE;
+    }
+    int32_t idx;
+    for (idx = 0; idx < count1; idx++) {
+        if (uprv_strcmp(array1[idx], array2[idx]) != 0) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+static void TestAppleLocalizationsToUse() {
+    const AppleLocToUseTestSet * testSetPtr;
+    const char * locsToUse[kMaxLocalizationsToUse];
+    int32_t numLocsToUse;
+    UErrorCode status;
+    char printExpected[kPrintArrayBufSize];
+    char printActual[kPrintArrayBufSize];
+
+    for (testSetPtr = altuTestSets; testSetPtr->locAndCountEntriesPtr != NULL; testSetPtr++) {
+        int32_t iLocSet, iLang;
+
+        for (iLocSet = 0; iLocSet < kNumLocSets; iLocSet++) {
+            for (iLang = 0; iLang < testSetPtr->appleLangAndLocCount; iLang++) {
+                status = U_ZERO_ERROR;
+                const char * language = testSetPtr->appleLangAndLocPtr[iLang].language;
+                const char ** expLocsForSet = testSetPtr->appleLangAndLocPtr[iLang].expLocsForSets[iLocSet];
+
+                numLocsToUse = ualoc_localizationsToUse(&language, 1,
+                                                        testSetPtr->locAndCountEntriesPtr[iLocSet].locs, testSetPtr->locAndCountEntriesPtr[iLocSet].locCount,
+                                                        locsToUse, kMaxLocalizationsToUse, &status);
+                if (U_FAILURE(status)) {
+                    log_err("FAIL: ualoc_localizationsToUse testSet %d, locSet %d, lang %s, status %s\n",
+                            testSetPtr-altuTestSets, iLocSet+1, language, u_errorName(status));
+                } else if (numLocsToUse == 0 && expLocsForSet != NULL) {
+                    printStringArray(expLocsForSet, -1, printExpected, kPrintArrayBufSize);
+                    log_err("FAIL: ualoc_localizationsToUse testSet %d, locSet %d, lang %s, expect {%s}, get no results\n",
+                            testSetPtr-altuTestSets, iLocSet+1, language, printExpected);
+                } else if (numLocsToUse > 0 && expLocsForSet == NULL) {
+                    printStringArray(locsToUse, numLocsToUse, printActual, kPrintArrayBufSize);
+                    log_err("FAIL: ualoc_localizationsToUse testSet %d, locSet %d, lang %s, expect no results, get {%s}\n",
+                            testSetPtr-altuTestSets, iLocSet+1, language, printActual);
+                } else if (numLocsToUse > 0 && !equalStringArrays(expLocsForSet, -1, locsToUse, numLocsToUse)) {
+                    printStringArray(expLocsForSet, -1, printExpected, kPrintArrayBufSize);
+                    printStringArray(locsToUse, numLocsToUse, printActual, kPrintArrayBufSize);
+                    log_err("FAIL: ualoc_localizationsToUse testSet %d, locSet %d, lang %s:\n            expect {%s}\n            get    {%s}\n",
+                            testSetPtr-altuTestSets, iLocSet+1, language, printExpected, printActual);
+                }
+            }
+        }
+    }
+
+
+    status = U_ZERO_ERROR;
+    numLocsToUse = ualoc_localizationsToUse(prefLangsM, kNumPrefLangsM, appleLocsM, kNumAppleLocsM, locsToUse, kMaxLocalizationsToUse, &status);
+    if (U_FAILURE(status)) {
+        log_err("FAIL: ualoc_localizationsToUse appleLocsM, langs prefLangsM, status %s\n", u_errorName(status));
+    } else if (!equalStringArrays(locsToUseM, kNumLocsToUseM, locsToUse, numLocsToUse)) {
+        printStringArray(locsToUseM, kNumLocsToUseM, printExpected, kPrintArrayBufSize);
+        printStringArray(locsToUse, numLocsToUse, printActual, kPrintArrayBufSize);
+        log_err("FAIL: ualoc_localizationsToUse appleLocsM, langs prefLangsM:\n            expect {%s}\n            get    {%s}\n",
+                printExpected, printActual);
+    }
+
+}