Skip to main content
Glama
LocaleSwitcher.tsx5.98 kB
'use client'; import { getHTMLTextDir, getLocaleName } from '@intlayer/core'; import { type Locale, Locales } from '@intlayer/types'; import Fuse, { type IFuseOptions } from 'fuse.js'; import { MoveVertical } from 'lucide-react'; import { type FC, useCallback, useMemo, useRef, useState } from 'react'; import { useIntlayer } from 'react-intlayer'; import { Button, ButtonColor, ButtonTextAlign, ButtonVariant } from '../Button'; import { Container } from '../Container'; import { DropDown, type PanelProps } from '../DropDown'; import { Input } from '../Input'; export type LocaleSwitcherProps = { locale?: Locale; localeList: Locale[]; availableLocales?: Locale[]; fullLocaleName?: boolean; setLocale: (locale: Locale) => void; panelProps?: Omit<PanelProps, 'identifier'>; }; const DROPDOWN_IDENTIFIER = 'locale-switcher'; type MultilingualAvailableLocales = { locale: Locale; englishName: string; currentLocaleName: string; ownLocaleName: string; }; export const LocaleSwitcher: FC<LocaleSwitcherProps> = ({ locale, localeList, availableLocales, fullLocaleName = true, setLocale, panelProps, }) => { let localeName = 'Select a locale'; const { switchTo, searchInput, languageListLabel } = useIntlayer('locale-switcher'); const inputRef = useRef<HTMLInputElement>(null); const multilingualAvailableLocales: MultilingualAvailableLocales[] = useMemo( () => localeList.map((localeEl) => { const englishName = getLocaleName(localeEl, Locales.ENGLISH); const currentLocaleName = getLocaleName(localeEl, locale); const ownLocaleName = getLocaleName(localeEl); return { locale: localeEl, englishName, currentLocaleName, ownLocaleName, }; }), [localeList, locale] ); const [results, setResults] = useState<MultilingualAvailableLocales[]>( multilingualAvailableLocales ); // Create a new Fuse instance with the options and documentation data const fuse = useMemo(() => { const fuseOptions: IFuseOptions<MultilingualAvailableLocales> = { keys: [ { name: 'ownLocaleName', weight: 0.4 }, { name: 'englishName', weight: 0.2 }, { name: 'currentLocaleName', weight: 0.2 }, { name: 'locale', weight: 0.2 }, ], threshold: 0.02, // Defines how fuzzy the matching should be (lower is more strict) }; return new Fuse(multilingualAvailableLocales, fuseOptions); }, [multilingualAvailableLocales]); const handleSearch = useCallback( (searchQuery: string) => { if (searchQuery) { // Perform search on every input change const searchResults = fuse .search(searchQuery) .map((result) => result.item); setResults(searchResults); } else { setResults(multilingualAvailableLocales); } }, [fuse, multilingualAvailableLocales] ); if (locale) { localeName = fullLocaleName ? getLocaleName(locale) : locale.toUpperCase(); } return ( <div className="rounded-xl border border-text text-text transition-colors" aria-label={localeSwitcherLabel.value} > <DropDown identifier={DROPDOWN_IDENTIFIER}> <DropDown.Trigger identifier={DROPDOWN_IDENTIFIER}> <div className="flex w-full items-center justify-between"> <div className="text-nowrap px-2">{localeName}</div> <MoveVertical className="w-5 self-center" /> </div> </DropDown.Trigger> <DropDown.Panel identifier={DROPDOWN_IDENTIFIER} isOverable isFocusable {...panelProps} > <Container className="max-h-[80vh] min-w-28" separator="y" role="listbox" transparency="sm" aria-label={languageListLabel.value} > <div className="p-3"> <Input type="search" aria-label={searchInput.ariaLabel.value} placeholder={searchInput.placeholder.value} onChange={(e) => handleSearch(e.target.value)} ref={inputRef} /> </div> <ol className="divide-y divide-dashed divide-text/20 overflow-y-auto p-1"> {results.map( ({ locale: localeItem, currentLocaleName, ownLocaleName }) => ( <li className="px-1.5 py-1" key={localeItem}> <Button onClick={() => setLocale(localeItem)} label={`${switchTo} ${currentLocaleName}`} disabled={ !(availableLocales ?? localeList).includes(localeItem) } isActive={locale === localeItem} variant={ButtonVariant.HOVERABLE} color={ButtonColor.TEXT} isFullWidth textAlign={ButtonTextAlign.LEFT} > <div className="flex flex-row items-center justify-between gap-3 px-2 py-1"> <div className="flex flex-col text-nowrap"> <span dir={getHTMLTextDir(localeItem)} lang={localeItem} > {ownLocaleName} </span> <span className="text-neutral text-xs"> {currentLocaleName} </span> </div> <span className="text-neutral text-sm"> {localeItem.toUpperCase()} </span> </div> </Button> </li> ) )} </ol> </Container> </DropDown.Panel> </DropDown> </div> ); };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/aymericzip/intlayer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server