Skip to content

Commit

Permalink
feat(frontend): add french language file
Browse files Browse the repository at this point in the history
also expanded translation coverage (still lots to do!)
  • Loading branch information
sct committed Nov 27, 2020
1 parent 2aefcfd commit cd6d8a8
Show file tree
Hide file tree
Showing 18 changed files with 749 additions and 111 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"build": "yarn build:next && yarn build:server",
"lint": "eslint \"./server/**/*.{ts,tsx}\" \"./src/**/*.{ts,tsx}\"",
"start": "NODE_ENV=production node dist/index.js",
"i18n:extract": "extract-messages -l=en,ja -o src/i18n/locale -d en --flat true './src/**/!(*.test).{ts,tsx}'",
"i18n:extract": "extract-messages -l=en,ja,fr -o src/i18n/locale -d en --flat true './src/**/!(*.test).{ts,tsx}'",
"migration:generate": "ts-node --project server/tsconfig.json ./node_modules/.bin/typeorm migration:generate",
"migration:run": "ts-node --project server/tsconfig.json ./node_modules/.bin/typeorm migration:run",
"format": "prettier --write ."
Expand Down
29 changes: 13 additions & 16 deletions server/routes/discover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,8 @@ import TheMovieDb, {
} from '../api/themoviedb';
import { mapMovieResult, mapTvResult, mapPersonResult } from '../models/Search';
import Media from '../entity/Media';

const isMovie = (
movie: TmdbMovieResult | TmdbTvResult | TmdbPersonResult
): movie is TmdbMovieResult => {
return (movie as TmdbMovieResult).title !== undefined;
};

const isPerson = (
person: TmdbMovieResult | TmdbTvResult | TmdbPersonResult
): person is TmdbPersonResult => {
return (person as TmdbPersonResult).known_for !== undefined;
};
import { isMovie, isPerson } from '../utils/typeHelpers';
import { MediaType } from '../constants/media';

const discoverRoutes = Router();

Expand Down Expand Up @@ -65,7 +55,9 @@ discoverRoutes.get('/movies/upcoming', async (req, res) => {
results: data.results.map((result) =>
mapMovieResult(
result,
media.find((req) => req.tmdbId === result.id)
media.find(
(med) => med.tmdbId === result.id && med.mediaType === MediaType.MOVIE
)
)
),
});
Expand All @@ -90,7 +82,9 @@ discoverRoutes.get('/tv', async (req, res) => {
results: data.results.map((result) =>
mapTvResult(
result,
media.find((req) => req.tmdbId === result.id)
media.find(
(med) => med.tmdbId === result.id && med.mediaType === MediaType.TV
)
)
),
});
Expand All @@ -116,13 +110,16 @@ discoverRoutes.get('/trending', async (req, res) => {
isMovie(result)
? mapMovieResult(
result,
media.find((req) => req.tmdbId === result.id)
media.find(
(req) =>
req.tmdbId === result.id && req.mediaType === MediaType.MOVIE
)
)
: isPerson(result)
? mapPersonResult(result)
: mapTvResult(
result,
media.find((req) => req.tmdbId === result.id)
media.find((req) => req.tmdbId === result.id && MediaType.TV)
)
),
});
Expand Down
44 changes: 44 additions & 0 deletions server/routes/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,17 @@ settingsRoutes.post('/radarr', (req, res) => {
const lastItem = settings.radarr[settings.radarr.length - 1];
newRadarr.id = lastItem ? lastItem.id + 1 : 0;

// If we are setting this as the default, clear any previous defaults for the same type first
// ex: if is4k is true, it will only remove defaults for other servers that have is4k set to true
// and are the default
if (req.body.isDefault) {
settings.radarr
.filter((radarrInstance) => radarrInstance.is4k === req.body.is4k)
.forEach((radarrInstance) => {
radarrInstance.isDefault = false;
});
}

settings.radarr = [...settings.radarr, newRadarr];
settings.save();

Expand Down Expand Up @@ -181,6 +192,17 @@ settingsRoutes.put<{ id: string }>('/radarr/:id', (req, res) => {
.json({ status: '404', message: 'Settings instance not found' });
}

// If we are setting this as the default, clear any previous defaults for the same type first
// ex: if is4k is true, it will only remove defaults for other servers that have is4k set to true
// and are the default
if (req.body.isDefault) {
settings.radarr
.filter((radarrInstance) => radarrInstance.is4k === req.body.is4k)
.forEach((radarrInstance) => {
radarrInstance.isDefault = false;
});
}

settings.radarr[radarrIndex] = {
...req.body,
id: Number(req.params.id),
Expand Down Expand Up @@ -252,6 +274,17 @@ settingsRoutes.post('/sonarr', (req, res) => {
const lastItem = settings.sonarr[settings.sonarr.length - 1];
newSonarr.id = lastItem ? lastItem.id + 1 : 0;

// If we are setting this as the default, clear any previous defaults for the same type first
// ex: if is4k is true, it will only remove defaults for other servers that have is4k set to true
// and are the default
if (req.body.isDefault) {
settings.sonarr
.filter((sonarrInstance) => sonarrInstance.is4k === req.body.is4k)
.forEach((sonarrInstance) => {
sonarrInstance.isDefault = false;
});
}

settings.sonarr = [...settings.sonarr, newSonarr];
settings.save();

Expand Down Expand Up @@ -300,6 +333,17 @@ settingsRoutes.put<{ id: string }>('/sonarr/:id', (req, res) => {
.json({ status: '404', message: 'Settings instance not found' });
}

// If we are setting this as the default, clear any previous defaults for the same type first
// ex: if is4k is true, it will only remove defaults for other servers that have is4k set to true
// and are the default
if (req.body.isDefault) {
settings.sonarr
.filter((sonarrInstance) => sonarrInstance.is4k === req.body.is4k)
.forEach((sonarrInstance) => {
sonarrInstance.isDefault = false;
});
}

settings.sonarr[sonarrIndex] = {
...req.body,
id: Number(req.params.id),
Expand Down
17 changes: 17 additions & 0 deletions server/utils/typeHelpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type {
TmdbMovieResult,
TmdbTvResult,
TmdbPersonResult,
} from '../api/themoviedb';

export const isMovie = (
movie: TmdbMovieResult | TmdbTvResult | TmdbPersonResult
): movie is TmdbMovieResult => {
return (movie as TmdbMovieResult).title !== undefined;
};

export const isPerson = (
person: TmdbMovieResult | TmdbTvResult | TmdbPersonResult
): person is TmdbPersonResult => {
return (person as TmdbPersonResult).known_for !== undefined;
};
4 changes: 4 additions & 0 deletions src/components/Layout/LanguagePicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ const availableLanguages: AvailableLanguageObject = {
code: 'ja',
display: '日本語',
},
fr: {
code: 'fr',
display: 'Français',
},
};

const LanguagePicker: React.FC = () => {
Expand Down
7 changes: 6 additions & 1 deletion src/components/Layout/UserDropdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import Transition from '../../Transition';
import { useUser } from '../../../hooks/useUser';
import axios from 'axios';
import useClickOutside from '../../../hooks/useClickOutside';
import { defineMessages, FormattedMessage } from 'react-intl';

const messages = defineMessages({
signout: 'Sign Out',
});

const UserDropdown: React.FC = () => {
const dropdownRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -56,7 +61,7 @@ const UserDropdown: React.FC = () => {
role="menuitem"
onClick={() => logout()}
>
Sign out
<FormattedMessage {...messages.signout} />
</a>
</div>
</div>
Expand Down
10 changes: 7 additions & 3 deletions src/components/Layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import Sidebar from './Sidebar';
import Notifications from './Notifications';
import LanguagePicker from './LanguagePicker';
import { useRouter } from 'next/router';
import { defineMessages, FormattedMessage } from 'react-intl';

const messages = defineMessages({
alphawarning:
'This is ALPHA software. Almost everything is bound to be nearly broken and/or unstable. Please report issues to the Overseerr Github!',
});

const Layout: React.FC = ({ children }) => {
const [isSidebarOpen, setSidebarOpen] = useState(false);
Expand Down Expand Up @@ -70,9 +76,7 @@ const Layout: React.FC = ({ children }) => {
</div>
<div className="ml-3 flex-1 md:flex md:justify-between">
<p className="text-sm leading-5 text-white">
This is ALPHA software. Almost everything is bound to be
nearly broken or unstable. Please report issues to the
Overseerr Github!
<FormattedMessage {...messages.alphawarning} />
</p>
<p className="mt-3 text-sm leading-5 md:mt-0 md:ml-6">
<a
Expand Down
7 changes: 6 additions & 1 deletion src/components/Login/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import { useUser } from '../../hooks/useUser';
import axios from 'axios';
import { useRouter } from 'next/dist/client/router';
import ImageFader from '../Common/ImageFader';
import { defineMessages, FormattedMessage } from 'react-intl';

const messages = defineMessages({
signinplex: 'Sign in to continue',
});

const Login: React.FC = () => {
const [authToken, setAuthToken] = useState<string | undefined>(undefined);
Expand Down Expand Up @@ -51,7 +56,7 @@ const Login: React.FC = () => {
alt="Overseerr Logo"
/>
<h2 className="mt-2 text-center text-3xl leading-9 font-extrabold text-gray-100">
Log in to continue
<FormattedMessage {...messages.signinplex} />
</h2>
</div>
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md relative z-50">
Expand Down
20 changes: 17 additions & 3 deletions src/components/PlexLoginButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import React, { useState } from 'react';
import PlexOAuth from '../../utils/plex';
import { defineMessages, useIntl } from 'react-intl';

const messages = defineMessages({
loginwithplex: 'Login with Plex',
loading: 'Loading...',
loggingin: 'Logging in...',
});

const plexOAuth = new PlexOAuth();

Expand All @@ -12,13 +19,16 @@ const PlexLoginButton: React.FC<PlexLoginButtonProps> = ({
onAuthToken,
onError,
}) => {
const [loading, setLoading] = useState<boolean>(false);
const intl = useIntl();
const [loading, setLoading] = useState(false);
const [isProcessing, setIsProcessing] = useState(false);

const getPlexLogin = async () => {
setLoading(true);
try {
const authToken = await plexOAuth.login();
setLoading(false);
setIsProcessing(true);
onAuthToken(authToken);
} catch (e) {
if (onError) {
Expand All @@ -35,10 +45,14 @@ const PlexLoginButton: React.FC<PlexLoginButtonProps> = ({
plexOAuth.preparePopup();
setTimeout(() => getPlexLogin(), 1500);
}}
disabled={loading}
disabled={loading || isProcessing}
className="plex-button"
>
{loading ? 'Loading...' : 'Login with Plex'}
{loading
? intl.formatMessage(messages.loading)
: isProcessing
? intl.formatMessage(messages.loggingin)
: intl.formatMessage(messages.loginwithplex)}
</button>
</span>
);
Expand Down

0 comments on commit cd6d8a8

Please sign in to comment.