| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- /**
- * 国家/地区拨号码(region dialing codes)资源 + 查询能力。
- *
- * 与原始扁平 `areaCodeList` 完全不同的设计要点:
- * - 按地理簇分组,便于做 SectionList 视觉分隔;
- * - 每条记录携带 flag emoji,不依赖图片资源;
- * - 提供按关键字(区号 / 中文名 / 英文名 / 短码)的搜索;
- * - 数据冻结,外部消费者不可篡改。
- */
- const SOURCE_TABLE = [
- { slug: 'hk', dial: '852', flag: '🇭🇰', zh: '中国香港', en: 'Hong Kong', cluster: 'sino' },
- { slug: 'mo', dial: '853', flag: '🇲🇴', zh: '中国澳门', en: 'Macau', cluster: 'sino' },
- { slug: 'tw', dial: '886', flag: '🇨🇳', zh: '中国台湾', en: 'Taiwan', cluster: 'sino' },
- { slug: 'cn', dial: '86', flag: '🇨🇳', zh: '中国大陆', en: 'Mainland China', cluster: 'sino' },
- { slug: 'sg', dial: '65', flag: '🇸🇬', zh: '新加坡', en: 'Singapore', cluster: 'apac' },
- { slug: 'my', dial: '60', flag: '🇲🇾', zh: '马来西亚', en: 'Malaysia', cluster: 'apac' },
- { slug: 'jp', dial: '81', flag: '🇯🇵', zh: '日本', en: 'Japan', cluster: 'apac' },
- { slug: 'kr', dial: '82', flag: '🇰🇷', zh: '韩国', en: 'South Korea', cluster: 'apac' },
- { slug: 'th', dial: '66', flag: '🇹🇭', zh: '泰国', en: 'Thailand', cluster: 'apac' },
- { slug: 'vn', dial: '84', flag: '🇻🇳', zh: '越南', en: 'Vietnam', cluster: 'apac' },
- { slug: 'id', dial: '62', flag: '🇮🇩', zh: '印度尼西亚', en: 'Indonesia', cluster: 'apac' },
- { slug: 'ph', dial: '63', flag: '🇵🇭', zh: '菲律宾', en: 'Philippines', cluster: 'apac' },
- { slug: 'us', dial: '1', flag: '🇺🇸', zh: '美国', en: 'United States', cluster: 'global' },
- { slug: 'ca', dial: '1', flag: '🇨🇦', zh: '加拿大', en: 'Canada', cluster: 'global' },
- { slug: 'uk', dial: '44', flag: '🇬🇧', zh: '英国', en: 'United Kingdom', cluster: 'global' },
- { slug: 'au', dial: '61', flag: '🇦🇺', zh: '澳大利亚', en: 'Australia', cluster: 'global' },
- { slug: 'nz', dial: '64', flag: '🇳🇿', zh: '新西兰', en: 'New Zealand', cluster: 'global' }
- ]
- export const REGION_ROSTER = Object.freeze(SOURCE_TABLE.map((row) => Object.freeze({ ...row })))
- const CLUSTER_TITLES = Object.freeze({
- sino: { zh: '大中华', en: 'Greater China' },
- apac: { zh: '亚太地区', en: 'Asia Pacific' },
- global: { zh: '其他国家或地区', en: 'Worldwide' },
- remote: { zh: '全部', en: 'All regions' }
- })
- export const DEFAULT_REGION = '852'
- function langKey(locale) {
- if (!locale) return 'zh'
- return String(locale).toLowerCase().startsWith('en') ? 'en' : 'zh'
- }
- export function localizeRegion(entry, locale) {
- if (!entry) return ''
- return langKey(locale) === 'en' ? entry.en : entry.zh
- }
- export function localizeCluster(clusterId, locale) {
- const meta = CLUSTER_TITLES[clusterId]
- if (!meta) return ''
- return meta[langKey(locale)] || meta.zh
- }
- /**
- * 把 ROSTER 折叠为「簇 + 行」结构,便于 SectionList 渲染。
- */
- export function clusterRegions(locale, roster = REGION_ROSTER) {
- const order = []
- const bucket = new Map()
- roster.forEach((row) => {
- if (!bucket.has(row.cluster)) {
- bucket.set(row.cluster, { id: row.cluster, label: localizeCluster(row.cluster, locale), rows: [] })
- order.push(row.cluster)
- }
- bucket.get(row.cluster).rows.push(row)
- })
- return order.map((id) => bucket.get(id))
- }
- /**
- * 按关键字筛选(匹配区号、国家名、slug)。
- */
- export function filterRegions(keyword, locale, roster = REGION_ROSTER) {
- const word = String(keyword || '').trim().toLowerCase()
- if (!word) return roster.slice()
- return roster.filter((row) => {
- if (row.dial.includes(word)) return true
- if (row.slug.includes(word)) return true
- if (row.en.toLowerCase().includes(word)) return true
- if (row.zh.toLowerCase().includes(word)) return true
- return localizeRegion(row, locale).toLowerCase().includes(word)
- })
- }
- /**
- * 优先按 slug 精确匹配,否则按区号取首条记录。
- */
- export function findRegion(idOrDial, roster = REGION_ROSTER) {
- const raw = String(idOrDial || '').replace(/^\+/, '')
- if (!raw) return null
- const bySlug = roster.find((row) => row.slug === raw)
- if (bySlug) return bySlug
- return roster.find((row) => row.dial === raw) || null
- }
|