♻️ 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,
PageTitle,
} from "@/app/components/page-layout";
import { getTranslation } from "@/app/i18n";
import { getTranslation } from "@/i18n/server";
export default async function Page({ params }: { params: Params }) {
const { t } = await getTranslation(params.locale);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,11 +4,11 @@ import * as Sentry from "@sentry/nextjs";
import React, { useState } from "react";
import { z } from "zod";
import { useTranslation } from "@/app/i18n/client";
import { OptimizedAvatarImage } from "@/components/optimized-avatar-image";
import { Trans } from "@/components/trans";
import { useUser } from "@/components/user-provider";
import { IfCloudHosted } from "@/contexts/environment";
import { useTranslation } from "@/i18n/client";
import { usePostHog } from "@/utils/posthog";
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 { Params } from "@/app/[locale]/types";
import { getTranslation } from "@/app/i18n";
import { AuthCard } from "@/components/auth/auth-layout";
import { getTranslation } from "@/i18n/server";
export default async function LoginPage({ params }: { params: Params }) {
const { t } = await getTranslation(params.locale);

View file

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

View file

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

View file

@ -3,7 +3,7 @@ import { Metadata } from "next";
import { notFound } from "next/navigation";
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";
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 { BackButton } from "@/app/[locale]/(admin)/menu/menu-button";
import { Params } from "@/app/[locale]/types";
import { getTranslation } from "@/app/i18n";
import { CreatePoll } from "@/components/create-poll";
import { UserDropdown } from "@/components/user-dropdown";
import { getTranslation } from "@/i18n/server";
export default async function Page({ params }: { params: Params }) {
const { t } = await getTranslation(params.locale);

View file

@ -2,7 +2,7 @@ import { Button } from "@rallly/ui/button";
import { FileSearchIcon } from "lucide-react";
import Link from "next/link";
import { getTranslation } from "@/app/i18n";
import { getTranslation } from "@/i18n/server";
export default async function Page() {
// 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 { useState } from "react";
import { I18nProvider } from "@/app/i18n/client";
import { UserProvider } from "@/components/user-provider";
import { I18nProvider } from "@/i18n/client";
import { AppRouter } from "@/trpc/routers";
import { ConnectedDayjsProvider } from "@/utils/dayjs";
import { trpcConfig } from "@/utils/trpc/config";

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
import { Trans as BaseTrans } from "react-i18next";
import { useTranslation } from "@/app/i18n/client";
import { useTranslation } from "@/i18n/client";
import { I18nNamespaces } from "../../declarations/i18next";
@ -11,6 +11,6 @@ export const Trans = (props: {
children?: React.ReactNode;
components?: Record<string, React.ReactElement> | React.ReactElement[];
}) => {
const { t } = useTranslation("app");
const { t } = useTranslation();
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 React from "react";
import { useTranslation } from "@/app/i18n/client";
import { Spinner } from "@/components/spinner";
import { useSubscription } from "@/contexts/plan";
import { PostHogProvider } from "@/contexts/posthog";
import { PreferencesProvider } from "@/contexts/preferences";
import { useTranslation } from "@/i18n/client";
import { trpc } from "@/utils/trpc/client";
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 ICU from "i18next-icu";
import resourcesToBackend from "i18next-resources-to-backend";
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();
await i18nInstance
.use(initReactI18next)
.use(ICU)
.use(
resourcesToBackend(
(language: string, namespace: string) =>
@ -17,14 +19,3 @@ const initI18next = async (lng: string, ns: Namespace) => {
.init(getOptions(lng, ns));
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,
): InitOptions {
return {
// debug: true,
supportedLngs: languages,
fallbackLng,
lng,

View file

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