| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "flutter/shell/platform/glfw/system_utils.h" |
| |
| #include <cstdlib> |
| #include <sstream> |
| |
| namespace flutter { |
| |
| namespace { |
| |
| const char* GetLocaleStringFromEnvironment() { |
| const char* retval; |
| retval = getenv("LANGUAGE"); |
| if ((retval != NULL) && (retval[0] != '\0')) { |
| return retval; |
| } |
| retval = getenv("LC_ALL"); |
| if ((retval != NULL) && (retval[0] != '\0')) { |
| return retval; |
| } |
| retval = getenv("LC_MESSAGES"); |
| if ((retval != NULL) && (retval[0] != '\0')) { |
| return retval; |
| } |
| retval = getenv("LANG"); |
| if ((retval != NULL) && (retval[0] != '\0')) { |
| return retval; |
| } |
| |
| return NULL; |
| } |
| |
| // The least specific to most specific components of a locale. |
| enum Component { |
| kCodeset = 1 << 0, |
| kTerritory = 1 << 1, |
| kModifier = 1 << 2, |
| }; |
| |
| // Construct a mask indicating which of the components in |info| are set. |
| int ComputeVariantMask(const LanguageInfo& info) { |
| int mask = 0; |
| if (!info.territory.empty()) { |
| mask |= kTerritory; |
| } |
| if (!info.codeset.empty()) { |
| mask |= kCodeset; |
| } |
| if (!info.modifier.empty()) { |
| mask |= kModifier; |
| } |
| return mask; |
| } |
| |
| // Appends most specific to least specific variants of |info| to |languages|. |
| // For example, "de_DE@euro" would append "de_DE@euro", "de@euro", "de_DE", |
| // and "de". |
| void AppendLocaleVariants(std::vector<LanguageInfo>& languages, |
| const LanguageInfo& info) { |
| int mask = ComputeVariantMask(info); |
| for (int i = mask; i >= 0; --i) { |
| if ((i & ~mask) == 0) { |
| LanguageInfo variant; |
| variant.language = info.language; |
| |
| if (i & kTerritory) { |
| variant.territory = info.territory; |
| } |
| if (i & kCodeset) { |
| variant.codeset = info.codeset; |
| } |
| if (i & kModifier) { |
| variant.modifier = info.modifier; |
| } |
| languages.push_back(variant); |
| } |
| } |
| } |
| |
| // Parses a locale into its components. |
| LanguageInfo ParseLocale(const std::string& locale) { |
| // Locales are of the form "language[_territory][.codeset][@modifier]" |
| LanguageInfo result; |
| std::string::size_type end = locale.size(); |
| std::string::size_type modifier_pos = locale.rfind('@'); |
| if (modifier_pos != std::string::npos) { |
| result.modifier = locale.substr(modifier_pos + 1, end - modifier_pos - 1); |
| end = modifier_pos; |
| } |
| |
| std::string::size_type codeset_pos = locale.rfind('.', end); |
| if (codeset_pos != std::string::npos) { |
| result.codeset = locale.substr(codeset_pos + 1, end - codeset_pos - 1); |
| end = codeset_pos; |
| } |
| |
| std::string::size_type territory_pos = locale.rfind('_', end); |
| if (territory_pos != std::string::npos) { |
| result.territory = |
| locale.substr(territory_pos + 1, end - territory_pos - 1); |
| end = territory_pos; |
| } |
| |
| result.language = locale.substr(0, end); |
| |
| return result; |
| } |
| |
| } // namespace |
| |
| std::vector<LanguageInfo> GetPreferredLanguageInfo() { |
| const char* locale_string; |
| locale_string = GetLocaleStringFromEnvironment(); |
| if (!locale_string || locale_string[0] == '\0') { |
| // This is the default locale if none is specified according to ISO C. |
| locale_string = "C"; |
| } |
| std::istringstream locales_stream(locale_string); |
| std::vector<LanguageInfo> languages; |
| std::string s; |
| while (getline(locales_stream, s, ':')) { |
| LanguageInfo info = ParseLocale(s); |
| AppendLocaleVariants(languages, info); |
| } |
| return languages; |
| } |
| |
| std::vector<FlutterLocale> ConvertToFlutterLocale( |
| const std::vector<LanguageInfo>& languages) { |
| std::vector<FlutterLocale> flutter_locales; |
| flutter_locales.reserve(languages.size()); |
| for (const auto& info : languages) { |
| FlutterLocale locale = {}; |
| locale.struct_size = sizeof(FlutterLocale); |
| locale.language_code = info.language.c_str(); |
| if (!info.territory.empty()) { |
| locale.country_code = info.territory.c_str(); |
| } |
| if (!info.codeset.empty()) { |
| locale.script_code = info.codeset.c_str(); |
| } |
| if (!info.modifier.empty()) { |
| locale.variant_code = info.modifier.c_str(); |
| } |
| flutter_locales.push_back(locale); |
| } |
| |
| return flutter_locales; |
| } |
| |
| } // namespace flutter |