diff --git a/src/public/app/services/i18n.ts b/src/public/app/services/i18n.ts index 20ac6e286..ec1e55acf 100644 --- a/src/public/app/services/i18n.ts +++ b/src/public/app/services/i18n.ts @@ -2,15 +2,10 @@ import options from "./options.js"; import i18next from "i18next"; import i18nextHttpBackend from "i18next-http-backend"; import server from "./server.js"; +import type { Locale } from "../../../services/i18n.js"; let locales: Locale[] | null; -// TODO: Deduplicate with server. -export interface Locale { - id: string; - name: string; -} - export async function initLocale() { const locale = (options.get("locale") as string) || "en"; @@ -28,7 +23,7 @@ export async function initLocale() { export function getAvailableLocales() { if (!locales) { - throw new Error("Tried to load list of locales, but localization is not yet initialized."); + throw new Error("Tried to load list of locales, but localization is not yet initialized.") } return locales; diff --git a/src/public/app/widgets/note_language.ts b/src/public/app/widgets/note_language.ts index 216d46a88..5f4008d85 100644 --- a/src/public/app/widgets/note_language.ts +++ b/src/public/app/widgets/note_language.ts @@ -1,10 +1,11 @@ import { Dropdown } from "bootstrap"; import NoteContextAwareWidget from "./note_context_aware_widget.js"; -import { getAvailableLocales, type Locale } from "../services/i18n.js"; +import { getAvailableLocales } from "../services/i18n.js"; import { t } from "i18next"; import type { EventData } from "../components/app_context.js"; import type FNote from "../entities/fnote.js"; import attributes from "../services/attributes.js"; +import type { Locale } from "../../../services/i18n.js"; const TPL = `\ `; @@ -56,6 +63,10 @@ export default class NoteLanguageWidget extends NoteContextAwareWidget { for (const locale of this.locales) { if (typeof locale === "object") { const $title = $("").text(locale.name); + if (locale.rtl) { + $title.attr("dir", "rtl"); + } + const $link = $('') .attr("data-language", locale.id) .append(' ') @@ -64,6 +75,7 @@ export default class NoteLanguageWidget extends NoteContextAwareWidget { const languageId = $link.attr("data-language") ?? ""; this.save(languageId); }) + this.$noteLanguageDropdown.append($link); } else { this.$noteLanguageDropdown.append(''); diff --git a/src/services/i18n.ts b/src/services/i18n.ts index 03bf98d8c..4dd8d4519 100644 --- a/src/services/i18n.ts +++ b/src/services/i18n.ts @@ -6,6 +6,13 @@ import { join } from "path"; import { getResourceDir } from "./utils.js"; import hidden_subtree from "./hidden_subtree.js"; +export interface Locale { + id: string; + name: string; + /** `true` if the language is a right-to-left one, or `false` if it's left-to-right. */ + rtl?: boolean; +} + export async function initializeTranslations() { const resourceDir = getResourceDir(); @@ -20,7 +27,7 @@ export async function initializeTranslations() { }); } -export function getLocales() { +export function getLocales(): Locale[] { // TODO: Currently hardcoded, needs to read the list of available languages. return [ { @@ -59,19 +66,23 @@ export function getLocales() { */ { // Arabic id: "ar", - name: "اَلْعَرَبِيَّةُ" + name: "اَلْعَرَبِيَّةُ", + rtl: true }, { // Hebrew id: "he", - name: "עברית" + name: "עברית", + rtl: true }, { // Kurdish id: "ku", - name: "کوردی" + name: "کوردی", + rtl: true }, { // Persian id: "fa", - name: "فارسی" + name: "فارسی", + rtl: true } ]; }