1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-04-18 21:35:27 -04:00

Use react-query for translations

This commit is contained in:
Mark McDowall
2025-12-01 20:28:55 -08:00
parent e73712bd8f
commit 66efb904f2
6 changed files with 46 additions and 56 deletions
-5
View File
@@ -1,4 +1,3 @@
import { Error } from './AppSectionState';
import BlocklistAppState from './BlocklistAppState';
import CaptchaAppState from './CaptchaAppState';
import CommandAppState from './CommandAppState';
@@ -26,10 +25,6 @@ export interface AppSectionState {
width: number;
height: number;
};
translations: {
error?: Error;
isPopulated: boolean;
};
messages: MessagesAppState;
}
+28
View File
@@ -0,0 +1,28 @@
import { useEffect } from 'react';
import useApiQuery from 'Helpers/Hooks/useApiQuery';
import { setTranslations } from 'Utilities/String/translate';
interface TranslationsResponse {
strings: Record<string, string>;
}
export function useTranslations() {
const { data, ...result } = useApiQuery<TranslationsResponse>({
path: '/localization',
queryOptions: {
staleTime: Infinity,
gcTime: Infinity,
},
});
useEffect(() => {
if (data) {
setTranslations(data.strings);
}
}, [data]);
return {
...result,
data,
};
}
+1 -1
View File
@@ -8,7 +8,7 @@ import styles from './ErrorPage.css';
interface ErrorPageProps {
version: string;
isLocalStorageSupported: boolean;
translationsError?: Error;
translationsError: ApiError | null;
seriesError: ApiError | null;
customFiltersError: ApiError | null;
tagsError: ApiError | null;
+11 -8
View File
@@ -2,9 +2,9 @@ import { useEffect, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import { useTranslations } from 'App/useTranslations';
import useCustomFilters from 'Filters/useCustomFilters';
import useSeries from 'Series/useSeries';
import { fetchTranslations } from 'Store/Actions/appActions';
import { fetchCustomFilters } from 'Store/Actions/customFilterActions';
import {
fetchImportLists,
@@ -21,11 +21,13 @@ const createErrorsSelector = ({
customFiltersError,
systemStatusError,
tagsError,
translationsError,
seriesError,
}: {
customFiltersError: ApiError | null;
systemStatusError: ApiError | null;
tagsError: ApiError | null;
translationsError: ApiError | null;
seriesError: ApiError | null;
}) =>
createSelector(
@@ -34,14 +36,12 @@ const createErrorsSelector = ({
(state: AppState) => state.settings.languages.error,
(state: AppState) => state.settings.importLists.error,
(state: AppState) => state.settings.indexerFlags.error,
(state: AppState) => state.app.translations.error,
(
uiSettingsError,
qualityProfilesError,
languagesError,
importListsError,
indexerFlagsError,
translationsError
indexerFlagsError
) => {
const hasError = !!(
customFiltersError ||
@@ -87,14 +87,16 @@ const useAppPage = () => {
const { isFetched: isTagsFetched, error: tagsError } = useTags();
const { isFetched: isTranslationsFetched, error: translationsError } =
useTranslations();
const isAppStatePopulated = useSelector(
(state: AppState) =>
state.settings.ui.isPopulated &&
state.settings.qualityProfiles.isPopulated &&
state.settings.languages.isPopulated &&
state.settings.importLists.isPopulated &&
state.settings.indexerFlags.isPopulated &&
state.app.translations.isPopulated
state.settings.indexerFlags.isPopulated
);
const isPopulated =
@@ -102,7 +104,8 @@ const useAppPage = () => {
isCustomFiltersFetched &&
isSeriesFetched &&
isSystemStatusFetched &&
isTagsFetched;
isTagsFetched &&
isTranslationsFetched;
const { hasError, errors } = useSelector(
createErrorsSelector({
@@ -110,6 +113,7 @@ const useAppPage = () => {
seriesError,
systemStatusError,
tagsError,
translationsError,
})
);
@@ -133,7 +137,6 @@ const useAppPage = () => {
dispatch(fetchImportLists());
dispatch(fetchIndexerFlags());
dispatch(fetchUISettings());
dispatch(fetchTranslations());
}, [dispatch]);
return useMemo(() => {
+1 -20
View File
@@ -4,7 +4,6 @@ import { createThunk, handleThunks } from 'Store/thunks';
import createAjaxRequest from 'Utilities/createAjaxRequest';
import getSectionState from 'Utilities/State/getSectionState';
import updateSectionState from 'Utilities/State/updateSectionState';
import { fetchTranslations as fetchAppTranslations } from 'Utilities/String/translate';
import createHandleActions from './Creators/createHandleActions';
function getDimensions(width, height) {
@@ -42,12 +41,7 @@ export const defaultState = {
isReconnecting: false,
isDisconnected: false,
isRestarting: false,
isSidebarVisible: !getDimensions(window.innerWidth, window.innerHeight).isSmallScreen,
translations: {
isFetching: true,
isPopulated: false,
error: null
}
isSidebarVisible: !getDimensions(window.innerWidth, window.innerHeight).isSmallScreen
};
//
@@ -59,7 +53,6 @@ export const SAVE_DIMENSIONS = 'app/saveDimensions';
export const SET_VERSION = 'app/setVersion';
export const SET_APP_VALUE = 'app/setAppValue';
export const SET_IS_SIDEBAR_VISIBLE = 'app/setIsSidebarVisible';
export const FETCH_TRANSLATIONS = 'app/fetchTranslations';
export const PING_SERVER = 'app/pingServer';
@@ -73,7 +66,6 @@ export const setAppValue = createAction(SET_APP_VALUE);
export const showMessage = createAction(SHOW_MESSAGE);
export const hideMessage = createAction(HIDE_MESSAGE);
export const pingServer = createThunk(PING_SERVER);
export const fetchTranslations = createThunk(FETCH_TRANSLATIONS);
//
// Helpers
@@ -135,17 +127,6 @@ function pingServerAfterTimeout(getState, dispatch) {
export const actionHandlers = handleThunks({
[PING_SERVER]: function(getState, payload, dispatch) {
pingServerAfterTimeout(getState, dispatch);
},
[FETCH_TRANSLATIONS]: async function(getState, payload, dispatch) {
const isFetchingComplete = await fetchAppTranslations();
dispatch(setAppValue({
translations: {
isFetching: false,
isPopulated: isFetchingComplete,
error: isFetchingComplete ? null : 'Failed to load translations from API'
}
}));
}
});
+5 -22
View File
@@ -1,29 +1,10 @@
import createAjaxRequest from 'Utilities/createAjaxRequest';
function getTranslations() {
return createAjaxRequest({
global: false,
dataType: 'json',
url: '/localization',
}).request;
}
let translations: Record<string, string> = {};
export async function fetchTranslations(): Promise<boolean> {
return new Promise(async (resolve) => {
try {
const data = await getTranslations();
translations = data.strings;
resolve(true);
} catch {
resolve(false);
}
});
export function setTranslations(translationData: Record<string, string>) {
translations = translationData;
}
export default function translate(
export function translate(
key: string,
tokens: Record<string, string | number | boolean> = {}
) {
@@ -41,3 +22,5 @@ export default function translate(
String(tokens[tokenMatch] ?? match)
);
}
export default translate;