diff --git a/src/common/index.js b/src/common/index.js index 55ccfe045..3354a64e4 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -26,6 +26,7 @@ const useStreamingServer = require('./useStreamingServer'); const useTorrent = require('./useTorrent'); const useTranslate = require('./useTranslate'); const { default: useOrientation } = require('./useOrientation'); +const { default: useLanguageSorting } = require('./useLanguageSorting'); module.exports = { FileDropProvider, @@ -59,4 +60,5 @@ module.exports = { useTorrent, useTranslate, useOrientation, + useLanguageSorting, }; diff --git a/src/common/useLanguageSorting.ts b/src/common/useLanguageSorting.ts new file mode 100644 index 000000000..44c8927bd --- /dev/null +++ b/src/common/useLanguageSorting.ts @@ -0,0 +1,36 @@ +import { useMemo } from 'react'; +import interfaceLanguages from 'stremio/common/interfaceLanguages.json'; + +const useLanguageSorting = (options: MultiselectMenuOption[]) => { + const userLangCode = useMemo(() => { + const lang = interfaceLanguages.find((l) => l.codes.includes(navigator.language || 'en-US')); + if (lang) { + const threeLetter = lang.codes[1] || 'eng'; + const fullLocale = navigator.language || 'en-US'; + return [threeLetter, fullLocale]; + } + return ['eng']; + }, []); + + const isLanguageDropdown = useMemo(() => { + return options?.some((opt) => interfaceLanguages.some((l) => l.name === opt.label)); + }, [options]); + + const sortedOptions = useMemo(() => { + const matchingIndex = options.findIndex((opt) => { + const lang = interfaceLanguages.find((l) => l.name === opt.label); + return userLangCode.some((code) => lang?.codes.includes(code)); + }); + + if (matchingIndex === -1) return options; + + const matchingOption = options[matchingIndex]; + const otherOptions = options.filter((_, index) => index !== matchingIndex); + + return [matchingOption, ...otherOptions]; + }, [options, userLangCode, isLanguageDropdown]); + + return { userLangCode, isLanguageDropdown, sortedOptions }; +}; + +export default useLanguageSorting; diff --git a/src/routes/Settings/General/useGeneralOptions.ts b/src/routes/Settings/General/useGeneralOptions.ts index 59e7b40c1..a4ab84c5e 100644 --- a/src/routes/Settings/General/useGeneralOptions.ts +++ b/src/routes/Settings/General/useGeneralOptions.ts @@ -1,16 +1,24 @@ import { useMemo } from 'react'; -import { interfaceLanguages } from 'stremio/common'; +import { interfaceLanguages, useLanguageSorting } from 'stremio/common'; import { useServices } from 'stremio/services'; const useGeneralOptions = (profile: Profile) => { const { core } = useServices(); - const interfaceLanguageSelect = useMemo(() => ({ - options: interfaceLanguages.map(({ name, codes }) => ({ + const interfaceLanguageOptions = useMemo(() => + interfaceLanguages.map(({ name, codes }) => ({ value: codes[0], label: name, })), - value: interfaceLanguages.find(({ codes }) => codes[1] === profile.settings.interfaceLanguage)?.codes?.[0] || profile.settings.interfaceLanguage, + []); + + const { sortedOptions } = useLanguageSorting(interfaceLanguageOptions); + + const interfaceLanguageSelect = useMemo(() => ({ + options: sortedOptions, + value: + interfaceLanguages.find(({ codes }) => codes[1] === profile.settings.interfaceLanguage)?.codes?.[0] || + profile.settings.interfaceLanguage, onSelect: (value: string) => { core.transport.dispatch({ action: 'Ctx', @@ -23,7 +31,7 @@ const useGeneralOptions = (profile: Profile) => { } }); } - }), [profile.settings]); + }), [profile.settings, sortedOptions]); const escExitFullscreenToggle = useMemo(() => ({ checked: profile.settings.escExitFullscreen, diff --git a/src/routes/Settings/Player/usePlayerOptions.ts b/src/routes/Settings/Player/usePlayerOptions.ts index 04c263d54..982c5138e 100644 --- a/src/routes/Settings/Player/usePlayerOptions.ts +++ b/src/routes/Settings/Player/usePlayerOptions.ts @@ -1,7 +1,7 @@ import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { useServices } from 'stremio/services'; -import { CONSTANTS, languageNames, usePlatform } from 'stremio/common'; +import { CONSTANTS, languageNames, usePlatform, useLanguageSorting } from 'stremio/common'; const LANGUAGES_NAMES: Record = languageNames; @@ -10,13 +10,18 @@ const usePlayerOptions = (profile: Profile) => { const { core } = useServices(); const platform = usePlatform(); + const languageOptions = useMemo(() => + Object.keys(LANGUAGES_NAMES).map((code) => ({ + value: code, + label: LANGUAGES_NAMES[code] + })), []); + + const { sortedOptions: sortedLanguageOptions } = useLanguageSorting(languageOptions); + const subtitlesLanguageSelect = useMemo(() => ({ options: [ { value: null, label: t('NONE') }, - ...Object.keys(LANGUAGES_NAMES).map((code) => ({ - value: code, - label: LANGUAGES_NAMES[code] - })) + ...sortedLanguageOptions ], value: profile.settings.subtitlesLanguage, onSelect: (value: string) => { @@ -31,7 +36,7 @@ const usePlayerOptions = (profile: Profile) => { } }); } - }), [profile.settings]); + }), [profile.settings, sortedLanguageOptions]); const subtitlesSizeSelect = useMemo(() => ({ options: CONSTANTS.SUBTITLES_SIZES.map((size) => ({ @@ -105,10 +110,7 @@ const usePlayerOptions = (profile: Profile) => { }), [profile.settings]); const audioLanguageSelect = useMemo(() => ({ - options: Object.keys(LANGUAGES_NAMES).map((code) => ({ - value: code, - label: LANGUAGES_NAMES [code] - })), + options: sortedLanguageOptions, value: profile.settings.audioLanguage, onSelect: (value: string) => { core.transport.dispatch({ @@ -122,7 +124,7 @@ const usePlayerOptions = (profile: Profile) => { } }); } - }), [profile.settings]); + }), [profile.settings, sortedLanguageOptions]); const surroundSoundToggle = useMemo(() => ({ checked: profile.settings.surroundSound,