fix: correctly fall back to English name in LanguageSelector (#1537)

* fix: correctly fall back to English name in LanguageSelector

* refactor: clean up language sort & name logic

* refactor: also clean up region sort & name logic

* refactor: use arrow functions
pull/1553/head
TheCatLady 3 years ago committed by GitHub
parent b7b55e275c
commit 189313e94a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -14,6 +14,7 @@ export interface Library {
export interface Region {
iso_3166_1: string;
english_name: string;
name?: string;
}
export interface Language {

@ -1,8 +1,10 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { sortBy } from 'lodash';
import dynamic from 'next/dynamic';
import React from 'react';
import React, { useMemo } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import type { OptionsType, OptionTypeBase } from 'react-select';
import useSWR from 'swr';
import { Language } from '../../../server/lib/settings';
import globalMessages from '../../i18n/globalMessages';
@ -29,7 +31,6 @@ const selectStyles = {
};
interface LanguageSelectorProps {
languages: Language[];
value?: string;
setFieldValue: (property: string, value: string) => void;
serverValue?: string;
@ -37,26 +38,33 @@ interface LanguageSelectorProps {
}
const LanguageSelector: React.FC<LanguageSelectorProps> = ({
languages,
value,
setFieldValue,
serverValue,
isUserSettings = false,
}) => {
const intl = useIntl();
const { data: languages } = useSWR<Language[]>('/api/v1/languages');
const defaultLanguageNameFallback = serverValue
? languages.find((language) => language.iso_639_1 === serverValue)
?.english_name ?? serverValue
: undefined;
const options: OptionType[] =
languages.map((language) => ({
label:
const sortedLanguages = useMemo(() => {
languages?.forEach((language) => {
language.name =
intl.formatDisplayName(language.iso_639_1, {
type: 'language',
fallback: 'none',
}) ?? language.english_name,
}) ?? language.english_name;
});
return sortBy(languages, 'name');
}, [intl, languages]);
const languageName = (languageCode: string) =>
sortedLanguages?.find((language) => language.iso_639_1 === languageCode)
?.name ?? languageCode;
const options: OptionType[] =
sortedLanguages?.map((language) => ({
label: language.name,
value: language.iso_639_1,
})) ?? [];
@ -67,13 +75,7 @@ const LanguageSelector: React.FC<LanguageSelectorProps> = ({
language: serverValue
? serverValue
.split('|')
.map(
(value) =>
intl.formatDisplayName(value, {
type: 'language',
fallback: 'none',
}) ?? defaultLanguageNameFallback
)
.map((value) => languageName(value))
.reduce((prev, curr) =>
intl.formatMessage(globalMessages.delimitedlist, {
a: prev,
@ -112,13 +114,7 @@ const LanguageSelector: React.FC<LanguageSelectorProps> = ({
language: serverValue
? serverValue
.split('|')
.map(
(value) =>
intl.formatDisplayName(value, {
type: 'language',
fallback: 'none',
}) ?? defaultLanguageNameFallback
)
.map((value) => languageName(value))
.reduce((prev, curr) =>
intl.formatMessage(globalMessages.delimitedlist, {
a: prev,
@ -130,7 +126,7 @@ const LanguageSelector: React.FC<LanguageSelectorProps> = ({
isFixed: true,
}
: value?.split('|').map((code) => {
const matchedLanguage = languages.find(
const matchedLanguage = sortedLanguages?.find(
(lang) => lang.iso_639_1 === code
);
@ -139,11 +135,7 @@ const LanguageSelector: React.FC<LanguageSelectorProps> = ({
}
return {
label:
intl.formatDisplayName(matchedLanguage.iso_639_1, {
type: 'language',
fallback: 'none',
}) ?? matchedLanguage.english_name,
label: matchedLanguage.name,
value: matchedLanguage.iso_639_1,
};
}) ?? undefined

@ -2,6 +2,7 @@ import { Listbox, Transition } from '@headlessui/react';
import { CheckIcon, ChevronDownIcon } from '@heroicons/react/solid';
import { hasFlag } from 'country-flag-icons';
import 'country-flag-icons/3x2/flags.css';
import { sortBy } from 'lodash';
import React, { useEffect, useMemo, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import useSWR from 'swr';
@ -39,32 +40,21 @@ const RegionSelector: React.FC<RegionSelectorProps> = ({
[]
);
const sortedRegions = useMemo(
() =>
regions?.sort((region1, region2) => {
const region1Name =
intl.formatDisplayName(region1.iso_3166_1, {
type: 'region',
fallback: 'none',
}) ?? region1.english_name;
const region2Name =
intl.formatDisplayName(region2.iso_3166_1, {
type: 'region',
fallback: 'none',
}) ?? region2.english_name;
const sortedRegions = useMemo(() => {
regions?.forEach((region) => {
region.name =
intl.formatDisplayName(region.iso_3166_1, {
type: 'region',
fallback: 'none',
}) ?? region.english_name;
});
return region1Name === region2Name
? 0
: region1Name > region2Name
? 1
: -1;
}),
[intl, regions]
);
return sortBy(regions, 'name');
}, [intl, regions]);
const defaultRegionNameFallback =
regions?.find((region) => region.iso_3166_1 === currentSettings.region)
?.english_name ?? currentSettings.region;
const regionName = (regionCode: string) =>
sortedRegions?.find((region) => region.iso_3166_1 === regionCode)?.name ??
regionCode;
useEffect(() => {
if (regions && value) {
@ -110,17 +100,11 @@ const RegionSelector: React.FC<RegionSelectorProps> = ({
)}
<span className="block truncate">
{selectedRegion && selectedRegion.iso_3166_1 !== 'all'
? intl.formatDisplayName(selectedRegion.iso_3166_1, {
type: 'region',
fallback: 'none',
}) ?? selectedRegion.english_name
? regionName(selectedRegion.iso_3166_1)
: isUserSetting && selectedRegion?.iso_3166_1 !== 'all'
? intl.formatMessage(messages.regionServerDefault, {
region: currentSettings.region
? intl.formatDisplayName(currentSettings.region, {
type: 'region',
fallback: 'none',
}) ?? defaultRegionNameFallback
? regionName(currentSettings.region)
: intl.formatMessage(messages.regionDefault),
})
: intl.formatMessage(messages.regionDefault)}
@ -168,13 +152,7 @@ const RegionSelector: React.FC<RegionSelectorProps> = ({
>
{intl.formatMessage(messages.regionServerDefault, {
region: currentSettings.region
? intl.formatDisplayName(
currentSettings.region,
{
type: 'region',
fallback: 'none',
}
) ?? defaultRegionNameFallback
? regionName(currentSettings.region)
: intl.formatMessage(messages.regionDefault),
})}
</span>
@ -241,10 +219,7 @@ const RegionSelector: React.FC<RegionSelectorProps> = ({
selected ? 'font-semibold' : 'font-normal'
} block truncate`}
>
{intl.formatDisplayName(region.iso_3166_1, {
type: 'region',
fallback: 'none',
}) ?? region.english_name}
{regionName(region.iso_3166_1)}
</span>
{selected && (
<span

@ -1,12 +1,12 @@
import { RefreshIcon } from '@heroicons/react/solid';
import axios from 'axios';
import { Field, Form, Formik } from 'formik';
import React, { useMemo } from 'react';
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications';
import useSWR, { mutate } from 'swr';
import * as Yup from 'yup';
import type { Language, MainSettings } from '../../../server/lib/settings';
import type { MainSettings } from '../../../server/lib/settings';
import { Permission, useUser } from '../../hooks/useUser';
import globalMessages from '../../i18n/globalMessages';
import Badge from '../Common/Badge';
@ -58,9 +58,7 @@ const SettingsMain: React.FC = () => {
const { data, error, revalidate } = useSWR<MainSettings>(
'/api/v1/settings/main'
);
const { data: languages, error: languagesError } = useSWR<Language[]>(
'/api/v1/languages'
);
const MainSettingsSchema = Yup.object().shape({
applicationTitle: Yup.string().required(
intl.formatMessage(messages.validationApplicationTitle)
@ -96,26 +94,7 @@ const SettingsMain: React.FC = () => {
}
};
const sortedLanguages = useMemo(
() =>
languages?.sort((lang1, lang2) => {
const lang1Name =
intl.formatDisplayName(lang1.iso_639_1, {
type: 'language',
fallback: 'none',
}) ?? lang1.english_name;
const lang2Name =
intl.formatDisplayName(lang2.iso_639_1, {
type: 'language',
fallback: 'none',
}) ?? lang2.english_name;
return lang1Name === lang2Name ? 0 : lang1Name > lang2Name ? 1 : -1;
}),
[intl, languages]
);
if (!data && !error && !languages && !languagesError) {
if (!data && !error) {
return <LoadingSpinner />;
}
@ -316,7 +295,6 @@ const SettingsMain: React.FC = () => {
<div className="form-input">
<div className="form-input-field">
<LanguageSelector
languages={sortedLanguages ?? []}
setFieldValue={setFieldValue}
value={values.originalLanguage}
/>

@ -1,12 +1,11 @@
import axios from 'axios';
import { Field, Form, Formik } from 'formik';
import { useRouter } from 'next/router';
import React, { useEffect, useMemo, useState } from 'react';
import React, { useEffect, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications';
import useSWR from 'swr';
import { UserSettingsGeneralResponse } from '../../../../../server/interfaces/api/userSettingsInterfaces';
import { Language } from '../../../../../server/lib/settings';
import {
availableLanguages,
AvailableLocales,
@ -72,38 +71,11 @@ const UserGeneralSettings: React.FC = () => {
);
}, [data]);
const { data: languages, error: languagesError } = useSWR<Language[]>(
'/api/v1/languages'
);
const sortedLanguages = useMemo(
() =>
languages?.sort((lang1, lang2) => {
const lang1Name =
intl.formatDisplayName(lang1.iso_639_1, {
type: 'language',
fallback: 'none',
}) ?? lang1.english_name;
const lang2Name =
intl.formatDisplayName(lang2.iso_639_1, {
type: 'language',
fallback: 'none',
}) ?? lang2.english_name;
return lang1Name === lang2Name ? 0 : lang1Name > lang2Name ? 1 : -1;
}),
[intl, languages]
);
if (!data && !error) {
return <LoadingSpinner />;
}
if (!languages && !languagesError) {
return <LoadingSpinner />;
}
if (!data || !languages) {
if (!data) {
return <Error statusCode={500} />;
}
@ -263,7 +235,6 @@ const UserGeneralSettings: React.FC = () => {
<div className="form-input">
<div className="form-input-field">
<LanguageSelector
languages={sortedLanguages ?? []}
setFieldValue={setFieldValue}
serverValue={currentSettings.originalLanguage}
value={values.originalLanguage}

Loading…
Cancel
Save