2025-06-26 00:45:24 +03:00
|
|
|
import i18n, { t } from "i18next";
|
2025-03-16 18:36:20 +03:00
|
|
|
import { initReactI18next } from "react-i18next";
|
|
|
|
|
import HttpBackend from "i18next-http-backend";
|
2025-10-15 22:02:08 +03:00
|
|
|
import { EventType } from "@/types/search";
|
2025-03-16 18:36:20 +03:00
|
|
|
|
2025-10-15 22:02:08 +03:00
|
|
|
export const getTranslatedLabel = (
|
|
|
|
|
label: string,
|
|
|
|
|
type: EventType = "object",
|
|
|
|
|
) => {
|
2025-06-26 00:45:24 +03:00
|
|
|
if (!label) return "";
|
|
|
|
|
|
2025-10-15 22:02:08 +03:00
|
|
|
if (type === "manual") return label;
|
|
|
|
|
|
|
|
|
|
const normalize = (s: string) =>
|
|
|
|
|
s
|
|
|
|
|
.trim()
|
|
|
|
|
.replace(/[-'\s]+/g, "_")
|
|
|
|
|
.replace(/__+/g, "_")
|
|
|
|
|
.replace(/^_+|_+$/g, "")
|
|
|
|
|
.toLowerCase();
|
|
|
|
|
|
|
|
|
|
const key = normalize(label);
|
|
|
|
|
|
|
|
|
|
const ns = type === "audio" ? "audio" : "objects";
|
|
|
|
|
|
|
|
|
|
return t(key, { ns });
|
2025-06-26 00:45:24 +03:00
|
|
|
};
|
|
|
|
|
|
2025-03-16 18:36:20 +03:00
|
|
|
i18n
|
|
|
|
|
.use(initReactI18next)
|
|
|
|
|
.use(HttpBackend)
|
|
|
|
|
.init({
|
|
|
|
|
fallbackLng: "en", // use en if detected lng is not available
|
|
|
|
|
|
|
|
|
|
backend: {
|
2025-11-14 18:36:46 +03:00
|
|
|
loadPath: `locales/{{lng}}/{{ns}}.json?v=${import.meta.env.VITE_GIT_COMMIT_HASH || "unknown"}`,
|
2025-03-16 18:36:20 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
ns: [
|
|
|
|
|
"common",
|
|
|
|
|
"objects",
|
|
|
|
|
"audio",
|
|
|
|
|
"components/camera",
|
|
|
|
|
"components/dialog",
|
|
|
|
|
"components/filter",
|
|
|
|
|
"components/icons",
|
|
|
|
|
"components/player",
|
|
|
|
|
"views/events",
|
|
|
|
|
"views/explore",
|
|
|
|
|
"views/live",
|
|
|
|
|
"views/settings",
|
|
|
|
|
"views/system",
|
|
|
|
|
"views/exports",
|
|
|
|
|
"views/explore",
|
|
|
|
|
],
|
|
|
|
|
defaultNS: "common",
|
|
|
|
|
|
|
|
|
|
react: {
|
|
|
|
|
transSupportBasicHtmlNodes: true,
|
|
|
|
|
transKeepBasicHtmlNodesFor: [
|
|
|
|
|
"br",
|
|
|
|
|
"strong",
|
|
|
|
|
"i",
|
|
|
|
|
"em",
|
|
|
|
|
"li",
|
|
|
|
|
"p",
|
|
|
|
|
"code",
|
|
|
|
|
"span",
|
|
|
|
|
"p",
|
|
|
|
|
"ul",
|
|
|
|
|
"li",
|
|
|
|
|
"ol",
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
interpolation: {
|
|
|
|
|
escapeValue: false, // react already safes from xss
|
|
|
|
|
},
|
|
|
|
|
keySeparator: ".",
|
|
|
|
|
parseMissingKeyHandler: (key: string) => {
|
|
|
|
|
const parts = key.split(".");
|
|
|
|
|
|
|
|
|
|
// Handle special cases for objects and audio
|
|
|
|
|
if (parts[0] === "object" || parts[0] === "audio") {
|
|
|
|
|
return (
|
|
|
|
|
parts[1]
|
|
|
|
|
?.split("_")
|
|
|
|
|
.map(
|
|
|
|
|
(word) =>
|
|
|
|
|
word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(),
|
|
|
|
|
)
|
|
|
|
|
.join(" ") || key
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For nested keys, try to make them more readable
|
|
|
|
|
if (parts.length > 1) {
|
|
|
|
|
const lastPart = parts[parts.length - 1];
|
|
|
|
|
return lastPart
|
|
|
|
|
.split("_")
|
|
|
|
|
.map(
|
|
|
|
|
(word) =>
|
|
|
|
|
word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(),
|
|
|
|
|
)
|
|
|
|
|
.join(" ");
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-23 01:21:09 +03:00
|
|
|
// For single keys, just smart-capitalize and format
|
2025-03-16 18:36:20 +03:00
|
|
|
return key
|
|
|
|
|
.split("_")
|
|
|
|
|
.map(
|
|
|
|
|
(word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(),
|
|
|
|
|
)
|
|
|
|
|
.join(" ");
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export default i18n;
|