mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-08-28 17:10:58 +00:00
feat: add nationality support with demonym in CountrySelect and related components
This commit is contained in:
@@ -2,13 +2,19 @@ import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Group, Select, Text, type ComboboxItem, type SelectProps } from '@mantine/core';
|
||||
import { registerLocale, getNames, getName, getAlpha2Code } from 'i18n-iso-countries';
|
||||
import {
|
||||
registerLocale as registerNationalityLocale,
|
||||
getName as getNationalityNameRaw,
|
||||
} from 'i18n-nationality';
|
||||
import * as Flags from 'country-flag-icons/react/3x2';
|
||||
import en from 'i18n-iso-countries/langs/en.json';
|
||||
import am from 'i18n-iso-countries/langs/am.json';
|
||||
import nationalityEn from 'i18n-nationality/langs/en.json';
|
||||
|
||||
// Registered once at module load — locale data is static.
|
||||
registerLocale(en);
|
||||
registerLocale(am);
|
||||
registerNationalityLocale(nationalityEn);
|
||||
|
||||
type CountryLang = 'en' | 'am';
|
||||
|
||||
@@ -26,6 +32,18 @@ export function getCountryCode(name: string | null | undefined, lang: CountryLan
|
||||
return name ? getAlpha2Code(name, lang) : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Localized demonym for an alpha-2 code (e.g. "ET" -> "Ethiopian"), for
|
||||
* nationality fields as opposed to plain country fields.
|
||||
* ponytail: i18n-nationality only ships an English locale — Amharic falls
|
||||
* back to the country name until an Amharic demonym dataset shows up.
|
||||
*/
|
||||
export function getNationalityName(code: string | null | undefined, lang: CountryLang = 'en'): string {
|
||||
if (!code) return '';
|
||||
if (lang === 'en') return getNationalityNameRaw(code, 'en') ?? getCountryName(code, lang);
|
||||
return getCountryName(code, lang);
|
||||
}
|
||||
|
||||
function CountryFlag({ code }: { code: string }) {
|
||||
const Flag = Flags[code as keyof typeof Flags];
|
||||
return Flag ? <Flag style={{ width: 22, borderRadius: 2, display: 'block' }} /> : null;
|
||||
@@ -57,12 +75,15 @@ export interface CountrySelectProps {
|
||||
error?: React.ReactNode;
|
||||
required?: boolean;
|
||||
disabled?: boolean;
|
||||
/** Show nationality labels ("Ethiopian") instead of country names ("Ethiopia"). */
|
||||
demonym?: boolean;
|
||||
}
|
||||
|
||||
export function CountrySelect({
|
||||
value,
|
||||
onChange,
|
||||
placeholder,
|
||||
demonym,
|
||||
...rest
|
||||
}: CountrySelectProps) {
|
||||
const { t, i18n } = useTranslation();
|
||||
@@ -70,10 +91,10 @@ export function CountrySelect({
|
||||
|
||||
const countries = useMemo(
|
||||
() =>
|
||||
Object.entries(getNames(lang))
|
||||
.map(([code, label]) => ({ value: code, label }))
|
||||
Object.keys(getNames(lang))
|
||||
.map((code) => ({ value: code, label: demonym ? getNationalityName(code, lang) : getCountryName(code, lang) }))
|
||||
.sort((a, b) => a.label.localeCompare(b.label, lang)),
|
||||
[lang],
|
||||
[lang, demonym],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user