#include "unicode/localematcher.h"
#include "unicode/locid.h"
#include "unicode/stringpiece.h"
+#include "unicode/uloc.h"
#include "unicode/uobject.h"
#include "cstring.h"
#include "localeprioritylist.h"
#include "lsr.h"
#include "uassert.h"
#include "uhash.h"
+#include "ustr_imp.h"
#include "uvector.h"
#define UND_LSR LSR("und", "", "", LSR::EXPLICIT_LSR)
U_NAMESPACE_END
+// uloc_acceptLanguage() --------------------------------------------------- ***
+
+U_NAMESPACE_USE
+
+namespace {
+
+class LocaleFromTag {
+public:
+ LocaleFromTag() : locale(Locale::getRoot()) {}
+ const Locale &operator()(const char *tag) { return locale = Locale(tag); }
+
+private:
+ // Store the locale in the converter, rather than return a reference to a temporary,
+ // or a value which could go out of scope with the caller's reference to it.
+ Locale locale;
+};
+
+int32_t acceptLanguage(UEnumeration &supportedLocales, Locale::Iterator &desiredLocales,
+ char *dest, int32_t capacity, UAcceptResult *acceptResult,
+ UErrorCode &errorCode) {
+ if (U_FAILURE(errorCode)) { return 0; }
+ LocaleMatcher::Builder builder;
+ const char *locString;
+ while ((locString = uenum_next(&supportedLocales, nullptr, &errorCode)) != nullptr) {
+ Locale loc(locString);
+ if (loc.isBogus()) {
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ builder.addSupportedLocale(loc);
+ }
+ LocaleMatcher matcher = builder.build(errorCode);
+ LocaleMatcher::Result result = matcher.getBestMatchResult(desiredLocales, errorCode);
+ if (U_FAILURE(errorCode)) { return 0; }
+ if (result.getDesiredIndex() >= 0) {
+ if (acceptResult != nullptr) {
+ *acceptResult = *result.getDesiredLocale() == *result.getSupportedLocale() ?
+ ULOC_ACCEPT_VALID : ULOC_ACCEPT_FALLBACK;
+ }
+ const char *bestStr = result.getSupportedLocale()->getName();
+ int32_t bestLength = (int32_t)uprv_strlen(bestStr);
+ if (bestLength <= capacity) {
+ uprv_memcpy(dest, bestStr, bestLength);
+ }
+ return u_terminateChars(dest, capacity, bestLength, &errorCode);
+ } else {
+ if (acceptResult != nullptr) {
+ *acceptResult = ULOC_ACCEPT_FAILED;
+ }
+ return u_terminateChars(dest, capacity, 0, &errorCode);
+ }
+}
+
+} // namespace
+
+U_CAPI int32_t U_EXPORT2
+uloc_acceptLanguage(char *result, int32_t resultAvailable,
+ UAcceptResult *outResult,
+ const char **acceptList, int32_t acceptListCount,
+ UEnumeration *availableLocales,
+ UErrorCode *status) {
+ if (U_FAILURE(*status)) { return 0; }
+ if ((result == nullptr ? resultAvailable != 0 : resultAvailable < 0) ||
+ (acceptList == nullptr ? acceptListCount != 0 : acceptListCount < 0) ||
+ availableLocales == nullptr) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ LocaleFromTag converter;
+ Locale::ConvertingIterator<const char **, LocaleFromTag> desiredLocales(
+ acceptList, acceptList + acceptListCount, converter);
+ return acceptLanguage(*availableLocales, desiredLocales,
+ result, resultAvailable, outResult, *status);
+}
+
+U_CAPI int32_t U_EXPORT2
+uloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable,
+ UAcceptResult *outResult,
+ const char *httpAcceptLanguage,
+ UEnumeration *availableLocales,
+ UErrorCode *status) {
+ if (U_FAILURE(*status)) { return 0; }
+ if ((result == nullptr ? resultAvailable != 0 : resultAvailable < 0) ||
+ httpAcceptLanguage == nullptr || availableLocales == nullptr) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ LocalePriorityList list(httpAcceptLanguage, *status);
+ LocalePriorityList::Iterator desiredLocales = list.iterator();
+ return acceptLanguage(*availableLocales, desiredLocales,
+ result, resultAvailable, outResult, *status);
+}
+
#endif // __LOCMATCHER_H__
if (U_FAILURE(errorCode)) { return; }
Locale locale = Locale(tag.data());
if (locale.isBogus()) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
int32_t weight = WEIGHT_ONE;
return COUNTRIES;
}
-
-/* this function to be moved into cstring.c later */
-static char gDecimal = 0;
-
-static /* U_CAPI */
-double
-/* U_EXPORT2 */
-_uloc_strtod(const char *start, char **end) {
- char *decimal;
- char *myEnd;
- char buf[30];
- double rv;
- if (!gDecimal) {
- char rep[5];
- /* For machines that decide to change the decimal on you,
- and try to be too smart with localization.
- This normally should be just a '.'. */
- sprintf(rep, "%+1.1f", 1.0);
- gDecimal = rep[2];
- }
-
- if(gDecimal == '.') {
- return uprv_strtod(start, end); /* fall through to OS */
- } else {
- uprv_strncpy(buf, start, 29);
- buf[29]=0;
- decimal = uprv_strchr(buf, '.');
- if(decimal) {
- *decimal = gDecimal;
- } else {
- return uprv_strtod(start, end); /* no decimal point */
- }
- rv = uprv_strtod(buf, &myEnd);
- if(end) {
- *end = (char*)(start+(myEnd-buf)); /* cast away const (to follow uprv_strtod API.) */
- }
- return rv;
- }
-}
-
-typedef struct {
- float q;
- int32_t dummy; /* to avoid uninitialized memory copy from qsort */
- char locale[ULOC_FULLNAME_CAPACITY+1];
-} _acceptLangItem;
-
-static int32_t U_CALLCONV
-uloc_acceptLanguageCompare(const void * /*context*/, const void *a, const void *b)
-{
- const _acceptLangItem *aa = (const _acceptLangItem*)a;
- const _acceptLangItem *bb = (const _acceptLangItem*)b;
-
- int32_t rc = 0;
- if(bb->q < aa->q) {
- rc = -1; /* A > B */
- } else if(bb->q > aa->q) {
- rc = 1; /* A < B */
- } else {
- rc = 0; /* A = B */
- }
-
- if(rc==0) {
- rc = uprv_stricmp(aa->locale, bb->locale);
- }
-
-#if defined(ULOC_DEBUG)
- /* fprintf(stderr, "a:[%s:%g], b:[%s:%g] -> %d\n",
- aa->locale, aa->q,
- bb->locale, bb->q,
- rc);*/
-#endif
-
- return rc;
-}
-
-/*
-mt-mt, ja;q=0.76, en-us;q=0.95, en;q=0.92, en-gb;q=0.89, fr;q=0.87, iu-ca;q=0.84, iu;q=0.82, ja-jp;q=0.79, mt;q=0.97, de-de;q=0.74, de;q=0.71, es;q=0.68, it-it;q=0.66, it;q=0.63, vi-vn;q=0.61, vi;q=0.58, nl-nl;q=0.55, nl;q=0.53
-*/
-
-U_CAPI int32_t U_EXPORT2
-uloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable, UAcceptResult *outResult,
- const char *httpAcceptLanguage,
- UEnumeration* availableLocales,
- UErrorCode *status)
-{
- MaybeStackArray<_acceptLangItem, 4> items; // Struct for collecting items.
- char tmp[ULOC_FULLNAME_CAPACITY +1];
- int32_t n = 0;
- const char *itemEnd;
- const char *paramEnd;
- const char *s;
- const char *t;
- int32_t res;
- int32_t i;
- int32_t l = (int32_t)uprv_strlen(httpAcceptLanguage);
-
- if(U_FAILURE(*status)) {
- return -1;
- }
-
- for(s=httpAcceptLanguage;s&&*s;) {
- while(isspace(*s)) /* eat space at the beginning */
- s++;
- itemEnd=uprv_strchr(s,',');
- paramEnd=uprv_strchr(s,';');
- if(!itemEnd) {
- itemEnd = httpAcceptLanguage+l; /* end of string */
- }
- if(paramEnd && paramEnd<itemEnd) {
- /* semicolon (;) is closer than end (,) */
- t = paramEnd+1;
- if(*t=='q') {
- t++;
- }
- while(isspace(*t)) {
- t++;
- }
- if(*t=='=') {
- t++;
- }
- while(isspace(*t)) {
- t++;
- }
- items[n].q = (float)_uloc_strtod(t,NULL);
- } else {
- /* no semicolon - it's 1.0 */
- items[n].q = 1.0f;
- paramEnd = itemEnd;
- }
- items[n].dummy=0;
- /* eat spaces prior to semi */
- for(t=(paramEnd-1);(paramEnd>s)&&isspace(*t);t--)
- ;
- int32_t slen = static_cast<int32_t>(((t+1)-s));
- if(slen > ULOC_FULLNAME_CAPACITY) {
- *status = U_BUFFER_OVERFLOW_ERROR;
- return -1; // too big
- }
- uprv_strncpy(items[n].locale, s, slen);
- items[n].locale[slen]=0; // terminate
- int32_t clen = uloc_canonicalize(items[n].locale, tmp, UPRV_LENGTHOF(tmp)-1, status);
- if(U_FAILURE(*status)) return -1;
- if((clen!=slen) || (uprv_strncmp(items[n].locale, tmp, slen))) {
- // canonicalization had an effect- copy back
- uprv_strncpy(items[n].locale, tmp, clen);
- items[n].locale[clen] = 0; // terminate
- }
-#if defined(ULOC_DEBUG)
- /*fprintf(stderr,"%d: s <%s> q <%g>\n", n, j[n].locale, j[n].q);*/
-#endif
- n++;
- s = itemEnd;
- while(*s==',') { /* eat duplicate commas */
- s++;
- }
- if(n>=items.getCapacity()) { // If we need more items
- if(NULL == items.resize(items.getCapacity()*2, items.getCapacity())) {
- *status = U_MEMORY_ALLOCATION_ERROR;
- return -1;
- }
-#if defined(ULOC_DEBUG)
- fprintf(stderr,"malloced at size %d\n", items.getCapacity());
-#endif
- }
- }
- uprv_sortArray(items.getAlias(), n, sizeof(items[0]), uloc_acceptLanguageCompare, NULL, TRUE, status);
- if (U_FAILURE(*status)) {
- return -1;
- }
- LocalMemory<const char*> strs(NULL);
- if (strs.allocateInsteadAndReset(n) == NULL) {
- *status = U_MEMORY_ALLOCATION_ERROR;
- return -1;
- }
- for(i=0;i<n;i++) {
-#if defined(ULOC_DEBUG)
- /*fprintf(stderr,"%d: s <%s> q <%g>\n", i, j[i].locale, j[i].q);*/
-#endif
- strs[i]=items[i].locale;
- }
- res = uloc_acceptLanguage(result, resultAvailable, outResult,
- strs.getAlias(), n, availableLocales, status);
- return res;
-}
-
-
-U_CAPI int32_t U_EXPORT2
-uloc_acceptLanguage(char *result, int32_t resultAvailable,
- UAcceptResult *outResult, const char **acceptList,
- int32_t acceptListCount,
- UEnumeration* availableLocales,
- UErrorCode *status)
-{
- int32_t i,j;
- int32_t len;
- int32_t maxLen=0;
- char tmp[ULOC_FULLNAME_CAPACITY+1];
- const char *l;
- char **fallbackList;
- if(U_FAILURE(*status)) {
- return -1;
- }
- fallbackList = static_cast<char **>(uprv_malloc((size_t)(sizeof(fallbackList[0])*acceptListCount)));
- if(fallbackList==NULL) {
- *status = U_MEMORY_ALLOCATION_ERROR;
- return -1;
- }
- for(i=0;i<acceptListCount;i++) {
-#if defined(ULOC_DEBUG)
- fprintf(stderr,"%02d: %s\n", i, acceptList[i]);
-#endif
- while((l=uenum_next(availableLocales, NULL, status)) != NULL) {
-#if defined(ULOC_DEBUG)
- fprintf(stderr," %s\n", l);
-#endif
- len = (int32_t)uprv_strlen(l);
- if(!uprv_strcmp(acceptList[i], l)) {
- if(outResult) {
- *outResult = ULOC_ACCEPT_VALID;
- }
-#if defined(ULOC_DEBUG)
- fprintf(stderr, "MATCH! %s\n", l);
-#endif
- if(len>0) {
- uprv_strncpy(result, l, uprv_min(len, resultAvailable));
- }
- for(j=0;j<i;j++) {
- uprv_free(fallbackList[j]);
- }
- uprv_free(fallbackList);
- return u_terminateChars(result, resultAvailable, len, status);
- }
- if(len>maxLen) {
- maxLen = len;
- }
- }
- uenum_reset(availableLocales, status);
- /* save off parent info */
- if(uloc_getParent(acceptList[i], tmp, UPRV_LENGTHOF(tmp), status)!=0) {
- fallbackList[i] = uprv_strdup(tmp);
- } else {
- fallbackList[i]=0;
- }
- }
-
- for(maxLen--;maxLen>0;maxLen--) {
- for(i=0;i<acceptListCount;i++) {
- if(fallbackList[i] && ((int32_t)uprv_strlen(fallbackList[i])==maxLen)) {
-#if defined(ULOC_DEBUG)
- fprintf(stderr,"Try: [%s]", fallbackList[i]);
-#endif
- while((l=uenum_next(availableLocales, NULL, status)) != NULL) {
-#if defined(ULOC_DEBUG)
- fprintf(stderr," %s\n", l);
-#endif
- len = (int32_t)uprv_strlen(l);
- if(!uprv_strcmp(fallbackList[i], l)) {
- if(outResult) {
- *outResult = ULOC_ACCEPT_FALLBACK;
- }
-#if defined(ULOC_DEBUG)
- fprintf(stderr, "fallback MATCH! %s\n", l);
-#endif
- if(len>0) {
- uprv_strncpy(result, l, uprv_min(len, resultAvailable));
- }
- for(j=0;j<acceptListCount;j++) {
- uprv_free(fallbackList[j]);
- }
- uprv_free(fallbackList);
- return u_terminateChars(result, resultAvailable, len, status);
- }
- }
- uenum_reset(availableLocales, status);
-
- if(uloc_getParent(fallbackList[i], tmp, UPRV_LENGTHOF(tmp), status)!=0) {
- uprv_free(fallbackList[i]);
- fallbackList[i] = uprv_strdup(tmp);
- } else {
- uprv_free(fallbackList[i]);
- fallbackList[i]=0;
- }
- }
- }
- if(outResult) {
- *outResult = ULOC_ACCEPT_FAILED;
- }
- }
- for(i=0;i<acceptListCount;i++) {
- uprv_free(fallbackList[i]);
- }
- uprv_free(fallbackList);
- return -1;
-}
-
U_CAPI const char* U_EXPORT2
uloc_toUnicodeLocaleKey(const char* keyword)
{
} tests[] = {
/*0*/{ 0, NULL, "mt_MT", ULOC_ACCEPT_VALID, U_ZERO_ERROR},
/*1*/{ 1, NULL, "en", ULOC_ACCEPT_VALID, U_ZERO_ERROR},
- /*2*/{ 2, NULL, "en", ULOC_ACCEPT_FALLBACK, U_ZERO_ERROR},
+ /*2*/{ 2, NULL, "en_GB", ULOC_ACCEPT_FALLBACK, U_ZERO_ERROR},
/*3*/{ 3, NULL, "", ULOC_ACCEPT_FAILED, U_ZERO_ERROR},
/*4*/{ 4, NULL, "es", ULOC_ACCEPT_VALID, U_ZERO_ERROR},
- /*5*/{ 5, NULL, "en", ULOC_ACCEPT_VALID, U_ZERO_ERROR}, /* XF */
+ /*5*/{ 5, NULL, "zh", ULOC_ACCEPT_FALLBACK, U_ZERO_ERROR}, /* XF */
/*6*/{ 6, NULL, "ja", ULOC_ACCEPT_FALLBACK, U_ZERO_ERROR}, /* XF */
/*7*/{ 7, NULL, "zh", ULOC_ACCEPT_FALLBACK, U_ZERO_ERROR}, /* XF */
- /*8*/{ 8, NULL, "", ULOC_ACCEPT_FAILED, U_ZERO_ERROR }, /* */
- /*9*/{ 9, NULL, "", ULOC_ACCEPT_FAILED, U_ZERO_ERROR }, /* */
- /*10*/{10, NULL, "", ULOC_ACCEPT_FAILED, U_BUFFER_OVERFLOW_ERROR }, /* */
- /*11*/{11, NULL, "", ULOC_ACCEPT_FAILED, U_BUFFER_OVERFLOW_ERROR }, /* */
+ /*8*/{ 8, NULL, "", ULOC_ACCEPT_FAILED, U_ILLEGAL_ARGUMENT_ERROR }, /* */
+ /*9*/{ 9, NULL, "", ULOC_ACCEPT_FAILED, U_ILLEGAL_ARGUMENT_ERROR }, /* */
+ /*10*/{10, NULL, "", ULOC_ACCEPT_FAILED, U_ILLEGAL_ARGUMENT_ERROR }, /* */
+ /*11*/{11, NULL, "", ULOC_ACCEPT_FAILED, U_ILLEGAL_ARGUMENT_ERROR }, /* */
};
const int32_t numTests = UPRV_LENGTHOF(tests);
static const char *http[] = {
- /*0*/ "mt-mt, ja;q=0.76, en-us;q=0.95, en;q=0.92, en-gb;q=0.89, fr;q=0.87, iu-ca;q=0.84, iu;q=0.82, ja-jp;q=0.79, mt;q=0.97, de-de;q=0.74, de;q=0.71, es;q=0.68, it-it;q=0.66, it;q=0.63, vi-vn;q=0.61, vi;q=0.58, nl-nl;q=0.55, nl;q=0.53, th-th-traditional;q=.01",
+ /*0*/ "mt-mt, ja;q=0.76, en-us;q=0.95, en;q=0.92, en-gb;q=0.89, fr;q=0.87, "
+ "iu-ca;q=0.84, iu;q=0.82, ja-jp;q=0.79, mt;q=0.97, de-de;q=0.74, de;q=0.71, "
+ "es;q=0.68, it-it;q=0.66, it;q=0.63, vi-vn;q=0.61, vi;q=0.58, "
+ "nl-nl;q=0.55, nl;q=0.53, th-th-traditional;q=0.01",
/*1*/ "ja;q=0.5, en;q=0.8, tlh",
/*2*/ "en-wf, de-lx;q=0.8",
- /*3*/ "mga-ie;q=0.9, tlh",
- /*4*/ "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
- "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
- "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
- "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
- "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
- "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
- "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xx-yy;q=.1, "
+ /*3*/ "mga-ie;q=0.9, sux",
+ /*4*/ "xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, "
+ "xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, "
+ "xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, "
+ "xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, "
+ "xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, "
+ "xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, "
+ "xxx-yyy;q=0.01, xxx-yyy;q=0.01, xxx-yyy;q=0.01, xx-yy;q=0.1, "
"es",
/*5*/ "zh-xx;q=0.9, en;q=0.6",
/*6*/ "ja-JA",
available = ures_openAvailableLocales(tests[i].icuSet, &status);
tmp[0]=0;
- rc = uloc_acceptLanguageFromHTTP(tmp, 199, &outResult, http[tests[i].httpSet], available, &status);
+ 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));
+ log_verbose(" got %s, %s [%s]\n",
+ tmp[0]?tmp:"(EMPTY)", acceptResult(outResult), u_errorName(status));
if(status != tests[i].expectStatus) {
- log_err_status(status, "FAIL: expected status %s but got %s\n", u_errorName(tests[i].expectStatus), u_errorName(status));
+ log_err_status(status,
+ "FAIL: expected status %s but got %s\n",
+ u_errorName(tests[i].expectStatus),
+ u_errorName(status));
} else if(U_SUCCESS(tests[i].expectStatus)) {
/* don't check content if expected failure */
if(outResult != tests[i].res) {
acceptResult( tests[i].res),
acceptResult( outResult));
log_info("test #%d: http[%s], ICU[%s], expect %s, %s\n",
- i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect,acceptResult(tests[i].res));
+ i, http[tests[i].httpSet], tests[i].icuSet,
+ tests[i].expect,acceptResult(tests[i].res));
}
if((outResult>0)&&uprv_strcmp(tmp, tests[i].expect)) {
- log_err_status(status, "FAIL: #%d: expected %s but got %s\n", i, tests[i].expect, tmp);
+ log_err_status(status,
+ "FAIL: #%d: expected %s but got %s\n",
+ i, tests[i].expect, tmp);
log_info("test #%d: http[%s], ICU[%s], expect %s, %s\n",
i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect, acceptResult(tests[i].res));
}
*/
package com.ibm.icu.util;
-import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
+import java.util.Set;
import com.ibm.icu.impl.Utility;
import com.ibm.icu.text.BreakIterator;
if (isFrozen()) {
throw new UnsupportedOperationException("Attempt to modify immutable object");
}
- ULocale[] acceptLocales = null;
- try {
- acceptLocales = ULocale.parseAcceptLanguage(acceptLanguageString, true);
- } catch (ParseException pe) {
- //TODO: revisit after 3.8
- throw new IllegalArgumentException("Invalid Accept-Language string");
- }
- return setLocales(acceptLocales);
+ Set<ULocale> acceptSet = LocalePriorityList.add(acceptLanguageString).build().getULocales();
+ // processLocales() wants a List even though it only iterates front-to-back.
+ locales = processLocales(new ArrayList<>(acceptSet));
+ return this;
}
/**
* @provisional This API might change or be removed in a future release.
*/
protected List<ULocale> processLocales(List<ULocale> inputLocales) {
+ // Note: Some of the callers, and non-ICU call sites, could be simpler/more efficient
+ // if this method took a Collection or even an Iterable.
+ // Maybe we can change it since this is still @draft and probably not widely overridden.
List<ULocale> result = new ArrayList<>();
/*
* Step 1: Relocate later occurrence of more specific locale
* Before - en_US, fr_FR, zh, en_US_Boston, zh_TW, zh_Hant, fr_CA
* After - en_US_Boston, en_US, fr_FR, zh_TW, zh_Hant, zh, fr_CA
*/
- for (int i = 0; i < inputLocales.size(); i++) {
- ULocale uloc = inputLocales.get(i);
-
+ for (ULocale uloc : inputLocales) {
String language = uloc.getLanguage();
String script = uloc.getScript();
String country = uloc.getCountry();
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import com.ibm.icu.impl.ICUResourceTableAccess;
import com.ibm.icu.impl.LocaleIDParser;
import com.ibm.icu.impl.LocaleIDs;
-import com.ibm.icu.impl.LocaleUtility;
import com.ibm.icu.impl.SoftCache;
import com.ibm.icu.impl.locale.AsciiUtil;
import com.ibm.icu.impl.locale.BaseLocale;
this.locale = locale;
}
- /**
- * Construct a ULocale object from a {@link java.util.Locale}.
- * @param loc a {@link java.util.Locale}
- */
- private ULocale(Locale loc) {
- this.localeID = getName(forLocale(loc).toString());
- this.locale = loc;
- }
-
/**
* {@icu} Returns a ULocale object for a {@link java.util.Locale}.
* The ULocale is canonicalized.
* ROOT ULocale if if a ROOT locale was used as a fallback (because nothing else in
* availableLocales matched). No ULocale array element should be null; behavior is
* undefined if this is the case.
+ *
+ * <p>This is a thin wrapper over {@link LocalePriorityList} + {@link LocaleMatcher}.
+ *
* @param acceptLanguageList list in HTTP "Accept-Language:" format of acceptable locales
* @param availableLocales list of available locales. One of these will be returned.
* @param fallback if non-null, a 1-element array containing a boolean to be set with
* the fallback status
* @return one of the locales from the availableLocales list, or null if none match
* @stable ICU 3.4
+ * @see LocaleMatcher
+ * @see LocalePriorityList
*/
public static ULocale acceptLanguage(String acceptLanguageList, ULocale[] availableLocales,
boolean[] fallback) {
- if (acceptLanguageList == null) {
- throw new NullPointerException();
+ if (fallback != null) {
+ fallback[0] = true;
}
- ULocale acceptList[] = null;
+ LocalePriorityList desired;
try {
- acceptList = parseAcceptLanguage(acceptLanguageList, true);
- } catch (ParseException pe) {
- acceptList = null;
- }
- if (acceptList == null) {
+ desired = LocalePriorityList.add(acceptLanguageList).build();
+ } catch (IllegalArgumentException e) {
return null;
}
- return acceptLanguage(acceptList, availableLocales, fallback);
+ LocaleMatcher.Builder builder = LocaleMatcher.builder();
+ for (ULocale locale : availableLocales) {
+ builder.addSupportedULocale(locale);
+ }
+ LocaleMatcher matcher = builder.build();
+ LocaleMatcher.Result result = matcher.getBestMatchResult(desired);
+ if (result.getDesiredIndex() >= 0) {
+ if (fallback != null && result.getDesiredULocale().equals(result.getSupportedULocale())) {
+ fallback[0] = false;
+ }
+ return result.getSupportedULocale();
+ }
+ return null;
}
/**
* will be one of the locales in availableLocales, or the ROOT ULocale if if a ROOT
* locale was used as a fallback (because nothing else in availableLocales matched).
* No ULocale array element should be null; behavior is undefined if this is the case.
+ *
+ * <p>This is a thin wrapper over {@link LocaleMatcher}.
+ *
* @param acceptLanguageList list of acceptable locales
* @param availableLocales list of available locales. One of these will be returned.
* @param fallback if non-null, a 1-element array containing a boolean to be set with
* the fallback status
* @return one of the locales from the availableLocales list, or null if none match
* @stable ICU 3.4
+ * @see LocaleMatcher
*/
- public static ULocale acceptLanguage(ULocale[] acceptLanguageList, ULocale[]
- availableLocales, boolean[] fallback) {
- // fallbacklist
- int i,j;
- if(fallback != null) {
- fallback[0]=true;
+ public static ULocale acceptLanguage(ULocale[] acceptLanguageList, ULocale[] availableLocales,
+ boolean[] fallback) {
+ if (fallback != null) {
+ fallback[0] = true;
}
- for(i=0;i<acceptLanguageList.length;i++) {
- ULocale aLocale = acceptLanguageList[i];
- boolean[] setFallback = fallback;
- do {
- for(j=0;j<availableLocales.length;j++) {
- if(availableLocales[j].equals(aLocale)) {
- if(setFallback != null) {
- setFallback[0]=false; // first time with this locale - not a fallback.
- }
- return availableLocales[j];
- }
- // compare to scriptless alias, so locales such as
- // zh_TW, zh_CN are considered as available locales - see #7190
- if (aLocale.getScript().length() == 0
- && availableLocales[j].getScript().length() > 0
- && availableLocales[j].getLanguage().equals(aLocale.getLanguage())
- && availableLocales[j].getCountry().equals(aLocale.getCountry())
- && availableLocales[j].getVariant().equals(aLocale.getVariant())) {
- ULocale minAvail = ULocale.minimizeSubtags(availableLocales[j]);
- if (minAvail.getScript().length() == 0) {
- if(setFallback != null) {
- setFallback[0] = false; // not a fallback.
- }
- return aLocale;
- }
- }
- }
- Locale loc = aLocale.toLocale();
- Locale parent = LocaleUtility.fallback(loc);
- if(parent != null) {
- aLocale = new ULocale(parent);
- } else {
- aLocale = null;
- }
- setFallback = null; // Do not set fallback in later iterations
- } while (aLocale != null);
+ LocaleMatcher.Builder builder = LocaleMatcher.builder();
+ for (ULocale locale : availableLocales) {
+ builder.addSupportedULocale(locale);
+ }
+ LocaleMatcher matcher = builder.build();
+ LocaleMatcher.Result result;
+ if (acceptLanguageList.length == 1) {
+ result = matcher.getBestMatchResult(acceptLanguageList[0]);
+ } else {
+ result = matcher.getBestMatchResult(Arrays.asList(acceptLanguageList));
+ }
+ if (result.getDesiredIndex() >= 0) {
+ if (fallback != null && result.getDesiredULocale().equals(result.getSupportedULocale())) {
+ fallback[0] = false;
+ }
+ return result.getSupportedULocale();
}
return null;
}
* availableLocales matched). No ULocale array element should be null; behavior is
* undefined if this is the case. This function will choose a locale from the
* ULocale.getAvailableLocales() list as available.
+ *
+ * <p>This is a thin wrapper over {@link LocalePriorityList} + {@link LocaleMatcher}.
+ *
* @param acceptLanguageList list in HTTP "Accept-Language:" format of acceptable locales
* @param fallback if non-null, a 1-element array containing a boolean to be set with
* the fallback status
* @return one of the locales from the ULocale.getAvailableLocales() list, or null if
* none match
* @stable ICU 3.4
+ * @see LocaleMatcher
+ * @see LocalePriorityList
*/
public static ULocale acceptLanguage(String acceptLanguageList, boolean[] fallback) {
return acceptLanguage(acceptLanguageList, ULocale.getAvailableLocales(),
* availableLocales matched). No ULocale array element should be null; behavior is
* undefined if this is the case. This function will choose a locale from the
* ULocale.getAvailableLocales() list as available.
+ *
+ * <p>This is a thin wrapper over {@link LocaleMatcher}.
+ *
* @param acceptLanguageList ordered array of acceptable locales (preferred are listed first)
* @param fallback if non-null, a 1-element array containing a boolean to be set with
* the fallback status
* @return one of the locales from the ULocale.getAvailableLocales() list, or null if none match
* @stable ICU 3.4
+ * @see LocaleMatcher
*/
public static ULocale acceptLanguage(ULocale[] acceptLanguageList, boolean[] fallback) {
return acceptLanguage(acceptLanguageList, ULocale.getAvailableLocales(),
fallback);
}
- /**
- * Package local method used for parsing Accept-Language string
- */
- static ULocale[] parseAcceptLanguage(String acceptLanguage, boolean isLenient)
- throws ParseException {
- class ULocaleAcceptLanguageQ implements Comparable<ULocaleAcceptLanguageQ> {
- private double q;
- private double serial;
- public ULocaleAcceptLanguageQ(double theq, int theserial) {
- q = theq;
- serial = theserial;
- }
- @Override
- public int compareTo(ULocaleAcceptLanguageQ other) {
- if (q > other.q) { // reverse - to sort in descending order
- return -1;
- } else if (q < other.q) {
- return 1;
- }
- if (serial < other.serial) {
- return -1;
- } else if (serial > other.serial) {
- return 1;
- } else {
- return 0; // same object
- }
- }
- }
-
- // parse out the acceptLanguage into an array
- TreeMap<ULocaleAcceptLanguageQ, ULocale> map =
- new TreeMap<>();
- StringBuilder languageRangeBuf = new StringBuilder();
- StringBuilder qvalBuf = new StringBuilder();
- int state = 0;
- acceptLanguage += ","; // append comma to simplify the parsing code
- int n;
- boolean subTag = false;
- boolean q1 = false;
- for (n = 0; n < acceptLanguage.length(); n++) {
- boolean gotLanguageQ = false;
- char c = acceptLanguage.charAt(n);
- switch (state) {
- case 0: // before language-range start
- if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) {
- // in language-range
- languageRangeBuf.append(c);
- state = 1;
- subTag = false;
- } else if (c == '*') {
- languageRangeBuf.append(c);
- state = 2;
- } else if (c != ' ' && c != '\t') {
- // invalid character
- state = -1;
- }
- break;
- case 1: // in language-range
- if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) {
- languageRangeBuf.append(c);
- } else if (c == '-') {
- subTag = true;
- languageRangeBuf.append(c);
- } else if (c == '_') {
- if (isLenient) {
- subTag = true;
- languageRangeBuf.append(c);
- } else {
- state = -1;
- }
- } else if ('0' <= c && c <= '9') {
- if (subTag) {
- languageRangeBuf.append(c);
- } else {
- // DIGIT is allowed only in language sub tag
- state = -1;
- }
- } else if (c == ',') {
- // language-q end
- gotLanguageQ = true;
- } else if (c == ' ' || c == '\t') {
- // language-range end
- state = 3;
- } else if (c == ';') {
- // before q
- state = 4;
- } else {
- // invalid character for language-range
- state = -1;
- }
- break;
- case 2: // saw wild card range
- if (c == ',') {
- // language-q end
- gotLanguageQ = true;
- } else if (c == ' ' || c == '\t') {
- // language-range end
- state = 3;
- } else if (c == ';') {
- // before q
- state = 4;
- } else {
- // invalid
- state = -1;
- }
- break;
- case 3: // language-range end
- if (c == ',') {
- // language-q end
- gotLanguageQ = true;
- } else if (c == ';') {
- // before q
- state =4;
- } else if (c != ' ' && c != '\t') {
- // invalid
- state = -1;
- }
- break;
- case 4: // before q
- if (c == 'q') {
- // before equal
- state = 5;
- } else if (c != ' ' && c != '\t') {
- // invalid
- state = -1;
- }
- break;
- case 5: // before equal
- if (c == '=') {
- // before q value
- state = 6;
- } else if (c != ' ' && c != '\t') {
- // invalid
- state = -1;
- }
- break;
- case 6: // before q value
- if (c == '0') {
- // q value start with 0
- q1 = false;
- qvalBuf.append(c);
- state = 7;
- } else if (c == '1') {
- // q value start with 1
- qvalBuf.append(c);
- state = 7;
- } else if (c == '.') {
- if (isLenient) {
- qvalBuf.append(c);
- state = 8;
- } else {
- state = -1;
- }
- } else if (c != ' ' && c != '\t') {
- // invalid
- state = -1;
- }
- break;
- case 7: // q value start
- if (c == '.') {
- // before q value fraction part
- qvalBuf.append(c);
- state = 8;
- } else if (c == ',') {
- // language-q end
- gotLanguageQ = true;
- } else if (c == ' ' || c == '\t') {
- // after q value
- state = 10;
- } else {
- // invalid
- state = -1;
- }
- break;
- case 8: // before q value fraction part
- if ('0' <= c && c <= '9') {
- if (q1 && c != '0' && !isLenient) {
- // if q value starts with 1, the fraction part must be 0
- state = -1;
- } else {
- // in q value fraction part
- qvalBuf.append(c);
- state = 9;
- }
- } else {
- // invalid
- state = -1;
- }
- break;
- case 9: // in q value fraction part
- if ('0' <= c && c <= '9') {
- if (q1 && c != '0') {
- // if q value starts with 1, the fraction part must be 0
- state = -1;
- } else {
- qvalBuf.append(c);
- }
- } else if (c == ',') {
- // language-q end
- gotLanguageQ = true;
- } else if (c == ' ' || c == '\t') {
- // after q value
- state = 10;
- } else {
- // invalid
- state = -1;
- }
- break;
- case 10: // after q value
- if (c == ',') {
- // language-q end
- gotLanguageQ = true;
- } else if (c != ' ' && c != '\t') {
- // invalid
- state = -1;
- }
- break;
- }
- if (state == -1) {
- // error state
- throw new ParseException("Invalid Accept-Language", n);
- }
- if (gotLanguageQ) {
- double q = 1.0;
- if (qvalBuf.length() != 0) {
- try {
- q = Double.parseDouble(qvalBuf.toString());
- } catch (NumberFormatException nfe) {
- // Already validated, so it should never happen
- q = 1.0;
- }
- if (q > 1.0) {
- q = 1.0;
- }
- }
- if (languageRangeBuf.charAt(0) != '*') {
- int serial = map.size();
- ULocaleAcceptLanguageQ entry = new ULocaleAcceptLanguageQ(q, serial);
- // sort in reverse order.. 1.0, 0.9, 0.8 .. etc
- map.put(entry, new ULocale(canonicalize(languageRangeBuf.toString())));
- }
-
- // reset buffer and parse state
- languageRangeBuf.setLength(0);
- qvalBuf.setLength(0);
- state = 0;
- }
- }
- if (state != 0) {
- // Well, the parser should handle all cases. So just in case.
- throw new ParseException("Invalid AcceptlLanguage", n);
- }
-
- // pull out the map
- ULocale acceptList[] = map.values().toArray(new ULocale[map.size()]);
- return acceptList;
- }
-
private static final String UNDEFINED_LANGUAGE = "und";
private static final String UNDEFINED_SCRIPT = "Zzzz";
private static final String UNDEFINED_REGION = "ZZ";
List<String>subtags = tag.getVariants();
// ICU-20478: Sort variants per UTS35.
- ArrayList<String> variants = new ArrayList<String>(subtags);
+ ArrayList<String> variants = new ArrayList<>(subtags);
Collections.sort(variants);
for (String s : variants) {
buf.append(LanguageTag.SEP);
{"fr_CA", "fr"},
{"fr", "fr_CA"},
{"es", "fr", "en_US"},
- {"zh_Hans", "zh_Hans_CN"},
+ {"zh_CN", "zh_Hans", "zh_Hans_CN"},
{"en_US_123"},
{"es_US", "es"},
{"de_DE", "es", "fr_FR"},
{"fr_CA", "fr"},
{"fr_CA", "fr"},
{"es", "fr", "en_US", "en"},
- {"zh_Hans_CN", "zh_Hans", "zh"},
+ {"zh_Hans_CN", "zh_CN", "zh_Hans", "zh"},
{"en_US_123", "en_US", "en"},
{"es_US", "es"},
{"de_DE", "de", "es", "fr_FR", "fr"},
gp.setLocales(acceptLanguage);
List<ULocale> resultLocales = gp.getLocales();
+ List<ULocale> expectedLocales = new ArrayList<>(RESULTS_LOCALEIDS[i].length);
+ for (String exp : RESULTS_LOCALEIDS[i]) {
+ expectedLocales.add(new ULocale(exp));
+ }
+ assertEquals("#" + i, expectedLocales.toString(), resultLocales.toString());
if (resultLocales.size() != RESULTS_LOCALEIDS[i].length) {
StringBuilder res = new StringBuilder();
for (ULocale l : resultLocales) {
}
// Invalid accept-language
- logln("Set locale - ko_KR");
- gp.setLocale(new ULocale("ko_KR"));
- boolean bException = false;
- try {
- logln("Set invlaid accept-language - ko=100");
- gp.setLocales("ko=100");
- } catch (IllegalArgumentException iae) {
- logln("IllegalArgumentException was thrown");
- bException = true;
- }
- if (!bException) {
- errln("FAIL: IllegalArgumentException was not thrown for illegal accept-language - ko=100");
- }
- if (!gp.getLocale(0).toString().equals("ko_KR")) {
- errln("FAIL: Previous valid locale list had gone");
- }
+ // ICU-20700 changed the parser to using LocalePriorityList which is more lenient.
+// logln("Set locale - ko_KR");
+// gp.setLocale(new ULocale("ko_KR"));
+// boolean bException = false;
+// try {
+// logln("Set invlaid accept-language - ko=100");
+// gp.setLocales("ko=100");
+// } catch (IllegalArgumentException iae) {
+// logln("IllegalArgumentException was thrown");
+// bException = true;
+// }
+// if (!bException) {
+// errln("FAIL: IllegalArgumentException was not thrown for illegal accept-language - ko=100");
+// }
+// if (!gp.getLocale(0).toString().equals("ko_KR")) {
+// errln("FAIL: Previous valid locale list had gone");
+// }
}
@Test
import java.util.Locale;
import java.util.Map;
import java.util.Set;
-import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Pattern;
import com.ibm.icu.dev.test.TestFmwk;
import com.ibm.icu.dev.test.TestUtil;
import com.ibm.icu.dev.test.TestUtil.JavaVendor;
-import com.ibm.icu.lang.UCharacter;
import com.ibm.icu.text.DateFormat;
import com.ibm.icu.text.DecimalFormat;
import com.ibm.icu.text.DisplayContext;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.IllformedLocaleException;
import com.ibm.icu.util.LocaleData;
+import com.ibm.icu.util.LocalePriorityList;
import com.ibm.icu.util.ULocale;
import com.ibm.icu.util.ULocale.Builder;
import com.ibm.icu.util.ULocale.Category;
/*3*/ { null, "true" },
/*4*/ { "es", "false" },
/*5*/ { "de", "false" },
- /*6*/ { "zh_Hant_TW", "false" },
- /*7*/ { "zh", "true" },
+ /*6*/ { "zh_Hant_TW", "true" },
+ /*7*/ { "zh_Hant", "true" },
};
private static final String ACCEPT_LANGUAGE_HTTP[] = {
/*0*/ "mt-mt, ja;q=0.76, en-us;q=0.95, en;q=0.92, en-gb;q=0.89, fr;q=0.87, iu-ca;q=0.84, iu;q=0.82, ja-jp;q=0.79, mt;q=0.97, de-de;q=0.74, de;q=0.71, es;q=0.68, it-it;q=0.66, it;q=0.63, vi-vn;q=0.61, vi;q=0.58, nl-nl;q=0.55, nl;q=0.53, th-th-traditional;q=.01",
/*1*/ "ja;q=0.5, en;q=0.8, tlh",
/*2*/ "en-zzz, de-lx;q=0.8",
- /*3*/ "mga-ie;q=0.9, tlh",
+ /*3*/ "mga-ie;q=0.9, sux",
/*4*/ "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "+
"xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "+
"xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "+
"xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "+
"xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "+
"es",
- /*5*/ "de;q=.9, fr;q=.9, xxx-yyy, sr;q=.8",
- /*6*/ "zh-tw",
- /*7*/ "zh-hant-cn",
+ /*5*/ "de;q=.9, fr;q=.9, xxx-yyy, sr;q=.8",
+ /*6*/ "zh-tw",
+ /*7*/ "zh-hant-cn",
};
@Test
public void TestAcceptLanguage() {
for(int i = 0 ; i < (ACCEPT_LANGUAGE_HTTP.length); i++) {
- Boolean expectBoolean = new Boolean(ACCEPT_LANGUAGE_TESTS[i][1]);
+ Boolean expectBoolean = Boolean.valueOf(ACCEPT_LANGUAGE_TESTS[i][1]);
String expectLocale=ACCEPT_LANGUAGE_TESTS[i][0];
logln("#" + i + ": expecting: " + expectLocale + " (" + expectBoolean + ")");
boolean r[] = { false };
ULocale n = ULocale.acceptLanguage(ACCEPT_LANGUAGE_HTTP[i], r);
if((n==null)&&(expectLocale!=null)) {
- errln("result was null! line #" + i);
+ errln("#" + i + ": result was null!");
continue;
}
if(((n==null)&&(expectLocale==null)) || (n.toString().equals(expectLocale))) {
- logln(" locale: OK." );
+ logln("#" + i + ": locale: OK." );
} else {
- errln("expected " + expectLocale + " but got " + n.toString());
+ errln("#" + i + ": locale: expected " + expectLocale + " but got " + n);
}
- if(expectBoolean.equals(new Boolean(r[0]))) {
- logln(" bool: OK.");
+ Boolean actualBoolean = Boolean.valueOf(r[0]);
+ if(expectBoolean.equals(actualBoolean)) {
+ logln("#" + i + ": fallback: OK.");
} else {
- errln("bool: not OK, was " + new Boolean(r[0]).toString() + " expected " + expectBoolean.toString());
+ errln("#" + i + ": fallback: was " + actualBoolean + " expected " + expectBoolean);
}
}
}
- private ULocale[] StringToULocaleArray(String acceptLanguageList){
- //following code is copied from
- //ULocale.acceptLanguage(String acceptLanguageList, ULocale[] availableLocales, boolean[] fallback)
- class ULocaleAcceptLanguageQ implements Comparable {
- private double q;
- private double serial;
- public ULocaleAcceptLanguageQ(double theq, int theserial) {
- q = theq;
- serial = theserial;
- }
- @Override
- public int compareTo(Object o) {
- ULocaleAcceptLanguageQ other = (ULocaleAcceptLanguageQ) o;
- if(q > other.q) { // reverse - to sort in descending order
- return -1;
- } else if(q < other.q) {
- return 1;
- }
- if(serial < other.serial) {
- return -1;
- } else if(serial > other.serial) {
- return 1;
- } else {
- return 0; // same object
- }
- }
- }
-
- // 1st: parse out the acceptLanguageList into an array
-
- TreeMap map = new TreeMap();
-
- final int l = acceptLanguageList.length();
- int n;
- for(n=0;n<l;n++) {
- int itemEnd = acceptLanguageList.indexOf(',',n);
- if(itemEnd == -1) {
- itemEnd = l;
- }
- int paramEnd = acceptLanguageList.indexOf(';',n);
- double q = 1.0;
-
- if((paramEnd != -1) && (paramEnd < itemEnd)) {
- /* semicolon (;) is closer than end (,) */
- int t = paramEnd + 1;
- while(UCharacter.isWhitespace(acceptLanguageList.charAt(t))) {
- t++;
- }
- if(acceptLanguageList.charAt(t)=='q') {
- t++;
- }
- while(UCharacter.isWhitespace(acceptLanguageList.charAt(t))) {
- t++;
- }
- if(acceptLanguageList.charAt(t)=='=') {
- t++;
- }
- while(UCharacter.isWhitespace(acceptLanguageList.charAt(t))) {
- t++;
- }
- try {
- String val = acceptLanguageList.substring(t,itemEnd).trim();
- q = Double.parseDouble(val);
- } catch (NumberFormatException nfe) {
- q = 1.0;
- }
- } else {
- q = 1.0; //default
- paramEnd = itemEnd;
- }
-
- String loc = acceptLanguageList.substring(n,paramEnd).trim();
- int serial = map.size();
- ULocaleAcceptLanguageQ entry = new ULocaleAcceptLanguageQ(q,serial);
- map.put(entry, new ULocale(ULocale.canonicalize(loc))); // sort in reverse order.. 1.0, 0.9, 0.8 .. etc
- n = itemEnd; // get next item. (n++ will skip over delimiter)
- }
-
- // 2. pull out the map
- ULocale acceptList[] = (ULocale[])map.values().toArray(new ULocale[map.size()]);
- return acceptList;
- }
-
@Test
public void TestAcceptLanguage2() {
for(int i = 0 ; i < (ACCEPT_LANGUAGE_HTTP.length); i++) {
- Boolean expectBoolean = new Boolean(ACCEPT_LANGUAGE_TESTS[i][1]);
+ Boolean expectBoolean = Boolean.valueOf(ACCEPT_LANGUAGE_TESTS[i][1]);
String expectLocale=ACCEPT_LANGUAGE_TESTS[i][0];
logln("#" + i + ": expecting: " + expectLocale + " (" + expectBoolean + ")");
boolean r[] = { false };
- ULocale n = ULocale.acceptLanguage(StringToULocaleArray(ACCEPT_LANGUAGE_HTTP[i]), r);
+ Set<ULocale> desiredSet =
+ LocalePriorityList.add(ACCEPT_LANGUAGE_HTTP[i]).build().getULocales();
+ ULocale[] desiredArray = desiredSet.toArray(new ULocale[desiredSet.size()]);
+ ULocale n = ULocale.acceptLanguage(desiredArray, r);
if((n==null)&&(expectLocale!=null)) {
- errln("result was null! line #" + i);
+ errln("#" + i + ": result was null!");
continue;
}
if(((n==null)&&(expectLocale==null)) || (n.toString().equals(expectLocale))) {
- logln(" locale: OK." );
+ logln("#" + i + ": locale: OK.");
} else {
- errln("expected " + expectLocale + " but got " + n.toString());
+ errln("#" + i + ": expected " + expectLocale + " but got " + n.toString());
}
- if(expectBoolean.equals(new Boolean(r[0]))) {
- logln(" bool: OK.");
+ Boolean actualBoolean = Boolean.valueOf(r[0]);
+ if(expectBoolean.equals(actualBoolean)) {
+ logln("#" + i + ": fallback: OK.");
} else {
- errln("bool: not OK, was " + new Boolean(r[0]).toString() + " expected " + expectBoolean.toString());
+ errln("#" + i + ": fallback: was " + actualBoolean + " expected " + expectBoolean);
}
}
}