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
36namespace {
37
38class 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
51class L10nUtilTest : public PlatformTest {
52};
53
54#if defined(OS_WIN)
55// TODO(beng): disabled until app strings move to app.
56TEST_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)
81const bool kPlatformHasDefaultLocale = 1;
82const bool kUseLocaleFromEnvironment = 1;
83const bool kSupportsLocalePreference = 0;
84#elif defined(OS_WIN)
85const bool kPlatformHasDefaultLocale = 1;
86const bool kUseLocaleFromEnvironment = 0;
87const bool kSupportsLocalePreference = 1;
88#else
89const bool kPlatformHasDefaultLocale = 0;
90const bool kUseLocaleFromEnvironment = 0;
91const bool kSupportsLocalePreference = 1;
92#endif
93
94void 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
101TEST_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
305TEST_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 */
325void 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
352TEST_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
404TEST_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
415TEST_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
426TEST_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