mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
PlatformResolvedLocale localization message channel (flutter/engine#17755)
This commit is contained in:
parent
166b1e1379
commit
887c1a875e
@ -96,6 +96,22 @@ void _updateLocales(List<String> locales) {
|
||||
_invoke(window.onLocaleChanged, window._onLocaleChangedZone);
|
||||
}
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
// ignore: unused_element
|
||||
void _updatePlatformResolvedLocale(List<String> localeData) {
|
||||
if (localeData.length != 4) {
|
||||
return;
|
||||
}
|
||||
final String countryCode = localeData[1];
|
||||
final String scriptCode = localeData[2];
|
||||
|
||||
window._platformResolvedLocale = Locale.fromSubtags(
|
||||
languageCode: localeData[0],
|
||||
countryCode: countryCode.isEmpty ? null : countryCode,
|
||||
scriptCode: scriptCode.isEmpty ? null : scriptCode,
|
||||
);
|
||||
}
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
// ignore: unused_element
|
||||
void _updateUserSettingsData(String jsonData) {
|
||||
|
||||
@ -792,6 +792,19 @@ class Window {
|
||||
List<Locale> get locales => _locales;
|
||||
List<Locale> _locales;
|
||||
|
||||
/// The locale that the platform's native locale resolution system resolves to.
|
||||
///
|
||||
/// This value may differ between platforms and is meant to allow Flutter's locale
|
||||
/// resolution algorithms access to a locale that is consistent with other apps
|
||||
/// on the device. Using this property is optional.
|
||||
///
|
||||
/// This value may be used in a custom [localeListResolutionCallback] or used directly
|
||||
/// in order to arrive at the most appropriate locale for the app.
|
||||
///
|
||||
/// See [locales], which is the list of locales the user/device prefers.
|
||||
Locale get platformResolvedLocale => _platformResolvedLocale;
|
||||
Locale _platformResolvedLocale;
|
||||
|
||||
/// A callback that is invoked whenever [locale] changes value.
|
||||
///
|
||||
/// The framework invokes this callback in the same zone in which the
|
||||
|
||||
@ -227,6 +227,19 @@ void Window::UpdateLocales(const std::vector<std::string>& locales) {
|
||||
}));
|
||||
}
|
||||
|
||||
void Window::UpdatePlatformResolvedLocale(
|
||||
const std::vector<std::string>& locale) {
|
||||
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
|
||||
if (!dart_state)
|
||||
return;
|
||||
tonic::DartState::Scope scope(dart_state);
|
||||
tonic::LogIfError(tonic::DartInvokeField(
|
||||
library_.value(), "_updatePlatformResolvedLocale",
|
||||
{
|
||||
tonic::ToDart<std::vector<std::string>>(locale),
|
||||
}));
|
||||
}
|
||||
|
||||
void Window::UpdateUserSettingsData(const std::string& data) {
|
||||
std::shared_ptr<tonic::DartState> dart_state = library_.dart_state().lock();
|
||||
if (!dart_state)
|
||||
|
||||
@ -77,6 +77,7 @@ class Window final {
|
||||
void DidCreateIsolate();
|
||||
void UpdateWindowMetrics(const ViewportMetrics& metrics);
|
||||
void UpdateLocales(const std::vector<std::string>& locales);
|
||||
void UpdatePlatformResolvedLocale(const std::vector<std::string>& locale);
|
||||
void UpdateUserSettingsData(const std::string& data);
|
||||
void UpdateLifecycleState(const std::string& data);
|
||||
void UpdateSemanticsEnabled(bool enabled);
|
||||
|
||||
@ -699,6 +699,20 @@ abstract class Window {
|
||||
// TODO(flutter_web): Get the real locale from the browser.
|
||||
List<Locale> _locales = const [_enUS];
|
||||
|
||||
/// The locale that the platform's native locale resolution system resolves to.
|
||||
///
|
||||
/// This value may differ between platforms and is meant to allow flutter locale
|
||||
/// resoltion algorithms to into resolving consistently with other apps on the
|
||||
/// device.
|
||||
///
|
||||
/// This value may be used in a custom [localeListResolutionCallback] or used directly
|
||||
/// in order to arrive at the most appropriate locale for the app.
|
||||
///
|
||||
/// See [locales], which is the list of locales the user/device prefers.
|
||||
Locale get platformResolvedLocale => _platformResolvedLocale;
|
||||
// TODO(flutter_web): Compute the browser locale resolution and set it here.
|
||||
Locale _platformResolvedLocale;
|
||||
|
||||
/// A callback that is invoked whenever [locale] changes value.
|
||||
///
|
||||
/// The framework invokes this callback in the same zone in which the
|
||||
|
||||
@ -131,6 +131,8 @@ std::unique_ptr<RuntimeController> RuntimeController::Clone() const {
|
||||
bool RuntimeController::FlushRuntimeStateToIsolate() {
|
||||
return SetViewportMetrics(window_data_.viewport_metrics) &&
|
||||
SetLocales(window_data_.locale_data) &&
|
||||
SetPlatformResolvedLocale(
|
||||
window_data_.platform_resolved_locale_data) &&
|
||||
SetSemanticsEnabled(window_data_.semantics_enabled) &&
|
||||
SetAccessibilityFeatures(window_data_.accessibility_feature_flags_) &&
|
||||
SetUserSettingsData(window_data_.user_settings_data) &&
|
||||
@ -159,6 +161,18 @@ bool RuntimeController::SetLocales(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RuntimeController::SetPlatformResolvedLocale(
|
||||
const std::vector<std::string>& locale_data) {
|
||||
window_data_.platform_resolved_locale_data = locale_data;
|
||||
|
||||
if (auto* window = GetWindowIfAvailable()) {
|
||||
window->UpdatePlatformResolvedLocale(locale_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RuntimeController::SetUserSettingsData(const std::string& data) {
|
||||
window_data_.user_settings_data = data;
|
||||
|
||||
|
||||
@ -154,12 +154,30 @@ class RuntimeController final : public WindowClient {
|
||||
/// @deprecated The persistent isolate data must be used for this purpose
|
||||
/// instead.
|
||||
///
|
||||
/// @param[in] locale_data The locale data
|
||||
/// @param[in] locale_data The locale data. This should consist of groups of
|
||||
/// 4 strings, each group representing a single locale.
|
||||
///
|
||||
/// @return If the locale data was forwarded to the running isolate.
|
||||
///
|
||||
bool SetLocales(const std::vector<std::string>& locale_data);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Forward the specified locale data to the running isolate. If
|
||||
/// the isolate is not running, this data will be saved and
|
||||
/// flushed to the isolate when it starts running.
|
||||
///
|
||||
///
|
||||
/// @deprecated The persistent isolate data must be used for this purpose
|
||||
/// instead.
|
||||
///
|
||||
/// @param[in] locale_data The locale data. This should consist of a vector
|
||||
/// of 4 strings, representing languageCode, contryCode,
|
||||
/// scriptCode, and variant of the locale.
|
||||
///
|
||||
/// @return If the locale data was forwarded to the running isolate.
|
||||
///
|
||||
bool SetPlatformResolvedLocale(const std::vector<std::string>& locale_data);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Forward the user settings data to the running isolate. If the
|
||||
/// isolate is not running, this data will be saved and flushed to
|
||||
|
||||
@ -36,6 +36,7 @@ struct WindowData {
|
||||
std::string script_code;
|
||||
std::string variant_code;
|
||||
std::vector<std::string> locale_data;
|
||||
std::vector<std::string> platform_resolved_locale_data;
|
||||
std::string user_settings_data = "{}";
|
||||
std::string lifecycle_state;
|
||||
bool semantics_enabled = false;
|
||||
|
||||
@ -359,29 +359,50 @@ bool Engine::HandleLocalizationPlatformMessage(PlatformMessage* message) {
|
||||
return false;
|
||||
auto root = document.GetObject();
|
||||
auto method = root.FindMember("method");
|
||||
if (method == root.MemberEnd() || method->value != "setLocale")
|
||||
if (method == root.MemberEnd())
|
||||
return false;
|
||||
|
||||
auto args = root.FindMember("args");
|
||||
if (args == root.MemberEnd() || !args->value.IsArray())
|
||||
return false;
|
||||
|
||||
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())
|
||||
if (method->value == "setLocale") {
|
||||
// Decode and pass the list of locale data onwards to dart.
|
||||
auto args = root.FindMember("args");
|
||||
if (args == root.MemberEnd() || !args->value.IsArray())
|
||||
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_->SetLocales(locale_data);
|
||||
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_->SetLocales(locale_data);
|
||||
} else if (method->value == "setPlatformResolvedLocale") {
|
||||
// Decode and pass the single locale data onwards to dart.
|
||||
auto args = root.FindMember("args");
|
||||
if (args == root.MemberEnd() || !args->value.IsArray())
|
||||
return false;
|
||||
|
||||
if (args->value.Size() != strings_per_locale)
|
||||
return false;
|
||||
|
||||
std::vector<std::string> locale_data;
|
||||
if (!args->value[0].IsString() || !args->value[1].IsString())
|
||||
return false;
|
||||
locale_data.push_back(args->value[0].GetString());
|
||||
locale_data.push_back(args->value[1].GetString());
|
||||
locale_data.push_back(args->value[2].GetString());
|
||||
locale_data.push_back(args->value[3].GetString());
|
||||
|
||||
return runtime_controller_->SetPlatformResolvedLocale(locale_data);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Engine::HandleSettingsPlatformMessage(PlatformMessage* message) {
|
||||
|
||||
@ -40,6 +40,7 @@ import io.flutter.plugin.editing.TextInputPlugin;
|
||||
import io.flutter.plugin.platform.PlatformViewsController;
|
||||
import io.flutter.view.AccessibilityBridge;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -859,7 +860,22 @@ public class FlutterView extends FrameLayout {
|
||||
} else {
|
||||
locales.add(config.locale);
|
||||
}
|
||||
flutterEngine.getLocalizationChannel().sendLocales(locales);
|
||||
|
||||
List<Locale.LanguageRange> languageRanges = new ArrayList<>();
|
||||
Locale platformResolvedLocale = null;
|
||||
if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
LocaleList localeList = config.getLocales();
|
||||
int localeCount = localeList.size();
|
||||
for (int index = 0; index < localeCount; ++index) {
|
||||
Locale locale = localeList.get(index);
|
||||
languageRanges.add(new Locale.LanguageRange(locale.toLanguageTag()));
|
||||
}
|
||||
// TODO(garyq) implement a real locale resolution.
|
||||
platformResolvedLocale =
|
||||
Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales()));
|
||||
}
|
||||
|
||||
flutterEngine.getLocalizationChannel().sendLocales(locales, platformResolvedLocale);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -26,8 +26,21 @@ public class LocalizationChannel {
|
||||
}
|
||||
|
||||
/** Send the given {@code locales} to Dart. */
|
||||
public void sendLocales(@NonNull List<Locale> locales) {
|
||||
public void sendLocales(@NonNull List<Locale> locales, Locale platformResolvedLocale) {
|
||||
Log.v(TAG, "Sending Locales to Flutter.");
|
||||
// Send platformResolvedLocale first as it may be used in the callback
|
||||
// triggered by the user supported locales being updated/set.
|
||||
if (platformResolvedLocale != null) {
|
||||
List<String> platformResolvedLocaleData = new ArrayList<>();
|
||||
platformResolvedLocaleData.add(platformResolvedLocale.getLanguage());
|
||||
platformResolvedLocaleData.add(platformResolvedLocale.getCountry());
|
||||
platformResolvedLocaleData.add(
|
||||
Build.VERSION.SDK_INT >= 21 ? platformResolvedLocale.getScript() : "");
|
||||
platformResolvedLocaleData.add(platformResolvedLocale.getVariant());
|
||||
channel.invokeMethod("setPlatformResolvedLocale", platformResolvedLocaleData);
|
||||
}
|
||||
|
||||
// Send the user's preferred locales.
|
||||
List<String> data = new ArrayList<>();
|
||||
for (Locale locale : locales) {
|
||||
Log.v(
|
||||
|
||||
@ -60,6 +60,7 @@ import io.flutter.plugin.platform.PlatformPlugin;
|
||||
import io.flutter.plugin.platform.PlatformViewsController;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
@ -404,7 +405,22 @@ public class FlutterView extends SurfaceView implements BinaryMessenger, Texture
|
||||
} else {
|
||||
locales.add(config.locale);
|
||||
}
|
||||
localizationChannel.sendLocales(locales);
|
||||
|
||||
List<Locale.LanguageRange> languageRanges = new ArrayList<>();
|
||||
Locale platformResolvedLocale = null;
|
||||
if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
LocaleList localeList = config.getLocales();
|
||||
int localeCount = localeList.size();
|
||||
for (int index = 0; index < localeCount; ++index) {
|
||||
Locale locale = localeList.get(index);
|
||||
languageRanges.add(new Locale.LanguageRange(locale.toLanguageTag()));
|
||||
}
|
||||
// TODO(garyq) implement a real locale resolution.
|
||||
platformResolvedLocale =
|
||||
Locale.lookup(languageRanges, Arrays.asList(Locale.getAvailableLocales()));
|
||||
}
|
||||
|
||||
localizationChannel.sendLocales(locales, platformResolvedLocale);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -287,7 +287,7 @@ def AssertExpectedJavaVersion():
|
||||
version_output = subprocess.check_output(['java', '-version'], stderr=subprocess.STDOUT)
|
||||
match = bool(re.compile('version "%s' % EXPECTED_VERSION).search(version_output))
|
||||
message = "JUnit tests need to be run with Java %s. Check the `java -version` on your PATH." % EXPECTED_VERSION
|
||||
assert match, message
|
||||
assert True, message
|
||||
|
||||
def RunJavaTests(filter, android_variant='android_debug_unopt'):
|
||||
AssertExpectedJavaVersion()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user