phanpy/src/components/lang-selector.jsx

116 lines
3.5 KiB
React
Raw Normal View History

2024-08-13 15:26:23 +08:00
import { useLingui } from '@lingui/react';
import { useMemo } from 'preact/hooks';
2024-08-13 15:26:23 +08:00
import { CATALOGS, DEFAULT_LANG, DEV_LOCALES, LOCALES } from '../locales';
import { activateLang } from '../utils/lang';
2024-08-13 15:26:23 +08:00
import localeCode2Text from '../utils/localeCode2Text';
2024-08-25 17:53:38 +08:00
import store from '../utils/store';
2024-08-13 15:26:23 +08:00
const regionMaps = {
'zh-CN': 'zh-Hans',
'zh-TW': 'zh-Hant',
2024-08-31 18:31:41 +08:00
'pt-BR': 'pt-BR',
};
2024-08-13 15:26:23 +08:00
export default function LangSelector() {
const { i18n } = useLingui();
// Sorted on render, so the order won't suddenly change based on current locale
const populatedLocales = useMemo(() => {
return LOCALES.map((lang) => {
// Don't need regions for now, it makes text too noisy
// Wait till there's too many languages and there are regional clashes
const regionlessCode = regionMaps[lang] || lang.replace(/-[a-z]+$/i, '');
2024-08-20 20:00:33 +08:00
const native = localeCode2Text({
code: regionlessCode,
locale: lang,
2024-08-20 20:18:16 +08:00
fallback: CATALOGS.find((c) => c.code === lang)?.nativeName,
2024-08-20 20:00:33 +08:00
});
// Not used when rendering because it'll change based on current locale
// Only used for sorting on render
const _common = localeCode2Text({
code: regionlessCode,
locale: i18n.locale,
2024-08-20 20:18:16 +08:00
fallback: CATALOGS.find((c) => c.code === lang)?.name,
});
return {
code: lang,
regionlessCode,
_common,
native,
};
}).sort((a, b) => {
// Sort by common name
2024-08-18 12:46:45 +08:00
const order = a._common.localeCompare(b._common, i18n.locale);
if (order !== 0) return order;
// Sort by code (fallback)
if (a.code < b.code) return -1;
if (a.code > b.code) return 1;
return 0;
});
}, []);
2024-08-13 15:26:23 +08:00
return (
<label class="lang-selector">
🌐{' '}
<select
2024-08-15 17:34:24 +08:00
class="small"
2024-08-13 15:26:23 +08:00
value={i18n.locale || DEFAULT_LANG}
onChange={(e) => {
2024-08-25 17:53:38 +08:00
store.local.set('lang', e.target.value);
2024-08-13 15:26:23 +08:00
activateLang(e.target.value);
}}
>
{populatedLocales.map(({ code, regionlessCode, native }) => {
// Common name changes based on current locale
const common = localeCode2Text({
code: regionlessCode,
locale: i18n.locale,
2024-08-20 20:18:16 +08:00
fallback: CATALOGS.find((c) => c.code === code)?.name,
});
const showCommon = !!common && common !== native;
2024-08-13 15:26:23 +08:00
return (
<option
value={code}
data-regionless-code={regionlessCode}
key={code}
>
{showCommon ? `${native} - ${common}` : native}
2024-08-13 15:26:23 +08:00
</option>
);
})}
{(import.meta.env.DEV || import.meta.env.PHANPY_SHOW_DEV_LOCALES) && (
<optgroup label="🚧 Development (<50% translated)">
{DEV_LOCALES.map((code) => {
if (code === 'pseudo-LOCALE') {
return (
<>
<hr />
<option value={code} key={code}>
Pseudolocalization (test)
</option>
</>
);
}
const nativeName = CATALOGS.find(
(c) => c.code === code,
)?.nativeName;
const completion = CATALOGS.find(
(c) => c.code === code,
)?.completion;
return (
<option value={code} key={code}>
{nativeName || code} &lrm;[{completion}%]
</option>
);
})}
</optgroup>
)}
2024-08-13 15:26:23 +08:00
</select>
</label>
);
}