mirror of
https://github.com/fallenbagel/jellyseerr.git
synced 2026-01-01 12:18:35 -05:00
feat(frontend/api): i18n support
This commit is contained in:
@@ -1,82 +1,136 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import '../styles/globals.css';
|
||||
import App, { AppInitialProps } from 'next/app';
|
||||
import App, { AppInitialProps, AppProps } from 'next/app';
|
||||
import { SWRConfig } from 'swr';
|
||||
import { ToastProvider } from 'react-toast-notifications';
|
||||
import { parseCookies, setCookie } from 'nookies';
|
||||
import Layout from '../components/Layout';
|
||||
import { UserContext } from '../context/UserContext';
|
||||
import axios from 'axios';
|
||||
import { User } from '../hooks/useUser';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { LanguageContext, AvailableLocales } from '../context/LanguageContext';
|
||||
|
||||
const loadLocaleData = (locale: string) => {
|
||||
switch (locale) {
|
||||
case 'ja':
|
||||
return import('../i18n/locale/ja.json');
|
||||
default:
|
||||
return import('../i18n/locale/en.json');
|
||||
}
|
||||
};
|
||||
|
||||
// Custom types so we can correctly type our GetInitialProps function
|
||||
// with our combined user prop
|
||||
// This is specific to _app.tsx. Other pages will not need to do this!
|
||||
type NextAppComponentType = typeof App;
|
||||
type GetInitialPropsFn = NextAppComponentType['getInitialProps'];
|
||||
type MessagesType = Record<string, any>;
|
||||
|
||||
interface AppProps {
|
||||
interface ExtendedAppProps extends AppProps {
|
||||
user: User;
|
||||
messages: MessagesType;
|
||||
locale: AvailableLocales;
|
||||
}
|
||||
|
||||
class CoreApp extends App<AppProps> {
|
||||
public static getInitialProps: GetInitialPropsFn = async (initialProps) => {
|
||||
// Run the default getInitialProps for the main nextjs initialProps
|
||||
const appInitialProps: AppInitialProps = await App.getInitialProps(
|
||||
initialProps
|
||||
);
|
||||
const { ctx, router } = initialProps;
|
||||
let user = undefined;
|
||||
if (ctx.res) {
|
||||
try {
|
||||
// Attempt to get the user by running a request to the local api
|
||||
const response = await axios.get<User>(
|
||||
`http://localhost:${process.env.PORT || 3000}/api/v1/auth/me`,
|
||||
{ headers: ctx.req ? { cookie: ctx.req.headers.cookie } : undefined }
|
||||
);
|
||||
user = response.data;
|
||||
} catch (e) {
|
||||
// If there is no user, and ctx.res is set (to check if we are on the server side)
|
||||
// _AND_ we are not already on the login or setup route, redirect to /login with a 307
|
||||
// before anything actually renders
|
||||
if (!router.pathname.match(/(login|setup)/)) {
|
||||
ctx.res.writeHead(307, {
|
||||
Location: '/login',
|
||||
});
|
||||
ctx.res.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof window === 'undefined') {
|
||||
global.Intl = require('intl');
|
||||
}
|
||||
|
||||
return { ...appInitialProps, user };
|
||||
};
|
||||
const CoreApp: Omit<NextAppComponentType, 'origGetInitialProps'> = ({
|
||||
Component,
|
||||
pageProps,
|
||||
router,
|
||||
user,
|
||||
messages,
|
||||
locale,
|
||||
}: ExtendedAppProps) => {
|
||||
let component: React.ReactNode;
|
||||
const [loadedMessages, setMessages] = useState<MessagesType>(messages);
|
||||
const [currentLocale, setLocale] = useState<AvailableLocales>(locale);
|
||||
|
||||
public render(): JSX.Element {
|
||||
const { Component, pageProps, router, user } = this.props;
|
||||
useEffect(() => {
|
||||
loadLocaleData(currentLocale).then(setMessages);
|
||||
setCookie(null, 'locale', currentLocale, { path: '/' });
|
||||
}, [currentLocale]);
|
||||
|
||||
let component: React.ReactNode;
|
||||
|
||||
if (router.asPath === '/login') {
|
||||
component = <Component {...pageProps} />;
|
||||
} else {
|
||||
component = (
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SWRConfig
|
||||
value={{
|
||||
fetcher: (url) => axios.get(url).then((res) => res.data),
|
||||
}}
|
||||
>
|
||||
<ToastProvider>
|
||||
<UserContext initialUser={user}>{component}</UserContext>
|
||||
</ToastProvider>
|
||||
</SWRConfig>
|
||||
if (router.asPath === '/login') {
|
||||
component = <Component {...pageProps} />;
|
||||
} else {
|
||||
component = (
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<SWRConfig
|
||||
value={{
|
||||
fetcher: (url) => axios.get(url).then((res) => res.data),
|
||||
}}
|
||||
>
|
||||
<LanguageContext.Provider value={{ locale: currentLocale, setLocale }}>
|
||||
<IntlProvider
|
||||
locale={currentLocale}
|
||||
defaultLocale="en"
|
||||
messages={loadedMessages}
|
||||
>
|
||||
<ToastProvider>
|
||||
<UserContext initialUser={user}>{component}</UserContext>
|
||||
</ToastProvider>
|
||||
</IntlProvider>
|
||||
</LanguageContext.Provider>
|
||||
</SWRConfig>
|
||||
);
|
||||
};
|
||||
|
||||
CoreApp.getInitialProps = async (initialProps) => {
|
||||
// Run the default getInitialProps for the main nextjs initialProps
|
||||
const appInitialProps: AppInitialProps = await App.getInitialProps(
|
||||
initialProps
|
||||
);
|
||||
const { ctx, router } = initialProps;
|
||||
let user = undefined;
|
||||
|
||||
let locale = 'en';
|
||||
|
||||
if (ctx.res) {
|
||||
const cookies = parseCookies(ctx);
|
||||
|
||||
if (cookies.locale) {
|
||||
locale = cookies.locale;
|
||||
}
|
||||
|
||||
try {
|
||||
// Attempt to get the user by running a request to the local api
|
||||
const response = await axios.get<User>(
|
||||
`http://localhost:${process.env.PORT || 3000}/api/v1/auth/me`,
|
||||
{ headers: ctx.req ? { cookie: ctx.req.headers.cookie } : undefined }
|
||||
);
|
||||
user = response.data;
|
||||
|
||||
if (router.pathname.match(/login/)) {
|
||||
ctx.res.writeHead(307, {
|
||||
Location: '/',
|
||||
});
|
||||
ctx.res.end();
|
||||
}
|
||||
} catch (e) {
|
||||
// If there is no user, and ctx.res is set (to check if we are on the server side)
|
||||
// _AND_ we are not already on the login or setup route, redirect to /login with a 307
|
||||
// before anything actually renders
|
||||
if (!router.pathname.match(/(login|setup)/)) {
|
||||
ctx.res.writeHead(307, {
|
||||
Location: '/login',
|
||||
});
|
||||
ctx.res.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const messages = await loadLocaleData(locale);
|
||||
|
||||
return { ...appInitialProps, user, messages, locale };
|
||||
};
|
||||
|
||||
export default CoreApp;
|
||||
|
||||
@@ -3,6 +3,7 @@ import { NextPage } from 'next';
|
||||
import type { MovieDetails as MovieDetailsType } from '../../../../server/models/Movie';
|
||||
import MovieDetails from '../../../components/MovieDetails';
|
||||
import axios from 'axios';
|
||||
import { parseCookies } from 'nookies';
|
||||
|
||||
interface MoviePageProps {
|
||||
movie?: MovieDetailsType;
|
||||
@@ -14,10 +15,11 @@ const MoviePage: NextPage<MoviePageProps> = ({ movie }) => {
|
||||
|
||||
MoviePage.getInitialProps = async (ctx) => {
|
||||
if (ctx.req) {
|
||||
const cookies = parseCookies(ctx);
|
||||
const response = await axios.get<MovieDetailsType>(
|
||||
`http://localhost:${process.env.PORT || 3000}/api/v1/movie/${
|
||||
ctx.query.movieId
|
||||
}`,
|
||||
}?language=${cookies.locale}`,
|
||||
{ headers: ctx.req ? { cookie: ctx.req.headers.cookie } : undefined }
|
||||
);
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import React from 'react';
|
||||
import { NextPage } from 'next';
|
||||
import PersonCard from '../components/PersonCard';
|
||||
|
||||
const PlexText: NextPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<PersonCard />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PlexText;
|
||||
Reference in New Issue
Block a user