import React, { memo, useCallback, useEffect, useMemo, useState, } from '../../../lib/teact/teact'; import { getActions, withGlobal } from '../../../global'; import type { FC } from '../../../lib/teact/teact'; import type { ISettings } from '../../../types'; import type { IRadioOption } from '../../ui/CheckboxGroup'; import { SUPPORTED_TRANSLATION_LANGUAGES } from '../../../config'; import { partition, unique } from '../../../util/iteratees'; import buildClassName from '../../../util/buildClassName'; import useHistoryBack from '../../../hooks/useHistoryBack'; import useEffectWithPrevDeps from '../../../hooks/useEffectWithPrevDeps'; import useLang from '../../../hooks/useLang'; import Checkbox from '../../ui/Checkbox'; import InputText from '../../ui/InputText'; import styles from './SettingsDoNotTranslate.module.scss'; // https://fasttext.cc/docs/en/language-identification.html const LOCAL_SUPPORTED_DETECTION_LANGUAGES = [ 'af', 'als', 'am', 'an', 'ar', 'arz', 'as', 'ast', 'av', 'az', 'azb', 'ba', 'bar', 'bcl', 'be', 'bg', 'bh', 'bn', 'bo', 'bpy', 'br', 'bs', 'bxr', 'ca', 'cbk', 'ce', 'ceb', 'ckb', 'co', 'cs', 'cv', 'cy', 'da', 'de', 'diq', 'dsb', 'dty', 'dv', 'el', 'eml', 'en', 'eo', 'es', 'et', 'eu', 'fa', 'fi', 'fr', 'frr', 'fy', 'ga', 'gd', 'gl', 'gn', 'gom', 'gu', 'gv', 'he', 'hi', 'hif', 'hr', 'hsb', 'ht', 'hu', 'hy', 'ia', 'id', 'ie', 'ilo', 'io', 'is', 'it', 'ja', 'jbo', 'jv', 'ka', 'kk', 'km', 'kn', 'ko', 'krc', 'ku', 'kv', 'kw', 'ky', 'la', 'lb', 'lez', 'li', 'lmo', 'lo', 'lrc', 'lt', 'lv', 'mai', 'mg', 'mhr', 'min', 'mk', 'ml', 'mn', 'mr', 'mrj', 'ms', 'mt', 'mwl', 'my', 'myv', 'mzn', 'nah', 'nap', 'nds', 'ne', 'new', 'nl', 'nn', 'no', 'oc', 'or', 'os', 'pa', 'pam', 'pfl', 'pl', 'pms', 'pnb', 'ps', 'pt', 'qu', 'rm', 'ro', 'ru', 'rue', 'sa', 'sah', 'sc', 'scn', 'sco', 'sd', 'sh', 'si', 'sk', 'sl', 'so', 'sq', 'sr', 'su', 'sv', 'sw', 'ta', 'te', 'tg', 'th', 'tk', 'tl', 'tr', 'tt', 'tyv', 'ug', 'uk', 'ur', 'uz', 'vec', 'vep', 'vi', 'vls', 'vo', 'wa', 'war', 'wuu', 'xal', 'xmf', 'yi', 'yo', 'yue', 'zh', ]; const SUPPORTED_LANGUAGES = SUPPORTED_TRANSLATION_LANGUAGES.filter((lang: string) => ( LOCAL_SUPPORTED_DETECTION_LANGUAGES.includes(lang) )); type OwnProps = { isActive?: boolean; onReset: () => void; }; type StateProps = Pick; const SettingsDoNotTranslate: FC = ({ isActive, language, doNotTranslate, onReset, }) => { const { setSettingOption } = getActions(); const lang = useLang(); const [displayedOptions, setDisplayedOptions] = useState([]); const [search, setSearch] = useState(''); const options: IRadioOption[] = useMemo(() => { return SUPPORTED_LANGUAGES.map((langCode: string) => { const translatedNames = new Intl.DisplayNames([language], { type: 'language' }); const translatedName = translatedNames.of(langCode)!; const originalNames = new Intl.DisplayNames([langCode], { type: 'language' }); const originalName = originalNames.of(langCode)!; return { langCode, translatedName, originalName, }; }).map(({ langCode, translatedName, originalName }) => ({ label: translatedName, subLabel: originalName, value: langCode, disabled: langCode === language, })); }, [language]); const allSelected = useMemo(() => { return unique([...doNotTranslate, language]); }, [doNotTranslate, language]); useEffect(() => { if (!isActive) setSearch(''); }, [isActive]); useEffectWithPrevDeps(([prevIsActive]) => { if (prevIsActive === isActive) return; if (isActive && displayedOptions.length) return; const [selected, unselected] = partition(options, (option) => allSelected.includes(option.value)); const current = selected.find((option) => option.value === language); const selectedFiltered = selected.filter((option) => option.value !== language); setDisplayedOptions([current!, ...selectedFiltered, ...unselected]); }, [isActive, allSelected, displayedOptions.length, language, options]); const handleChange = useCallback((event: React.ChangeEvent) => { const { value, checked } = event.currentTarget; let newDoNotTranslate: string[]; if (checked) { newDoNotTranslate = unique([...doNotTranslate, value]); } else { newDoNotTranslate = doNotTranslate.filter((v) => v !== value); } setSettingOption({ doNotTranslate: newDoNotTranslate, }); }, [doNotTranslate, setSettingOption]); const handleSearch = useCallback((e: React.ChangeEvent) => { setSearch(e.target.value); }, []); const filteredDisplayedOptions = useMemo(() => { if (!search.trim()) { return displayedOptions; } return displayedOptions.filter((option) => ( option.label.toLowerCase().includes(search.toLowerCase()) || option.subLabel?.toLowerCase().includes(search.toLowerCase()) || option.value.toLowerCase().includes(search.toLowerCase()) )); }, [displayedOptions, search]); useHistoryBack({ isActive, onBack: onReset, }); return (
{filteredDisplayedOptions.map((option) => ( ))}
); }; export default memo(withGlobal( (global): StateProps => { const { language, doNotTranslate, } = global.settings.byKey; return { language, doNotTranslate, }; }, )(SettingsDoNotTranslate));