Merge "Make default resources a better match for en-US requests"
This commit is contained in:
committed by
Android (Google) Code Review
commit
ed553f6b0d
@@ -29,6 +29,8 @@ int localeDataCompareRegions(
|
||||
|
||||
void localeDataComputeScript(char out[4], const char* language, const char* region);
|
||||
|
||||
bool localeDataIsCloseToUsEnglish(const char* region);
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _LIBS_UTILS_LOCALE_DATA_H
|
||||
|
||||
@@ -70,13 +70,17 @@ uint32_t findParent(uint32_t packed_locale, const char* script) {
|
||||
//
|
||||
// Returns the number of ancestors written in the output, which is always
|
||||
// at least one.
|
||||
//
|
||||
// (If 'out' is nullptr, we do everything the same way but we simply don't write
|
||||
// any results in 'out'.)
|
||||
size_t findAncestors(uint32_t* out, ssize_t* stop_list_index,
|
||||
uint32_t packed_locale, const char* script,
|
||||
const uint32_t* stop_list, size_t stop_set_length) {
|
||||
uint32_t ancestor = packed_locale;
|
||||
size_t count = 0;
|
||||
do {
|
||||
out[count++] = ancestor;
|
||||
if (out != nullptr) out[count] = ancestor;
|
||||
count++;
|
||||
for (size_t i = 0; i < stop_set_length; i++) {
|
||||
if (stop_list[i] == ancestor) {
|
||||
*stop_list_index = (ssize_t) i;
|
||||
@@ -93,10 +97,9 @@ size_t findDistance(uint32_t supported,
|
||||
const char* script,
|
||||
const uint32_t* request_ancestors,
|
||||
size_t request_ancestors_count) {
|
||||
uint32_t supported_ancestors[MAX_PARENT_DEPTH+1];
|
||||
ssize_t request_ancestors_index;
|
||||
const size_t supported_ancestor_count = findAncestors(
|
||||
supported_ancestors, &request_ancestors_index,
|
||||
nullptr, &request_ancestors_index,
|
||||
supported, script,
|
||||
request_ancestors, request_ancestors_count);
|
||||
// Since both locales share the same root, there will always be a shared
|
||||
@@ -198,4 +201,19 @@ void localeDataComputeScript(char out[4], const char* language, const char* regi
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t ENGLISH_STOP_LIST[2] = {
|
||||
0x656E0000lu, // en
|
||||
0x656E8400lu, // en-001
|
||||
};
|
||||
const char ENGLISH_CHARS[2] = {'e', 'n'};
|
||||
const char LATIN_CHARS[4] = {'L', 'a', 't', 'n'};
|
||||
|
||||
bool localeDataIsCloseToUsEnglish(const char* region) {
|
||||
const uint32_t locale = packLocale(ENGLISH_CHARS, region);
|
||||
ssize_t stop_list_index;
|
||||
findAncestors(nullptr, &stop_list_index, locale, LATIN_CHARS, ENGLISH_STOP_LIST, 2);
|
||||
// A locale is like US English if we see "en" before "en-001" in its ancestor list.
|
||||
return stop_list_index == 0; // 'en' is first in ENGLISH_STOP_LIST
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
||||
@@ -2196,7 +2196,32 @@ bool ResTable_config::isLocaleBetterThan(const ResTable_config& o,
|
||||
// The languages of the two resources are not the same. We can only
|
||||
// assume that one of the two resources matched the request because one
|
||||
// doesn't have a language and the other has a matching language.
|
||||
return (language[0] != 0);
|
||||
//
|
||||
// We consider the one that has the language specified a better match.
|
||||
//
|
||||
// The exception is that we consider no-language resources a better match
|
||||
// for US English and similar locales than locales that are a descendant
|
||||
// of Internatinal English (en-001), since no-language resources are
|
||||
// where the US English resource have traditionally lived for most apps.
|
||||
if (requested->language[0] == 'e' && requested->language[1] == 'n') {
|
||||
if (requested->country[0] == 'U' && requested->country[1] == 'S') {
|
||||
// For US English itself, we consider a no-locale resource a
|
||||
// better match if the other resource has a country other than
|
||||
// US specified.
|
||||
if (language[0] != '\0') {
|
||||
return country[0] == '\0' || (country[0] == 'U' && country[1] == 'S');
|
||||
} else {
|
||||
return !(o.country[0] == '\0' || (o.country[0] == 'U' && o.country[1] == 'S'));
|
||||
}
|
||||
} else if (localeDataIsCloseToUsEnglish(requested->country)) {
|
||||
if (language[0] != '\0') {
|
||||
return localeDataIsCloseToUsEnglish(country);
|
||||
} else {
|
||||
return !localeDataIsCloseToUsEnglish(o.country);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (language[0] != '\0');
|
||||
}
|
||||
|
||||
// If we are here, both the resources have the same non-empty language as
|
||||
|
||||
@@ -592,4 +592,52 @@ TEST(ConfigLocaleTest, isLocaleBetterThan_regionComparison) {
|
||||
EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
|
||||
}
|
||||
|
||||
// Default resources are considered better matches for US English
|
||||
// and US-like English locales than International English locales
|
||||
TEST(ConfigLocaleTest, isLocaleBetterThan_UsEnglishIsSpecial) {
|
||||
ResTable_config config1, config2, request;
|
||||
|
||||
fillIn("en", "US", NULL, NULL, &request);
|
||||
fillIn(NULL, NULL, NULL, NULL, &config1);
|
||||
fillIn("en", "001", NULL, NULL, &config2);
|
||||
// default is better than International English
|
||||
EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
|
||||
EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
|
||||
|
||||
fillIn("en", "US", NULL, NULL, &request);
|
||||
fillIn(NULL, NULL, NULL, NULL, &config1);
|
||||
fillIn("en", "GB", NULL, NULL, &config2);
|
||||
// default is better than British English
|
||||
EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
|
||||
EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
|
||||
|
||||
fillIn("en", "PR", NULL, NULL, &request);
|
||||
fillIn(NULL, NULL, NULL, NULL, &config1);
|
||||
fillIn("en", "001", NULL, NULL, &config2);
|
||||
// Even for Puerto Rico, default is better than International English
|
||||
EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
|
||||
EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
|
||||
|
||||
fillIn("en", "US", NULL, NULL, &request);
|
||||
fillIn("en", NULL, NULL, NULL, &config1);
|
||||
fillIn(NULL, NULL, NULL, NULL, &config2);
|
||||
// "English" is better than default, since it's a parent of US English
|
||||
EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
|
||||
EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
|
||||
|
||||
fillIn("en", "PR", NULL, NULL, &request);
|
||||
fillIn("en", NULL, NULL, NULL, &config1);
|
||||
fillIn(NULL, NULL, NULL, NULL, &config2);
|
||||
// "English" is better than default, since it's a parent of Puerto Rico English
|
||||
EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
|
||||
EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
|
||||
|
||||
fillIn("en", "US", NULL, NULL, &request);
|
||||
fillIn(NULL, NULL, NULL, NULL, &config1);
|
||||
fillIn("en", "PR", NULL, NULL, &config2);
|
||||
// For US English itself, we prefer default to its siblings in the parent tree
|
||||
EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
|
||||
EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
||||
Reference in New Issue
Block a user