2 * Copyright (C) 2010, 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
27 #include "platform/Language.h"
29 #include "public/platform/Platform.h"
30 #include "wtf/text/WTFString.h"
34 static String
canonicalizeLanguageIdentifier(const String
& languageCode
)
36 String copiedCode
= languageCode
;
37 // Platform::defaultLocale() might provide a language code with '_'.
38 copiedCode
.replace('_', '-');
42 static const AtomicString
& platformLanguage()
44 DEFINE_STATIC_LOCAL(AtomicString
, computedDefaultLanguage
, ());
45 if (computedDefaultLanguage
.isEmpty()) {
46 computedDefaultLanguage
= AtomicString(canonicalizeLanguageIdentifier(Platform::current()->defaultLocale()));
47 ASSERT(!computedDefaultLanguage
.isEmpty());
49 return computedDefaultLanguage
;
52 static Vector
<AtomicString
>& preferredLanguagesOverride()
54 DEFINE_STATIC_LOCAL(Vector
<AtomicString
>, override
, ());
58 void overrideUserPreferredLanguages(const Vector
<AtomicString
>& override
)
60 Vector
<AtomicString
>& canonicalized
= preferredLanguagesOverride();
61 canonicalized
.resize(0);
62 canonicalized
.reserveCapacity(override
.size());
63 for (const auto& lang
: override
)
64 canonicalized
.append(canonicalizeLanguageIdentifier(lang
));
67 AtomicString
defaultLanguage()
69 Vector
<AtomicString
>& override
= preferredLanguagesOverride();
70 if (!override
.isEmpty())
72 return platformLanguage();
75 Vector
<AtomicString
> userPreferredLanguages()
77 Vector
<AtomicString
>& override
= preferredLanguagesOverride();
78 if (!override
.isEmpty())
81 Vector
<AtomicString
> languages
;
82 languages
.reserveInitialCapacity(1);
83 languages
.append(platformLanguage());
87 size_t indexOfBestMatchingLanguageInList(const AtomicString
& language
, const Vector
<AtomicString
>& languageList
)
89 AtomicString languageWithoutLocaleMatch
;
90 AtomicString languageMatchButNotLocale
;
91 size_t languageWithoutLocaleMatchIndex
= 0;
92 size_t languageMatchButNotLocaleMatchIndex
= 0;
93 bool canMatchLanguageOnly
= (language
.length() == 2 || (language
.length() >= 3 && language
[2] == '-'));
95 for (size_t i
= 0; i
< languageList
.size(); ++i
) {
96 String canonicalizedLanguageFromList
= canonicalizeLanguageIdentifier(languageList
[i
]);
98 if (language
== canonicalizedLanguageFromList
)
101 if (canMatchLanguageOnly
&& canonicalizedLanguageFromList
.length() >= 2) {
102 if (language
[0] == canonicalizedLanguageFromList
[0] && language
[1] == canonicalizedLanguageFromList
[1]) {
103 if (!languageWithoutLocaleMatch
.length() && canonicalizedLanguageFromList
.length() == 2) {
104 languageWithoutLocaleMatch
= languageList
[i
];
105 languageWithoutLocaleMatchIndex
= i
;
107 if (!languageMatchButNotLocale
.length() && canonicalizedLanguageFromList
.length() >= 3) {
108 languageMatchButNotLocale
= languageList
[i
];
109 languageMatchButNotLocaleMatchIndex
= i
;
115 // If we have both a language-only match and a languge-but-not-locale match, return the
116 // languge-only match as is considered a "better" match. For example, if the list
117 // provided has both "en-GB" and "en" and the user prefers "en-US" we will return "en".
118 if (languageWithoutLocaleMatch
.length())
119 return languageWithoutLocaleMatchIndex
;
121 if (languageMatchButNotLocale
.length())
122 return languageMatchButNotLocaleMatchIndex
;
124 return languageList
.size();