fix(deps): update dependency next-intl to v4 (#2580)
* fix(deps): update dependency next-intl to v4 * fix: typecheck issue * refactor: implement improvements for next-intl v4 * fix: typecheck issues * fix: typecheck issue --------- Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com> Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
This commit is contained in:
committed by
GitHub
parent
47ebc66c9e
commit
f55d8a9c2e
3
.gitignore
vendored
3
.gitignore
vendored
@@ -65,3 +65,6 @@ e2e/shared/tmp
|
|||||||
|
|
||||||
#personal backgrounds
|
#personal backgrounds
|
||||||
apps/nextjs/public/images/background.png
|
apps/nextjs/public/images/background.png
|
||||||
|
|
||||||
|
# next-intl
|
||||||
|
en.d.json.ts
|
||||||
@@ -10,7 +10,12 @@ import MillionLint from "@million/lint";
|
|||||||
import createNextIntlPlugin from "next-intl/plugin";
|
import createNextIntlPlugin from "next-intl/plugin";
|
||||||
|
|
||||||
// Package path does not work... so we need to use relative path
|
// Package path does not work... so we need to use relative path
|
||||||
const withNextIntl = createNextIntlPlugin("../../packages/translation/src/request.ts");
|
const withNextIntl = createNextIntlPlugin({
|
||||||
|
experimental: {
|
||||||
|
createMessagesDeclaration: "../../packages/translation/src/lang/en.json",
|
||||||
|
},
|
||||||
|
requestConfig: "../../packages/translation/src/request.ts",
|
||||||
|
});
|
||||||
|
|
||||||
interface WebpackConfig {
|
interface WebpackConfig {
|
||||||
module: {
|
module: {
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ export default async function InviteUsagePage(props: InviteUsagePageProps) {
|
|||||||
<RegistrationForm invite={invite} />
|
<RegistrationForm invite={invite} />
|
||||||
</Card>
|
</Card>
|
||||||
<Text size="xs" c="gray.5" ta="center">
|
<Text size="xs" c="gray.5" ta="center">
|
||||||
{t("description", { username: invite.creator.name })}
|
{/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */}
|
||||||
|
{t("description", { username: invite.creator.name! })}
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Center>
|
</Center>
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import { SettingsProvider } from "@homarr/settings";
|
|||||||
import { SpotlightProvider } from "@homarr/spotlight";
|
import { SpotlightProvider } from "@homarr/spotlight";
|
||||||
import type { SupportedLanguage } from "@homarr/translation";
|
import type { SupportedLanguage } from "@homarr/translation";
|
||||||
import { isLocaleRTL, isLocaleSupported } from "@homarr/translation";
|
import { isLocaleRTL, isLocaleSupported } from "@homarr/translation";
|
||||||
import { getI18nMessages } from "@homarr/translation/server";
|
|
||||||
|
|
||||||
import { Analytics } from "~/components/layout/analytics";
|
import { Analytics } from "~/components/layout/analytics";
|
||||||
import { SearchEngineOptimization } from "~/components/layout/search-engine-optimization";
|
import { SearchEngineOptimization } from "~/components/layout/search-engine-optimization";
|
||||||
@@ -81,7 +80,6 @@ export default async function Layout(props: {
|
|||||||
const serverSettings = await getServerSettingsAsync(db);
|
const serverSettings = await getServerSettingsAsync(db);
|
||||||
const colorScheme = await getCurrentColorSchemeAsync();
|
const colorScheme = await getCurrentColorSchemeAsync();
|
||||||
const direction = isLocaleRTL((await props.params).locale) ? "rtl" : "ltr";
|
const direction = isLocaleRTL((await props.params).locale) ? "rtl" : "ltr";
|
||||||
const i18nMessages = await getI18nMessages();
|
|
||||||
|
|
||||||
const StackedProvider = composeWrappers([
|
const StackedProvider = composeWrappers([
|
||||||
(innerProps) => {
|
(innerProps) => {
|
||||||
@@ -105,7 +103,7 @@ export default async function Layout(props: {
|
|||||||
(innerProps) => <JotaiProvider {...innerProps} />,
|
(innerProps) => <JotaiProvider {...innerProps} />,
|
||||||
(innerProps) => <TRPCReactProvider {...innerProps} />,
|
(innerProps) => <TRPCReactProvider {...innerProps} />,
|
||||||
(innerProps) => <DayJsLoader {...innerProps} />,
|
(innerProps) => <DayJsLoader {...innerProps} />,
|
||||||
(innerProps) => <NextIntlClientProvider {...innerProps} messages={i18nMessages} />,
|
(innerProps) => <NextIntlClientProvider {...innerProps} />,
|
||||||
(innerProps) => <CustomMantineProvider {...innerProps} defaultColorScheme={colorScheme} />,
|
(innerProps) => <CustomMantineProvider {...innerProps} defaultColorScheme={colorScheme} />,
|
||||||
(innerProps) => <ModalProvider {...innerProps} />,
|
(innerProps) => <ModalProvider {...innerProps} />,
|
||||||
(innerProps) => <SpotlightProvider {...innerProps} />,
|
(innerProps) => <SpotlightProvider {...innerProps} />,
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ export default async function AboutPage() {
|
|||||||
<Text>{t("accordion.contributors.title")}</Text>
|
<Text>{t("accordion.contributors.title")}</Text>
|
||||||
<Text size="sm" c="dimmed">
|
<Text size="sm" c="dimmed">
|
||||||
{t("accordion.contributors.subtitle", {
|
{t("accordion.contributors.subtitle", {
|
||||||
count: githubContributors.length,
|
count: String(githubContributors.length),
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -104,7 +104,7 @@ export default async function AboutPage() {
|
|||||||
<Text>{t("accordion.translators.title")}</Text>
|
<Text>{t("accordion.translators.title")}</Text>
|
||||||
<Text size="sm" c="dimmed">
|
<Text size="sm" c="dimmed">
|
||||||
{t("accordion.translators.subtitle", {
|
{t("accordion.translators.subtitle", {
|
||||||
count: crowdinContributors.length,
|
count: String(crowdinContributors.length),
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -128,7 +128,7 @@ export default async function AboutPage() {
|
|||||||
<Text>{t("accordion.libraries.title")}</Text>
|
<Text>{t("accordion.libraries.title")}</Text>
|
||||||
<Text size="sm" c="dimmed">
|
<Text size="sm" c="dimmed">
|
||||||
{t("accordion.libraries.subtitle", {
|
{t("accordion.libraries.subtitle", {
|
||||||
count: Object.keys(attributes.dependencies).length,
|
count: String(Object.keys(attributes.dependencies).length),
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ export const AppDeleteButton = ({ app }: AppDeleteButtonProps) => {
|
|||||||
const onClick = useCallback(() => {
|
const onClick = useCallback(() => {
|
||||||
openConfirmModal({
|
openConfirmModal({
|
||||||
title: t("title"),
|
title: t("title"),
|
||||||
children: t("message", app),
|
children: t("message", {
|
||||||
|
name: app.name,
|
||||||
|
}),
|
||||||
onConfirm: () => {
|
onConfirm: () => {
|
||||||
mutate(
|
mutate(
|
||||||
{ id: app.id },
|
{ id: app.id },
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ export const SearchEngineDeleteButton = ({ searchEngine }: SearchEngineDeleteBut
|
|||||||
const onClick = useCallback(() => {
|
const onClick = useCallback(() => {
|
||||||
openConfirmModal({
|
openConfirmModal({
|
||||||
title: t("title"),
|
title: t("title"),
|
||||||
children: t("message", searchEngine),
|
children: t("message", {
|
||||||
|
name: searchEngine.name,
|
||||||
|
}),
|
||||||
onConfirm: () => {
|
onConfirm: () => {
|
||||||
mutate(
|
mutate(
|
||||||
{ id: searchEngine.id },
|
{ id: searchEngine.id },
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export function DockerTable(initialData: RouterOutputs["docker"]["getContainers"
|
|||||||
enableBottomToolbar: false,
|
enableBottomToolbar: false,
|
||||||
positionGlobalFilter: "right",
|
positionGlobalFilter: "right",
|
||||||
mantineSearchTextInputProps: {
|
mantineSearchTextInputProps: {
|
||||||
placeholder: tDocker("table.search", { count: data.containers.length }),
|
placeholder: tDocker("table.search", { count: String(data.containers.length) }),
|
||||||
style: { minWidth: 300 },
|
style: { minWidth: 300 },
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
},
|
},
|
||||||
@@ -146,8 +146,8 @@ export function DockerTable(initialData: RouterOutputs["docker"]["getContainers"
|
|||||||
{groupedAlert}
|
{groupedAlert}
|
||||||
<Text fw={500}>
|
<Text fw={500}>
|
||||||
{tDocker("table.selected", {
|
{tDocker("table.selected", {
|
||||||
selectCount: table.getSelectedRowModel().rows.length,
|
selectCount: String(table.getSelectedRowModel().rows.length),
|
||||||
totalCount: table.getRowCount(),
|
totalCount: String(table.getRowCount()),
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
<ContainerActionBar selectedContainers={dockerContainers} />
|
<ContainerActionBar selectedContainers={dockerContainers} />
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export function ConfigmapsTable(initialData: ConfigMapsTableComponentProps) {
|
|||||||
positionGlobalFilter: "right",
|
positionGlobalFilter: "right",
|
||||||
initialState: { density: "xs", showGlobalFilter: true },
|
initialState: { density: "xs", showGlobalFilter: true },
|
||||||
mantineSearchTextInputProps: {
|
mantineSearchTextInputProps: {
|
||||||
placeholder: tConfigMaps("table.search", { count: data.length }),
|
placeholder: tConfigMaps("table.search", { count: String(data.length) }),
|
||||||
style: { minWidth: 300 },
|
style: { minWidth: 300 },
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export function IngressesTable(initialData: IngressesTableComponentProps) {
|
|||||||
positionGlobalFilter: "right",
|
positionGlobalFilter: "right",
|
||||||
initialState: { density: "xs", showGlobalFilter: true },
|
initialState: { density: "xs", showGlobalFilter: true },
|
||||||
mantineSearchTextInputProps: {
|
mantineSearchTextInputProps: {
|
||||||
placeholder: tIngresses("table.search", { count: data.length }),
|
placeholder: tIngresses("table.search", { count: String(data.length) }),
|
||||||
style: { minWidth: 300 },
|
style: { minWidth: 300 },
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ export function NamespacesTable(initialData: NamespacesTableComponentProps) {
|
|||||||
positionGlobalFilter: "right",
|
positionGlobalFilter: "right",
|
||||||
initialState: { density: "xs", showGlobalFilter: true },
|
initialState: { density: "xs", showGlobalFilter: true },
|
||||||
mantineSearchTextInputProps: {
|
mantineSearchTextInputProps: {
|
||||||
placeholder: tNamespaces("table.search", { count: data.length }),
|
placeholder: tNamespaces("table.search", { count: String(data.length) }),
|
||||||
style: { minWidth: 300 },
|
style: { minWidth: 300 },
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ export function NodesTable(initialData: NodesListComponentProps) {
|
|||||||
positionGlobalFilter: "right",
|
positionGlobalFilter: "right",
|
||||||
initialState: { density: "xs", showGlobalFilter: true },
|
initialState: { density: "xs", showGlobalFilter: true },
|
||||||
mantineSearchTextInputProps: {
|
mantineSearchTextInputProps: {
|
||||||
placeholder: tNodes("table.search", { count: data.length }),
|
placeholder: tNodes("table.search", { count: String(data.length) }),
|
||||||
style: { minWidth: 300 },
|
style: { minWidth: 300 },
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export function PodsTable(initialData: PodsTableComponentProps) {
|
|||||||
positionGlobalFilter: "right",
|
positionGlobalFilter: "right",
|
||||||
initialState: { density: "xs", showGlobalFilter: true, expanded: true },
|
initialState: { density: "xs", showGlobalFilter: true, expanded: true },
|
||||||
mantineSearchTextInputProps: {
|
mantineSearchTextInputProps: {
|
||||||
placeholder: tPods("table.search", { count: data.length }),
|
placeholder: tPods("table.search", { count: String(data.length) }),
|
||||||
style: { minWidth: 300 },
|
style: { minWidth: 300 },
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export function SecretsTable(initialData: SecretsTableComponentProps) {
|
|||||||
positionGlobalFilter: "right",
|
positionGlobalFilter: "right",
|
||||||
initialState: { density: "xs", showGlobalFilter: true },
|
initialState: { density: "xs", showGlobalFilter: true },
|
||||||
mantineSearchTextInputProps: {
|
mantineSearchTextInputProps: {
|
||||||
placeholder: tSecrets("table.search", { count: data.length }),
|
placeholder: tSecrets("table.search", { count: String(data.length) }),
|
||||||
style: { minWidth: 300 },
|
style: { minWidth: 300 },
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export function ServicesTable(initialData: ServicesTableComponentProps) {
|
|||||||
positionGlobalFilter: "right",
|
positionGlobalFilter: "right",
|
||||||
initialState: { density: "xs", showGlobalFilter: true },
|
initialState: { density: "xs", showGlobalFilter: true },
|
||||||
mantineSearchTextInputProps: {
|
mantineSearchTextInputProps: {
|
||||||
placeholder: tServices("table.search", { count: data.length }),
|
placeholder: tServices("table.search", { count: String(data.length) }),
|
||||||
style: { minWidth: 300 },
|
style: { minWidth: 300 },
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ export function VolumesTable(initialData: VolumesTableComponentProps) {
|
|||||||
positionGlobalFilter: "right",
|
positionGlobalFilter: "right",
|
||||||
initialState: { density: "xs", showGlobalFilter: true },
|
initialState: { density: "xs", showGlobalFilter: true },
|
||||||
mantineSearchTextInputProps: {
|
mantineSearchTextInputProps: {
|
||||||
placeholder: tVolumes("table.search", { count: data.length }),
|
placeholder: tVolumes("table.search", { count: String(data.length) }),
|
||||||
style: { minWidth: 300 },
|
style: { minWidth: 300 },
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ export const DeleteUserButton = ({ user }: DeleteUserButtonProps) => {
|
|||||||
() =>
|
() =>
|
||||||
openConfirmModal({
|
openConfirmModal({
|
||||||
title: t("user.action.delete.label"),
|
title: t("user.action.delete.label"),
|
||||||
children: t("user.action.delete.confirm", { username: user.name }),
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
children: t("user.action.delete.confirm", { username: user.name! }),
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
async onConfirm() {
|
async onConfirm() {
|
||||||
await mutateUserDeletionAsync({
|
await mutateUserDeletionAsync({
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ export async function generateMetadata(props: Props) {
|
|||||||
const t = await getScopedI18n("management.page.user.edit");
|
const t = await getScopedI18n("management.page.user.edit");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: createMetaTitle(t("metaTitle", { username: user.name })),
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
title: createMetaTitle(t("metaTitle", { username: user.name! })),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,10 @@ export const UserAvatarMenu = ({ children, availableUpdates }: UserAvatarMenuPro
|
|||||||
leftSection={<IconBellRinging size="1rem" />}
|
leftSection={<IconBellRinging size="1rem" />}
|
||||||
>
|
>
|
||||||
<Text fw="bold" size="sm">
|
<Text fw="bold" size="sm">
|
||||||
{t("updateAvailable", { countUpdates: availableUpdates.length, tag: availableUpdates[0].tagName })}
|
{t("updateAvailable", {
|
||||||
|
countUpdates: String(availableUpdates.length),
|
||||||
|
tag: availableUpdates[0].tagName,
|
||||||
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ export const IconPicker = ({ value: propsValue, onChange, error, onFocus, onBlur
|
|||||||
withAsterisk
|
withAsterisk
|
||||||
error={error}
|
error={error}
|
||||||
label={tCommon("iconPicker.label")}
|
label={tCommon("iconPicker.label")}
|
||||||
placeholder={tCommon("iconPicker.header", { countIcons: data?.countIcons ?? 0 })}
|
placeholder={tCommon("iconPicker.header", { countIcons: String(data?.countIcons ?? 0) })}
|
||||||
/>
|
/>
|
||||||
{session?.user.permissions.includes("media-upload") && (
|
{session?.user.permissions.includes("media-upload") && (
|
||||||
<UploadMedia
|
<UploadMedia
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export const BoardSelectionCard = ({ selections, updateSelections }: BoardSelect
|
|||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Stack gap={0}>
|
<Stack gap={0}>
|
||||||
<Group justify="space-between" align="center">
|
<Group justify="space-between" align="center">
|
||||||
<Text fw={500}>{tBoardSelection("title", { count: selections.size })}</Text>
|
<Text fw={500}>{tBoardSelection("title", { count: String(selections.size) })}</Text>
|
||||||
<Anchor component="button" onClick={handleToggleAll}>
|
<Anchor component="button" onClick={handleToggleAll}>
|
||||||
{areAllChecked ? tBoardSelection("action.unselectAll") : tBoardSelection("action.selectAll")}
|
{areAllChecked ? tBoardSelection("action.unselectAll") : tBoardSelection("action.selectAll")}
|
||||||
</Anchor>
|
</Anchor>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
"deepmerge": "4.3.1",
|
"deepmerge": "4.3.1",
|
||||||
"mantine-react-table": "2.0.0-beta.9",
|
"mantine-react-table": "2.0.0-beta.9",
|
||||||
"next": "15.1.7",
|
"next": "15.1.7",
|
||||||
"next-intl": "3.26.5",
|
"next-intl": "4.0.0",
|
||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
"react-dom": "19.0.0"
|
"react-dom": "19.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,18 +2,26 @@
|
|||||||
|
|
||||||
import { useMessages, useTranslations } from "next-intl";
|
import { useMessages, useTranslations } from "next-intl";
|
||||||
|
|
||||||
import type { TranslationObject } from "../type";
|
import type { SupportedLanguage } from "../config";
|
||||||
|
import type englishTranslation from "../lang/en.json";
|
||||||
|
|
||||||
export { useChangeLocale } from "./use-change-locale";
|
export { useChangeLocale } from "./use-change-locale";
|
||||||
export { useCurrentLocale } from "./use-current-locale";
|
export { useCurrentLocale } from "./use-current-locale";
|
||||||
|
|
||||||
|
declare module "next-intl" {
|
||||||
|
interface AppConfig {
|
||||||
|
Messages: typeof englishTranslation;
|
||||||
|
Locale: SupportedLanguage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const { useI18n, useScopedI18n } = {
|
export const { useI18n, useScopedI18n } = {
|
||||||
useI18n: useTranslations,
|
useI18n: useTranslations,
|
||||||
useScopedI18n: useTranslations,
|
useScopedI18n: useTranslations,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const { useI18nMessages } = {
|
export const { useI18nMessages } = {
|
||||||
useI18nMessages: () => useMessages() as TranslationObject,
|
useI18nMessages: () => useMessages(),
|
||||||
};
|
};
|
||||||
|
|
||||||
export { useTranslations };
|
export { useTranslations };
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { useLocale } from "next-intl";
|
import { useLocale } from "next-intl";
|
||||||
|
|
||||||
import type { SupportedLanguage } from "../config";
|
export const useCurrentLocale = useLocale;
|
||||||
|
|
||||||
export const useCurrentLocale = () => useLocale() as SupportedLanguage;
|
|
||||||
|
|||||||
@@ -3594,7 +3594,7 @@
|
|||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
"title": "Delete search engine",
|
"title": "Delete search engine",
|
||||||
"message": "Are you sure you want to delete the search engine '{name}'?",
|
"message": "Are you sure you want to delete the search engine {name}?",
|
||||||
"notification": {
|
"notification": {
|
||||||
"success": {
|
"success": {
|
||||||
"title": "Search engine deleted",
|
"title": "Search engine deleted",
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default getRequestConfig(async ({ requestLocale }) => {
|
|||||||
if (currentLocale !== fallbackLocale) {
|
if (currentLocale !== fallbackLocale) {
|
||||||
const fallbackMessages = (await languageMap[fallbackLocale]()).default;
|
const fallbackMessages = (await languageMap[fallbackLocale]()).default;
|
||||||
return {
|
return {
|
||||||
locale: currentLocale,
|
locale: typedLocale,
|
||||||
messages: deepmerge(fallbackMessages, currentMessages),
|
messages: deepmerge(fallbackMessages, currentMessages),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ export const createRouting = (defaultLocale: SupportedLanguage) =>
|
|||||||
defaultLocale,
|
defaultLocale,
|
||||||
localeCookie: {
|
localeCookie: {
|
||||||
name: localeCookieKey,
|
name: localeCookieKey,
|
||||||
|
// 1 year
|
||||||
|
maxAge: 60 * 60 * 24 * 365,
|
||||||
},
|
},
|
||||||
localePrefix: {
|
localePrefix: {
|
||||||
mode: "never", // Rewrite the URL with locale parameter but without shown in url
|
mode: "never", // Rewrite the URL with locale parameter but without shown in url
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
import { getTranslations } from "next-intl/server";
|
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 } = {
|
export const { getI18n, getScopedI18n } = {
|
||||||
getI18n: getTranslations,
|
getI18n: getTranslations,
|
||||||
getScopedI18n: getTranslations,
|
getScopedI18n: getTranslations,
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ export const zodErrorMap = <TFunction extends TranslationFunction>(t: TFunction)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
message: t(error.key ? `common.zod.${error.key}` : "common.zod.errors.default", error.params ?? {}),
|
// use never to make ts happy
|
||||||
|
message: t(error.key ? `common.zod.${error.key}` : "common.zod.errors.default", (error.params ?? {}) as never),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ const LocationSelectTableRow = ({ city, onLocationSelect, closeModal }: Location
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
label={t("action.select", {
|
label={t("action.select", {
|
||||||
city: city.name,
|
city: city.name,
|
||||||
countryCode: city.country_code,
|
countryCode: city.country_code ?? "??",
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<ActionIcon color="red" variant="subtle" onClick={onSelect}>
|
<ActionIcon color="red" variant="subtle" onClick={onSelect}>
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ export const SystemHealthMonitoring = ({
|
|||||||
<List.Item className="health-monitoring-information-memory" icon={<IconBrain size={30} />}>
|
<List.Item className="health-monitoring-information-memory" icon={<IconBrain size={30} />}>
|
||||||
{t("widget.healthMonitoring.popover.memoryAvailable", {
|
{t("widget.healthMonitoring.popover.memoryAvailable", {
|
||||||
memoryAvailable: memoryUsage.memFree.GB,
|
memoryAvailable: memoryUsage.memFree.GB,
|
||||||
percent: memoryUsage.memFree.percent,
|
percent: String(memoryUsage.memFree.percent),
|
||||||
})}
|
})}
|
||||||
</List.Item>
|
</List.Item>
|
||||||
<List.Item className="health-monitoring-information-version" icon={<IconVersions size={30} />}>
|
<List.Item className="health-monitoring-information-version" icon={<IconVersions size={30} />}>
|
||||||
@@ -159,10 +159,11 @@ export const SystemHealthMonitoring = ({
|
|||||||
{t("widget.healthMonitoring.popover.minute")} {healthInfo.loadAverage["1min"]}%
|
{t("widget.healthMonitoring.popover.minute")} {healthInfo.loadAverage["1min"]}%
|
||||||
</List.Item>
|
</List.Item>
|
||||||
<List.Item className="health-monitoring-information-load-average-5min">
|
<List.Item className="health-monitoring-information-load-average-5min">
|
||||||
{t("widget.healthMonitoring.popover.minutes", { count: 5 })} {healthInfo.loadAverage["5min"]}%
|
{t("widget.healthMonitoring.popover.minutes", { count: "5" })} {healthInfo.loadAverage["5min"]}%
|
||||||
</List.Item>
|
</List.Item>
|
||||||
<List.Item className="health-monitoring-information-load-average-15min">
|
<List.Item className="health-monitoring-information-load-average-15min">
|
||||||
{t("widget.healthMonitoring.popover.minutes", { count: 15 })} {healthInfo.loadAverage["15min"]}%
|
{t("widget.healthMonitoring.popover.minutes", { count: "15" })}{" "}
|
||||||
|
{healthInfo.loadAverage["15min"]}%
|
||||||
</List.Item>
|
</List.Item>
|
||||||
</List>
|
</List>
|
||||||
</List>
|
</List>
|
||||||
@@ -274,7 +275,12 @@ export const formatUptime = (uptimeInSeconds: number, t: TranslationFunction) =>
|
|||||||
const hours = uptimeDuration.hours();
|
const hours = uptimeDuration.hours();
|
||||||
const minutes = uptimeDuration.minutes();
|
const minutes = uptimeDuration.minutes();
|
||||||
|
|
||||||
return t("widget.healthMonitoring.popover.uptime", { months, days, hours, minutes });
|
return t("widget.healthMonitoring.popover.uptime", {
|
||||||
|
months: String(months),
|
||||||
|
days: String(days),
|
||||||
|
hours: String(hours),
|
||||||
|
minutes: String(minutes),
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const progressColor = (percentage: number) => {
|
export const progressColor = (percentage: number) => {
|
||||||
|
|||||||
@@ -95,9 +95,9 @@ export default function MediaTranscodingWidget({
|
|||||||
</Pagination.Root>
|
</Pagination.Root>
|
||||||
<Text size="xs">
|
<Text size="xs">
|
||||||
{t("currentIndex", {
|
{t("currentIndex", {
|
||||||
start: transcodingData.data.queue.startIndex + 1,
|
start: String(transcodingData.data.queue.startIndex + 1),
|
||||||
end: transcodingData.data.queue.endIndex + 1,
|
end: String(transcodingData.data.queue.endIndex + 1),
|
||||||
total: transcodingData.data.queue.totalCount,
|
total: String(transcodingData.data.queue.totalCount),
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -280,10 +280,10 @@ export function Notebook({ options, isEditMode, boardId, itemId }: WidgetCompone
|
|||||||
</RichTextEditor.ControlsGroup>
|
</RichTextEditor.ControlsGroup>
|
||||||
|
|
||||||
<RichTextEditor.ControlsGroup>
|
<RichTextEditor.ControlsGroup>
|
||||||
<RichTextEditor.H1 title={tControls("heading", { level: 1 })} />
|
<RichTextEditor.H1 title={tControls("heading", { level: "1" })} />
|
||||||
<RichTextEditor.H2 title={tControls("heading", { level: 2 })} />
|
<RichTextEditor.H2 title={tControls("heading", { level: "2" })} />
|
||||||
<RichTextEditor.H3 title={tControls("heading", { level: 3 })} />
|
<RichTextEditor.H3 title={tControls("heading", { level: "3" })} />
|
||||||
<RichTextEditor.H4 title={tControls("heading", { level: 4 })} />
|
<RichTextEditor.H4 title={tControls("heading", { level: "4" })} />
|
||||||
</RichTextEditor.ControlsGroup>
|
</RichTextEditor.ControlsGroup>
|
||||||
|
|
||||||
<RichTextEditor.ControlsGroup>
|
<RichTextEditor.ControlsGroup>
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ const DailyWeather = ({ options, weather }: WeatherProps) => {
|
|||||||
{options.showCurrentWindSpeed && (
|
{options.showCurrentWindSpeed && (
|
||||||
<Group className="weather-current-wind-speed-group" wrap="nowrap" gap="xs">
|
<Group className="weather-current-wind-speed-group" wrap="nowrap" gap="xs">
|
||||||
<IconWind size={16} />
|
<IconWind size={16} />
|
||||||
<Text fz={16}>{t("currentWindSpeed", { currentWindSpeed: weather.current.windspeed })}</Text>
|
<Text fz={16}>{t("currentWindSpeed", { currentWindSpeed: String(weather.current.windspeed) })}</Text>
|
||||||
</Group>
|
</Group>
|
||||||
)}
|
)}
|
||||||
<Group className="weather-max-min-temp-group" wrap="nowrap" gap="sm">
|
<Group className="weather-max-min-temp-group" wrap="nowrap" gap="sm">
|
||||||
|
|||||||
@@ -94,8 +94,16 @@ export const WeatherDescription = ({
|
|||||||
<List.Item icon={<IconTemperatureMinus size={15} />}>{`${tCommon("information.min")}: ${minTemp}`}</List.Item>
|
<List.Item icon={<IconTemperatureMinus size={15} />}>{`${tCommon("information.min")}: ${minTemp}`}</List.Item>
|
||||||
<List.Item icon={<IconSun size={15} />}>{`${t("dailyForecast.sunrise")}: ${sunrise}`}</List.Item>
|
<List.Item icon={<IconSun size={15} />}>{`${t("dailyForecast.sunrise")}: ${sunrise}`}</List.Item>
|
||||||
<List.Item icon={<IconMoon size={15} />}>{`${t("dailyForecast.sunset")}: ${sunset}`}</List.Item>
|
<List.Item icon={<IconMoon size={15} />}>{`${t("dailyForecast.sunset")}: ${sunset}`}</List.Item>
|
||||||
<List.Item icon={<IconWind size={15} />}>{t("dailyForecast.maxWindSpeed", { maxWindSpeed })}</List.Item>
|
{maxWindSpeed !== undefined && (
|
||||||
<List.Item icon={<IconWind size={15} />}>{t("dailyForecast.maxWindGusts", { maxWindGusts })}</List.Item>
|
<List.Item icon={<IconWind size={15} />}>
|
||||||
|
{t("dailyForecast.maxWindSpeed", { maxWindSpeed: String(maxWindSpeed) })}
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
{maxWindGusts !== undefined && (
|
||||||
|
<List.Item icon={<IconWind size={15} />}>
|
||||||
|
{t("dailyForecast.maxWindGusts", { maxWindGusts: String(maxWindGusts) })}
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
</List>
|
</List>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|||||||
34
pnpm-lock.yaml
generated
34
pnpm-lock.yaml
generated
@@ -1893,8 +1893,8 @@ importers:
|
|||||||
specifier: 15.1.7
|
specifier: 15.1.7
|
||||||
version: 15.1.7(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.85.1)
|
version: 15.1.7(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.85.1)
|
||||||
next-intl:
|
next-intl:
|
||||||
specifier: 3.26.5
|
specifier: 4.0.0
|
||||||
version: 3.26.5(next@15.1.7(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.85.1))(react@19.0.0)
|
version: 4.0.0(next@15.1.7(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.85.1))(react@19.0.0)(typescript@5.8.2)
|
||||||
react:
|
react:
|
||||||
specifier: 19.0.0
|
specifier: 19.0.0
|
||||||
version: 19.0.0
|
version: 19.0.0
|
||||||
@@ -4081,6 +4081,9 @@ packages:
|
|||||||
'@scarf/scarf@1.4.0':
|
'@scarf/scarf@1.4.0':
|
||||||
resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==}
|
resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==}
|
||||||
|
|
||||||
|
'@schummar/icu-type-parser@1.21.5':
|
||||||
|
resolution: {integrity: sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==}
|
||||||
|
|
||||||
'@sec-ant/readable-stream@0.4.1':
|
'@sec-ant/readable-stream@0.4.1':
|
||||||
resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
|
resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
|
||||||
|
|
||||||
@@ -7850,11 +7853,15 @@ packages:
|
|||||||
nodemailer:
|
nodemailer:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
next-intl@3.26.5:
|
next-intl@4.0.0:
|
||||||
resolution: {integrity: sha512-EQlCIfY0jOhRldiFxwSXG+ImwkQtDEfQeSOEQp6ieAGSLWGlgjdb/Ck/O7wMfC430ZHGeUKVKax8KGusTPKCgg==}
|
resolution: {integrity: sha512-l+I1PLAFrjzYzrc340n1vssDJ7pP1gtYT1jOWlRWIHkyrPdyosEIHPC+LiqJP4vWvWtCZzzqTn9AaBF+x5Ja8g==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
next: ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0
|
next: ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0
|
||||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0
|
||||||
|
typescript: ^5.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
typescript:
|
||||||
|
optional: true
|
||||||
|
|
||||||
next@15.1.7:
|
next@15.1.7:
|
||||||
resolution: {integrity: sha512-GNeINPGS9c6OZKCvKypbL8GTsT5GhWPp4DM0fzkXJuXMilOO2EeFxuAY6JZbtk6XIl6Ws10ag3xRINDjSO5+wg==}
|
resolution: {integrity: sha512-GNeINPGS9c6OZKCvKypbL8GTsT5GhWPp4DM0fzkXJuXMilOO2EeFxuAY6JZbtk6XIl6Ws10ag3xRINDjSO5+wg==}
|
||||||
@@ -9977,10 +9984,10 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: '>=16.13'
|
react: '>=16.13'
|
||||||
|
|
||||||
use-intl@3.26.5:
|
use-intl@4.0.0:
|
||||||
resolution: {integrity: sha512-OdsJnC/znPvHCHLQH/duvQNXnP1w0hPfS+tkSi3mAbfjYBGh4JnyfdwkQBfIVf7t8gs9eSX/CntxUMvtKdG2MQ==}
|
resolution: {integrity: sha512-/fmC7haEMVNa0isXGRGUir56fD4I9LRnOgbeBmji+bow6U8pE7WD+2X2sjqh+0h3yJ0T36PA6JXZ6PlVeRyt8w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0
|
react: ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0
|
||||||
|
|
||||||
use-isomorphic-layout-effect@1.1.2:
|
use-isomorphic-layout-effect@1.1.2:
|
||||||
resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==}
|
resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==}
|
||||||
@@ -11995,6 +12002,8 @@ snapshots:
|
|||||||
|
|
||||||
'@scarf/scarf@1.4.0': {}
|
'@scarf/scarf@1.4.0': {}
|
||||||
|
|
||||||
|
'@schummar/icu-type-parser@1.21.5': {}
|
||||||
|
|
||||||
'@sec-ant/readable-stream@0.4.1': {}
|
'@sec-ant/readable-stream@0.4.1': {}
|
||||||
|
|
||||||
'@semantic-release/changelog@6.0.3(semantic-release@24.2.3(typescript@5.8.2))':
|
'@semantic-release/changelog@6.0.3(semantic-release@24.2.3(typescript@5.8.2))':
|
||||||
@@ -16501,13 +16510,15 @@ snapshots:
|
|||||||
next: 15.1.7(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.85.1)
|
next: 15.1.7(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.85.1)
|
||||||
react: 19.0.0
|
react: 19.0.0
|
||||||
|
|
||||||
next-intl@3.26.5(next@15.1.7(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.85.1))(react@19.0.0):
|
next-intl@4.0.0(next@15.1.7(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.85.1))(react@19.0.0)(typescript@5.8.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@formatjs/intl-localematcher': 0.5.5
|
'@formatjs/intl-localematcher': 0.5.5
|
||||||
negotiator: 1.0.0
|
negotiator: 1.0.0
|
||||||
next: 15.1.7(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.85.1)
|
next: 15.1.7(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.85.1)
|
||||||
react: 19.0.0
|
react: 19.0.0
|
||||||
use-intl: 3.26.5(react@19.0.0)
|
use-intl: 4.0.0(react@19.0.0)
|
||||||
|
optionalDependencies:
|
||||||
|
typescript: 5.8.2
|
||||||
|
|
||||||
next@15.1.7(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.85.1):
|
next@15.1.7(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.85.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -18934,9 +18945,10 @@ snapshots:
|
|||||||
dequal: 2.0.3
|
dequal: 2.0.3
|
||||||
react: 19.0.0
|
react: 19.0.0
|
||||||
|
|
||||||
use-intl@3.26.5(react@19.0.0):
|
use-intl@4.0.0(react@19.0.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@formatjs/fast-memoize': 2.2.1
|
'@formatjs/fast-memoize': 2.2.1
|
||||||
|
'@schummar/icu-type-parser': 1.21.5
|
||||||
intl-messageformat: 10.7.1
|
intl-messageformat: 10.7.1
|
||||||
react: 19.0.0
|
react: 19.0.0
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,7 @@
|
|||||||
"$schema": "https://json.schemastore.org/tsconfig",
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2022",
|
"target": "ES2022",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "ES2022"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"ES2022"
|
|
||||||
],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
@@ -15,6 +11,7 @@
|
|||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "Bundler",
|
"moduleResolution": "Bundler",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
|
"allowArbitraryExtensions": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"moduleDetection": "force",
|
"moduleDetection": "force",
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
@@ -23,15 +20,8 @@
|
|||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"*": [
|
"*": ["node_modules/*"]
|
||||||
"node_modules/*"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": ["node_modules", "build", "dist", ".next"]
|
||||||
"node_modules",
|
|
||||||
"build",
|
|
||||||
"dist",
|
|
||||||
".next"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user