Loading libs/androidfw/LocaleData.cpp +27 −4 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ * limitations under the License. */ #include <array> #include <cstdint> #include <cstdlib> #include <cstring> Loading Loading @@ -121,6 +122,16 @@ inline bool isRepresentative(uint32_t language_and_region, const char* script) { return (REPRESENTATIVE_LOCALES.count(packed_locale) != 0); } const uint32_t US_SPANISH = 0x65735553lu; // es-US const uint32_t MEXICAN_SPANISH = 0x65734D58lu; // es-MX const uint32_t LATIN_AMERICAN_SPANISH = 0x6573A424lu; // es-419 // The two locales es-US and es-MX are treated as special fallbacks for es-419. // If there is no es-419, they are considered its equivalent. inline bool isSpecialSpanish(uint32_t language_and_region) { return (language_and_region == US_SPANISH || language_and_region == MEXICAN_SPANISH); } int localeDataCompareRegions( const char* left_region, const char* right_region, const char* requested_language, const char* requested_script, Loading @@ -129,18 +140,30 @@ int localeDataCompareRegions( if (left_region[0] == right_region[0] && left_region[1] == right_region[1]) { return 0; } const uint32_t left = packLocale(requested_language, left_region); const uint32_t right = packLocale(requested_language, right_region); uint32_t left = packLocale(requested_language, left_region); uint32_t right = packLocale(requested_language, right_region); const uint32_t request = packLocale(requested_language, requested_region); // If one and only one of the two locales is a special Spanish locale, we // replace it with es-419. We don't do the replacement if the other locale // is already es-419, or both locales are special Spanish locales (when // es-US is being compared to es-MX). const bool leftIsSpecialSpanish = isSpecialSpanish(left); const bool rightIsSpecialSpanish = isSpecialSpanish(right); if (leftIsSpecialSpanish && !rightIsSpecialSpanish && right != LATIN_AMERICAN_SPANISH) { left = LATIN_AMERICAN_SPANISH; } else if (rightIsSpecialSpanish && !leftIsSpecialSpanish && left != LATIN_AMERICAN_SPANISH) { right = LATIN_AMERICAN_SPANISH; } uint32_t request_ancestors[MAX_PARENT_DEPTH+1]; ssize_t left_right_index; // Find the parents of the request, but stop as soon as we saw left or right const uint32_t left_and_right[] = {left, right}; const std::array<uint32_t, 2> left_and_right = {{left, right}}; const size_t ancestor_count = findAncestors( request_ancestors, &left_right_index, request, requested_script, left_and_right, sizeof(left_and_right)/sizeof(left_and_right[0])); left_and_right.data(), left_and_right.size()); if (left_right_index == 0) { // We saw left earlier return 1; } Loading libs/androidfw/tests/ConfigLocale_test.cpp +66 −1 Original line number Diff line number Diff line Loading @@ -469,16 +469,81 @@ TEST(ConfigLocaleTest, isLocaleBetterThan_regionComparison) { EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "AR", NULL, NULL, &request); fillIn("es", "US", NULL, NULL, &config1); fillIn("es", NULL, NULL, NULL, &config2); // Special case for Latin American Spanish: es-MX and es-US are // pseudo-parents of all Latin Ameircan Spanish locales. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "MX", NULL, NULL, &request); fillIn("es", "US", NULL, NULL, &config1); fillIn("es", NULL, NULL, NULL, &config2); // Special case for Latin American Spanish: es-MX and es-US are // pseudo-parents of all Latin Ameircan Spanish locales. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "AR", NULL, NULL, &request); fillIn("es", "MX", NULL, NULL, &config1); fillIn("es", NULL, NULL, NULL, &config2); // Special case for Latin American Spanish: es-MX and es-US are // pseudo-parents of all Latin Ameircan Spanish locales. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "US", NULL, NULL, &request); fillIn("es", "MX", NULL, NULL, &config1); fillIn("es", NULL, NULL, NULL, &config2); // Special case for Latin American Spanish: es-MX and es-US are // pseudo-parents of all Latin Ameircan Spanish locales. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "AR", NULL, NULL, &request); fillIn("es", "419", NULL, NULL, &config1); fillIn("es", "MX", NULL, NULL, &config2); // Even though es-MX and es-US are pseudo-parents of all Latin Ameircan // Spanish locales, es-419 is a closer parent. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "US", NULL, NULL, &request); fillIn("es", "419", NULL, NULL, &config1); fillIn("es", "MX", NULL, NULL, &config2); // Even though es-MX and es-US are pseudo-parents of all Latin Ameircan // Spanish locales, es-419 is a closer parent. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "MX", NULL, NULL, &request); fillIn("es", "419", NULL, NULL, &config1); fillIn("es", "US", NULL, NULL, &config2); // Even though es-MX and es-US are pseudo-parents of all Latin Ameircan // Spanish locales, es-419 is a closer parent. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "AR", NULL, NULL, &request); fillIn("es", "MX", NULL, NULL, &config1); fillIn("es", "BO", NULL, NULL, &config2); // A representative locale is better if they are equidistant. // Special case for Latin American Spanish: es-MX and es-US are // pseudo-parents of all Latin Ameircan Spanish locales. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "AR", NULL, NULL, &request); fillIn("es", "US", NULL, NULL, &config1); fillIn("es", "BO", NULL, NULL, &config2); // Special case for Latin American Spanish: es-MX and es-US are // pseudo-parents of all Latin Ameircan Spanish locales. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "IC", NULL, NULL, &request); fillIn("es", "ES", NULL, NULL, &config1); fillIn("es", "GQ", NULL, NULL, &config2); // A representative locale is better if they are equidistant. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); Loading Loading
libs/androidfw/LocaleData.cpp +27 −4 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ * limitations under the License. */ #include <array> #include <cstdint> #include <cstdlib> #include <cstring> Loading Loading @@ -121,6 +122,16 @@ inline bool isRepresentative(uint32_t language_and_region, const char* script) { return (REPRESENTATIVE_LOCALES.count(packed_locale) != 0); } const uint32_t US_SPANISH = 0x65735553lu; // es-US const uint32_t MEXICAN_SPANISH = 0x65734D58lu; // es-MX const uint32_t LATIN_AMERICAN_SPANISH = 0x6573A424lu; // es-419 // The two locales es-US and es-MX are treated as special fallbacks for es-419. // If there is no es-419, they are considered its equivalent. inline bool isSpecialSpanish(uint32_t language_and_region) { return (language_and_region == US_SPANISH || language_and_region == MEXICAN_SPANISH); } int localeDataCompareRegions( const char* left_region, const char* right_region, const char* requested_language, const char* requested_script, Loading @@ -129,18 +140,30 @@ int localeDataCompareRegions( if (left_region[0] == right_region[0] && left_region[1] == right_region[1]) { return 0; } const uint32_t left = packLocale(requested_language, left_region); const uint32_t right = packLocale(requested_language, right_region); uint32_t left = packLocale(requested_language, left_region); uint32_t right = packLocale(requested_language, right_region); const uint32_t request = packLocale(requested_language, requested_region); // If one and only one of the two locales is a special Spanish locale, we // replace it with es-419. We don't do the replacement if the other locale // is already es-419, or both locales are special Spanish locales (when // es-US is being compared to es-MX). const bool leftIsSpecialSpanish = isSpecialSpanish(left); const bool rightIsSpecialSpanish = isSpecialSpanish(right); if (leftIsSpecialSpanish && !rightIsSpecialSpanish && right != LATIN_AMERICAN_SPANISH) { left = LATIN_AMERICAN_SPANISH; } else if (rightIsSpecialSpanish && !leftIsSpecialSpanish && left != LATIN_AMERICAN_SPANISH) { right = LATIN_AMERICAN_SPANISH; } uint32_t request_ancestors[MAX_PARENT_DEPTH+1]; ssize_t left_right_index; // Find the parents of the request, but stop as soon as we saw left or right const uint32_t left_and_right[] = {left, right}; const std::array<uint32_t, 2> left_and_right = {{left, right}}; const size_t ancestor_count = findAncestors( request_ancestors, &left_right_index, request, requested_script, left_and_right, sizeof(left_and_right)/sizeof(left_and_right[0])); left_and_right.data(), left_and_right.size()); if (left_right_index == 0) { // We saw left earlier return 1; } Loading
libs/androidfw/tests/ConfigLocale_test.cpp +66 −1 Original line number Diff line number Diff line Loading @@ -469,16 +469,81 @@ TEST(ConfigLocaleTest, isLocaleBetterThan_regionComparison) { EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "AR", NULL, NULL, &request); fillIn("es", "US", NULL, NULL, &config1); fillIn("es", NULL, NULL, NULL, &config2); // Special case for Latin American Spanish: es-MX and es-US are // pseudo-parents of all Latin Ameircan Spanish locales. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "MX", NULL, NULL, &request); fillIn("es", "US", NULL, NULL, &config1); fillIn("es", NULL, NULL, NULL, &config2); // Special case for Latin American Spanish: es-MX and es-US are // pseudo-parents of all Latin Ameircan Spanish locales. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "AR", NULL, NULL, &request); fillIn("es", "MX", NULL, NULL, &config1); fillIn("es", NULL, NULL, NULL, &config2); // Special case for Latin American Spanish: es-MX and es-US are // pseudo-parents of all Latin Ameircan Spanish locales. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "US", NULL, NULL, &request); fillIn("es", "MX", NULL, NULL, &config1); fillIn("es", NULL, NULL, NULL, &config2); // Special case for Latin American Spanish: es-MX and es-US are // pseudo-parents of all Latin Ameircan Spanish locales. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "AR", NULL, NULL, &request); fillIn("es", "419", NULL, NULL, &config1); fillIn("es", "MX", NULL, NULL, &config2); // Even though es-MX and es-US are pseudo-parents of all Latin Ameircan // Spanish locales, es-419 is a closer parent. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "US", NULL, NULL, &request); fillIn("es", "419", NULL, NULL, &config1); fillIn("es", "MX", NULL, NULL, &config2); // Even though es-MX and es-US are pseudo-parents of all Latin Ameircan // Spanish locales, es-419 is a closer parent. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "MX", NULL, NULL, &request); fillIn("es", "419", NULL, NULL, &config1); fillIn("es", "US", NULL, NULL, &config2); // Even though es-MX and es-US are pseudo-parents of all Latin Ameircan // Spanish locales, es-419 is a closer parent. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "AR", NULL, NULL, &request); fillIn("es", "MX", NULL, NULL, &config1); fillIn("es", "BO", NULL, NULL, &config2); // A representative locale is better if they are equidistant. // Special case for Latin American Spanish: es-MX and es-US are // pseudo-parents of all Latin Ameircan Spanish locales. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "AR", NULL, NULL, &request); fillIn("es", "US", NULL, NULL, &config1); fillIn("es", "BO", NULL, NULL, &config2); // Special case for Latin American Spanish: es-MX and es-US are // pseudo-parents of all Latin Ameircan Spanish locales. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); fillIn("es", "IC", NULL, NULL, &request); fillIn("es", "ES", NULL, NULL, &config1); fillIn("es", "GQ", NULL, NULL, &config2); // A representative locale is better if they are equidistant. EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request)); EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request)); Loading