mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-07-26 13:47:03 +02:00
Support automatic language selection based on system language (#17953)
* Support automatic language selection * Handle non-matching keys * Cleanup * Handle region specific language codes from browser * Fix passing in requestor
This commit is contained in:
parent
9291543705
commit
e57dde7bb0
@ -120,7 +120,7 @@ class EmbeddingMaintainer(threading.Thread):
|
|||||||
if self.config.face_recognition.enabled:
|
if self.config.face_recognition.enabled:
|
||||||
self.realtime_processors.append(
|
self.realtime_processors.append(
|
||||||
FaceRealTimeProcessor(
|
FaceRealTimeProcessor(
|
||||||
self.config, self.event_metadata_publisher, metrics
|
self.config, self.requestor, self.event_metadata_publisher, metrics
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ import {
|
|||||||
useTheme,
|
useTheme,
|
||||||
} from "@/context/theme-provider";
|
} from "@/context/theme-provider";
|
||||||
import { IoColorPalette } from "react-icons/io5";
|
import { IoColorPalette } from "react-icons/io5";
|
||||||
import { useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { useRestart } from "@/api/ws";
|
import { useRestart } from "@/api/ws";
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
@ -62,6 +62,7 @@ import { toast } from "sonner";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { FrigateConfig } from "@/types/frigateConfig";
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { supportedLanguageKeys } from "@/lib/const";
|
||||||
|
|
||||||
type GeneralSettingsProps = {
|
type GeneralSettingsProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
@ -75,20 +76,21 @@ export default function GeneralSettings({ className }: GeneralSettingsProps) {
|
|||||||
|
|
||||||
// languages
|
// languages
|
||||||
|
|
||||||
const languages = [
|
const languages = useMemo(() => {
|
||||||
{ code: "en", label: t("menu.language.en") },
|
// Handle language keys that aren't directly used for translation key
|
||||||
{ code: "es", label: t("menu.language.es") },
|
const specialKeyMap: { [key: string]: string } = {
|
||||||
{ code: "fr", label: t("menu.language.fr") },
|
"nb-NO": "nb",
|
||||||
{ code: "de", label: t("menu.language.de") },
|
"yue-Hant": "yue",
|
||||||
{ code: "it", label: t("menu.language.it") },
|
"zh-CN": "zhCN",
|
||||||
{ code: "nl", label: t("menu.language.nl") },
|
};
|
||||||
{ code: "nb-NO", label: t("menu.language.nb") },
|
|
||||||
{ code: "tr", label: t("menu.language.tr") },
|
return supportedLanguageKeys.map((key) => {
|
||||||
{ code: "pl", label: t("menu.language.pl") },
|
return {
|
||||||
{ code: "zh-CN", label: t("menu.language.zhCN") },
|
code: key,
|
||||||
{ code: "yue-Hant", label: t("menu.language.yue") },
|
label: t(`menu.language.${specialKeyMap[key] || key}`),
|
||||||
{ code: "ru", label: t("menu.language.ru") },
|
};
|
||||||
];
|
});
|
||||||
|
}, [t]);
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
|
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import { createContext, useContext, useState, useEffect, useMemo } from "react";
|
import { createContext, useContext, useState, useEffect, useMemo } from "react";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
import { supportedLanguageKeys } from "@/lib/const";
|
||||||
|
|
||||||
type LanguageProviderState = {
|
type LanguageProviderState = {
|
||||||
language: string;
|
language: string;
|
||||||
systemLanguage: string;
|
|
||||||
setLanguage: (language: string) => void;
|
setLanguage: (language: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialState: LanguageProviderState = {
|
const initialState: LanguageProviderState = {
|
||||||
language: i18next.language || "en",
|
language: i18next.language || "en",
|
||||||
systemLanguage: "en",
|
|
||||||
setLanguage: () => null,
|
setLanguage: () => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -26,10 +25,31 @@ export function LanguageProvider({
|
|||||||
defaultLanguage?: string;
|
defaultLanguage?: string;
|
||||||
storageKey?: string;
|
storageKey?: string;
|
||||||
}) {
|
}) {
|
||||||
|
const systemLanguage = useMemo<string>(() => {
|
||||||
|
if (typeof window === "undefined") return defaultLanguage;
|
||||||
|
|
||||||
|
const systemLanguage = window.navigator.language;
|
||||||
|
|
||||||
|
if (supportedLanguageKeys.includes(systemLanguage)) {
|
||||||
|
return systemLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
// browser languages may include a -REGION (ex: en-US)
|
||||||
|
if (systemLanguage.includes("-")) {
|
||||||
|
const shortenedSystemLanguage = systemLanguage.split("-")[0];
|
||||||
|
|
||||||
|
if (supportedLanguageKeys.includes(shortenedSystemLanguage)) {
|
||||||
|
return shortenedSystemLanguage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultLanguage;
|
||||||
|
}, [defaultLanguage]);
|
||||||
|
|
||||||
const [language, setLanguage] = useState<string>(() => {
|
const [language, setLanguage] = useState<string>(() => {
|
||||||
try {
|
try {
|
||||||
const storedData = localStorage.getItem(storageKey);
|
const storedData = localStorage.getItem(storageKey);
|
||||||
const newLanguage = storedData || defaultLanguage;
|
const newLanguage = storedData || systemLanguage;
|
||||||
i18next.changeLanguage(newLanguage);
|
i18next.changeLanguage(newLanguage);
|
||||||
return newLanguage;
|
return newLanguage;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -39,11 +59,6 @@ export function LanguageProvider({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const systemLanguage = useMemo<string>(() => {
|
|
||||||
if (typeof window === "undefined") return "en";
|
|
||||||
return window.navigator.language;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// set document lang for smart capitalization
|
// set document lang for smart capitalization
|
||||||
document.documentElement.lang = language;
|
document.documentElement.lang = language;
|
||||||
@ -54,7 +69,6 @@ export function LanguageProvider({
|
|||||||
|
|
||||||
const value = {
|
const value = {
|
||||||
language,
|
language,
|
||||||
systemLanguage,
|
|
||||||
setLanguage: (language: string) => {
|
setLanguage: (language: string) => {
|
||||||
localStorage.setItem(storageKey, language);
|
localStorage.setItem(storageKey, language);
|
||||||
setLanguage(language);
|
setLanguage(language);
|
||||||
|
14
web/src/lib/const.ts
Normal file
14
web/src/lib/const.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
export const supportedLanguageKeys = [
|
||||||
|
"en",
|
||||||
|
"es",
|
||||||
|
"fr",
|
||||||
|
"de",
|
||||||
|
"it",
|
||||||
|
"nl",
|
||||||
|
"nb-NO",
|
||||||
|
"tr",
|
||||||
|
"pl",
|
||||||
|
"zh-CN",
|
||||||
|
"yue-Hant",
|
||||||
|
"ru",
|
||||||
|
];
|
Loading…
Reference in New Issue
Block a user