refactor(options/i18n): share locale selector with content language selector

This commit is contained in:
Elian Doran 2025-10-14 18:42:20 +03:00
parent 5693b59318
commit dd9d13b175
No known key found for this signature in database
3 changed files with 83 additions and 77 deletions

View File

@ -5,7 +5,7 @@ import { FormDropdownDivider, FormListBadge, FormListItem } from "../react/FormL
import { getAvailableLocales, t } from "../../services/i18n";
import { useNoteLabel, useNoteLabelBoolean, useNoteProperty, useTriliumEvent, useTriliumOption } from "../react/hooks";
import mime_types from "../../services/mime_types";
import { Locale, NoteType, ToggleInParentResponse } from "@triliumnext/commons";
import { Locale, LOCALES, NoteType, ToggleInParentResponse } from "@triliumnext/commons";
import server from "../../services/server";
import dialog from "../../services/dialog";
import FormToggle from "../react/FormToggle";
@ -20,6 +20,7 @@ import { TabContext } from "./ribbon-interface";
import Modal from "../react/Modal";
import { CodeMimeTypesList } from "../type_widgets/options/code_notes";
import { ContentLanguagesList } from "../type_widgets/options/i18n";
import { LocaleSelector } from "../type_widgets/options/components/LocaleSelector";
export default function BasicPropertiesTab({ note }: TabContext) {
return (
@ -290,68 +291,30 @@ function NoteLanguageSwitch({ note }: { note?: FNote | null }) {
id: "",
name: t("note_language.not_set")
};
const [ currentNoteLanguage, setCurrentNoteLanguage ] = useNoteLabel(note, "language");
const [ modalShown, setModalShown ] = useState(false);
const locales = useMemo(() => {
const enabledLanguages = JSON.parse(languages ?? "[]") as string[];
const filteredLanguages = getAvailableLocales().filter((l) => typeof l !== "object" || enabledLanguages.includes(l.id));
const leftToRightLanguages = filteredLanguages.filter((l) => !l.rtl);
const rightToLeftLanguages = filteredLanguages.filter((l) => l.rtl);
let locales: ("---" | Locale)[] = [
DEFAULT_LOCALE
];
if (leftToRightLanguages.length > 0) {
locales = [
...locales,
"---",
...leftToRightLanguages
];
}
if (rightToLeftLanguages.length > 0) {
locales = [
...locales,
"---",
...rightToLeftLanguages
];
}
// This will separate the list of languages from the "Configure languages" button.
// If there is at least one language.
locales.push("---");
return locales;
return filteredLanguages;
}, [ languages ]);
const currentLocale = useMemo(() => {
return locales.find(locale => typeof locale === "object" && locale.id === currentNoteLanguage) as Locale | undefined;
}, [ currentNoteLanguage ]);
return (
<div className="note-language-container">
<span>{t("basic_properties.language")}:</span>
&nbsp;
<Dropdown text={currentLocale?.name ?? DEFAULT_LOCALE.name}>
{locales.map(locale => {
if (typeof locale === "object") {
const checked = locale.id === (currentNoteLanguage ?? "");
return <FormListItem
rtl={locale.rtl}
checked={checked}
onClick={() => setCurrentNoteLanguage(locale.id || null)}
>{locale.name}</FormListItem>
} else {
return <FormDropdownDivider />
}
})}
<LocaleSelector
locales={locales}
defaultLocale={DEFAULT_LOCALE}
currentValue={currentNoteLanguage ?? ""} onChange={setCurrentNoteLanguage}
extraChildren={(
<FormListItem
onClick={() => setModalShown(true)}
>{t("note_language.configure-languages")}</FormListItem>
)}
>
<FormListItem
onClick={() => setModalShown(true)}
>{t("note_language.configure-languages")}</FormListItem>
</Dropdown>
</LocaleSelector>
<HelpButton helpPage="B0lcI9xz1r8K" style={{ marginInlineStart: "4px" }} />
@ -364,7 +327,7 @@ function NoteLanguageSwitch({ note }: { note?: FNote | null }) {
<ContentLanguagesList />
</Modal>
</div>
)
);
}
function findTypeTitle(type?: NoteType, mime?: string | null) {

View File

@ -0,0 +1,63 @@
import { Locale } from "@triliumnext/commons";
import Dropdown from "../../../react/Dropdown";
import { FormDropdownDivider, FormListItem } from "../../../react/FormList";
import { ComponentChildren } from "preact";
import { useMemo, useState } from "preact/hooks";
export function LocaleSelector({ id, locales, currentValue, onChange, defaultLocale, extraChildren }: {
id?: string;
locales: Locale[],
currentValue: string,
onChange: (newLocale: string) => void,
defaultLocale?: Locale,
extraChildren?: ComponentChildren
}) {
const [ activeLocale, setActiveLocale ] = useState(defaultLocale?.id === currentValue ? defaultLocale : locales.find(l => l.id === currentValue));
console.log("defaultLocale ", defaultLocale, currentValue, activeLocale)
const processedLocales = useMemo(() => {
const leftToRightLanguages = locales.filter((l) => !l.rtl);
const rightToLeftLanguages = locales.filter((l) => l.rtl);
let items: ("---" | Locale)[] = [];
if (defaultLocale) items.push(defaultLocale);
if (leftToRightLanguages.length > 0) {
if (items.length > 0) items.push("---");
items = [ ...items, ...leftToRightLanguages ];
}
if (rightToLeftLanguages.length > 0) {
items = [
...items,
"---",
...rightToLeftLanguages
];
}
if (extraChildren) {
items.push("---");
}
return items;
}, [ locales ]);
return (
<Dropdown id={id} text={activeLocale?.name}>
{processedLocales.map(locale => {
if (typeof locale === "object") {
return <FormListItem
rtl={locale.rtl}
checked={locale.id === currentValue}
onClick={() => {
setActiveLocale(locale);
onChange(locale.id);
}}
>{locale.name}</FormListItem>
} else {
return <FormDropdownDivider />
}
})}
{extraChildren}
</Dropdown>
)
}

View File

@ -1,20 +1,18 @@
import { useMemo, useState } from "preact/hooks";
import { useMemo } from "preact/hooks";
import { getAvailableLocales, t } from "../../../services/i18n";
import FormSelect from "../../react/FormSelect";
import OptionsRow from "./components/OptionsRow";
import OptionsSection from "./components/OptionsSection";
import { useTriliumOption, useTriliumOptionJson } from "../../react/hooks";
import type { Locale } from "@triliumnext/commons";
import { isElectron, restartDesktopApp } from "../../../services/utils";
import FormRadioGroup, { FormInlineRadioGroup } from "../../react/FormRadioGroup";
import { restartDesktopApp } from "../../../services/utils";
import FormRadioGroup from "../../react/FormRadioGroup";
import FormText from "../../react/FormText";
import RawHtml from "../../react/RawHtml";
import Admonition from "../../react/Admonition";
import Button from "../../react/Button";
import CheckboxList from "./components/CheckboxList";
import FormDropdownList from "../../react/FormDropdownList";
import Dropdown from "../../react/Dropdown";
import { FormListItem } from "../../react/FormList";
import { LocaleSelector } from "./components/LocaleSelector";
export default function InternationalizationOptions() {
return (
@ -35,7 +33,6 @@ function LocalizationOptions() {
return true;
}),
formattingLocales: [
{ id: "", name: t("i18n.formatting-locale-auto") },
...allLocales.filter(locale => locale.electronLocale)
]
}
@ -51,7 +48,7 @@ function LocalizationOptions() {
</OptionsRow>
{<OptionsRow name="formatting-locale" label={t("i18n.formatting-locale")}>
<LocaleSelector locales={contentLocales} currentValue={formattingLocale} onChange={setFormattingLocale} />
<LocaleSelector locales={contentLocales} currentValue={formattingLocale} onChange={setFormattingLocale} defaultLocale={{ id: "", name: t("i18n.formatting-locale-auto") }} />
</OptionsRow>}
<DateSettings />
@ -59,23 +56,6 @@ function LocalizationOptions() {
)
}
function LocaleSelector({ id, locales, currentValue, onChange }: { id?: string; locales: Locale[], currentValue: string, onChange: (newLocale: string) => void }) {
const [ activeLocale, setActiveLocale ] = useState(locales.find(l => l.id === currentValue));
return (
<Dropdown id={id} text={activeLocale?.name}>
{locales.map(locale => (
<FormListItem
checked={locale === activeLocale }
onClick={() => {
setActiveLocale(locale);
onChange(locale.id);
}}
>{locale.name}</FormListItem>
))}
</Dropdown>
)
}
function DateSettings() {
const [ firstDayOfWeek, setFirstDayOfWeek ] = useTriliumOption("firstDayOfWeek");
const [ firstWeekOfYear, setFirstWeekOfYear ] = useTriliumOption("firstWeekOfYear");