diff --git a/.gitignore b/.gitignore
index 76c8f08fc..0aa3ed4c7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,3 +65,6 @@ e2e/shared/tmp
#personal backgrounds
apps/nextjs/public/images/background.png
+
+# next-intl
+en.d.json.ts
\ No newline at end of file
diff --git a/apps/nextjs/next.config.ts b/apps/nextjs/next.config.ts
index a8a022a60..d88dac644 100644
--- a/apps/nextjs/next.config.ts
+++ b/apps/nextjs/next.config.ts
@@ -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: {
diff --git a/apps/nextjs/src/app/[locale]/auth/invite/[id]/page.tsx b/apps/nextjs/src/app/[locale]/auth/invite/[id]/page.tsx
index 7de11ff0f..cc6535703 100644
--- a/apps/nextjs/src/app/[locale]/auth/invite/[id]/page.tsx
+++ b/apps/nextjs/src/app/[locale]/auth/invite/[id]/page.tsx
@@ -63,7 +63,8 @@ export default async function InviteUsagePage(props: InviteUsagePageProps) {
- {t("description", { username: invite.creator.name })}
+ {/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */}
+ {t("description", { username: invite.creator.name! })}
diff --git a/apps/nextjs/src/app/[locale]/layout.tsx b/apps/nextjs/src/app/[locale]/layout.tsx
index b988647bc..5fbd3c3f7 100644
--- a/apps/nextjs/src/app/[locale]/layout.tsx
+++ b/apps/nextjs/src/app/[locale]/layout.tsx
@@ -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) => ,
(innerProps) => ,
(innerProps) => ,
- (innerProps) => ,
+ (innerProps) => ,
(innerProps) => ,
(innerProps) => ,
(innerProps) => ,
diff --git a/apps/nextjs/src/app/[locale]/manage/about/page.tsx b/apps/nextjs/src/app/[locale]/manage/about/page.tsx
index 024267be2..ece275534 100644
--- a/apps/nextjs/src/app/[locale]/manage/about/page.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/about/page.tsx
@@ -80,7 +80,7 @@ export default async function AboutPage() {
{t("accordion.contributors.title")}
{t("accordion.contributors.subtitle", {
- count: githubContributors.length,
+ count: String(githubContributors.length),
})}
@@ -104,7 +104,7 @@ export default async function AboutPage() {
{t("accordion.translators.title")}
{t("accordion.translators.subtitle", {
- count: crowdinContributors.length,
+ count: String(crowdinContributors.length),
})}
@@ -128,7 +128,7 @@ export default async function AboutPage() {
{t("accordion.libraries.title")}
{t("accordion.libraries.subtitle", {
- count: Object.keys(attributes.dependencies).length,
+ count: String(Object.keys(attributes.dependencies).length),
})}
diff --git a/apps/nextjs/src/app/[locale]/manage/apps/_app-delete-button.tsx b/apps/nextjs/src/app/[locale]/manage/apps/_app-delete-button.tsx
index bdc520579..2fb1dce56 100644
--- a/apps/nextjs/src/app/[locale]/manage/apps/_app-delete-button.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/apps/_app-delete-button.tsx
@@ -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 },
diff --git a/apps/nextjs/src/app/[locale]/manage/search-engines/_search-engine-delete-button.tsx b/apps/nextjs/src/app/[locale]/manage/search-engines/_search-engine-delete-button.tsx
index b8df69619..6857c4714 100644
--- a/apps/nextjs/src/app/[locale]/manage/search-engines/_search-engine-delete-button.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/search-engines/_search-engine-delete-button.tsx
@@ -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 },
diff --git a/apps/nextjs/src/app/[locale]/manage/tools/docker/docker-table.tsx b/apps/nextjs/src/app/[locale]/manage/tools/docker/docker-table.tsx
index b2478d5d9..e94d2be6a 100644
--- a/apps/nextjs/src/app/[locale]/manage/tools/docker/docker-table.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/tools/docker/docker-table.tsx
@@ -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}
{tDocker("table.selected", {
- selectCount: table.getSelectedRowModel().rows.length,
- totalCount: table.getRowCount(),
+ selectCount: String(table.getSelectedRowModel().rows.length),
+ totalCount: String(table.getRowCount()),
})}
diff --git a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/configmaps/configmaps-table.tsx b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/configmaps/configmaps-table.tsx
index ac144ee15..9723171eb 100644
--- a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/configmaps/configmaps-table.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/configmaps/configmaps-table.tsx
@@ -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,
},
diff --git a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/ingresses/ingresses-table.tsx b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/ingresses/ingresses-table.tsx
index e53e492eb..fbb250806 100644
--- a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/ingresses/ingresses-table.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/ingresses/ingresses-table.tsx
@@ -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,
},
diff --git a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/namespaces/namespaces-table.tsx b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/namespaces/namespaces-table.tsx
index 9ef0e4a5b..2486a4ad0 100644
--- a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/namespaces/namespaces-table.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/namespaces/namespaces-table.tsx
@@ -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,
},
diff --git a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/nodes/nodes-table.tsx b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/nodes/nodes-table.tsx
index b7b17d984..2fc69d51f 100644
--- a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/nodes/nodes-table.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/nodes/nodes-table.tsx
@@ -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,
},
diff --git a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/pods/pods-table.tsx b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/pods/pods-table.tsx
index 3a1e10820..dd600b387 100644
--- a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/pods/pods-table.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/pods/pods-table.tsx
@@ -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,
},
diff --git a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/secrets/secrets-table.tsx b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/secrets/secrets-table.tsx
index 3c24ad0f1..d0a902f22 100644
--- a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/secrets/secrets-table.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/secrets/secrets-table.tsx
@@ -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,
},
diff --git a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/services/services-table.tsx b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/services/services-table.tsx
index 7e13a630a..04a2924d7 100644
--- a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/services/services-table.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/services/services-table.tsx
@@ -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,
},
diff --git a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/volumes/volumes-table.tsx b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/volumes/volumes-table.tsx
index be217d314..e911ee7a6 100644
--- a/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/volumes/volumes-table.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/tools/kubernetes/volumes/volumes-table.tsx
@@ -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,
},
diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_delete-user-button.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_delete-user-button.tsx
index ebaf1b0cb..0b93f2388 100644
--- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_delete-user-button.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_delete-user-button.tsx
@@ -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({
diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/page.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/page.tsx
index 48a2e8aa3..add232243 100644
--- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/page.tsx
+++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/page.tsx
@@ -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! })),
};
}
diff --git a/apps/nextjs/src/components/user-avatar-menu.tsx b/apps/nextjs/src/components/user-avatar-menu.tsx
index d7a53f901..cc676ee09 100644
--- a/apps/nextjs/src/components/user-avatar-menu.tsx
+++ b/apps/nextjs/src/components/user-avatar-menu.tsx
@@ -74,7 +74,10 @@ export const UserAvatarMenu = ({ children, availableUpdates }: UserAvatarMenuPro
leftSection={}
>
- {t("updateAvailable", { countUpdates: availableUpdates.length, tag: availableUpdates[0].tagName })}
+ {t("updateAvailable", {
+ countUpdates: String(availableUpdates.length),
+ tag: availableUpdates[0].tagName,
+ })}
diff --git a/packages/forms-collection/src/icon-picker/icon-picker.tsx b/packages/forms-collection/src/icon-picker/icon-picker.tsx
index d3abda661..9dbfb55f7 100644
--- a/packages/forms-collection/src/icon-picker/icon-picker.tsx
+++ b/packages/forms-collection/src/icon-picker/icon-picker.tsx
@@ -148,7 +148,7 @@ export const IconPicker = ({ value: propsValue, onChange, error, onFocus, onBlur
withAsterisk
error={error}
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") && (
- {tBoardSelection("title", { count: selections.size })}
+ {tBoardSelection("title", { count: String(selections.size) })}
{areAllChecked ? tBoardSelection("action.unselectAll") : tBoardSelection("action.selectAll")}
diff --git a/packages/translation/package.json b/packages/translation/package.json
index 45c65045d..461ddde18 100644
--- a/packages/translation/package.json
+++ b/packages/translation/package.json
@@ -33,7 +33,7 @@
"deepmerge": "4.3.1",
"mantine-react-table": "2.0.0-beta.9",
"next": "15.1.7",
- "next-intl": "3.26.5",
+ "next-intl": "4.0.0",
"react": "19.0.0",
"react-dom": "19.0.0"
},
diff --git a/packages/translation/src/client/index.ts b/packages/translation/src/client/index.ts
index 16d73330b..5c6755883 100644
--- a/packages/translation/src/client/index.ts
+++ b/packages/translation/src/client/index.ts
@@ -2,18 +2,26 @@
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 { 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() as TranslationObject,
+ useI18nMessages: () => useMessages(),
};
export { useTranslations };
diff --git a/packages/translation/src/client/use-current-locale.ts b/packages/translation/src/client/use-current-locale.ts
index f05eff7e5..a0e796010 100644
--- a/packages/translation/src/client/use-current-locale.ts
+++ b/packages/translation/src/client/use-current-locale.ts
@@ -1,5 +1,3 @@
import { useLocale } from "next-intl";
-import type { SupportedLanguage } from "../config";
-
-export const useCurrentLocale = () => useLocale() as SupportedLanguage;
+export const useCurrentLocale = useLocale;
diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json
index 320abee21..57eca7c72 100644
--- a/packages/translation/src/lang/en.json
+++ b/packages/translation/src/lang/en.json
@@ -3594,7 +3594,7 @@
},
"delete": {
"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": {
"success": {
"title": "Search engine deleted",
diff --git a/packages/translation/src/request.ts b/packages/translation/src/request.ts
index 9b901d2ba..1d680e50b 100644
--- a/packages/translation/src/request.ts
+++ b/packages/translation/src/request.ts
@@ -22,7 +22,7 @@ export default getRequestConfig(async ({ requestLocale }) => {
if (currentLocale !== fallbackLocale) {
const fallbackMessages = (await languageMap[fallbackLocale]()).default;
return {
- locale: currentLocale,
+ locale: typedLocale,
messages: deepmerge(fallbackMessages, currentMessages),
};
}
diff --git a/packages/translation/src/routing.ts b/packages/translation/src/routing.ts
index db81f0228..e6f268690 100644
--- a/packages/translation/src/routing.ts
+++ b/packages/translation/src/routing.ts
@@ -11,6 +11,8 @@ export const createRouting = (defaultLocale: SupportedLanguage) =>
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
diff --git a/packages/translation/src/server.ts b/packages/translation/src/server.ts
index bfab90719..ebcc6442b 100644
--- a/packages/translation/src/server.ts
+++ b/packages/translation/src/server.ts
@@ -1,5 +1,15 @@
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,
diff --git a/packages/validation/src/form/i18n.ts b/packages/validation/src/form/i18n.ts
index db53d1e95..e1f01041a 100644
--- a/packages/validation/src/form/i18n.ts
+++ b/packages/validation/src/form/i18n.ts
@@ -12,7 +12,8 @@ export const zodErrorMap = (t: TFunction)
};
}
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),
};
};
};
diff --git a/packages/widgets/src/_inputs/widget-location-input.tsx b/packages/widgets/src/_inputs/widget-location-input.tsx
index a27be85cb..37d26cf2e 100644
--- a/packages/widgets/src/_inputs/widget-location-input.tsx
+++ b/packages/widgets/src/_inputs/widget-location-input.tsx
@@ -224,7 +224,7 @@ const LocationSelectTableRow = ({ city, onLocationSelect, closeModal }: Location
diff --git a/packages/widgets/src/health-monitoring/system-health.tsx b/packages/widgets/src/health-monitoring/system-health.tsx
index e2f064ebd..6e4aa2ed4 100644
--- a/packages/widgets/src/health-monitoring/system-health.tsx
+++ b/packages/widgets/src/health-monitoring/system-health.tsx
@@ -140,7 +140,7 @@ export const SystemHealthMonitoring = ({
}>
{t("widget.healthMonitoring.popover.memoryAvailable", {
memoryAvailable: memoryUsage.memFree.GB,
- percent: memoryUsage.memFree.percent,
+ percent: String(memoryUsage.memFree.percent),
})}
}>
@@ -159,10 +159,11 @@ export const SystemHealthMonitoring = ({
{t("widget.healthMonitoring.popover.minute")} {healthInfo.loadAverage["1min"]}%
- {t("widget.healthMonitoring.popover.minutes", { count: 5 })} {healthInfo.loadAverage["5min"]}%
+ {t("widget.healthMonitoring.popover.minutes", { count: "5" })} {healthInfo.loadAverage["5min"]}%
- {t("widget.healthMonitoring.popover.minutes", { count: 15 })} {healthInfo.loadAverage["15min"]}%
+ {t("widget.healthMonitoring.popover.minutes", { count: "15" })}{" "}
+ {healthInfo.loadAverage["15min"]}%
@@ -274,7 +275,12 @@ export const formatUptime = (uptimeInSeconds: number, t: TranslationFunction) =>
const hours = uptimeDuration.hours();
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) => {
diff --git a/packages/widgets/src/media-transcoding/component.tsx b/packages/widgets/src/media-transcoding/component.tsx
index cad468681..d66da98e6 100644
--- a/packages/widgets/src/media-transcoding/component.tsx
+++ b/packages/widgets/src/media-transcoding/component.tsx
@@ -95,9 +95,9 @@ export default function MediaTranscodingWidget({
{t("currentIndex", {
- start: transcodingData.data.queue.startIndex + 1,
- end: transcodingData.data.queue.endIndex + 1,
- total: transcodingData.data.queue.totalCount,
+ start: String(transcodingData.data.queue.startIndex + 1),
+ end: String(transcodingData.data.queue.endIndex + 1),
+ total: String(transcodingData.data.queue.totalCount),
})}
>
diff --git a/packages/widgets/src/notebook/notebook.tsx b/packages/widgets/src/notebook/notebook.tsx
index 257dcfc50..a30048427 100644
--- a/packages/widgets/src/notebook/notebook.tsx
+++ b/packages/widgets/src/notebook/notebook.tsx
@@ -280,10 +280,10 @@ export function Notebook({ options, isEditMode, boardId, itemId }: WidgetCompone
-
-
-
-
+
+
+
+
diff --git a/packages/widgets/src/weather/component.tsx b/packages/widgets/src/weather/component.tsx
index fb1fecdc9..88df5cce5 100644
--- a/packages/widgets/src/weather/component.tsx
+++ b/packages/widgets/src/weather/component.tsx
@@ -75,7 +75,7 @@ const DailyWeather = ({ options, weather }: WeatherProps) => {
{options.showCurrentWindSpeed && (
- {t("currentWindSpeed", { currentWindSpeed: weather.current.windspeed })}
+ {t("currentWindSpeed", { currentWindSpeed: String(weather.current.windspeed) })}
)}
diff --git a/packages/widgets/src/weather/icon.tsx b/packages/widgets/src/weather/icon.tsx
index f93eba241..17e9c03c5 100644
--- a/packages/widgets/src/weather/icon.tsx
+++ b/packages/widgets/src/weather/icon.tsx
@@ -94,8 +94,16 @@ export const WeatherDescription = ({
}>{`${tCommon("information.min")}: ${minTemp}`}
}>{`${t("dailyForecast.sunrise")}: ${sunrise}`}
}>{`${t("dailyForecast.sunset")}: ${sunset}`}
- }>{t("dailyForecast.maxWindSpeed", { maxWindSpeed })}
- }>{t("dailyForecast.maxWindGusts", { maxWindGusts })}
+ {maxWindSpeed !== undefined && (
+ }>
+ {t("dailyForecast.maxWindSpeed", { maxWindSpeed: String(maxWindSpeed) })}
+
+ )}
+ {maxWindGusts !== undefined && (
+ }>
+ {t("dailyForecast.maxWindGusts", { maxWindGusts: String(maxWindGusts) })}
+
+ )}
);
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 935c447c3..7ca1e920c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1893,8 +1893,8 @@ importers:
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)
next-intl:
- specifier: 3.26.5
- 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)
+ specifier: 4.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:
specifier: 19.0.0
version: 19.0.0
@@ -4081,6 +4081,9 @@ packages:
'@scarf/scarf@1.4.0':
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':
resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
@@ -7850,11 +7853,15 @@ packages:
nodemailer:
optional: true
- next-intl@3.26.5:
- resolution: {integrity: sha512-EQlCIfY0jOhRldiFxwSXG+ImwkQtDEfQeSOEQp6ieAGSLWGlgjdb/Ck/O7wMfC430ZHGeUKVKax8KGusTPKCgg==}
+ next-intl@4.0.0:
+ resolution: {integrity: sha512-l+I1PLAFrjzYzrc340n1vssDJ7pP1gtYT1jOWlRWIHkyrPdyosEIHPC+LiqJP4vWvWtCZzzqTn9AaBF+x5Ja8g==}
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
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
next@15.1.7:
resolution: {integrity: sha512-GNeINPGS9c6OZKCvKypbL8GTsT5GhWPp4DM0fzkXJuXMilOO2EeFxuAY6JZbtk6XIl6Ws10ag3xRINDjSO5+wg==}
@@ -9977,10 +9984,10 @@ packages:
peerDependencies:
react: '>=16.13'
- use-intl@3.26.5:
- resolution: {integrity: sha512-OdsJnC/znPvHCHLQH/duvQNXnP1w0hPfS+tkSi3mAbfjYBGh4JnyfdwkQBfIVf7t8gs9eSX/CntxUMvtKdG2MQ==}
+ use-intl@4.0.0:
+ resolution: {integrity: sha512-/fmC7haEMVNa0isXGRGUir56fD4I9LRnOgbeBmji+bow6U8pE7WD+2X2sjqh+0h3yJ0T36PA6JXZ6PlVeRyt8w==}
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:
resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==}
@@ -11995,6 +12002,8 @@ snapshots:
'@scarf/scarf@1.4.0': {}
+ '@schummar/icu-type-parser@1.21.5': {}
+
'@sec-ant/readable-stream@0.4.1': {}
'@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)
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:
'@formatjs/intl-localematcher': 0.5.5
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)
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):
dependencies:
@@ -18934,9 +18945,10 @@ snapshots:
dequal: 2.0.3
react: 19.0.0
- use-intl@3.26.5(react@19.0.0):
+ use-intl@4.0.0(react@19.0.0):
dependencies:
'@formatjs/fast-memoize': 2.2.1
+ '@schummar/icu-type-parser': 1.21.5
intl-messageformat: 10.7.1
react: 19.0.0
diff --git a/tooling/typescript/base.json b/tooling/typescript/base.json
index 37f6290fb..ae235642b 100644
--- a/tooling/typescript/base.json
+++ b/tooling/typescript/base.json
@@ -2,11 +2,7 @@
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"target": "ES2022",
- "lib": [
- "dom",
- "dom.iterable",
- "ES2022"
- ],
+ "lib": ["dom", "dom.iterable", "ES2022"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@@ -15,6 +11,7 @@
"module": "esnext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
+ "allowArbitraryExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"jsx": "preserve",
@@ -23,15 +20,8 @@
"strictNullChecks": true,
"baseUrl": ".",
"paths": {
- "*": [
- "node_modules/*"
- ]
+ "*": ["node_modules/*"]
}
},
- "exclude": [
- "node_modules",
- "build",
- "dist",
- ".next"
- ]
-}
\ No newline at end of file
+ "exclude": ["node_modules", "build", "dist", ".next"]
+}