1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "build/build_config.h" 6 7 #if defined(OS_POSIX) && !defined(OS_MACOSX) 8 #include <cstdlib> 9 #endif 10 11 #include "base/basictypes.h" 12 #include "base/environment.h" 13 #include "base/file_util.h" 14 #include "base/i18n/case_conversion.h" 15 #include "base/i18n/rtl.h" 16 #include "base/path_service.h" 17 #include "base/stl_util.h" 18 #include "base/strings/string_util.h" 19 #include "base/strings/utf_string_conversions.h" 20 #include "base/test/scoped_path_override.h" 21 #include "testing/gtest/include/gtest/gtest.h" 22 #include "testing/platform_test.h" 23 #include "third_party/icu/source/common/unicode/locid.h" 24 #include "ui/base/l10n/l10n_util.h" 25 #include "ui/base/l10n/l10n_util_collator.h" 26 #include "ui/base/ui_base_paths.h" 27 28 #if defined(OS_WIN) 29 #include "base/win/windows_version.h" 30 #endif 31 32 #if !defined(OS_MACOSX) 33 #include "ui/base/test/data/resource.h" 34 #endif 35 36 namespace { 37 38 class StringWrapper { 39 public: 40 explicit StringWrapper(const string16& string) : string_(string) {} 41 const string16& string() const { return string_; } 42 43 private: 44 string16 string_; 45 46 DISALLOW_COPY_AND_ASSIGN(StringWrapper); 47 }; 48 49 } // namespace 50 51 class L10nUtilTest : public PlatformTest { 52 }; 53 54 #if defined(OS_WIN) 55 // TODO(beng): disabled until app strings move to app. 56 TEST_F(L10nUtilTest, DISABLED_GetString) { 57 std::string s = l10n_util::GetStringUTF8(IDS_SIMPLE); 58 EXPECT_EQ(std::string("Hello World!"), s); 59 60 s = l10n_util::GetStringFUTF8(IDS_PLACEHOLDERS, 61 UTF8ToUTF16("chrome"), 62 UTF8ToUTF16("10")); 63 EXPECT_EQ(std::string("Hello, chrome. Your number is 10."), s); 64 65 string16 s16 = l10n_util::GetStringFUTF16Int(IDS_PLACEHOLDERS_2, 20); 66 EXPECT_EQ(UTF8ToUTF16("You owe me $20."), s16); 67 } 68 #endif // defined(OS_WIN) 69 70 #if !defined(OS_MACOSX) && !defined(OS_ANDROID) 71 // On Mac, we are disabling this test because GetApplicationLocale() as an 72 // API isn't something that we'll easily be able to unit test in this manner. 73 // The meaning of that API, on the Mac, is "the locale used by Cocoa's main 74 // nib file", which clearly can't be stubbed by a test app that doesn't use 75 // Cocoa. 76 77 // On Android, we are disabling this test since GetApplicationLocale() just 78 // returns the system's locale, which, similarly, is not easily unit tested. 79 80 #if defined(OS_POSIX) && defined(USE_GLIB) && !defined(OS_CHROMEOS) 81 const bool kPlatformHasDefaultLocale = 1; 82 const bool kUseLocaleFromEnvironment = 1; 83 const bool kSupportsLocalePreference = 0; 84 #elif defined(OS_WIN) 85 const bool kPlatformHasDefaultLocale = 1; 86 const bool kUseLocaleFromEnvironment = 0; 87 const bool kSupportsLocalePreference = 1; 88 #else 89 const bool kPlatformHasDefaultLocale = 0; 90 const bool kUseLocaleFromEnvironment = 0; 91 const bool kSupportsLocalePreference = 1; 92 #endif 93 94 void SetDefaultLocaleForTest(const std::string& tag, base::Environment* env) { 95 if (kUseLocaleFromEnvironment) 96 env->SetVar("LANGUAGE", tag); 97 else 98 base::i18n::SetICUDefaultLocale(tag); 99 } 100 101 TEST_F(L10nUtilTest, GetAppLocale) { 102 scoped_ptr<base::Environment> env; 103 // Use a temporary locale dir so we don't have to actually build the locale 104 // pak files for this test. 105 base::ScopedPathOverride locale_dir_override(ui::DIR_LOCALES); 106 base::FilePath new_locale_dir; 107 ASSERT_TRUE(PathService::Get(ui::DIR_LOCALES, &new_locale_dir)); 108 // Make fake locale files. 109 std::string filenames[] = { 110 "en-US", 111 "en-GB", 112 "fr", 113 "es-419", 114 "es", 115 "zh-TW", 116 "zh-CN", 117 "he", 118 "fil", 119 "nb", 120 "am", 121 "ca", 122 "ca@valencia", 123 }; 124 125 for (size_t i = 0; i < arraysize(filenames); ++i) { 126 base::FilePath filename = new_locale_dir.AppendASCII( 127 filenames[i] + ".pak"); 128 file_util::WriteFile(filename, "", 0); 129 } 130 131 // Keep a copy of ICU's default locale before we overwrite it. 132 const std::string original_locale = base::i18n::GetConfiguredLocale(); 133 134 if (kPlatformHasDefaultLocale && kUseLocaleFromEnvironment) { 135 env.reset(base::Environment::Create()); 136 137 // Test the support of LANGUAGE environment variable. 138 base::i18n::SetICUDefaultLocale("en-US"); 139 env->SetVar("LANGUAGE", "xx:fr_CA"); 140 EXPECT_EQ("fr", l10n_util::GetApplicationLocale(std::string())); 141 142 env->SetVar("LANGUAGE", "xx:yy:en_gb.utf-8@quot"); 143 EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale(std::string())); 144 145 env->SetVar("LANGUAGE", "xx:zh-hk"); 146 EXPECT_EQ("zh-TW", l10n_util::GetApplicationLocale(std::string())); 147 148 // We emulate gettext's behavior here, which ignores LANG/LC_MESSAGES/LC_ALL 149 // when LANGUAGE is specified. If no language specified in LANGUAGE is 150 // valid, 151 // then just fallback to the default language, which is en-US for us. 152 base::i18n::SetICUDefaultLocale("fr-FR"); 153 env->SetVar("LANGUAGE", "xx:yy"); 154 EXPECT_EQ("en-US", l10n_util::GetApplicationLocale(std::string())); 155 156 env->SetVar("LANGUAGE", "/fr:zh_CN"); 157 EXPECT_EQ("zh-CN", l10n_util::GetApplicationLocale(std::string())); 158 159 // Test prioritization of the different environment variables. 160 env->SetVar("LANGUAGE", "fr"); 161 env->SetVar("LC_ALL", "es"); 162 env->SetVar("LC_MESSAGES", "he"); 163 env->SetVar("LANG", "nb"); 164 EXPECT_EQ("fr", l10n_util::GetApplicationLocale(std::string())); 165 env->UnSetVar("LANGUAGE"); 166 EXPECT_EQ("es", l10n_util::GetApplicationLocale(std::string())); 167 env->UnSetVar("LC_ALL"); 168 EXPECT_EQ("he", l10n_util::GetApplicationLocale(std::string())); 169 env->UnSetVar("LC_MESSAGES"); 170 EXPECT_EQ("nb", l10n_util::GetApplicationLocale(std::string())); 171 env->UnSetVar("LANG"); 172 173 SetDefaultLocaleForTest("ca", env.get()); 174 EXPECT_EQ("ca", l10n_util::GetApplicationLocale(std::string())); 175 176 SetDefaultLocaleForTest("ca-ES", env.get()); 177 EXPECT_EQ("ca", l10n_util::GetApplicationLocale(std::string())); 178 179 SetDefaultLocaleForTest("ca@valencia", env.get()); 180 EXPECT_EQ("ca@valencia", l10n_util::GetApplicationLocale(std::string())); 181 182 SetDefaultLocaleForTest("ca_ES@valencia", env.get()); 183 EXPECT_EQ("ca@valencia", l10n_util::GetApplicationLocale(std::string())); 184 185 SetDefaultLocaleForTest("ca_ES.UTF8@valencia", env.get()); 186 EXPECT_EQ("ca@valencia", l10n_util::GetApplicationLocale(std::string())); 187 } 188 189 SetDefaultLocaleForTest("en-US", env.get()); 190 EXPECT_EQ("en-US", l10n_util::GetApplicationLocale(std::string())); 191 192 SetDefaultLocaleForTest("xx", env.get()); 193 EXPECT_EQ("en-US", l10n_util::GetApplicationLocale(std::string())); 194 195 if (!kPlatformHasDefaultLocale) { 196 // ChromeOS & embedded use only browser prefs in GetApplicationLocale(), 197 // ignoring the environment, and default to en-US. Other platforms honor 198 // the default locale from the OS or environment. 199 SetDefaultLocaleForTest("en-GB", env.get()); 200 EXPECT_EQ("en-US", l10n_util::GetApplicationLocale("")); 201 202 SetDefaultLocaleForTest("en-US", env.get()); 203 EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale("en-GB")); 204 205 SetDefaultLocaleForTest("en-US", env.get()); 206 EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale("en-AU")); 207 208 SetDefaultLocaleForTest("en-US", env.get()); 209 EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale("en-NZ")); 210 211 SetDefaultLocaleForTest("en-US", env.get()); 212 EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale("en-CA")); 213 214 SetDefaultLocaleForTest("en-US", env.get()); 215 EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale("en-ZA")); 216 } else { 217 // Most platforms have an OS-provided locale. This locale is preferred. 218 SetDefaultLocaleForTest("en-GB", env.get()); 219 EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale(std::string())); 220 221 SetDefaultLocaleForTest("fr-CA", env.get()); 222 EXPECT_EQ("fr", l10n_util::GetApplicationLocale(std::string())); 223 224 SetDefaultLocaleForTest("es-MX", env.get()); 225 EXPECT_EQ("es-419", l10n_util::GetApplicationLocale(std::string())); 226 227 SetDefaultLocaleForTest("es-AR", env.get()); 228 EXPECT_EQ("es-419", l10n_util::GetApplicationLocale(std::string())); 229 230 SetDefaultLocaleForTest("es-ES", env.get()); 231 EXPECT_EQ("es", l10n_util::GetApplicationLocale(std::string())); 232 233 SetDefaultLocaleForTest("es", env.get()); 234 EXPECT_EQ("es", l10n_util::GetApplicationLocale(std::string())); 235 236 SetDefaultLocaleForTest("zh-HK", env.get()); 237 EXPECT_EQ("zh-TW", l10n_util::GetApplicationLocale(std::string())); 238 239 SetDefaultLocaleForTest("zh-MO", env.get()); 240 EXPECT_EQ("zh-TW", l10n_util::GetApplicationLocale(std::string())); 241 242 SetDefaultLocaleForTest("zh-SG", env.get()); 243 EXPECT_EQ("zh-CN", l10n_util::GetApplicationLocale(std::string())); 244 245 SetDefaultLocaleForTest("en-CA", env.get()); 246 EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale(std::string())); 247 248 SetDefaultLocaleForTest("en-AU", env.get()); 249 EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale(std::string())); 250 251 SetDefaultLocaleForTest("en-NZ", env.get()); 252 EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale(std::string())); 253 254 SetDefaultLocaleForTest("en-ZA", env.get()); 255 EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale(std::string())); 256 } 257 258 if (kSupportsLocalePreference) { 259 // On windows, the user can override the locale in preferences. 260 base::i18n::SetICUDefaultLocale("en-US"); 261 EXPECT_EQ("fr", l10n_util::GetApplicationLocale("fr")); 262 EXPECT_EQ("fr", l10n_util::GetApplicationLocale("fr-CA")); 263 264 base::i18n::SetICUDefaultLocale("en-US"); 265 // Aliases iw, no, tl to he, nb, fil. 266 EXPECT_EQ("he", l10n_util::GetApplicationLocale("iw")); 267 EXPECT_EQ("nb", l10n_util::GetApplicationLocale("no")); 268 EXPECT_EQ("fil", l10n_util::GetApplicationLocale("tl")); 269 // es-419 and es-XX (where XX is not Spain) should be 270 // mapped to es-419 (Latin American Spanish). 271 EXPECT_EQ("es-419", l10n_util::GetApplicationLocale("es-419")); 272 EXPECT_EQ("es", l10n_util::GetApplicationLocale("es-ES")); 273 EXPECT_EQ("es-419", l10n_util::GetApplicationLocale("es-AR")); 274 275 base::i18n::SetICUDefaultLocale("es-AR"); 276 EXPECT_EQ("es", l10n_util::GetApplicationLocale("es")); 277 278 base::i18n::SetICUDefaultLocale("zh-HK"); 279 EXPECT_EQ("zh-CN", l10n_util::GetApplicationLocale("zh-CN")); 280 281 base::i18n::SetICUDefaultLocale("he"); 282 EXPECT_EQ("en-US", l10n_util::GetApplicationLocale("en")); 283 } 284 285 #if defined(OS_WIN) 286 // Amharic should be blocked unless OS is Vista or newer. 287 if (base::win::GetVersion() < base::win::VERSION_VISTA) { 288 base::i18n::SetICUDefaultLocale("am"); 289 EXPECT_EQ("en-US", l10n_util::GetApplicationLocale("")); 290 base::i18n::SetICUDefaultLocale("en-GB"); 291 EXPECT_EQ("en-GB", l10n_util::GetApplicationLocale("am")); 292 } else { 293 base::i18n::SetICUDefaultLocale("am"); 294 EXPECT_EQ("am", l10n_util::GetApplicationLocale("")); 295 base::i18n::SetICUDefaultLocale("en-GB"); 296 EXPECT_EQ("am", l10n_util::GetApplicationLocale("am")); 297 } 298 #endif // defined(OS_WIN) 299 300 // Clean up. 301 base::i18n::SetICUDefaultLocale(original_locale); 302 } 303 #endif // !defined(OS_MACOSX) 304 305 TEST_F(L10nUtilTest, SortStringsUsingFunction) { 306 std::vector<StringWrapper*> strings; 307 strings.push_back(new StringWrapper(UTF8ToUTF16("C"))); 308 strings.push_back(new StringWrapper(UTF8ToUTF16("d"))); 309 strings.push_back(new StringWrapper(UTF8ToUTF16("b"))); 310 strings.push_back(new StringWrapper(UTF8ToUTF16("a"))); 311 l10n_util::SortStringsUsingMethod("en-US", 312 &strings, 313 &StringWrapper::string); 314 ASSERT_TRUE(UTF8ToUTF16("a") == strings[0]->string()); 315 ASSERT_TRUE(UTF8ToUTF16("b") == strings[1]->string()); 316 ASSERT_TRUE(UTF8ToUTF16("C") == strings[2]->string()); 317 ASSERT_TRUE(UTF8ToUTF16("d") == strings[3]->string()); 318 STLDeleteElements(&strings); 319 } 320 321 /** 322 * Helper method for validating strings that require direcitonal markup. 323 * Checks that parentheses are enclosed in appropriate direcitonal markers. 324 */ 325 void CheckUiDisplayNameForLocale(const std::string& locale, 326 const std::string& display_locale, 327 bool is_rtl) { 328 EXPECT_EQ(true, base::i18n::IsRTL()); 329 string16 result = l10n_util::GetDisplayNameForLocale(locale, 330 display_locale, 331 /* is_for_ui */ true); 332 333 bool rtl_direction = true; 334 for (size_t i = 0; i < result.length() - 1; i++) { 335 char16 ch = result.at(i); 336 switch (ch) { 337 case base::i18n::kLeftToRightMark: 338 case base::i18n::kLeftToRightEmbeddingMark: 339 rtl_direction = false; 340 break; 341 case base::i18n::kRightToLeftMark: 342 case base::i18n::kRightToLeftEmbeddingMark: 343 rtl_direction = true; 344 break; 345 case '(': 346 case ')': 347 EXPECT_EQ(is_rtl, rtl_direction); 348 } 349 } 350 } 351 352 TEST_F(L10nUtilTest, GetDisplayNameForLocale) { 353 // TODO(jungshik): Make this test more extensive. 354 // Test zh-CN and zh-TW are treated as zh-Hans and zh-Hant. 355 string16 result = l10n_util::GetDisplayNameForLocale("zh-CN", "en", false); 356 EXPECT_EQ(ASCIIToUTF16("Chinese (Simplified Han)"), result); 357 358 result = l10n_util::GetDisplayNameForLocale("zh-TW", "en", false); 359 EXPECT_EQ(ASCIIToUTF16("Chinese (Traditional Han)"), result); 360 361 result = l10n_util::GetDisplayNameForLocale("pt-BR", "en", false); 362 EXPECT_EQ(ASCIIToUTF16("Portuguese (Brazil)"), result); 363 364 result = l10n_util::GetDisplayNameForLocale("es-419", "en", false); 365 EXPECT_EQ(ASCIIToUTF16("Spanish (Latin America)"), result); 366 367 result = l10n_util::GetDisplayNameForLocale("-BR", "en", false); 368 EXPECT_EQ(ASCIIToUTF16("Brazil"), result); 369 370 result = l10n_util::GetDisplayNameForLocale("xyz-xyz", "en", false); 371 EXPECT_EQ(ASCIIToUTF16("xyz (XYZ)"), result); 372 373 #if !defined(TOOLKIT_GTK) 374 // Check for directional markers when using RTL languages to ensure that 375 // direction neutral characters such as parentheses are properly formatted. 376 377 // Keep a copy of ICU's default locale before we overwrite it. 378 const std::string original_locale = base::i18n::GetConfiguredLocale(); 379 380 base::i18n::SetICUDefaultLocale("he"); 381 CheckUiDisplayNameForLocale("en-US", "en", false); 382 CheckUiDisplayNameForLocale("en-US", "he", true); 383 384 // Clean up. 385 base::i18n::SetICUDefaultLocale(original_locale); 386 #endif 387 388 // ToUpper and ToLower should work with embedded NULLs. 389 const size_t length_with_null = 4; 390 char16 buf_with_null[length_with_null] = { 0, 'a', 0, 'b' }; 391 string16 string16_with_null(buf_with_null, length_with_null); 392 393 string16 upper_with_null = base::i18n::ToUpper(string16_with_null); 394 ASSERT_EQ(length_with_null, upper_with_null.size()); 395 EXPECT_TRUE(upper_with_null[0] == 0 && upper_with_null[1] == 'A' && 396 upper_with_null[2] == 0 && upper_with_null[3] == 'B'); 397 398 string16 lower_with_null = base::i18n::ToLower(upper_with_null); 399 ASSERT_EQ(length_with_null, upper_with_null.size()); 400 EXPECT_TRUE(lower_with_null[0] == 0 && lower_with_null[1] == 'a' && 401 lower_with_null[2] == 0 && lower_with_null[3] == 'b'); 402 } 403 404 TEST_F(L10nUtilTest, GetDisplayNameForCountry) { 405 string16 result = l10n_util::GetDisplayNameForCountry("BR", "en"); 406 EXPECT_EQ(ASCIIToUTF16("Brazil"), result); 407 408 result = l10n_util::GetDisplayNameForCountry("419", "en"); 409 EXPECT_EQ(ASCIIToUTF16("Latin America"), result); 410 411 result = l10n_util::GetDisplayNameForCountry("xyz", "en"); 412 EXPECT_EQ(ASCIIToUTF16("XYZ"), result); 413 } 414 415 TEST_F(L10nUtilTest, GetParentLocales) { 416 std::vector<std::string> locales; 417 const std::string top_locale("sr_Cyrl_RS"); 418 l10n_util::GetParentLocales(top_locale, &locales); 419 420 ASSERT_EQ(3U, locales.size()); 421 EXPECT_EQ("sr_Cyrl_RS", locales[0]); 422 EXPECT_EQ("sr_Cyrl", locales[1]); 423 EXPECT_EQ("sr", locales[2]); 424 } 425 426 TEST_F(L10nUtilTest, IsValidLocaleSyntax) { 427 // Test valid locales. 428 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("en")); 429 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("fr")); 430 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("de")); 431 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("pt")); 432 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("zh")); 433 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("fil")); 434 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("haw")); 435 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("en-US")); 436 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("en_US")); 437 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("en_GB")); 438 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("pt-BR")); 439 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("zh_CN")); 440 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("zh_Hans")); 441 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("zh_Hans_CN")); 442 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("zh_Hant")); 443 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("zh_Hant_TW")); 444 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("fr_CA")); 445 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("i-klingon")); 446 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("es-419")); 447 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("en_IE_PREEURO")); 448 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("en_IE_u_cu_IEP")); 449 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("en_IE@currency=IEP")); 450 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("fr@x=y")); 451 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax("zn_CN@foo=bar")); 452 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax( 453 "fr@collation=phonebook;calendar=islamic-civil")); 454 EXPECT_TRUE(l10n_util::IsValidLocaleSyntax( 455 "sr_Latn_RS_REVISED@currency=USD")); 456 457 // Test invalid locales. 458 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax(std::string())); 459 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("x")); 460 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("12")); 461 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("456")); 462 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("a1")); 463 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("enUS")); 464 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("zhcn")); 465 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("en.US")); 466 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("en#US")); 467 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("-en-US")); 468 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("en-US-")); 469 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("123-en-US")); 470 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("Latin")); 471 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("German")); 472 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("pt--BR")); 473 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("sl-macedonia")); 474 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("@")); 475 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("en-US@")); 476 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("en-US@x")); 477 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("en-US@x=")); 478 EXPECT_FALSE(l10n_util::IsValidLocaleSyntax("en-US@=y")); 479 } 480