LibWebView: Add language settings to about:settings

This implements a setting to change the languages provided to websites
from `navigator.language(s)` and the `Accept-Language` header. Whereas
the existing Qt settings dialog allows users to type their language of
choice, this setting allows users to select from a predefined list of
languages. They may choose any number of languages and their preferred
order.

This patch only implements the persisted settings and their UI. It does
not integrate the choses languages into the WebContent process.
This commit is contained in:
Timothy Flynn 2025-04-03 13:42:39 -04:00 committed by Jelle Raaijmakers
commit f242920cc9
Notes: github-actions[bot] 2025-04-04 08:17:38 +00:00
8 changed files with 466 additions and 13 deletions

View file

@ -14,6 +14,7 @@
#include <LibCore/File.h>
#include <LibCore/StandardPaths.h>
#include <LibURL/Parser.h>
#include <LibUnicode/Locale.h>
#include <LibWebView/Application.h>
#include <LibWebView/Settings.h>
@ -21,6 +22,9 @@ namespace WebView {
static constexpr auto new_tab_page_url_key = "newTabPageURL"sv;
static constexpr auto languages_key = "languages"sv;
static auto default_language = "en"_string;
static constexpr auto search_engine_key = "searchEngine"sv;
static constexpr auto search_engine_name_key = "name"sv;
@ -81,6 +85,9 @@ Settings Settings::create(Badge<Application>)
settings.m_new_tab_page_url = parsed_new_tab_page_url.release_value();
}
if (auto languages = settings_json.value().get(languages_key); languages.has_value())
settings.m_languages = parse_json_languages(*languages);
if (auto search_engine = settings_json.value().get_object(search_engine_key); search_engine.has_value()) {
if (auto search_engine_name = search_engine->get_string(search_engine_name_key); search_engine_name.has_value())
settings.m_search_engine = find_search_engine_by_name(*search_engine_name);
@ -120,6 +127,7 @@ Settings Settings::create(Badge<Application>)
Settings::Settings(ByteString settings_path)
: m_settings_path(move(settings_path))
, m_new_tab_page_url(URL::about_newtab())
, m_languages({ default_language })
{
}
@ -128,6 +136,14 @@ JsonValue Settings::serialize_json() const
JsonObject settings;
settings.set(new_tab_page_url_key, m_new_tab_page_url.serialize());
JsonArray languages;
languages.ensure_capacity(m_languages.size());
for (auto const& language : m_languages)
languages.must_append(language);
settings.set(languages_key, move(languages));
if (m_search_engine.has_value()) {
JsonObject search_engine;
search_engine.set(search_engine_name_key, m_search_engine->name);
@ -166,6 +182,7 @@ JsonValue Settings::serialize_json() const
void Settings::restore_defaults()
{
m_new_tab_page_url = URL::about_newtab();
m_languages = { default_language };
m_search_engine.clear();
m_autocomplete_engine.clear();
m_autoplay = SiteSetting {};
@ -175,6 +192,7 @@ void Settings::restore_defaults()
for (auto& observer : m_observers) {
observer.new_tab_page_url_changed();
observer.languages_changed();
observer.search_engine_changed();
observer.autocomplete_engine_changed();
observer.autoplay_settings_changed();
@ -191,6 +209,34 @@ void Settings::set_new_tab_page_url(URL::URL new_tab_page_url)
observer.new_tab_page_url_changed();
}
Vector<String> Settings::parse_json_languages(JsonValue const& languages)
{
if (!languages.is_array())
return { default_language };
Vector<String> parsed_languages;
parsed_languages.ensure_capacity(languages.as_array().size());
languages.as_array().for_each([&](JsonValue const& language) {
if (language.is_string() && Unicode::is_locale_available(language.as_string()))
parsed_languages.append(language.as_string());
});
if (parsed_languages.is_empty())
return { default_language };
return parsed_languages;
}
void Settings::set_languages(Vector<String> languages)
{
m_languages = move(languages);
persist_settings();
for (auto& observer : m_observers)
observer.languages_changed();
}
void Settings::set_search_engine(Optional<StringView> search_engine_name)
{
if (search_engine_name.has_value())

View file

@ -35,6 +35,7 @@ public:
virtual ~SettingsObserver();
virtual void new_tab_page_url_changed() { }
virtual void languages_changed() { }
virtual void search_engine_changed() { }
virtual void autocomplete_engine_changed() { }
virtual void autoplay_settings_changed() { }
@ -52,6 +53,10 @@ public:
URL::URL const& new_tab_page_url() const { return m_new_tab_page_url; }
void set_new_tab_page_url(URL::URL);
static Vector<String> parse_json_languages(JsonValue const&);
Vector<String> const& languages() const { return m_languages; }
void set_languages(Vector<String>);
Optional<SearchEngine> const& search_engine() const { return m_search_engine; }
void set_search_engine(Optional<StringView> search_engine_name);
@ -78,6 +83,7 @@ private:
ByteString m_settings_path;
URL::URL m_new_tab_page_url;
Vector<String> m_languages;
Optional<SearchEngine> m_search_engine;
Optional<AutocompleteEngine> m_autocomplete_engine;
SiteSetting m_autoplay;

View file

@ -24,6 +24,9 @@ void SettingsUI::register_interfaces()
register_interface("setNewTabPageURL"sv, [this](auto const& data) {
set_new_tab_page_url(data);
});
register_interface("setLanguages"sv, [this](auto const& data) {
set_languages(data);
});
register_interface("loadAvailableEngines"sv, [this](auto const&) {
load_available_engines();
@ -80,6 +83,14 @@ void SettingsUI::set_new_tab_page_url(JsonValue const& new_tab_page_url)
WebView::Application::settings().set_new_tab_page_url(parsed_new_tab_page_url.release_value());
}
void SettingsUI::set_languages(JsonValue const& languages)
{
auto parsed_languages = Settings::parse_json_languages(languages);
WebView::Application::settings().set_languages(move(parsed_languages));
load_current_settings();
}
void SettingsUI::load_available_engines()
{
JsonArray search_engines;

View file

@ -20,6 +20,7 @@ private:
void restore_default_settings();
void set_new_tab_page_url(JsonValue const&);
void set_languages(JsonValue const&);
void load_available_engines();
void set_search_engine(JsonValue const&);