mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
The other linux shell (and all the other embedding) have support for getting the locales from the system and sending them over the flutter/localization channel. The glfw shell does not have that which is causing a crash on an assert now that Locale is no longer nullable in Platform. This adds a similar approach to what is going on over in the other linux shell.
155 lines
4.2 KiB
C++
155 lines
4.2 KiB
C++
// 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,
|
|
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
|