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:
homarr-renovate[bot]
2025-03-12 18:37:43 +01:00
committed by GitHub
parent 47ebc66c9e
commit f55d8a9c2e
37 changed files with 127 additions and 76 deletions

View File

@@ -10,7 +10,12 @@ import MillionLint from "@million/lint";
import createNextIntlPlugin from "next-intl/plugin";
// 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 {
module: {

View File

@@ -63,7 +63,8 @@ export default async function InviteUsagePage(props: InviteUsagePageProps) {
<RegistrationForm invite={invite} />
</Card>
<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>
</Stack>
</Center>

View File

@@ -20,7 +20,6 @@ import { SettingsProvider } from "@homarr/settings";
import { SpotlightProvider } from "@homarr/spotlight";
import type { SupportedLanguage } from "@homarr/translation";
import { isLocaleRTL, isLocaleSupported } from "@homarr/translation";
import { getI18nMessages } from "@homarr/translation/server";
import { Analytics } from "~/components/layout/analytics";
import { SearchEngineOptimization } from "~/components/layout/search-engine-optimization";
@@ -81,7 +80,6 @@ export default async function Layout(props: {
const serverSettings = await getServerSettingsAsync(db);
const colorScheme = await getCurrentColorSchemeAsync();
const direction = isLocaleRTL((await props.params).locale) ? "rtl" : "ltr";
const i18nMessages = await getI18nMessages();
const StackedProvider = composeWrappers([
(innerProps) => {
@@ -105,7 +103,7 @@ export default async function Layout(props: {
(innerProps) => <JotaiProvider {...innerProps} />,
(innerProps) => <TRPCReactProvider {...innerProps} />,
(innerProps) => <DayJsLoader {...innerProps} />,
(innerProps) => <NextIntlClientProvider {...innerProps} messages={i18nMessages} />,
(innerProps) => <NextIntlClientProvider {...innerProps} />,
(innerProps) => <CustomMantineProvider {...innerProps} defaultColorScheme={colorScheme} />,
(innerProps) => <ModalProvider {...innerProps} />,
(innerProps) => <SpotlightProvider {...innerProps} />,

View File

@@ -80,7 +80,7 @@ export default async function AboutPage() {
<Text>{t("accordion.contributors.title")}</Text>
<Text size="sm" c="dimmed">
{t("accordion.contributors.subtitle", {
count: githubContributors.length,
count: String(githubContributors.length),
})}
</Text>
</Stack>
@@ -104,7 +104,7 @@ export default async function AboutPage() {
<Text>{t("accordion.translators.title")}</Text>
<Text size="sm" c="dimmed">
{t("accordion.translators.subtitle", {
count: crowdinContributors.length,
count: String(crowdinContributors.length),
})}
</Text>
</Stack>
@@ -128,7 +128,7 @@ export default async function AboutPage() {
<Text>{t("accordion.libraries.title")}</Text>
<Text size="sm" c="dimmed">
{t("accordion.libraries.subtitle", {
count: Object.keys(attributes.dependencies).length,
count: String(Object.keys(attributes.dependencies).length),
})}
</Text>
</Stack>

View File

@@ -23,7 +23,9 @@ export const AppDeleteButton = ({ app }: AppDeleteButtonProps) => {
const onClick = useCallback(() => {
openConfirmModal({
title: t("title"),
children: t("message", app),
children: t("message", {
name: app.name,
}),
onConfirm: () => {
mutate(
{ id: app.id },

View File

@@ -23,7 +23,9 @@ export const SearchEngineDeleteButton = ({ searchEngine }: SearchEngineDeleteBut
const onClick = useCallback(() => {
openConfirmModal({
title: t("title"),
children: t("message", searchEngine),
children: t("message", {
name: searchEngine.name,
}),
onConfirm: () => {
mutate(
{ id: searchEngine.id },

View File

@@ -104,7 +104,7 @@ export function DockerTable(initialData: RouterOutputs["docker"]["getContainers"
enableBottomToolbar: false,
positionGlobalFilter: "right",
mantineSearchTextInputProps: {
placeholder: tDocker("table.search", { count: data.containers.length }),
placeholder: tDocker("table.search", { count: String(data.containers.length) }),
style: { minWidth: 300 },
autoFocus: true,
},
@@ -146,8 +146,8 @@ export function DockerTable(initialData: RouterOutputs["docker"]["getContainers"
{groupedAlert}
<Text fw={500}>
{tDocker("table.selected", {
selectCount: table.getSelectedRowModel().rows.length,
totalCount: table.getRowCount(),
selectCount: String(table.getSelectedRowModel().rows.length),
totalCount: String(table.getRowCount()),
})}
</Text>
<ContainerActionBar selectedContainers={dockerContainers} />

View File

@@ -62,7 +62,7 @@ export function ConfigmapsTable(initialData: ConfigMapsTableComponentProps) {
positionGlobalFilter: "right",
initialState: { density: "xs", showGlobalFilter: true },
mantineSearchTextInputProps: {
placeholder: tConfigMaps("table.search", { count: data.length }),
placeholder: tConfigMaps("table.search", { count: String(data.length) }),
style: { minWidth: 300 },
autoFocus: true,
},

View File

@@ -95,7 +95,7 @@ export function IngressesTable(initialData: IngressesTableComponentProps) {
positionGlobalFilter: "right",
initialState: { density: "xs", showGlobalFilter: true },
mantineSearchTextInputProps: {
placeholder: tIngresses("table.search", { count: data.length }),
placeholder: tIngresses("table.search", { count: String(data.length) }),
style: { minWidth: 300 },
autoFocus: true,
},

View File

@@ -79,7 +79,7 @@ export function NamespacesTable(initialData: NamespacesTableComponentProps) {
positionGlobalFilter: "right",
initialState: { density: "xs", showGlobalFilter: true },
mantineSearchTextInputProps: {
placeholder: tNamespaces("table.search", { count: data.length }),
placeholder: tNamespaces("table.search", { count: String(data.length) }),
style: { minWidth: 300 },
autoFocus: true,
},

View File

@@ -105,7 +105,7 @@ export function NodesTable(initialData: NodesListComponentProps) {
positionGlobalFilter: "right",
initialState: { density: "xs", showGlobalFilter: true },
mantineSearchTextInputProps: {
placeholder: tNodes("table.search", { count: data.length }),
placeholder: tNodes("table.search", { count: String(data.length) }),
style: { minWidth: 300 },
autoFocus: true,
},

View File

@@ -70,7 +70,7 @@ export function PodsTable(initialData: PodsTableComponentProps) {
positionGlobalFilter: "right",
initialState: { density: "xs", showGlobalFilter: true, expanded: true },
mantineSearchTextInputProps: {
placeholder: tPods("table.search", { count: data.length }),
placeholder: tPods("table.search", { count: String(data.length) }),
style: { minWidth: 300 },
autoFocus: true,
},

View File

@@ -65,7 +65,7 @@ export function SecretsTable(initialData: SecretsTableComponentProps) {
positionGlobalFilter: "right",
initialState: { density: "xs", showGlobalFilter: true },
mantineSearchTextInputProps: {
placeholder: tSecrets("table.search", { count: data.length }),
placeholder: tSecrets("table.search", { count: String(data.length) }),
style: { minWidth: 300 },
autoFocus: true,
},

View File

@@ -84,7 +84,7 @@ export function ServicesTable(initialData: ServicesTableComponentProps) {
positionGlobalFilter: "right",
initialState: { density: "xs", showGlobalFilter: true },
mantineSearchTextInputProps: {
placeholder: tServices("table.search", { count: data.length }),
placeholder: tServices("table.search", { count: String(data.length) }),
style: { minWidth: 300 },
autoFocus: true,
},

View File

@@ -89,7 +89,7 @@ export function VolumesTable(initialData: VolumesTableComponentProps) {
positionGlobalFilter: "right",
initialState: { density: "xs", showGlobalFilter: true },
mantineSearchTextInputProps: {
placeholder: tVolumes("table.search", { count: data.length }),
placeholder: tVolumes("table.search", { count: String(data.length) }),
style: { minWidth: 300 },
autoFocus: true,
},

View File

@@ -28,7 +28,8 @@ export const DeleteUserButton = ({ user }: DeleteUserButtonProps) => {
() =>
openConfirmModal({
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
async onConfirm() {
await mutateUserDeletionAsync({

View File

@@ -41,7 +41,8 @@ export async function generateMetadata(props: Props) {
const t = await getScopedI18n("management.page.user.edit");
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! })),
};
}

View File

@@ -74,7 +74,10 @@ export const UserAvatarMenu = ({ children, availableUpdates }: UserAvatarMenuPro
leftSection={<IconBellRinging size="1rem" />}
>
<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>
</Menu.Item>
<Menu.Divider />