diff --git a/src/actions/localization-actions.js b/src/actions/localization-actions.js index ab2cbc655..d6846ff6a 100644 --- a/src/actions/localization-actions.js +++ b/src/actions/localization-actions.js @@ -21,6 +21,7 @@ import { getLanguageData, getLanguages, getLocaleData, + getLocaleKeyboardLayouts, getLocales, } from "../apis/localization.js"; @@ -69,3 +70,14 @@ export const getCommonLocalesAction = () => { }); }; }; + +export const getKeyboardLayoutsAction = ({ language }) => { + return async (dispatch) => { + const keyboardLayouts = await getLocaleKeyboardLayouts({ locale: language }); + + dispatch({ + payload: { keyboardLayouts }, + type: "GET_KEYBOARD_LAYOUTS" + }); + }; +}; diff --git a/src/apis/localization.js b/src/apis/localization.js index abb1a40a1..e88c141a6 100644 --- a/src/apis/localization.js +++ b/src/apis/localization.js @@ -17,7 +17,7 @@ import cockpit from "cockpit"; -import { getLanguageAction, getLanguagesAction } from "../actions/localization-actions.js"; +import { getKeyboardLayoutsAction, getLanguageAction, getLanguagesAction } from "../actions/localization-actions.js"; import { debug } from "../helpers/log.js"; import { _callClient, _getProperty, _setProperty } from "./helpers.js"; @@ -62,18 +62,22 @@ export class LocalizationClient { } async initData () { + const language = await getLanguage(); await this.dispatch(getLanguageAction()); await this.dispatch(getLanguagesAction()); + await this.dispatch(getKeyboardLayoutsAction({ language })); } startEventMonitor () { this.client.subscribe( { }, - (path, iface, signal, args) => { + async (path, iface, signal, args) => { switch (signal) { case "PropertiesChanged": if (args[0] === INTERFACE_NAME && Object.hasOwn(args[1], "Language")) { - this.dispatch(getLanguageAction()); + await this.dispatch(getLanguageAction()); + const language = await getLanguage(); + await this.dispatch(getKeyboardLayoutsAction({ language })); } else { debug(`Unhandled signal on ${path}: ${iface}.${signal}`, JSON.stringify(args)); } @@ -139,3 +143,19 @@ export const getLocaleData = ({ locale }) => { export const setLanguage = ({ lang }) => { return setProperty("Language", cockpit.variant("s", lang)); }; + +/** + * @param {string} layout Keyboard layout id + */ +export const setKeyboardLayout = ({ layout }) => { + return setProperty("SetCompositorSelectedLayout", cockpit.variant("s", layout)); +}; + +/** + * @param {string} lang Locale id + * + * @returns {Promise} Resolves a list of locale keyboards + */ +export const getLocaleKeyboardLayouts = ({ locale }) => { + return callClient("GetLocaleKeyboardLayouts", [locale]); +}; diff --git a/src/components/localization/InstallationLanguage.jsx b/src/components/localization/InstallationLanguage.jsx index 8e95a0ad2..b935b8b5c 100644 --- a/src/components/localization/InstallationLanguage.jsx +++ b/src/components/localization/InstallationLanguage.jsx @@ -17,7 +17,7 @@ import cockpit from "cockpit"; -import React, { useContext, useEffect } from "react"; +import React, { useContext, useEffect, useState } from "react"; import { Button, Form, @@ -36,6 +36,7 @@ import { SearchIcon, TimesIcon } from "@patternfly/react-icons"; import { setLocale } from "../../apis/boss.js"; import { + setKeyboardLayout, setLanguage, } from "../../apis/localization.js"; @@ -47,6 +48,8 @@ import { import { LanguageContext } from "../../contexts/Common.jsx"; +import { KeyboardSelector } from "./Keyboard.jsx"; + import "./InstallationLanguage.scss"; const _ = cockpit.gettext; @@ -295,7 +298,13 @@ class LanguageSelector extends React.Component { } const InstallationLanguage = ({ setIsFormValid, setStepNotification }) => { - const { commonLocales, language, languages } = useContext(LanguageContext); + const { commonLocales, keyboardLayouts, language, languages } = useContext(LanguageContext); + const [keyboard, setKeyboard] = useState(""); + + const handleSetKeyboard = (value) => { + setKeyboard(value); + setKeyboardLayout(value); + }; useEffect(() => { setIsFormValid(language !== ""); @@ -303,13 +312,9 @@ const InstallationLanguage = ({ setIsFormValid, setStepNotification }) => { return ( <> -