|  | /* | 
|  | * Copyright (C) 2010, 2013 Apple Inc. All rights reserved. | 
|  | * | 
|  | * Redistribution and use in source and binary forms, with or without | 
|  | * modification, are permitted provided that the following conditions | 
|  | * are met: | 
|  | * 1. Redistributions of source code must retain the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer. | 
|  | * 2. Redistributions in binary form must reproduce the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer in the | 
|  | *    documentation and/or other materials provided with the distribution. | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | 
|  | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | 
|  | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
|  | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | 
|  | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 
|  | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 
|  | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 
|  | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 
|  | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 
|  | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | 
|  | * THE POSSIBILITY OF SUCH DAMAGE. | 
|  | */ | 
|  |  | 
|  | #include "sky/engine/config.h" | 
|  | #include "sky/engine/platform/Language.h" | 
|  |  | 
|  | #include "sky/engine/public/platform/Platform.h" | 
|  | #include "sky/engine/wtf/text/WTFString.h" | 
|  |  | 
|  | namespace blink { | 
|  |  | 
|  | static const AtomicString& platformLanguage() | 
|  | { | 
|  | DEFINE_STATIC_LOCAL(AtomicString, computedDefaultLanguage, ()); | 
|  | if (computedDefaultLanguage.isEmpty()) { | 
|  | computedDefaultLanguage = blink::Platform::current()->defaultLocale(); | 
|  | ASSERT(!computedDefaultLanguage.isEmpty()); | 
|  | } | 
|  | return computedDefaultLanguage; | 
|  | } | 
|  |  | 
|  | AtomicString defaultLanguage() | 
|  | { | 
|  | Vector<AtomicString> languages = userPreferredLanguages(); | 
|  | if (!languages.isEmpty()) | 
|  | return languages[0]; | 
|  |  | 
|  | return emptyAtom; | 
|  | } | 
|  |  | 
|  | static Vector<AtomicString>& preferredLanguagesOverride() | 
|  | { | 
|  | DEFINE_STATIC_LOCAL(Vector<AtomicString>, override, ()); | 
|  | return override; | 
|  | } | 
|  |  | 
|  | Vector<AtomicString> userPreferredLanguagesOverride() | 
|  | { | 
|  | return preferredLanguagesOverride(); | 
|  | } | 
|  |  | 
|  | void overrideUserPreferredLanguages(const Vector<AtomicString>& override) | 
|  | { | 
|  | preferredLanguagesOverride() = override; | 
|  | } | 
|  |  | 
|  | Vector<AtomicString> userPreferredLanguages() | 
|  | { | 
|  | Vector<AtomicString>& override = preferredLanguagesOverride(); | 
|  | if (!override.isEmpty()) | 
|  | return override; | 
|  |  | 
|  | Vector<AtomicString> languages; | 
|  | languages.reserveInitialCapacity(1); | 
|  | languages.append(platformLanguage()); | 
|  | return languages; | 
|  | } | 
|  |  | 
|  | static String canonicalLanguageIdentifier(const String& languageCode) | 
|  | { | 
|  | String lowercaseLanguageCode = languageCode.lower(); | 
|  |  | 
|  | if (lowercaseLanguageCode.length() >= 3 && lowercaseLanguageCode[2] == '_') | 
|  | lowercaseLanguageCode.replace(2, 1, "-"); | 
|  |  | 
|  | return lowercaseLanguageCode; | 
|  | } | 
|  |  | 
|  | size_t indexOfBestMatchingLanguageInList(const AtomicString& language, const Vector<AtomicString>& languageList) | 
|  | { | 
|  | AtomicString languageWithoutLocaleMatch; | 
|  | AtomicString languageMatchButNotLocale; | 
|  | size_t languageWithoutLocaleMatchIndex = 0; | 
|  | size_t languageMatchButNotLocaleMatchIndex = 0; | 
|  | bool canMatchLanguageOnly = (language.length() == 2 || (language.length() >= 3 && language[2] == '-')); | 
|  |  | 
|  | for (size_t i = 0; i < languageList.size(); ++i) { | 
|  | String canonicalizedLanguageFromList = canonicalLanguageIdentifier(languageList[i]); | 
|  |  | 
|  | if (language == canonicalizedLanguageFromList) | 
|  | return i; | 
|  |  | 
|  | if (canMatchLanguageOnly && canonicalizedLanguageFromList.length() >= 2) { | 
|  | if (language[0] == canonicalizedLanguageFromList[0] && language[1] == canonicalizedLanguageFromList[1]) { | 
|  | if (!languageWithoutLocaleMatch.length() && canonicalizedLanguageFromList.length() == 2) { | 
|  | languageWithoutLocaleMatch = languageList[i]; | 
|  | languageWithoutLocaleMatchIndex = i; | 
|  | } | 
|  | if (!languageMatchButNotLocale.length() && canonicalizedLanguageFromList.length() >= 3) { | 
|  | languageMatchButNotLocale = languageList[i]; | 
|  | languageMatchButNotLocaleMatchIndex = i; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // If we have both a language-only match and a languge-but-not-locale match, return the | 
|  | // languge-only match as is considered a "better" match. For example, if the list | 
|  | // provided has both "en-GB" and "en" and the user prefers "en-US" we will return "en". | 
|  | if (languageWithoutLocaleMatch.length()) | 
|  | return languageWithoutLocaleMatchIndex; | 
|  |  | 
|  | if (languageMatchButNotLocale.length()) | 
|  | return languageMatchButNotLocaleMatchIndex; | 
|  |  | 
|  | return languageList.size(); | 
|  | } | 
|  |  | 
|  | } |