fix: canonicalize widget date locales

This commit is contained in:
Thomas Camlong authored and ajnart committed 2026-08-14 11:07:08 +02:00
1 parent 2efa6bcd4c
commit 25b835dca9
9 files changed
+39 -11

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@ import type { SupportedLanguage } from "../config";
import type englishTranslation from "../lang/en.json";
export { useChangeLocale } from "./use-change-locale";
export { useCurrentLocale } from "./use-current-locale";
export { useCurrentIntlLocale, useCurrentLocale } from "./use-current-locale";
declare module "next-intl" {
interface AppConfig {
@@ -1,3 +1,7 @@
import { useLocale } from "next-intl";
import { getIntlLocale } from "../config";
export const useCurrentLocale = useLocale;
export const useCurrentIntlLocale = () => getIntlLocale(useLocale());
+16
View File
@@ -0,0 +1,16 @@
import { describe, expect, it } from "vitest";
import { getIntlLocale } from "./config";
describe("getIntlLocale", () => {
it("maps Homarr-specific locale keys to canonical Intl locales", () => {
expect(getIntlLocale("cn")).toBe("zh-CN");
expect(getIntlLocale("zh")).toBe("zh-TW");
expect(getIntlLocale("cr")).toBe("en");
});
it("preserves locale keys that Intl already understands", () => {
expect(getIntlLocale("fr")).toBe("fr");
expect(getIntlLocale("de-CH")).toBe("de-CH");
});
});
+8
View File
@@ -438,5 +438,13 @@ export type LanguageIconDefinition =
export { fallbackLocale } from "./languages";
const intlLocaleOverrides: Partial<Record<SupportedLanguage, string>> = {
cn: "zh-CN",
cr: "en",
zh: "zh-TW",
};
export const getIntlLocale = (locale: SupportedLanguage): string => intlLocaleOverrides[locale] ?? locale;
export const isLocaleRTL = (locale: SupportedLanguage) =>
"isRTL" in localeConfigurations[locale] && localeConfigurations[locale].isRTL;
@@ -5,7 +5,7 @@ import { Avatar, Badge, Card, Group, ScrollArea, SimpleGrid, Stack, Text } from
import { clientApi } from "@homarr/api/client";
import { formatByteRate } from "@homarr/common";
import { getIconUrl } from "@homarr/definitions";
import { useCurrentLocale, useScopedI18n } from "@homarr/translation/client";
import { useCurrentIntlLocale, useScopedI18n } from "@homarr/translation/client";
import type { WidgetComponentProps } from "../definition";
@@ -47,7 +47,7 @@ const ArchiveTeamWarriorWidgetContent = ({
isAdvanced: boolean;
}) => {
const t = useScopedI18n("widget.archiveTeamWarrior");
const locale = useCurrentLocale();
const locale = useCurrentIntlLocale();
const [data] = clientApi.widget.archiveTeamWarrior.getStatus.useSuspenseQuery({ integrationId });
const status = data.status;
@@ -24,7 +24,7 @@ import { getIconUrl } from "@homarr/definitions";
import type { MediaRelease } from "@homarr/integrations/types";
import { mediaTypeConfigurations } from "@homarr/integrations/types";
import type { TranslationFunction } from "@homarr/translation";
import { useCurrentLocale, useI18n } from "@homarr/translation/client";
import { useCurrentIntlLocale, useI18n } from "@homarr/translation/client";
import type { TablerIcon } from "@homarr/ui";
import { OverflowBadge } from "@homarr/ui";
@@ -78,7 +78,7 @@ const formatReleaseDate = (value: unknown, locale: string, compact: boolean) =>
};
const Item = ({ item, options, isAdvanced, width, height }: ItemProps) => {
const locale = useCurrentLocale();
const locale = useCurrentIntlLocale();
const t = useI18n();
const length = formatLength(item.length, item.type, t);
const isCompact = !isAdvanced && (width < 340 || height < 180);
@@ -7,7 +7,7 @@ import { IconBinaryTree } from "@tabler/icons-react";
import { clientApi } from "@homarr/api/client";
import { useIntegrationsWithInteractAccess } from "@homarr/auth/client";
import { useRegisterSpotlightContextActions } from "@homarr/spotlight";
import { useCurrentLocale, useI18n } from "@homarr/translation/client";
import { useCurrentIntlLocale, useI18n } from "@homarr/translation/client";
import type { WidgetComponentProps } from "../../definition";
@@ -20,7 +20,7 @@ export default function SmartHomeEntityStateWidget({
displayMode,
}: WidgetComponentProps<"smartHome-entityState">) {
const t = useI18n();
const locale = useCurrentLocale();
const locale = useCurrentIntlLocale();
// It will always have at least one integration as otherwise the NoIntegrationSelectedError would be thrown in item-content.tsx
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const integrationId = integrationIds[0]!;
@@ -4,7 +4,7 @@ import { Group, SimpleGrid, Stack, Text } from "@mantine/core";
import { IconArrowDown, IconArrowUp, IconCircleCheck, IconCircleX, IconWaveSine } from "@tabler/icons-react";
import type { SpeedtestTrackerResult } from "@homarr/integrations/types";
import { useCurrentLocale, useScopedI18n } from "@homarr/translation/client";
import { useCurrentIntlLocale, useScopedI18n } from "@homarr/translation/client";
import { formatResultSpeed } from "./helpers";
import { SectionLabel } from "./section-label";
@@ -12,7 +12,7 @@ import { SpeedStatCard } from "./speed-stat-card";
export function LatestResultSection({ result, width = 500 }: { result: SpeedtestTrackerResult; width?: number }) {
const t = useScopedI18n("widget.speedtestTracker");
const locale = useCurrentLocale();
const locale = useCurrentIntlLocale();
const timestamp = Intl.DateTimeFormat(locale, {
month: "short",
day: "numeric",
+2 -2
View File
@@ -3,7 +3,7 @@
import { Center, Flex, ScrollArea, SimpleGrid, Stack, Text } from "@mantine/core";
import { clientApi } from "@homarr/api/client";
import { useCurrentLocale, useScopedI18n } from "@homarr/translation/client";
import { useCurrentIntlLocale, useScopedI18n } from "@homarr/translation/client";
import type { WidgetComponentProps } from "../definition";
import { VpnIntegrationCard } from "./vpn-card";
@@ -21,7 +21,7 @@ export default function VpnWidget({
});
const t = useScopedI18n("widget.vpn");
const tCommon = useScopedI18n("common");
const locale = useCurrentLocale();
const locale = useCurrentIntlLocale();
const dense = displayMode === "compact" && (width < 240 || height < 120);
if (isPending || integrations.length === 0) {