♻️ Move i18n config (#1418)

This commit is contained in:
Luke Vella 2024-10-31 08:52:38 +00:00 committed by GitHub
parent a2414ff8ca
commit 641eb13cb6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 80 additions and 92 deletions

View file

@ -6,7 +6,7 @@ import {
PageHeader, PageHeader,
PageTitle, PageTitle,
} from "@/app/components/page-layout"; } from "@/app/components/page-layout";
import { getTranslation } from "@/app/i18n"; import { getTranslation } from "@/i18n/server";
export default async function Page({ params }: { params: Params }) { export default async function Page({ params }: { params: Params }) {
const { t } = await getTranslation(params.locale); const { t } = await getTranslation(params.locale);

View file

@ -8,7 +8,7 @@ import {
PageHeader, PageHeader,
PageTitle, PageTitle,
} from "@/app/components/page-layout"; } from "@/app/components/page-layout";
import { getTranslation } from "@/app/i18n"; import { getTranslation } from "@/i18n/server";
export default async function Page({ params }: { params: Params }) { export default async function Page({ params }: { params: Params }) {
const { t } = await getTranslation(params.locale); const { t } = await getTranslation(params.locale);

View file

@ -10,7 +10,7 @@ import {
PageIcon, PageIcon,
PageTitle, PageTitle,
} from "@/app/components/page-layout"; } from "@/app/components/page-layout";
import { getTranslation } from "@/app/i18n"; import { getTranslation } from "@/i18n/server";
export default async function Page({ params }: { params: Params }) { export default async function Page({ params }: { params: Params }) {
const { t } = await getTranslation(params.locale); const { t } = await getTranslation(params.locale);

View file

@ -9,7 +9,7 @@ import {
PageIcon, PageIcon,
PageTitle, PageTitle,
} from "@/app/components/page-layout"; } from "@/app/components/page-layout";
import { getTranslation } from "@/app/i18n"; import { getTranslation } from "@/i18n/server";
export default async function Page({ export default async function Page({
params, params,

View file

@ -3,8 +3,8 @@ import { notFound } from "next/navigation";
import { BillingPage } from "@/app/[locale]/(admin)/settings/billing/billing-page"; import { BillingPage } from "@/app/[locale]/(admin)/settings/billing/billing-page";
import { Params } from "@/app/[locale]/types"; import { Params } from "@/app/[locale]/types";
import { getTranslation } from "@/app/i18n";
import { env } from "@/env"; import { env } from "@/env";
import { getTranslation } from "@/i18n/server";
export default async function Page() { export default async function Page() {
if (env.NEXT_PUBLIC_SELF_HOSTED === "true") { if (env.NEXT_PUBLIC_SELF_HOSTED === "true") {

View file

@ -6,7 +6,7 @@ import {
PageHeader, PageHeader,
PageTitle, PageTitle,
} from "@/app/components/page-layout"; } from "@/app/components/page-layout";
import { getTranslation } from "@/app/i18n"; import { getTranslation } from "@/i18n/server";
import { SettingsMenu } from "./settings-menu"; import { SettingsMenu } from "./settings-menu";

View file

@ -1,5 +1,5 @@
import { Params } from "@/app/[locale]/types"; import { Params } from "@/app/[locale]/types";
import { getTranslation } from "@/app/i18n"; import { getTranslation } from "@/i18n/server";
import { PreferencesPage } from "./preferences-page"; import { PreferencesPage } from "./preferences-page";

View file

@ -1,7 +1,6 @@
"use client"; "use client";
import Head from "next/head"; import Head from "next/head";
import { useTranslation } from "@/app/i18n/client";
import { DateTimePreferences } from "@/components/settings/date-time-preferences"; import { DateTimePreferences } from "@/components/settings/date-time-preferences";
import { LanguagePreference } from "@/components/settings/language-preference"; import { LanguagePreference } from "@/components/settings/language-preference";
import { import {
@ -10,6 +9,7 @@ import {
SettingsSection, SettingsSection,
} from "@/components/settings/settings"; } from "@/components/settings/settings";
import { Trans } from "@/components/trans"; import { Trans } from "@/components/trans";
import { useTranslation } from "@/i18n/client";
export function PreferencesPage() { export function PreferencesPage() {
const { t } = useTranslation(); const { t } = useTranslation();

View file

@ -15,8 +15,8 @@ import { Input } from "@rallly/ui/input";
import { signOut } from "next-auth/react"; import { signOut } from "next-auth/react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { useTranslation } from "@/app/i18n/client";
import { Trans } from "@/components/trans"; import { Trans } from "@/components/trans";
import { useTranslation } from "@/i18n/client";
import { usePostHog } from "@/utils/posthog"; import { usePostHog } from "@/utils/posthog";
import { trpc } from "@/utils/trpc/client"; import { trpc } from "@/utils/trpc/client";
@ -32,7 +32,7 @@ export function DeleteAccountDialog({
email: "", email: "",
}, },
}); });
const { t } = useTranslation("app"); const { t } = useTranslation();
const trpcUtils = trpc.useUtils(); const trpcUtils = trpc.useUtils();
const posthog = usePostHog(); const posthog = usePostHog();
const deleteAccount = trpc.user.delete.useMutation({ const deleteAccount = trpc.user.delete.useMutation({

View file

@ -1,5 +1,5 @@
import { Params } from "@/app/[locale]/types"; import { Params } from "@/app/[locale]/types";
import { getTranslation } from "@/app/i18n"; import { getTranslation } from "@/i18n/server";
import { ProfilePage } from "./profile-page"; import { ProfilePage } from "./profile-page";

View file

@ -4,11 +4,11 @@ import * as Sentry from "@sentry/nextjs";
import React, { useState } from "react"; import React, { useState } from "react";
import { z } from "zod"; import { z } from "zod";
import { useTranslation } from "@/app/i18n/client";
import { OptimizedAvatarImage } from "@/components/optimized-avatar-image"; import { OptimizedAvatarImage } from "@/components/optimized-avatar-image";
import { Trans } from "@/components/trans"; import { Trans } from "@/components/trans";
import { useUser } from "@/components/user-provider"; import { useUser } from "@/components/user-provider";
import { IfCloudHosted } from "@/contexts/environment"; import { IfCloudHosted } from "@/contexts/environment";
import { useTranslation } from "@/i18n/client";
import { usePostHog } from "@/utils/posthog"; import { usePostHog } from "@/utils/posthog";
import { trpc } from "@/utils/trpc/client"; import { trpc } from "@/utils/trpc/client";

View file

@ -3,8 +3,8 @@ import { Trans } from "react-i18next/TransWithoutContext";
import { LoginForm } from "@/app/[locale]/(auth)/login/login-form"; import { LoginForm } from "@/app/[locale]/(auth)/login/login-form";
import { Params } from "@/app/[locale]/types"; import { Params } from "@/app/[locale]/types";
import { getTranslation } from "@/app/i18n";
import { AuthCard } from "@/components/auth/auth-layout"; import { AuthCard } from "@/components/auth/auth-layout";
import { getTranslation } from "@/i18n/server";
export default async function LoginPage({ params }: { params: Params }) { export default async function LoginPage({ params }: { params: Params }) {
const { t } = await getTranslation(params.locale); const { t } = await getTranslation(params.locale);

View file

@ -1,6 +1,6 @@
import { RegisterForm } from "@/app/[locale]/(auth)/register/register-page"; import { RegisterForm } from "@/app/[locale]/(auth)/register/register-page";
import { Params } from "@/app/[locale]/types"; import { Params } from "@/app/[locale]/types";
import { getTranslation } from "@/app/i18n"; import { getTranslation } from "@/i18n/server";
export default async function Page() { export default async function Page() {
return <RegisterForm />; return <RegisterForm />;

View file

@ -1,7 +1,7 @@
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import { z } from "zod"; import { z } from "zod";
import { getTranslation } from "@/app/i18n"; import { getTranslation } from "@/i18n/server";
import { LoginPage } from "./login-page"; import { LoginPage } from "./login-page";

View file

@ -3,7 +3,7 @@ import { Metadata } from "next";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import { InvitePage } from "@/app/[locale]/invite/[urlId]/invite-page"; import { InvitePage } from "@/app/[locale]/invite/[urlId]/invite-page";
import { getTranslation } from "@/app/i18n"; import { getTranslation } from "@/i18n/server";
import { absoluteUrl } from "@/utils/absolute-url"; import { absoluteUrl } from "@/utils/absolute-url";
export default async function Page() { export default async function Page() {

View file

@ -3,9 +3,9 @@ import { Trans } from "react-i18next/TransWithoutContext";
import { GroupPollIcon } from "@/app/[locale]/(admin)/app-card"; import { GroupPollIcon } from "@/app/[locale]/(admin)/app-card";
import { BackButton } from "@/app/[locale]/(admin)/menu/menu-button"; import { BackButton } from "@/app/[locale]/(admin)/menu/menu-button";
import { Params } from "@/app/[locale]/types"; import { Params } from "@/app/[locale]/types";
import { getTranslation } from "@/app/i18n";
import { CreatePoll } from "@/components/create-poll"; import { CreatePoll } from "@/components/create-poll";
import { UserDropdown } from "@/components/user-dropdown"; import { UserDropdown } from "@/components/user-dropdown";
import { getTranslation } from "@/i18n/server";
export default async function Page({ params }: { params: Params }) { export default async function Page({ params }: { params: Params }) {
const { t } = await getTranslation(params.locale); const { t } = await getTranslation(params.locale);

View file

@ -2,7 +2,7 @@ import { Button } from "@rallly/ui/button";
import { FileSearchIcon } from "lucide-react"; import { FileSearchIcon } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { getTranslation } from "@/app/i18n"; import { getTranslation } from "@/i18n/server";
export default async function Page() { export default async function Page() {
// TODO (Luke Vella) [2023-11-03]: not-found doesn't have access to params right now // TODO (Luke Vella) [2023-11-03]: not-found doesn't have access to params right now

View file

@ -1,52 +0,0 @@
"use client";
import i18next, { Namespace } from "i18next";
import ICU from "i18next-icu";
import resourcesToBackend from "i18next-resources-to-backend";
import { useParams } from "next/navigation";
import React from "react";
import {
I18nextProvider,
initReactI18next,
useTranslation as useTranslationOrg,
} from "react-i18next";
import { useAsync } from "react-use";
import { defaultNS, getOptions } from "./settings";
async function initTranslations(lng: string) {
const i18n = i18next
.use(initReactI18next)
.use(ICU)
.use(
resourcesToBackend(
(language: string, namespace: string) =>
import(`../../../public/locales/${language}/${namespace}.json`),
),
);
await i18n.init(getOptions(lng));
return i18n;
}
export function useTranslation(ns?: Namespace) {
return useTranslationOrg(ns);
}
export function I18nProvider({ children }: { children: React.ReactNode }) {
const params = useParams<{ locale: string }>();
const locale = params?.locale ?? defaultNS;
const res = useAsync(async () => {
return await initTranslations(locale);
});
if (!res.value) {
return null;
}
return (
<I18nextProvider i18n={res.value} defaultNS={defaultNS}>
{children}
</I18nextProvider>
);
}

View file

@ -6,8 +6,8 @@ import { domMax, LazyMotion } from "framer-motion";
import { SessionProvider } from "next-auth/react"; import { SessionProvider } from "next-auth/react";
import { useState } from "react"; import { useState } from "react";
import { I18nProvider } from "@/app/i18n/client";
import { UserProvider } from "@/components/user-provider"; import { UserProvider } from "@/components/user-provider";
import { I18nProvider } from "@/i18n/client";
import { AppRouter } from "@/trpc/routers"; import { AppRouter } from "@/trpc/routers";
import { ConnectedDayjsProvider } from "@/utils/dayjs"; import { ConnectedDayjsProvider } from "@/utils/dayjs";
import { trpcConfig } from "@/utils/trpc/config"; import { trpcConfig } from "@/utils/trpc/config";

View file

@ -5,13 +5,13 @@ import { Icon } from "@rallly/ui/icon";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { DotIcon, MapPinIcon, PauseIcon } from "lucide-react"; import { DotIcon, MapPinIcon, PauseIcon } from "lucide-react";
import { useTranslation } from "@/app/i18n/client";
import TruncatedLinkify from "@/components/poll/truncated-linkify"; import TruncatedLinkify from "@/components/poll/truncated-linkify";
import VoteIcon from "@/components/poll/vote-icon"; import VoteIcon from "@/components/poll/vote-icon";
import { PollStatusBadge } from "@/components/poll-status"; import { PollStatusBadge } from "@/components/poll-status";
import { RandomGradientBar } from "@/components/random-gradient-bar"; import { RandomGradientBar } from "@/components/random-gradient-bar";
import { Trans } from "@/components/trans"; import { Trans } from "@/components/trans";
import { usePoll } from "@/contexts/poll"; import { usePoll } from "@/contexts/poll";
import { useTranslation } from "@/i18n/client";
function IconGuide() { function IconGuide() {
return ( return (

View file

@ -23,11 +23,11 @@ import {
EmptyStateIcon, EmptyStateIcon,
EmptyStateTitle, EmptyStateTitle,
} from "@/app/components/empty-state"; } from "@/app/components/empty-state";
import { useTranslation } from "@/app/i18n/client";
import { TimesShownIn } from "@/components/clock"; import { TimesShownIn } from "@/components/clock";
import { useVotingForm } from "@/components/poll/voting-form"; import { useVotingForm } from "@/components/poll/voting-form";
import { usePermissions } from "@/contexts/permissions"; import { usePermissions } from "@/contexts/permissions";
import { usePoll } from "@/contexts/poll"; import { usePoll } from "@/contexts/poll";
import { useTranslation } from "@/i18n/client";
import { import {
useParticipants, useParticipants,

View file

@ -7,11 +7,11 @@ import { ChevronDownIcon, ChevronUpIcon } from "lucide-react";
import * as React from "react"; import * as React from "react";
import { useToggle } from "react-use"; import { useToggle } from "react-use";
import { useTranslation } from "@/app/i18n/client";
import { OptimizedAvatarImage } from "@/components/optimized-avatar-image"; import { OptimizedAvatarImage } from "@/components/optimized-avatar-image";
import { useParticipants } from "@/components/participants-provider"; import { useParticipants } from "@/components/participants-provider";
import { usePoll } from "@/contexts/poll"; import { usePoll } from "@/contexts/poll";
import { useRole } from "@/contexts/role"; import { useRole } from "@/contexts/role";
import { useTranslation } from "@/i18n/client";
import { ConnectedScoreSummary } from "../score-summary"; import { ConnectedScoreSummary } from "../score-summary";
import VoteIcon from "../vote-icon"; import VoteIcon from "../vote-icon";

View file

@ -1,6 +1,6 @@
import { Trans as BaseTrans } from "react-i18next"; import { Trans as BaseTrans } from "react-i18next";
import { useTranslation } from "@/app/i18n/client"; import { useTranslation } from "@/i18n/client";
import { I18nNamespaces } from "../../declarations/i18next"; import { I18nNamespaces } from "../../declarations/i18next";
@ -11,6 +11,6 @@ export const Trans = (props: {
children?: React.ReactNode; children?: React.ReactNode;
components?: Record<string, React.ReactElement> | React.ReactElement[]; components?: Record<string, React.ReactElement> | React.ReactElement[];
}) => { }) => {
const { t } = useTranslation("app"); const { t } = useTranslation();
return <BaseTrans ns="app" t={t} {...props} />; return <BaseTrans ns="app" t={t} {...props} />;
}; };

View file

@ -3,11 +3,11 @@ import { Session } from "next-auth";
import { useSession } from "next-auth/react"; import { useSession } from "next-auth/react";
import React from "react"; import React from "react";
import { useTranslation } from "@/app/i18n/client";
import { Spinner } from "@/components/spinner"; import { Spinner } from "@/components/spinner";
import { useSubscription } from "@/contexts/plan"; import { useSubscription } from "@/contexts/plan";
import { PostHogProvider } from "@/contexts/posthog"; import { PostHogProvider } from "@/contexts/posthog";
import { PreferencesProvider } from "@/contexts/preferences"; import { PreferencesProvider } from "@/contexts/preferences";
import { useTranslation } from "@/i18n/client";
import { trpc } from "@/utils/trpc/client"; import { trpc } from "@/utils/trpc/client";
import { useRequiredContext } from "./use-required-context"; import { useRequiredContext } from "./use-required-context";

View file

@ -0,0 +1,34 @@
"use client";
import { useParams } from "next/navigation";
import React from "react";
import {
I18nextProvider,
useTranslation as useTranslationOrg,
} from "react-i18next";
import useAsync from "react-use/lib/useAsync";
import { initI18next } from "./i18n";
import { defaultNS } from "./settings";
export function useTranslation() {
return useTranslationOrg("app");
}
export function I18nProvider({ children }: { children: React.ReactNode }) {
const params = useParams<{ locale: string }>();
const locale = params?.locale ?? defaultNS;
const res = useAsync(async () => {
return await initI18next(locale, "app");
});
if (!res.value) {
return null;
}
return (
<I18nextProvider i18n={res.value} defaultNS={defaultNS}>
{children}
</I18nextProvider>
);
}

View file

@ -1,13 +1,15 @@
import { createInstance, Namespace } from "i18next"; import { createInstance, Namespace } from "i18next";
import ICU from "i18next-icu";
import resourcesToBackend from "i18next-resources-to-backend"; import resourcesToBackend from "i18next-resources-to-backend";
import { initReactI18next } from "react-i18next/initReactI18next"; import { initReactI18next } from "react-i18next/initReactI18next";
import { defaultNS, getOptions } from "./i18n/settings"; import { getOptions } from "./settings";
const initI18next = async (lng: string, ns: Namespace) => { export const initI18next = async (lng: string, ns: Namespace) => {
const i18nInstance = createInstance(); const i18nInstance = createInstance();
await i18nInstance await i18nInstance
.use(initReactI18next) .use(initReactI18next)
.use(ICU)
.use( .use(
resourcesToBackend( resourcesToBackend(
(language: string, namespace: string) => (language: string, namespace: string) =>
@ -17,14 +19,3 @@ const initI18next = async (lng: string, ns: Namespace) => {
.init(getOptions(lng, ns)); .init(getOptions(lng, ns));
return i18nInstance; return i18nInstance;
}; };
export async function getTranslation(
locale: string,
ns: Namespace = defaultNS,
) {
const i18nextInstance = await initI18next(locale, ns);
return {
t: i18nextInstance.getFixedT(locale, Array.isArray(ns) ? ns[0] : ns),
i18n: i18nextInstance,
};
}

View file

@ -0,0 +1,16 @@
import type { Namespace } from "i18next";
import { defaultNS } from "@/i18n/settings";
import { initI18next } from "./i18n";
export async function getTranslation(
locale: string,
ns: Namespace = defaultNS,
) {
const i18nextInstance = await initI18next(locale, ns);
return {
t: i18nextInstance.getFixedT(locale, Array.isArray(ns) ? ns[0] : ns),
i18n: i18nextInstance,
};
}

View file

@ -10,7 +10,6 @@ export function getOptions(
ns: string | string[] = defaultNS, ns: string | string[] = defaultNS,
): InitOptions { ): InitOptions {
return { return {
// debug: true,
supportedLngs: languages, supportedLngs: languages,
fallbackLng, fallbackLng,
lng, lng,

View file

@ -11,9 +11,9 @@ import Head from "next/head";
import { SessionProvider, signIn, useSession } from "next-auth/react"; import { SessionProvider, signIn, useSession } from "next-auth/react";
import React from "react"; import React from "react";
import { I18nProvider } from "@/app/i18n/client";
import Maintenance from "@/components/maintenance"; import Maintenance from "@/components/maintenance";
import { UserProvider } from "@/components/user-provider"; import { UserProvider } from "@/components/user-provider";
import { I18nProvider } from "@/i18n/client";
import { ConnectedDayjsProvider } from "@/utils/dayjs"; import { ConnectedDayjsProvider } from "@/utils/dayjs";
import { trpc } from "@/utils/trpc/client"; import { trpc } from "@/utils/trpc/client";