# Defaults: LocaleSwitcher (/themes/sdk/reference/chrome/defaults-1)

```ts
import { … } from '@poltura/theme-sdk/chrome';
```

## `LocaleSwitcher` [#localeswitcher]

The complete language and currency switcher: each group shows only when it offers a choice, and with neither it draws nothing.

```ts
LocaleSwitcher(props: LocaleSwitcherProps): ReactElement | null
```

The dropdown's button shows the current language as `label` asks and the current currency's symbol, such as `HU` and `Ft`, divided by a thin rule; picking a currency switches through [`useCurrencySwitcher`](/themes/sdk/reference/chrome/hooks#usecurrencyswitcher). A store with other storefronts adds them as a group of its own, each by its country's flag and name, moving there through [`useStorefrontSwitcher`](/themes/sdk/reference/chrome/hooks#usestorefrontswitcher).

**Props:** [`LocaleSwitcherProps`](/themes/sdk/reference/chrome/types#localeswitcherprops)

<Tab value='Example'>

```tsx
import { LocaleSwitcher } from '@poltura/theme-sdk/chrome';

export function FooterLanguages() {
  return <LocaleSwitcher display="inline" flags />;
}
```

</Tab>
<Tab value='Source'>

```tsx title="source/locale-switcher.tsx"
import { useId, type ReactElement, type ReactNode } from 'react';
import { Check, ChevronDown } from 'lucide-react';
import {
  CurrencySwitcher,
  useCurrencySwitcher,
  useLocaleSwitcher,
  useStorefrontSwitcher,
  type LocaleSwitcherProps,
  type StorefrontChoice,
} from '@poltura/theme-sdk/chrome';
import { useIsEditing } from '@poltura/theme-sdk/editor';
import { useTranslations, type Locale } from '@poltura/theme-sdk/i18n';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
  cn,
} from '@poltura/theme-sdk/ui';

function MenuGroup({
  label,
  className,
  children,
}: {
  label: string;
  className?: string;
  children: ReactNode;
}): ReactElement {
  const id = useId();
  return (
    <div role='group' aria-labelledby={id} className={cn('py-1', className)}>
      <div id={id} className='px-2 py-1 text-xs font-medium text-muted-foreground'>
        {label}
      </div>
      {children}
    </div>
  );
}

function CountryFlag({ storefront }: { storefront: StorefrontChoice }): ReactElement {
  return (
    <span aria-hidden='true' className={`fi fi-${storefront.country.toLowerCase()} rounded-sm`} />
  );
}

function MenuChoice({
  selected,
  onSelect,
  lang,
  children,
}: {
  selected: boolean;
  onSelect: () => void;
  lang?: string;
  children: ReactNode;
}): ReactElement {
  return (
    <DropdownMenuItem role='menuitemradio' aria-checked={selected} lang={lang} onSelect={onSelect}>
      {children}
      {selected ? <Check aria-hidden='true' className='ml-auto size-4' /> : null}
    </DropdownMenuItem>
  );
}

export function LocaleSwitcher({
  display = 'dropdown',
  label = 'name',
  flags = false,
  currency = true,
  className,
  attrs,
}: LocaleSwitcherProps): ReactElement | null {
  const { current, available, hrefFor, switchTo, flagOf } = useLocaleSwitcher();
  const currencies = useCurrencySwitcher();
  const storefronts = useStorefrontSwitcher();
  const editing = useIsEditing();
  const t = useTranslations('languageSelector');
  const tAtoms = useTranslations('elements.atoms');
  const languageChoice = available.length > 1;
  const currencyChoice = currency && currencies.available.length > 1;
  const storefrontChoice = storefronts.others.length > 0;
  const shownMarket = storefronts.current;
  const markets: StorefrontChoice[] = storefrontChoice
    ? [...(shownMarket === null ? [] : [shownMarket]), ...storefronts.others]
    : [];
  const isShown = (market: StorefrontChoice): boolean => market.id === shownMarket?.id;
  // Several markets at one address look alike but for their prices: the button names the one shown.
  const marketFace =
    shownMarket !== null && storefronts.others.some((other) => other.host === shownMarket.host)
      ? shownMarket
      : null;
  if (!languageChoice && !currencyChoice && !storefrontChoice && !editing) return null;
  const sample = !languageChoice && !currencyChoice && !storefrontChoice;
  const showLanguages = languageChoice || sample;
  const showCurrencies = currencyChoice || (sample && currency);
  const languages = languageChoice ? available : [current];
  const currencyOptions = currencyChoice ? currencies.available : [currencies.current];
  const flagOnly = label === 'flag';
  const showFlags = flagOnly || flags;
  const nameOf = (locale: Locale): string => {
    if (flagOnly && flagOf(locale) !== null) return '';
    return label === 'name' ? locale.label : locale.language.toUpperCase();
  };
  const flagMark = (locale: Locale): ReactNode => {
    const country = flagOf(locale);
    return showFlags && country !== null ? (
      <span aria-hidden='true' className={`fi fi-${country.toLowerCase()} rounded-sm`} />
    ) : null;
  };
  const languageLabel = t('language');
  const currencyLabel = tAtoms('currency');
  const storefrontLabel = t('markets');

  if (display === 'inline') {
    return (
      <div
        {...attrs}
        className={cn(
          attrs?.className,
          className,
          'flex flex-wrap items-center gap-x-6 gap-y-2 text-sm',
        )}
      >
        {showLanguages ? (
          <nav aria-label={languageLabel} className='flex flex-wrap items-center gap-3'>
            {languages.map((option) => (
              <a
                key={option.tag}
                data-locale-option=''
                href={hrefFor(option)}
                hrefLang={option.tag}
                lang={option.tag}
                aria-current={option.tag === current.tag ? 'true' : undefined}
                aria-label={flagOnly ? option.label : undefined}
                onClick={(event) => {
                  if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
                  event.preventDefault();
                  switchTo(option);
                }}
                className={cn(
                  'inline-flex items-center gap-1.5 transition-colors hover:text-foreground',
                  option.tag === current.tag
                    ? 'font-semibold text-foreground'
                    : 'text-muted-foreground',
                )}
              >
                {flagMark(option)}
                {nameOf(option)}
              </a>
            ))}
          </nav>
        ) : null}
        {showCurrencies ? <CurrencySwitcher display='inline' /> : null}
        {storefrontChoice ? (
          <nav aria-label={storefrontLabel} className='flex flex-wrap items-center gap-3'>
            {markets.map((storefront) =>
              isShown(storefront) ? (
                <span
                  key={storefront.id}
                  aria-current='true'
                  className='inline-flex items-center gap-1.5 font-semibold text-foreground'
                >
                  <CountryFlag storefront={storefront} />
                  {storefront.name}
                </span>
              ) : (
                <button
                  key={storefront.id}
                  type='button'
                  onClick={() => storefronts.moveTo(storefront)}
                  className='inline-flex items-center gap-1.5 text-muted-foreground transition-colors hover:text-foreground'
                >
                  <CountryFlag storefront={storefront} />
                  {storefront.name}
                </button>
              ),
            )}
          </nav>
        ) : null}
      </div>
    );
  }

  const triggerLabel =
    showLanguages && showCurrencies
      ? t('languageAndCurrency')
      : showLanguages
        ? languageLabel
        : showCurrencies
          ? currencyLabel
          : storefrontLabel;
  // A button offering only other markets reads the market shown, else the page's own language.
  const languageFace = showLanguages || (!showCurrencies && marketFace === null);
  const languageName =
    marketFace === null || label === 'name' ? nameOf(current) : current.language.toUpperCase();
  return (
    <div
      {...attrs}
      className={cn(attrs?.className, className, 'inline-flex text-sm font-medium text-foreground')}
    >
      <DropdownMenu>
        <DropdownMenuTrigger asChild>
          <button
            type='button'
            aria-label={marketFace === null ? triggerLabel : `${triggerLabel}: ${marketFace.name}`}
            className='inline-flex items-center gap-1.5 rounded-md px-2 py-1.5 transition-colors hover:bg-muted'
          >
            {marketFace === null ? null : <CountryFlag storefront={marketFace} />}
            {marketFace !== null && !languageFace && !showCurrencies ? marketFace.name : null}
            {languageFace && marketFace === null ? flagMark(current) : null}
            {languageFace ? languageName : null}
            {showLanguages && showCurrencies ? (
              <span aria-hidden='true' className='h-3 w-px bg-current opacity-40' />
            ) : null}
            {showCurrencies ? currencies.symbolOf(currencies.current) : null}
            <ChevronDown aria-hidden='true' className='size-3.5' />
          </button>
        </DropdownMenuTrigger>
        <DropdownMenuContent align='end' className='min-w-44'>
          {showLanguages ? (
            <MenuGroup label={languageLabel}>
              {languages.map((option) => (
                <MenuChoice
                  key={option.tag}
                  selected={option.tag === current.tag}
                  lang={option.tag}
                  onSelect={() => switchTo(option)}
                >
                  {flagMark(option)}
                  {option.label}
                </MenuChoice>
              ))}
            </MenuGroup>
          ) : null}
          {showCurrencies ? (
            <MenuGroup
              label={currencyLabel}
              className={showLanguages ? 'border-t border-border' : undefined}
            >
              {currencyOptions.map((option) => (
                <MenuChoice
                  key={option}
                  selected={option === currencies.current}
                  onSelect={() => currencies.switchTo(option)}
                >
                  {option}
                  <span className='text-muted-foreground'>{currencies.symbolOf(option)}</span>
                </MenuChoice>
              ))}
            </MenuGroup>
          ) : null}
          {storefrontChoice ? (
            <MenuGroup
              label={storefrontLabel}
              className={showLanguages || showCurrencies ? 'border-t border-border' : undefined}
            >
              {markets.map((storefront) => (
                <MenuChoice
                  key={storefront.id}
                  selected={isShown(storefront)}
                  onSelect={() => {
                    if (!isShown(storefront)) storefronts.moveTo(storefront);
                  }}
                >
                  <CountryFlag storefront={storefront} />
                  {storefront.name}
                  <span className='ml-auto text-muted-foreground'>{storefront.host}</span>
                </MenuChoice>
              ))}
            </MenuGroup>
          ) : null}
        </DropdownMenuContent>
      </DropdownMenu>
    </div>
  );
}
```

</Tab>


**See also:** [`useLocaleSwitcher`](/themes/sdk/reference/chrome/hooks#uselocaleswitcher)
