Replace entire codebase with homarr-labs/homarr
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
import baseConfig from "@homarr/eslint-config/base";
|
||||
|
||||
/** @type {import('typescript-eslint').Config} */
|
||||
export default [...baseConfig];
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./src";
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "@homarr/translation",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"license": "Apache-2.0",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./index.ts",
|
||||
"./client": "./src/client/index.ts",
|
||||
"./server": "./src/server.ts",
|
||||
"./middleware": "./src/middleware.ts",
|
||||
"./request": "./src/request.ts",
|
||||
"./dayjs": "./src/dayjs.ts"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rm -rf .turbo node_modules",
|
||||
"format": "prettier --check . --ignore-path ../../.gitignore",
|
||||
"lint": "eslint",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"prettier": "@homarr/prettier-config",
|
||||
"dependencies": {
|
||||
"@homarr/common": "workspace:^0.1.0",
|
||||
"@homarr/definitions": "workspace:^0.1.0",
|
||||
"dayjs": "^1.11.19",
|
||||
"deepmerge": "4.3.1",
|
||||
"mantine-react-table": "2.0.0-beta.9",
|
||||
"next": "16.1.1",
|
||||
"next-intl": "4.7.0",
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||
"eslint": "^9.39.2",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
"use client";
|
||||
|
||||
import { useMessages, useTranslations } from "next-intl";
|
||||
|
||||
import type { SupportedLanguage } from "../config";
|
||||
import type englishTranslation from "../lang/en.json";
|
||||
|
||||
export { useChangeLocale } from "./use-change-locale";
|
||||
export { useCurrentLocale } from "./use-current-locale";
|
||||
|
||||
declare module "next-intl" {
|
||||
interface AppConfig {
|
||||
Messages: typeof englishTranslation;
|
||||
Locale: SupportedLanguage;
|
||||
}
|
||||
}
|
||||
|
||||
export const { useI18n, useScopedI18n } = {
|
||||
useI18n: useTranslations,
|
||||
useScopedI18n: useTranslations,
|
||||
};
|
||||
|
||||
export const { useI18nMessages } = {
|
||||
useI18nMessages: () => useMessages(),
|
||||
};
|
||||
|
||||
export { useTranslations };
|
||||
@@ -0,0 +1,25 @@
|
||||
import { useTransition } from "react";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
|
||||
import type { SupportedLanguage } from "../config";
|
||||
import { useCurrentLocale } from "./use-current-locale";
|
||||
|
||||
export const useChangeLocale = () => {
|
||||
const currentLocale = useCurrentLocale();
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const [isPending, startTransition] = useTransition();
|
||||
|
||||
return {
|
||||
changeLocale: (newLocale: SupportedLanguage) => {
|
||||
if (newLocale === currentLocale) {
|
||||
return;
|
||||
}
|
||||
|
||||
startTransition(() => {
|
||||
router.replace(`/${newLocale}/${pathname}`);
|
||||
});
|
||||
},
|
||||
isPending,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
import { useLocale } from "next-intl";
|
||||
|
||||
export const useCurrentLocale = useLocale;
|
||||
@@ -0,0 +1,420 @@
|
||||
import type { MRT_Localization } from "mantine-react-table";
|
||||
|
||||
import { objectKeys } from "@homarr/common";
|
||||
|
||||
export const localeConfigurations = {
|
||||
ca: {
|
||||
name: "Català",
|
||||
translatedName: "Catalan",
|
||||
icon: flagIcon("es-ct"),
|
||||
importMrtLocalization() {
|
||||
return import("./mantine-react-table/ca.json");
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/ca").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
cn: {
|
||||
name: "中文",
|
||||
translatedName: "Chinese (Simplified)",
|
||||
icon: flagIcon("cn"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/zh-Hans/index.esm.mjs").then(
|
||||
(module) => module.MRT_Localization_ZH_HANS,
|
||||
);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/zh-cn").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
cr: {
|
||||
name: "Crowdin",
|
||||
translatedName: "Live translation",
|
||||
icon: {
|
||||
type: "custom" as const,
|
||||
url: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/crowdin.svg",
|
||||
},
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/en/index.esm.mjs").then((module) => module.MRT_Localization_EN);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/en-gb").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
cs: {
|
||||
name: "Čeština",
|
||||
translatedName: "Czech",
|
||||
icon: flagIcon("cz"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/cs/index.esm.mjs").then((module) => module.MRT_Localization_CS);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/cs").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
da: {
|
||||
name: "Dansk",
|
||||
translatedName: "Danish",
|
||||
icon: flagIcon("dk"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/da/index.esm.mjs").then((module) => module.MRT_Localization_DA);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/da").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
de: {
|
||||
name: "Deutsch",
|
||||
translatedName: "German",
|
||||
icon: flagIcon("de"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/de/index.esm.mjs").then((module) => module.MRT_Localization_DE);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/de").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
"de-CH": {
|
||||
name: "Deutsch (Schweiz)",
|
||||
translatedName: "German (Swiss)",
|
||||
icon: flagIcon("ch"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/de/index.esm.mjs").then((module) => module.MRT_Localization_DE);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/de-ch").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
"en-gb": {
|
||||
name: "English (UK)",
|
||||
translatedName: "English (UK)",
|
||||
icon: flagIcon("gb"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/en/index.esm.mjs").then((module) => module.MRT_Localization_EN);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/en-gb").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
en: {
|
||||
name: "English (US)",
|
||||
translatedName: "English (US)",
|
||||
icon: flagIcon("us"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/en/index.esm.mjs").then((module) => module.MRT_Localization_EN);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/en").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
el: {
|
||||
name: "Ελληνικά",
|
||||
translatedName: "Greek",
|
||||
icon: flagIcon("gr"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/el/index.esm.mjs").then((module) => module.MRT_Localization_EL);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/el").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
es: {
|
||||
name: "Español",
|
||||
translatedName: "Spanish",
|
||||
icon: flagIcon("es"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/es/index.esm.mjs").then((module) => module.MRT_Localization_ES);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/es").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
et: {
|
||||
name: "Eesti",
|
||||
translatedName: "Estonian",
|
||||
icon: flagIcon("ee"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/et/index.esm.mjs").then((module) => module.MRT_Localization_ET);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/et").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
fr: {
|
||||
name: "Français",
|
||||
translatedName: "French",
|
||||
icon: flagIcon("fr"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/fr/index.esm.mjs").then((module) => module.MRT_Localization_FR);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/fr").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
he: {
|
||||
name: "עברית",
|
||||
translatedName: "Hebrew",
|
||||
icon: flagIcon("il"),
|
||||
isRTL: true,
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/he/index.esm.mjs").then((module) => module.MRT_Localization_HE);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/he").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
hr: {
|
||||
name: "Hrvatski",
|
||||
translatedName: "Croatian",
|
||||
icon: flagIcon("hr"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/hr/index.esm.mjs").then((module) => module.MRT_Localization_HR);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/hr").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
hu: {
|
||||
name: "Magyar",
|
||||
translatedName: "Hungarian",
|
||||
icon: flagIcon("hu"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/hu/index.esm.mjs").then((module) => module.MRT_Localization_HU);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/hu").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
it: {
|
||||
name: "Italiano",
|
||||
translatedName: "Italian",
|
||||
icon: flagIcon("it"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/it/index.esm.mjs").then((module) => module.MRT_Localization_IT);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/it").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
ja: {
|
||||
name: "日本語",
|
||||
translatedName: "Japanese",
|
||||
icon: flagIcon("jp"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/ja/index.esm.mjs").then((module) => module.MRT_Localization_JA);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/ja").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
ko: {
|
||||
name: "한국어",
|
||||
translatedName: "Korean",
|
||||
icon: flagIcon("kr"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/ko/index.esm.mjs").then((module) => module.MRT_Localization_KO);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/ko").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
lt: {
|
||||
name: "Lietuvių",
|
||||
translatedName: "Lithuanian",
|
||||
icon: flagIcon("lt"),
|
||||
importMrtLocalization() {
|
||||
return import("./mantine-react-table/lt.json");
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/lt").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
lv: {
|
||||
name: "Latviešu",
|
||||
translatedName: "Latvian",
|
||||
icon: flagIcon("lv"),
|
||||
importMrtLocalization() {
|
||||
return import("./mantine-react-table/lv.json");
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/lv").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
nl: {
|
||||
name: "Nederlands",
|
||||
translatedName: "Dutch",
|
||||
icon: flagIcon("nl"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/nl/index.esm.mjs").then((module) => module.MRT_Localization_NL);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/nl").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
no: {
|
||||
name: "Norsk",
|
||||
translatedName: "Norwegian",
|
||||
icon: flagIcon("no"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/no/index.esm.mjs").then((module) => module.MRT_Localization_NO);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/nb").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
pl: {
|
||||
name: "Polski",
|
||||
translatedName: "Polish",
|
||||
icon: flagIcon("pl"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/pl/index.esm.mjs").then((module) => module.MRT_Localization_PL);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/pl").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
pt: {
|
||||
name: "Português",
|
||||
translatedName: "Portuguese",
|
||||
icon: flagIcon("pt"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/pt/index.esm.mjs").then((module) => module.MRT_Localization_PT);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/pt").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
ro: {
|
||||
name: "Românesc",
|
||||
translatedName: "Romanian",
|
||||
icon: flagIcon("ro"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/ro/index.esm.mjs").then((module) => module.MRT_Localization_RO);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/ro").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
ru: {
|
||||
name: "Русский",
|
||||
translatedName: "Russian",
|
||||
icon: flagIcon("ru"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/ru/index.esm.mjs").then((module) => module.MRT_Localization_RU);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/ru").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
sk: {
|
||||
name: "Slovenčina",
|
||||
translatedName: "Slovak",
|
||||
icon: flagIcon("sk"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/sk/index.esm.mjs").then((module) => module.MRT_Localization_SK);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/sk").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
sl: {
|
||||
name: "Slovenščina",
|
||||
translatedName: "Slovenian",
|
||||
icon: flagIcon("si"),
|
||||
importMrtLocalization() {
|
||||
return import("./mantine-react-table/sl.json");
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/sl").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
sv: {
|
||||
name: "Svenska",
|
||||
translatedName: "Swedish",
|
||||
icon: flagIcon("se"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/sv/index.esm.mjs").then((module) => module.MRT_Localization_SV);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/sv").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
tr: {
|
||||
name: "Türkçe",
|
||||
translatedName: "Turkish",
|
||||
icon: flagIcon("tr"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/tr/index.esm.mjs").then((module) => module.MRT_Localization_TR);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/tr").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
zh: {
|
||||
name: "中文",
|
||||
translatedName: "Chinese (Traditional)",
|
||||
icon: flagIcon("tw"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/zh-Hant/index.esm.mjs").then(
|
||||
(module) => module.MRT_Localization_ZH_HANT,
|
||||
);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/zh-tw").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
uk: {
|
||||
name: "Українська",
|
||||
translatedName: "Ukrainian",
|
||||
icon: flagIcon("ua"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/uk/index.esm.mjs").then((module) => module.MRT_Localization_UK);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/uk").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
vi: {
|
||||
name: "Tiếng Việt",
|
||||
translatedName: "Vietnamese",
|
||||
icon: flagIcon("vn"),
|
||||
importMrtLocalization() {
|
||||
return import("mantine-react-table/locales/vi/index.esm.mjs").then((module) => module.MRT_Localization_VI);
|
||||
},
|
||||
importDayJsLocale() {
|
||||
return import("dayjs/locale/vi").then((module) => module.default);
|
||||
},
|
||||
},
|
||||
} satisfies Record<
|
||||
string,
|
||||
{
|
||||
name: string;
|
||||
translatedName: string;
|
||||
icon: LanguageIconDefinition;
|
||||
importMrtLocalization: () => Promise<MRT_Localization>;
|
||||
importDayJsLocale: () => Promise<ILocale>;
|
||||
isRTL?: boolean;
|
||||
}
|
||||
>;
|
||||
|
||||
function flagIcon<TCode extends string>(flag: TCode) {
|
||||
return { type: "flag" as const, flag };
|
||||
}
|
||||
|
||||
export type LanguageIconDefinition =
|
||||
| {
|
||||
type: "flag";
|
||||
flag: string;
|
||||
}
|
||||
| {
|
||||
type: "custom";
|
||||
url: string;
|
||||
};
|
||||
|
||||
export const supportedLanguages = objectKeys(localeConfigurations);
|
||||
export type SupportedLanguage = (typeof supportedLanguages)[number];
|
||||
|
||||
export const fallbackLocale = "en" satisfies SupportedLanguage;
|
||||
|
||||
export const isLocaleRTL = (locale: SupportedLanguage) =>
|
||||
"isRTL" in localeConfigurations[locale] && localeConfigurations[locale].isRTL;
|
||||
@@ -0,0 +1,48 @@
|
||||
import { useParams } from "next/navigation";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import type { SupportedLanguage } from "./config";
|
||||
import { localeConfigurations } from "./config";
|
||||
|
||||
let promise: Promise<void> | null = null;
|
||||
let loading = true;
|
||||
let previousLocale: SupportedLanguage | null = null;
|
||||
const load = () => {
|
||||
if (loading) {
|
||||
// eslint-disable-next-line @typescript-eslint/only-throw-error
|
||||
throw promise;
|
||||
}
|
||||
};
|
||||
const dayJsLocalization = (locale: SupportedLanguage) => {
|
||||
if (promise && previousLocale === locale) {
|
||||
return {
|
||||
load,
|
||||
};
|
||||
}
|
||||
promise = localeConfigurations[locale]
|
||||
.importDayJsLocale()
|
||||
.then((dayJsLocale) => {
|
||||
dayjs.locale(dayJsLocale);
|
||||
loading = false;
|
||||
previousLocale = locale;
|
||||
})
|
||||
.catch(() => {
|
||||
loading = false;
|
||||
});
|
||||
|
||||
return {
|
||||
load,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Load the dayjs localization for the current locale with suspense
|
||||
* This allows us to have the loading spinner shown until the localization is loaded and applied.
|
||||
* Suspense works by throwing a promise, which is caught by the nearest Suspense boundary.
|
||||
*/
|
||||
export const useSuspenseDayJsLocalization = () => {
|
||||
const { locale } = useParams<{ locale: SupportedLanguage }>();
|
||||
const resource = dayJsLocalization(locale);
|
||||
|
||||
resource.load();
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { SupportedLanguage } from "./config";
|
||||
import { supportedLanguages } from "./config";
|
||||
import type { stringOrTranslation, TranslationFunction } from "./type";
|
||||
|
||||
export * from "./type";
|
||||
export * from "./config";
|
||||
export { createLanguageMapping } from "./mapping";
|
||||
export type { TranslationKeys } from "./mapping";
|
||||
|
||||
export const translateIfNecessary = (t: TranslationFunction, value: stringOrTranslation | undefined) => {
|
||||
if (typeof value === "function") {
|
||||
return value(t);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
export const isLocaleSupported = (locale: string): locale is SupportedLanguage => {
|
||||
return supportedLanguages.includes(locale as SupportedLanguage);
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,93 @@
|
||||
{
|
||||
"actions": "",
|
||||
"and": "",
|
||||
"cancel": "",
|
||||
"changeFilterMode": "",
|
||||
"changeSearchMode": "",
|
||||
"clearFilter": "",
|
||||
"clearSearch": "",
|
||||
"clearSelection": "",
|
||||
"clearSort": "",
|
||||
"clickToCopy": "",
|
||||
"copy": "",
|
||||
"collapse": "",
|
||||
"collapseAll": "",
|
||||
"columnActions": "",
|
||||
"copiedToClipboard": "",
|
||||
"dropToGroupBy": "",
|
||||
"edit": "",
|
||||
"expand": "",
|
||||
"expandAll": "",
|
||||
"filterArrIncludes": "",
|
||||
"filterArrIncludesAll": "",
|
||||
"filterArrIncludesSome": "",
|
||||
"filterBetween": "",
|
||||
"filterBetweenInclusive": "",
|
||||
"filterByColumn": "",
|
||||
"filterContains": "",
|
||||
"filterEmpty": "",
|
||||
"filterEndsWith": "",
|
||||
"filterEquals": "",
|
||||
"filterEqualsString": "",
|
||||
"filterFuzzy": "",
|
||||
"filterGreaterThan": "",
|
||||
"filterGreaterThanOrEqualTo": "",
|
||||
"filterInNumberRange": "",
|
||||
"filterIncludesString": "",
|
||||
"filterIncludesStringSensitive": "",
|
||||
"filterLessThan": "",
|
||||
"filterLessThanOrEqualTo": "",
|
||||
"filterMode": "",
|
||||
"filterNotEmpty": "",
|
||||
"filterNotEquals": "",
|
||||
"filterStartsWith": "",
|
||||
"filterWeakEquals": "",
|
||||
"filteringByColumn": "",
|
||||
"goToFirstPage": "",
|
||||
"goToLastPage": "",
|
||||
"goToNextPage": "",
|
||||
"goToPreviousPage": "",
|
||||
"grab": "",
|
||||
"groupByColumn": "",
|
||||
"groupedBy": "",
|
||||
"hideAll": "",
|
||||
"hideColumn": "",
|
||||
"max": "",
|
||||
"min": "",
|
||||
"move": "",
|
||||
"noRecordsToDisplay": "",
|
||||
"noResultsFound": "",
|
||||
"of": "",
|
||||
"or": "",
|
||||
"pin": "",
|
||||
"pinToLeft": "",
|
||||
"pinToRight": "",
|
||||
"resetColumnSize": "",
|
||||
"resetOrder": "",
|
||||
"rowActions": "",
|
||||
"rowNumber": "",
|
||||
"rowNumbers": "",
|
||||
"rowsPerPage": "",
|
||||
"save": "",
|
||||
"search": "",
|
||||
"selectedCountOfRowCountRowsSelected": "",
|
||||
"select": "",
|
||||
"showAll": "",
|
||||
"showAllColumns": "",
|
||||
"showHideColumns": "",
|
||||
"showHideFilters": "",
|
||||
"showHideSearch": "",
|
||||
"sortByColumnAsc": "",
|
||||
"sortByColumnDesc": "",
|
||||
"sortedByColumnAsc": "",
|
||||
"sortedByColumnDesc": "",
|
||||
"thenBy": "",
|
||||
"toggleDensity": "",
|
||||
"toggleFullScreen": "",
|
||||
"toggleSelectAll": "",
|
||||
"toggleSelectRow": "",
|
||||
"toggleVisibility": "",
|
||||
"ungroupByColumn": "",
|
||||
"unpin": "",
|
||||
"unpinAll": ""
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
{
|
||||
"actions": "Actions",
|
||||
"and": "and",
|
||||
"cancel": "Cancel",
|
||||
"changeFilterMode": "Change filter mode",
|
||||
"changeSearchMode": "Change search mode",
|
||||
"clearFilter": "Clear filter",
|
||||
"clearSearch": "Clear search",
|
||||
"clearSelection": "Clear selection",
|
||||
"clearSort": "Clear sort",
|
||||
"clickToCopy": "Click to copy",
|
||||
"copy": "Copy",
|
||||
"collapse": "Collapse",
|
||||
"collapseAll": "Collapse all",
|
||||
"columnActions": "Column Actions",
|
||||
"copiedToClipboard": "Copied to clipboard",
|
||||
"dropToGroupBy": "Drop to group by {column}",
|
||||
"edit": "Edit",
|
||||
"expand": "Expand",
|
||||
"expandAll": "Expand all",
|
||||
"filterArrIncludes": "Includes",
|
||||
"filterArrIncludesAll": "Includes all",
|
||||
"filterArrIncludesSome": "Includes",
|
||||
"filterBetween": "Between",
|
||||
"filterBetweenInclusive": "Between Inclusive",
|
||||
"filterByColumn": "Filter by {column}",
|
||||
"filterContains": "Contains",
|
||||
"filterEmpty": "Empty",
|
||||
"filterEndsWith": "Ends With",
|
||||
"filterEquals": "Equals",
|
||||
"filterEqualsString": "Equals",
|
||||
"filterFuzzy": "Fuzzy",
|
||||
"filterGreaterThan": "Greater Than",
|
||||
"filterGreaterThanOrEqualTo": "Greater Than Or Equal To",
|
||||
"filterInNumberRange": "Between",
|
||||
"filterIncludesString": "Contains",
|
||||
"filterIncludesStringSensitive": "Contains",
|
||||
"filterLessThan": "Less Than",
|
||||
"filterLessThanOrEqualTo": "Less Than Or Equal To",
|
||||
"filterMode": "Filter Mode: {filterType}",
|
||||
"filterNotEmpty": "Not Empty",
|
||||
"filterNotEquals": "Not Equals",
|
||||
"filterStartsWith": "Starts With",
|
||||
"filterWeakEquals": "Equals",
|
||||
"filteringByColumn": "Filtering by {column} - {filterType} {filterValue}",
|
||||
"goToFirstPage": "Go to first page",
|
||||
"goToLastPage": "Go to last page",
|
||||
"goToNextPage": "Go to next page",
|
||||
"goToPreviousPage": "Go to previous page",
|
||||
"grab": "Grab",
|
||||
"groupByColumn": "Group by {column}",
|
||||
"groupedBy": "Grouped by ",
|
||||
"hideAll": "Hide all",
|
||||
"hideColumn": "Hide {column} column",
|
||||
"max": "Max",
|
||||
"min": "Min",
|
||||
"move": "Move",
|
||||
"noRecordsToDisplay": "No records to display",
|
||||
"noResultsFound": "No results found",
|
||||
"of": "of",
|
||||
"or": "or",
|
||||
"pin": "Pin",
|
||||
"pinToLeft": "Pin to left",
|
||||
"pinToRight": "Pin to right",
|
||||
"resetColumnSize": "Reset column size",
|
||||
"resetOrder": "Reset order",
|
||||
"rowActions": "Row Actions",
|
||||
"rowNumber": "#",
|
||||
"rowNumbers": "Row Numbers",
|
||||
"rowsPerPage": "Rows per page",
|
||||
"save": "Save",
|
||||
"search": "Search",
|
||||
"selectedCountOfRowCountRowsSelected": "{selectedCount} of {rowCount} row(s) selected",
|
||||
"select": "Select",
|
||||
"showAll": "Show all",
|
||||
"showAllColumns": "Show all columns",
|
||||
"showHideColumns": "Show/Hide columns",
|
||||
"showHideFilters": "Show/Hide filters",
|
||||
"showHideSearch": "Show/Hide search",
|
||||
"sortByColumnAsc": "Sort by {column} ascending",
|
||||
"sortByColumnDesc": "Sort by {column} descending",
|
||||
"sortedByColumnAsc": "Sorted by {column} ascending",
|
||||
"sortedByColumnDesc": "Sorted by {column} descending",
|
||||
"thenBy": ", then by ",
|
||||
"toggleDensity": "Toggle density",
|
||||
"toggleFullScreen": "Toggle full screen",
|
||||
"toggleSelectAll": "Toggle select all",
|
||||
"toggleSelectRow": "Toggle select row",
|
||||
"toggleVisibility": "Toggle visibility",
|
||||
"ungroupByColumn": "Ungroup by {column}",
|
||||
"unpin": "Unpin",
|
||||
"unpinAll": "Unpin all"
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
{
|
||||
"actions": "",
|
||||
"and": "",
|
||||
"cancel": "",
|
||||
"changeFilterMode": "",
|
||||
"changeSearchMode": "",
|
||||
"clearFilter": "",
|
||||
"clearSearch": "",
|
||||
"clearSelection": "",
|
||||
"clearSort": "",
|
||||
"clickToCopy": "",
|
||||
"copy": "",
|
||||
"collapse": "",
|
||||
"collapseAll": "",
|
||||
"columnActions": "",
|
||||
"copiedToClipboard": "",
|
||||
"dropToGroupBy": "",
|
||||
"edit": "",
|
||||
"expand": "",
|
||||
"expandAll": "",
|
||||
"filterArrIncludes": "",
|
||||
"filterArrIncludesAll": "",
|
||||
"filterArrIncludesSome": "",
|
||||
"filterBetween": "",
|
||||
"filterBetweenInclusive": "",
|
||||
"filterByColumn": "",
|
||||
"filterContains": "",
|
||||
"filterEmpty": "",
|
||||
"filterEndsWith": "",
|
||||
"filterEquals": "",
|
||||
"filterEqualsString": "",
|
||||
"filterFuzzy": "",
|
||||
"filterGreaterThan": "",
|
||||
"filterGreaterThanOrEqualTo": "",
|
||||
"filterInNumberRange": "",
|
||||
"filterIncludesString": "",
|
||||
"filterIncludesStringSensitive": "",
|
||||
"filterLessThan": "",
|
||||
"filterLessThanOrEqualTo": "",
|
||||
"filterMode": "",
|
||||
"filterNotEmpty": "",
|
||||
"filterNotEquals": "",
|
||||
"filterStartsWith": "",
|
||||
"filterWeakEquals": "",
|
||||
"filteringByColumn": "",
|
||||
"goToFirstPage": "",
|
||||
"goToLastPage": "",
|
||||
"goToNextPage": "",
|
||||
"goToPreviousPage": "",
|
||||
"grab": "",
|
||||
"groupByColumn": "",
|
||||
"groupedBy": "",
|
||||
"hideAll": "",
|
||||
"hideColumn": "",
|
||||
"max": "",
|
||||
"min": "",
|
||||
"move": "",
|
||||
"noRecordsToDisplay": "",
|
||||
"noResultsFound": "",
|
||||
"of": "",
|
||||
"or": "",
|
||||
"pin": "",
|
||||
"pinToLeft": "",
|
||||
"pinToRight": "",
|
||||
"resetColumnSize": "",
|
||||
"resetOrder": "",
|
||||
"rowActions": "",
|
||||
"rowNumber": "",
|
||||
"rowNumbers": "",
|
||||
"rowsPerPage": "",
|
||||
"save": "",
|
||||
"search": "",
|
||||
"selectedCountOfRowCountRowsSelected": "",
|
||||
"select": "",
|
||||
"showAll": "",
|
||||
"showAllColumns": "",
|
||||
"showHideColumns": "",
|
||||
"showHideFilters": "",
|
||||
"showHideSearch": "",
|
||||
"sortByColumnAsc": "",
|
||||
"sortByColumnDesc": "",
|
||||
"sortedByColumnAsc": "",
|
||||
"sortedByColumnDesc": "",
|
||||
"thenBy": "",
|
||||
"toggleDensity": "",
|
||||
"toggleFullScreen": "",
|
||||
"toggleSelectAll": "",
|
||||
"toggleSelectRow": "",
|
||||
"toggleVisibility": "",
|
||||
"ungroupByColumn": "",
|
||||
"unpin": "",
|
||||
"unpinAll": ""
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
{
|
||||
"actions": "",
|
||||
"and": "",
|
||||
"cancel": "",
|
||||
"changeFilterMode": "",
|
||||
"changeSearchMode": "",
|
||||
"clearFilter": "",
|
||||
"clearSearch": "",
|
||||
"clearSelection": "",
|
||||
"clearSort": "",
|
||||
"clickToCopy": "",
|
||||
"copy": "",
|
||||
"collapse": "",
|
||||
"collapseAll": "",
|
||||
"columnActions": "",
|
||||
"copiedToClipboard": "",
|
||||
"dropToGroupBy": "",
|
||||
"edit": "",
|
||||
"expand": "",
|
||||
"expandAll": "",
|
||||
"filterArrIncludes": "",
|
||||
"filterArrIncludesAll": "",
|
||||
"filterArrIncludesSome": "",
|
||||
"filterBetween": "",
|
||||
"filterBetweenInclusive": "",
|
||||
"filterByColumn": "",
|
||||
"filterContains": "",
|
||||
"filterEmpty": "",
|
||||
"filterEndsWith": "",
|
||||
"filterEquals": "",
|
||||
"filterEqualsString": "",
|
||||
"filterFuzzy": "",
|
||||
"filterGreaterThan": "",
|
||||
"filterGreaterThanOrEqualTo": "",
|
||||
"filterInNumberRange": "",
|
||||
"filterIncludesString": "",
|
||||
"filterIncludesStringSensitive": "",
|
||||
"filterLessThan": "",
|
||||
"filterLessThanOrEqualTo": "",
|
||||
"filterMode": "",
|
||||
"filterNotEmpty": "",
|
||||
"filterNotEquals": "",
|
||||
"filterStartsWith": "",
|
||||
"filterWeakEquals": "",
|
||||
"filteringByColumn": "",
|
||||
"goToFirstPage": "",
|
||||
"goToLastPage": "",
|
||||
"goToNextPage": "",
|
||||
"goToPreviousPage": "",
|
||||
"grab": "",
|
||||
"groupByColumn": "",
|
||||
"groupedBy": "",
|
||||
"hideAll": "",
|
||||
"hideColumn": "",
|
||||
"max": "",
|
||||
"min": "",
|
||||
"move": "",
|
||||
"noRecordsToDisplay": "",
|
||||
"noResultsFound": "",
|
||||
"of": "",
|
||||
"or": "",
|
||||
"pin": "",
|
||||
"pinToLeft": "",
|
||||
"pinToRight": "",
|
||||
"resetColumnSize": "",
|
||||
"resetOrder": "",
|
||||
"rowActions": "",
|
||||
"rowNumber": "",
|
||||
"rowNumbers": "",
|
||||
"rowsPerPage": "",
|
||||
"save": "",
|
||||
"search": "",
|
||||
"selectedCountOfRowCountRowsSelected": "",
|
||||
"select": "",
|
||||
"showAll": "",
|
||||
"showAllColumns": "",
|
||||
"showHideColumns": "",
|
||||
"showHideFilters": "",
|
||||
"showHideSearch": "",
|
||||
"sortByColumnAsc": "",
|
||||
"sortByColumnDesc": "",
|
||||
"sortedByColumnAsc": "",
|
||||
"sortedByColumnDesc": "",
|
||||
"thenBy": "",
|
||||
"toggleDensity": "",
|
||||
"toggleFullScreen": "",
|
||||
"toggleSelectAll": "",
|
||||
"toggleSelectRow": "",
|
||||
"toggleVisibility": "",
|
||||
"ungroupByColumn": "",
|
||||
"unpin": "",
|
||||
"unpinAll": ""
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
{
|
||||
"actions": "",
|
||||
"and": "",
|
||||
"cancel": "",
|
||||
"changeFilterMode": "",
|
||||
"changeSearchMode": "",
|
||||
"clearFilter": "",
|
||||
"clearSearch": "",
|
||||
"clearSelection": "",
|
||||
"clearSort": "",
|
||||
"clickToCopy": "",
|
||||
"copy": "",
|
||||
"collapse": "",
|
||||
"collapseAll": "",
|
||||
"columnActions": "",
|
||||
"copiedToClipboard": "",
|
||||
"dropToGroupBy": "",
|
||||
"edit": "",
|
||||
"expand": "",
|
||||
"expandAll": "",
|
||||
"filterArrIncludes": "",
|
||||
"filterArrIncludesAll": "",
|
||||
"filterArrIncludesSome": "",
|
||||
"filterBetween": "",
|
||||
"filterBetweenInclusive": "",
|
||||
"filterByColumn": "",
|
||||
"filterContains": "",
|
||||
"filterEmpty": "",
|
||||
"filterEndsWith": "",
|
||||
"filterEquals": "",
|
||||
"filterEqualsString": "",
|
||||
"filterFuzzy": "",
|
||||
"filterGreaterThan": "",
|
||||
"filterGreaterThanOrEqualTo": "",
|
||||
"filterInNumberRange": "",
|
||||
"filterIncludesString": "",
|
||||
"filterIncludesStringSensitive": "",
|
||||
"filterLessThan": "",
|
||||
"filterLessThanOrEqualTo": "",
|
||||
"filterMode": "",
|
||||
"filterNotEmpty": "",
|
||||
"filterNotEquals": "",
|
||||
"filterStartsWith": "",
|
||||
"filterWeakEquals": "",
|
||||
"filteringByColumn": "",
|
||||
"goToFirstPage": "",
|
||||
"goToLastPage": "",
|
||||
"goToNextPage": "",
|
||||
"goToPreviousPage": "",
|
||||
"grab": "",
|
||||
"groupByColumn": "",
|
||||
"groupedBy": "",
|
||||
"hideAll": "",
|
||||
"hideColumn": "",
|
||||
"max": "",
|
||||
"min": "",
|
||||
"move": "",
|
||||
"noRecordsToDisplay": "",
|
||||
"noResultsFound": "",
|
||||
"of": "",
|
||||
"or": "",
|
||||
"pin": "",
|
||||
"pinToLeft": "",
|
||||
"pinToRight": "",
|
||||
"resetColumnSize": "",
|
||||
"resetOrder": "",
|
||||
"rowActions": "",
|
||||
"rowNumber": "",
|
||||
"rowNumbers": "",
|
||||
"rowsPerPage": "",
|
||||
"save": "",
|
||||
"search": "",
|
||||
"selectedCountOfRowCountRowsSelected": "",
|
||||
"select": "",
|
||||
"showAll": "",
|
||||
"showAllColumns": "",
|
||||
"showHideColumns": "",
|
||||
"showHideFilters": "",
|
||||
"showHideSearch": "",
|
||||
"sortByColumnAsc": "",
|
||||
"sortByColumnDesc": "",
|
||||
"sortedByColumnAsc": "",
|
||||
"sortedByColumnDesc": "",
|
||||
"thenBy": "",
|
||||
"toggleDensity": "",
|
||||
"toggleFullScreen": "",
|
||||
"toggleSelectAll": "",
|
||||
"toggleSelectRow": "",
|
||||
"toggleVisibility": "",
|
||||
"ungroupByColumn": "",
|
||||
"unpin": "",
|
||||
"unpinAll": ""
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { supportedLanguages } from "./config";
|
||||
|
||||
const _enTranslations = () => import("./lang/en.json");
|
||||
type EnTranslation = typeof _enTranslations;
|
||||
|
||||
export const createLanguageMapping = () => {
|
||||
const mapping: Record<string, unknown> = {};
|
||||
|
||||
for (const language of supportedLanguages) {
|
||||
mapping[language] = () => import(`./lang/${language}.json`);
|
||||
}
|
||||
|
||||
return mapping as Record<(typeof supportedLanguages)[number], () => ReturnType<EnTranslation>>;
|
||||
};
|
||||
|
||||
type NestedKeyOf<ObjectType extends object> = {
|
||||
[Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object
|
||||
? `${Key}` | `${Key}.${NestedKeyOf<ObjectType[Key]>}`
|
||||
: `${Key}`;
|
||||
}[keyof ObjectType & (string | number)];
|
||||
|
||||
export type TranslationKeys = NestedKeyOf<EnTranslation>;
|
||||
@@ -0,0 +1,13 @@
|
||||
import createMiddleware from "next-intl/middleware";
|
||||
|
||||
import type { SupportedLanguage } from ".";
|
||||
import { supportedLanguages } from "./config";
|
||||
import { createRouting } from "./routing";
|
||||
|
||||
export const createI18nMiddleware = (defaultLocale: SupportedLanguage) =>
|
||||
createMiddleware(createRouting(defaultLocale));
|
||||
|
||||
export const config = {
|
||||
// Match only internationalized pathnames
|
||||
matcher: ["/", `/(${supportedLanguages.join("|")})/:path*`],
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
import deepmerge from "deepmerge";
|
||||
import { getRequestConfig } from "next-intl/server";
|
||||
|
||||
import type { TranslationObject } from ".";
|
||||
import { fallbackLocale, isLocaleSupported } from ".";
|
||||
import type { SupportedLanguage } from "./config";
|
||||
import { createLanguageMapping } from "./mapping";
|
||||
|
||||
// This file is referenced in the `next.config.js` file. See https://next-intl-docs.vercel.app/docs/usage/configuration
|
||||
export default getRequestConfig(async ({ requestLocale }) => {
|
||||
let currentLocale = await requestLocale;
|
||||
|
||||
if (!currentLocale || !isLocaleSupported(currentLocale)) {
|
||||
currentLocale = fallbackLocale;
|
||||
}
|
||||
const typedLocale = currentLocale as SupportedLanguage;
|
||||
|
||||
const languageMap = createLanguageMapping();
|
||||
const currentMessages = removeEmptyTranslations((await languageMap[typedLocale]()).default) as TranslationObject;
|
||||
|
||||
// Fallback to default locale if the current locales messages if not all messages are present
|
||||
if (currentLocale !== fallbackLocale) {
|
||||
const fallbackMessages = (await languageMap[fallbackLocale]()).default;
|
||||
return {
|
||||
locale: typedLocale,
|
||||
messages: deepmerge(fallbackMessages, currentMessages),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
locale: currentLocale,
|
||||
messages: currentMessages,
|
||||
};
|
||||
});
|
||||
|
||||
const removeEmptyTranslations = (translations: Record<string, unknown>): Record<string, unknown> => {
|
||||
return Object.entries(translations).reduce(
|
||||
(acc, [key, value]) => {
|
||||
if (typeof value !== "string") {
|
||||
return {
|
||||
...acc,
|
||||
[key]: removeEmptyTranslations(value as Record<string, unknown>),
|
||||
};
|
||||
}
|
||||
|
||||
if (value.trim() === "") {
|
||||
return acc;
|
||||
}
|
||||
|
||||
return {
|
||||
...acc,
|
||||
[key]: value,
|
||||
};
|
||||
},
|
||||
{} as Record<string, unknown>,
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import { defineRouting } from "next-intl/routing";
|
||||
|
||||
import { localeCookieKey } from "@homarr/definitions";
|
||||
|
||||
import type { SupportedLanguage } from "./config";
|
||||
import { supportedLanguages } from "./config";
|
||||
|
||||
export const createRouting = (defaultLocale: SupportedLanguage) =>
|
||||
defineRouting({
|
||||
locales: supportedLanguages,
|
||||
defaultLocale,
|
||||
localeCookie: {
|
||||
name: localeCookieKey,
|
||||
// 1 year
|
||||
maxAge: 60 * 60 * 24 * 365,
|
||||
},
|
||||
localePrefix: {
|
||||
mode: "never", // Rewrite the URL with locale parameter but without shown in url
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import { getTranslations } from "next-intl/server";
|
||||
|
||||
import type { SupportedLanguage } from "./config";
|
||||
import type englishTranslation from "./lang/en.json";
|
||||
|
||||
declare module "next-intl" {
|
||||
interface AppConfig {
|
||||
Messages: typeof englishTranslation;
|
||||
Locale: SupportedLanguage;
|
||||
}
|
||||
}
|
||||
|
||||
export const { getI18n, getScopedI18n } = {
|
||||
getI18n: getTranslations,
|
||||
getScopedI18n: getTranslations,
|
||||
};
|
||||
|
||||
export { getMessages as getI18nMessages } from "next-intl/server";
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { NamespaceKeys, NestedKeyOf } from "next-intl";
|
||||
|
||||
import type { RemoveReadonly } from "@homarr/common/types";
|
||||
|
||||
import type { useI18n, useScopedI18n } from "./client";
|
||||
import type enTranslation from "./lang/en.json";
|
||||
|
||||
export type TranslationFunction = ReturnType<typeof useI18n<never>>;
|
||||
export type ScopedTranslationFunction<
|
||||
NestedKey extends NamespaceKeys<IntlMessages, NestedKeyOf<IntlMessages>> = never,
|
||||
> = ReturnType<typeof useScopedI18n<NestedKey>>;
|
||||
export type TranslationObject = typeof enTranslation;
|
||||
export type stringOrTranslation = string | ((t: TranslationFunction) => string);
|
||||
|
||||
declare global {
|
||||
// Use type safe message keys with `next-intl`
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
interface IntlMessages extends RemoveReadonly<TranslationObject> {}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "@homarr/tsconfig/base.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
|
||||
},
|
||||
"include": ["*.ts", "src"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user