未验证 提交 35340cea 编写于 作者: G Gary Qian 提交者: GitHub

Pass full locale list with script and variant codes to framework (#6557)

* Locale Passing

* Pass full locale list and script and variant codes to framework

* Working Android locale list passing and fallback
上级 04c860fa
......@@ -42,14 +42,20 @@ void _updateWindowMetrics(double devicePixelRatio,
typedef _LocaleClosure = String Function();
String _localeClosure() => window._locale.toString();
String _localeClosure() => window.locale.toString();
@pragma('vm:entry-point')
_LocaleClosure _getLocaleClosure() => _localeClosure;
@pragma('vm:entry-point')
void _updateLocale(String languageCode, String countryCode, String scriptCode, String variantCode) {
window._locale = new Locale(languageCode, countryCode);
void _updateLocales(List<String> locales) {
const int stringsPerLocale = 4;
final int numLocales = locales.length ~/ stringsPerLocale;
window._locales = new List<Locale>(numLocales);
for (int localeIndex = 0; localeIndex < numLocales; localeIndex++) {
window._locales[localeIndex] = new Locale(locales[localeIndex * stringsPerLocale],
locales[localeIndex * stringsPerLocale + 1]);
}
_invoke(window.onLocaleChanged, window._onLocaleChangedZone);
}
......
......@@ -152,6 +152,9 @@ class Locale {
/// the region subtag should be uppercase.
const Locale(this._languageCode, [ this._countryCode ]) : assert(_languageCode != null);
/// Empty locale constant. This is an invalid locale.
static const Locale none = const Locale('', '');
/// The primary language subtag for the locale.
///
/// This must not be null.
......@@ -426,19 +429,39 @@ class Window {
_onMetricsChangedZone = Zone.current;
}
/// The system-reported locale.
/// The system-reported default locale of the device.
///
/// This establishes the language and formatting conventions that application
/// should, if possible, use to render their user interface.
///
/// This is the first locale selected by the user and is the user's
/// primary locale (the locale the device UI is displayed in)
///
/// This is equivalent to `locales.first` and will provide an empty non-null locale
/// if the [locales] list has not been set or is empty.
Locale get locale {
if (_locales != null && _locales.isNotEmpty) {
return _locales.first;
}
return Locale.none;
}
/// The full system-reported supported locales of the device.
///
/// This establishes the language and formatting conventions that application
/// should, if possible, use to render their user interface.
///
/// The list is ordered in order of priority, with lower-indexed locales being
/// preferred over higher-indexed ones. The first element is the primary [locale].
///
/// The [onLocaleChanged] callback is called whenever this value changes.
///
/// See also:
///
/// * [WidgetsBindingObserver], for a mechanism at the widgets layer to
/// observe when this value changes.
Locale get locale => _locale;
Locale _locale;
List<Locale> get locales => _locales;
List<Locale> _locales;
/// A callback that is invoked whenever [locale] changes value.
///
......
......@@ -162,21 +162,14 @@ void Window::UpdateWindowMetrics(const ViewportMetrics& metrics) {
});
}
void Window::UpdateLocale(const std::string& language_code,
const std::string& country_code,
const std::string& script_code,
const std::string& variant_code) {
void Window::UpdateLocales(const std::vector<std::string>& locales) {
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
DartInvokeField(library_.value(), "_updateLocale",
DartInvokeField(library_.value(), "_updateLocales",
{
StdStringToDart(language_code),
StdStringToDart(country_code),
StdStringToDart(script_code),
StdStringToDart(variant_code),
tonic::ToDart<std::vector<std::string>>(locales),
});
}
......
......@@ -5,7 +5,9 @@
#ifndef FLUTTER_LIB_UI_WINDOW_WINDOW_H_
#define FLUTTER_LIB_UI_WINDOW_WINDOW_H_
#include <string>
#include <unordered_map>
#include <vector>
#include "flutter/fml/time/time_point.h"
#include "flutter/lib/ui/semantics/semantics_update.h"
......@@ -59,10 +61,7 @@ class Window final {
void DidCreateIsolate();
void UpdateWindowMetrics(const ViewportMetrics& metrics);
void UpdateLocale(const std::string& language_code,
const std::string& country_code,
const std::string& script_code,
const std::string& variant_code);
void UpdateLocales(const std::vector<std::string>& locales);
void UpdateUserSettingsData(const std::string& data);
void UpdateSemanticsEnabled(bool enabled);
void UpdateAccessibilityFeatures(int32_t flags);
......
......@@ -124,8 +124,7 @@ std::unique_ptr<RuntimeController> RuntimeController::Clone() const {
bool RuntimeController::FlushRuntimeStateToIsolate() {
return SetViewportMetrics(window_data_.viewport_metrics) &&
SetLocale(window_data_.language_code, window_data_.country_code,
window_data_.script_code, window_data_.variant_code) &&
SetLocales(window_data_.locale_data) &&
SetSemanticsEnabled(window_data_.semantics_enabled) &&
SetAccessibilityFeatures(window_data_.accessibility_feature_flags_);
}
......@@ -140,22 +139,15 @@ bool RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) {
return false;
}
bool RuntimeController::SetLocale(const std::string& language_code,
const std::string& country_code,
const std::string& script_code,
const std::string& variant_code) {
window_data_.language_code = language_code;
window_data_.country_code = country_code;
window_data_.script_code = script_code;
window_data_.variant_code = variant_code;
bool RuntimeController::SetLocales(
const std::vector<std::string>& locale_data) {
window_data_.locale_data = locale_data;
if (auto window = GetWindowIfAvailable()) {
window->UpdateLocale(window_data_.language_code, window_data_.country_code,
window_data_.script_code, window_data_.variant_code);
window->UpdateLocales(locale_data);
return true;
}
return false;
return true;
}
bool RuntimeController::SetUserSettingsData(const std::string& data) {
......
......@@ -6,6 +6,7 @@
#define FLUTTER_RUNTIME_RUNTIME_CONTROLLER_H_
#include <memory>
#include <vector>
#include "flutter/common/task_runners.h"
#include "flutter/flow/layers/layer_tree.h"
......@@ -15,6 +16,8 @@
#include "flutter/lib/ui/window/pointer_data_packet.h"
#include "flutter/lib/ui/window/window.h"
#include "flutter/runtime/dart_vm.h"
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
namespace blink {
class Scene;
......@@ -40,10 +43,7 @@ class RuntimeController final : public WindowClient {
bool SetViewportMetrics(const ViewportMetrics& metrics);
bool SetLocale(const std::string& language_code,
const std::string& country_code,
const std::string& script_code,
const std::string& variant_code);
bool SetLocales(const std::vector<std::string>& locale_data);
bool SetUserSettingsData(const std::string& data);
......@@ -78,12 +78,29 @@ class RuntimeController final : public WindowClient {
std::pair<bool, uint32_t> GetRootIsolateReturnCode();
private:
struct Locale {
Locale(std::string language_code_,
std::string country_code_,
std::string script_code_,
std::string variant_code_)
: language_code(language_code_),
country_code(country_code_),
script_code(script_code_),
variant_code(variant_code_) {}
std::string language_code;
std::string country_code;
std::string script_code;
std::string variant_code;
};
struct WindowData {
ViewportMetrics viewport_metrics;
std::string language_code;
std::string country_code;
std::string script_code;
std::string variant_code;
std::vector<std::string> locale_data;
std::string user_settings_data = "{}";
bool semantics_enabled = false;
bool assistive_technology_enabled = false;
......
......@@ -7,6 +7,7 @@
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "flutter/common/settings.h"
#include "flutter/fml/eintr_wrapper.h"
......@@ -325,17 +326,22 @@ bool Engine::HandleLocalizationPlatformMessage(
if (args == root.MemberEnd() || !args->value.IsArray())
return false;
const auto& language = args->value[0];
const auto& country = args->value[1];
const auto& script = args->value[2];
const auto& variant = args->value[3];
if (!language.IsString() || !country.IsString())
const size_t strings_per_locale = 4;
if (args->value.Size() % strings_per_locale != 0)
return false;
std::vector<std::string> locale_data;
for (size_t locale_index = 0; locale_index < args->value.Size();
locale_index += strings_per_locale) {
if (!args->value[locale_index].IsString() ||
!args->value[locale_index + 1].IsString())
return false;
locale_data.push_back(args->value[locale_index].GetString());
locale_data.push_back(args->value[locale_index + 1].GetString());
locale_data.push_back(args->value[locale_index + 2].GetString());
locale_data.push_back(args->value[locale_index + 3].GetString());
}
return runtime_controller_->SetLocale(language.GetString(),
country.GetString(), script.GetString(),
variant.GetString());
return runtime_controller_->SetLocales(locale_data);
}
void Engine::HandleSettingsPlatformMessage(blink::PlatformMessage* message) {
......
......@@ -37,6 +37,7 @@ import io.flutter.plugin.platform.PlatformPlugin;
import org.json.JSONException;
import org.json.JSONObject;
import java.lang.reflect.Method;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
......@@ -170,7 +171,8 @@ public class FlutterView extends SurfaceView
mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
mTextInputPlugin = new TextInputPlugin(this);
setLocale(getResources().getConfiguration().locale);
setLocales(getResources().getConfiguration());
setUserSettings();
}
......@@ -316,14 +318,43 @@ public class FlutterView extends SurfaceView
mFlutterSettingsChannel.send(message);
}
private void setLocale(Locale locale) {
private void setLocales(Configuration config) {
if (Build.VERSION.SDK_INT >= 24) {
try {
// Passes the full list of locales for android API >= 24 with reflection.
Object localeList = config.getClass().getDeclaredMethod("getLocales").invoke(config);
Method localeListGet = localeList.getClass().getDeclaredMethod("get", int.class);
Method localeListSize = localeList.getClass().getDeclaredMethod("size");
int localeCount = (int)localeListSize.invoke(localeList);
List<String> data = new ArrayList<String>();
for (int index = 0; index < localeCount; ++index) {
Locale locale = (Locale)localeListGet.invoke(localeList, index);
data.add(locale.getLanguage());
data.add(locale.getCountry());
data.add(locale.getScript());
data.add(locale.getVariant());
}
mFlutterLocalizationChannel.invokeMethod("setLocale", data);
return;
} catch (Exception exception) {
// Any exception is a failure. Resort to fallback of sending only one locale.
}
}
// Fallback single locale passing for android API < 24. Should work always.
Locale locale = config.locale;
List<String> data = new ArrayList<String>();
data.add(locale.getLanguage());
data.add(locale.getCountry());
data.add(locale.getScript());
data.add(locale.getVariant());
mFlutterLocalizationChannel.invokeMethod("setLocale", Arrays.asList(locale.getLanguage(), locale.getCountry(), locale.getScript(), locale.getVariant()));
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setLocale(newConfig.locale);
setLocales(newConfig);
setUserSettings();
}
......
......@@ -905,19 +905,26 @@ static blink::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch) {
#pragma mark - Locale updates
- (void)onLocaleUpdated:(NSNotification*)notification {
NSLocale* currentLocale = [NSLocale currentLocale];
NSString* languageCode = [currentLocale objectForKey:NSLocaleLanguageCode];
NSString* countryCode = [currentLocale objectForKey:NSLocaleCountryCode];
NSString* scriptCode = [currentLocale objectForKey:NSLocaleScriptCode];
NSString* variantCode = [currentLocale objectForKey:NSLocaleVariantCode];
if (languageCode && countryCode)
// We pass empty strings for undefined scripts and variants to ensure the JSON encoder/decoder
// functions properly.
[_localizationChannel.get() invokeMethod:@"setLocale"
arguments:@[
languageCode, countryCode, scriptCode ? scriptCode : @"",
variantCode ? variantCode : @""
]];
NSArray<NSString*>* preferredLocales = [NSLocale preferredLanguages];
NSMutableArray<NSString*>* data = [NSMutableArray new];
for (NSString* localeID in preferredLocales) {
NSLocale* currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:localeID];
NSString* languageCode = [currentLocale objectForKey:NSLocaleLanguageCode];
NSString* countryCode = [currentLocale objectForKey:NSLocaleCountryCode];
NSString* scriptCode = [currentLocale objectForKey:NSLocaleScriptCode];
NSString* variantCode = [currentLocale objectForKey:NSLocaleVariantCode];
if (!languageCode || !countryCode) {
continue;
}
[data addObject:languageCode];
[data addObject:countryCode];
[data addObject:(scriptCode ? scriptCode : @"")];
[data addObject:(variantCode ? variantCode : @"")];
}
if (data.count == 0) {
return;
}
[_localizationChannel.get() invokeMethod:@"setLocale" arguments:data];
}
#pragma mark - Set user settings
......
......@@ -100,7 +100,7 @@ void main() {
};
});
_updateLocale('en', 'US', '', '');
_updateLocales(<String>['en', 'US', '', '']);
expect(runZone, isNotNull);
expect(runZone, same(innerZone));
expect(locale, equals(const Locale('en', 'US')));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册