Replace entire codebase with homarr-labs/homarr
This commit is contained in:
4
packages/translation/eslint.config.js
Normal file
4
packages/translation/eslint.config.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import baseConfig from "@homarr/eslint-config/base";
|
||||
|
||||
/** @type {import('typescript-eslint').Config} */
|
||||
export default [...baseConfig];
|
||||
1
packages/translation/index.ts
Normal file
1
packages/translation/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./src";
|
||||
47
packages/translation/package.json
Normal file
47
packages/translation/package.json
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
27
packages/translation/src/client/index.ts
Normal file
27
packages/translation/src/client/index.ts
Normal file
@@ -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 };
|
||||
25
packages/translation/src/client/use-change-locale.ts
Normal file
25
packages/translation/src/client/use-change-locale.ts
Normal file
@@ -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,
|
||||
};
|
||||
};
|
||||
3
packages/translation/src/client/use-current-locale.ts
Normal file
3
packages/translation/src/client/use-current-locale.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { useLocale } from "next-intl";
|
||||
|
||||
export const useCurrentLocale = useLocale;
|
||||
420
packages/translation/src/config.ts
Normal file
420
packages/translation/src/config.ts
Normal file
@@ -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;
|
||||
48
packages/translation/src/dayjs.ts
Normal file
48
packages/translation/src/dayjs.ts
Normal file
@@ -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();
|
||||
};
|
||||
19
packages/translation/src/index.ts
Normal file
19
packages/translation/src/index.ts
Normal file
@@ -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);
|
||||
};
|
||||
4535
packages/translation/src/lang/ca.json
Normal file
4535
packages/translation/src/lang/ca.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/cn.json
Normal file
4535
packages/translation/src/lang/cn.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/cr.json
Normal file
4535
packages/translation/src/lang/cr.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/cs.json
Normal file
4535
packages/translation/src/lang/cs.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/da.json
Normal file
4535
packages/translation/src/lang/da.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/de-CH.json
Normal file
4535
packages/translation/src/lang/de-CH.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/de.json
Normal file
4535
packages/translation/src/lang/de.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/el.json
Normal file
4535
packages/translation/src/lang/el.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/en-gb.json
Normal file
4535
packages/translation/src/lang/en-gb.json
Normal file
File diff suppressed because it is too large
Load Diff
4542
packages/translation/src/lang/en.json
Normal file
4542
packages/translation/src/lang/en.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/es.json
Normal file
4535
packages/translation/src/lang/es.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/et.json
Normal file
4535
packages/translation/src/lang/et.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/fr.json
Normal file
4535
packages/translation/src/lang/fr.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/he.json
Normal file
4535
packages/translation/src/lang/he.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/hr.json
Normal file
4535
packages/translation/src/lang/hr.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/hu.json
Normal file
4535
packages/translation/src/lang/hu.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/it.json
Normal file
4535
packages/translation/src/lang/it.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/ja.json
Normal file
4535
packages/translation/src/lang/ja.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/ko.json
Normal file
4535
packages/translation/src/lang/ko.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/lt.json
Normal file
4535
packages/translation/src/lang/lt.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/lv.json
Normal file
4535
packages/translation/src/lang/lv.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/nl.json
Normal file
4535
packages/translation/src/lang/nl.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/no.json
Normal file
4535
packages/translation/src/lang/no.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/pl.json
Normal file
4535
packages/translation/src/lang/pl.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/pt.json
Normal file
4535
packages/translation/src/lang/pt.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/ro.json
Normal file
4535
packages/translation/src/lang/ro.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/ru.json
Normal file
4535
packages/translation/src/lang/ru.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/sk.json
Normal file
4535
packages/translation/src/lang/sk.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/sl.json
Normal file
4535
packages/translation/src/lang/sl.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/sv.json
Normal file
4535
packages/translation/src/lang/sv.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/tr.json
Normal file
4535
packages/translation/src/lang/tr.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/uk.json
Normal file
4535
packages/translation/src/lang/uk.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/vi.json
Normal file
4535
packages/translation/src/lang/vi.json
Normal file
File diff suppressed because it is too large
Load Diff
4535
packages/translation/src/lang/zh.json
Normal file
4535
packages/translation/src/lang/zh.json
Normal file
File diff suppressed because it is too large
Load Diff
93
packages/translation/src/mantine-react-table/ca.json
Normal file
93
packages/translation/src/mantine-react-table/ca.json
Normal file
@@ -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": ""
|
||||
}
|
||||
93
packages/translation/src/mantine-react-table/en.json
Normal file
93
packages/translation/src/mantine-react-table/en.json
Normal file
@@ -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"
|
||||
}
|
||||
93
packages/translation/src/mantine-react-table/lt.json
Normal file
93
packages/translation/src/mantine-react-table/lt.json
Normal file
@@ -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": ""
|
||||
}
|
||||
93
packages/translation/src/mantine-react-table/lv.json
Normal file
93
packages/translation/src/mantine-react-table/lv.json
Normal file
@@ -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": ""
|
||||
}
|
||||
93
packages/translation/src/mantine-react-table/sl.json
Normal file
93
packages/translation/src/mantine-react-table/sl.json
Normal file
@@ -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": ""
|
||||
}
|
||||
22
packages/translation/src/mapping.ts
Normal file
22
packages/translation/src/mapping.ts
Normal file
@@ -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>;
|
||||
13
packages/translation/src/middleware.ts
Normal file
13
packages/translation/src/middleware.ts
Normal file
@@ -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*`],
|
||||
};
|
||||
57
packages/translation/src/request.ts
Normal file
57
packages/translation/src/request.ts
Normal file
@@ -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>,
|
||||
);
|
||||
};
|
||||
20
packages/translation/src/routing.ts
Normal file
20
packages/translation/src/routing.ts
Normal file
@@ -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
|
||||
},
|
||||
});
|
||||
18
packages/translation/src/server.ts
Normal file
18
packages/translation/src/server.ts
Normal file
@@ -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";
|
||||
19
packages/translation/src/type.ts
Normal file
19
packages/translation/src/type.ts
Normal file
@@ -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> {}
|
||||
}
|
||||
8
packages/translation/tsconfig.json
Normal file
8
packages/translation/tsconfig.json
Normal file
@@ -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