/*
* Copyright (C) 2022 Red Hat, Inc.
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
import cockpit from "cockpit";
import React, { useContext, useEffect, useState } from "react";
import { Form, FormGroup } from "@patternfly/react-core/dist/esm/components/Form/index.js";
import { setLocale } from "../../apis/boss.js";
import {
setLanguage,
} from "../../apis/localization.js";
import {
convertToCockpitLang,
getLangCookie,
setLangCookie
} from "../../helpers/language.js";
import { error as loggerError } from "../../helpers/log.js";
import { LanguageContext, PageContext, SystemTypeContext } from "../../contexts/Common.jsx";
import { MenuSearch } from "../common/MenuSearch.jsx";
import { Keyboard } from "./Keyboard.jsx";
import "./InstallationLanguage.scss";
const _ = cockpit.gettext;
const SCREEN_ID = "anaconda-screen-language";
const error = loggerError.bind(null, SCREEN_ID + ":");
const getLanguageEnglishName = lang => lang["english-name"].v;
const getLanguageNativeName = lang => lang["native-name"].v;
const getLocaleId = locale => locale["locale-id"].v;
const getLocaleNativeName = locale => locale["native-name"].v;
class LanguageSelector extends React.Component {
static contextType = PageContext;
constructor (props) {
super(props);
this.initiallySelectedLanguage = props.language;
this.renderOptions = this.renderOptions.bind(this);
}
componentDidMount () {
try {
const cockpitLang = convertToCockpitLang({ lang: this.props.language });
if (getLangCookie() !== cockpitLang) {
setLangCookie({ cockpitLang });
window.location.reload(true);
}
setLocale({ locale: this.props.language });
} catch (e) {
this.context?.setStepNotification?.({
step: SCREEN_ID,
...e,
});
}
}
renderOptions () {
const { commonLocales, languages } = this.props;
const options = [];
// Returns a locale with a given code.
const findLocaleWithId = (localeCode) => {
for (const languageId in languages) {
const languageItem = languages[languageId];
for (const locale of languageItem.locales) {
if (getLocaleId(locale) === localeCode) {
return locale;
}
}
}
error(`Locale with code ${localeCode} not found.`);
};
const onSearch = (locale, search) => {
const searchLower = search.toLowerCase();
return (
getLocaleNativeName(locale).toLowerCase()
.includes(searchLower) ||
getLanguageNativeName(locale).toLowerCase()
.includes(searchLower) ||
getLanguageEnglishName(locale).toLowerCase()
.includes(searchLower)
);
};
// Helper to create a menu item
const createMenuItem = (locale, prefix) => {
return ({
id: `${SCREEN_ID}-language-${prefix}-${getLocaleId(locale).split(".UTF-8")[0]}`,
item: locale,
itemId: getLocaleId(locale),
itemLang: convertToCockpitLang({ lang: getLocaleId(locale) }),
itemText: getLocaleNativeName(locale),
itemType: "menu-item",
key: `${prefix}-${getLocaleId(locale)}`,
onSearch: onSearch.bind(null, locale),
});
};
const suggestedItems = commonLocales
.map(findLocaleWithId)
.filter(locale => locale !== undefined)
.sort((a, b) => {
// Sort alphabetically by native name but keep the default locale at the top
if (getLocaleId(a) === this.initiallySelectedLanguage) {
return -1;
} else if (getLocaleId(b) === this.initiallySelectedLanguage) {
return 1;
}
return getLocaleNativeName(a).localeCompare(getLocaleNativeName(b));
})
.map(locale => createMenuItem(locale, "option-common"));
if (suggestedItems.length > 0) {
options.push({
id: `${SCREEN_ID}-common-languages`,
itemChildren: suggestedItems,
itemLabel: _("Suggested languages"),
itemLabelHeadingLevel: "h3",
itemType: "menu-group",
});
}
const otherItems = Object.keys(languages)
.sort((a, b) => {
return getLanguageNativeName(languages[a].locales[0]).localeCompare(getLanguageNativeName(languages[b].locales[0]));
})
.flatMap(languageId => {
const languageItem = languages[languageId];
return languageItem.locales;
})
.filter(locale => commonLocales.indexOf(getLocaleId(locale)) === -1)
.map(locale => createMenuItem(locale, "option-alpha"));
if (otherItems.length > 0) {
options.push({
id: `${SCREEN_ID}-additional-languages`,
itemChildren: otherItems,
itemLabel: _("Additional languages"),
itemLabelHeadingLevel: "h3",
itemType: "menu-group",
});
}
return options;
}
render () {
const { languages } = this.props;
const handleOnSelect = (_event, item) => {
for (const languageItem in languages) {
for (const localeItem of languages[languageItem].locales) {
if (getLocaleId(localeItem) === item) {
setLangCookie({ cockpitLang: convertToCockpitLang({ lang: getLocaleId(localeItem) }) });
setLanguage({ lang: getLocaleId(localeItem) })
.then(() => setLocale({ locale: getLocaleId(localeItem) }))
.catch(ex => {
this.context?.setStepNotification?.({
step: SCREEN_ID,
...ex,
});
});
this.setState({ lang: item });
fetch("po.js").then(response => response.text())
.then(body => {
// always reset old translations
cockpit.locale(null);
// en_US is always null
if (body.trim() === "") {
cockpit.locale({
"": {
language: "en_US",
"language-direction": "ltr",
}
});
} else {
// eslint-disable-next-line no-eval
eval(body);
}
const langEvent = new CustomEvent("cockpit-lang");
window.dispatchEvent(langEvent);
});
return;
}
}
}
};
const options = this.renderOptions();
return (