From c7691ae9a70a4c2a94a9435c84a5dff6c5e30edf Mon Sep 17 00:00:00 2001 From: laoboli <1293528695@qq.com> Date: Thu, 23 Jul 2026 16:30:02 +0800 Subject: [PATCH] fix: geo show --- src/components/hooks/useFormat.ts | 5 ++- src/components/hooks/useRegionNames.ts | 3 +- src/lib/detect.ts | 45 +------------------- src/lib/geo.test.ts | 11 +++++ src/lib/geo.ts | 57 ++++++++++++++++++++++++++ 5 files changed, 74 insertions(+), 47 deletions(-) create mode 100644 src/lib/geo.test.ts create mode 100644 src/lib/geo.ts diff --git a/src/components/hooks/useFormat.ts b/src/components/hooks/useFormat.ts index 998102c31..b03059b68 100644 --- a/src/components/hooks/useFormat.ts +++ b/src/components/hooks/useFormat.ts @@ -1,5 +1,5 @@ import { BROWSERS, OS_NAMES } from '@/lib/constants'; -import regions from '../../../public/iso-3166-2.json'; +import { getRegionNames } from '@/lib/geo'; import { useCountryNames } from './useCountryNames'; import { useLanguageNames } from './useLanguageNames'; import { useLocale } from './useLocale'; @@ -10,6 +10,7 @@ export function useFormat() { const { locale } = useLocale(); const { countryNames } = useCountryNames(locale); const { languageNames } = useLanguageNames(locale); + const regionNames = getRegionNames(locale); const formatOS = (value: string): string => { return OS_NAMES[value] || value; @@ -29,7 +30,7 @@ export function useFormat() { const formatRegion = (value?: string): string => { const [country] = value?.split('-') || []; - return regions[value] ? `${regions[value]}, ${countryNames[country]}` : value; + return regionNames[value] ? `${regionNames[value]}, ${countryNames[country]}` : value; }; const formatCity = (value: string, country?: string): string => { diff --git a/src/components/hooks/useRegionNames.ts b/src/components/hooks/useRegionNames.ts index 57dcc416c..b90ab8157 100644 --- a/src/components/hooks/useRegionNames.ts +++ b/src/components/hooks/useRegionNames.ts @@ -1,8 +1,9 @@ -import regions from '../../../public/iso-3166-2.json'; +import { getRegionNames } from '@/lib/geo'; import { useCountryNames } from './useCountryNames'; export function useRegionNames(locale: string) { const { countryNames } = useCountryNames(locale); + const regions = getRegionNames(locale); const getRegionName = (regionCode: string, countryCode?: string) => { if (!countryCode) { diff --git a/src/lib/detect.ts b/src/lib/detect.ts index ad9e22ff4..e9a511cbf 100644 --- a/src/lib/detect.ts +++ b/src/lib/detect.ts @@ -4,6 +4,7 @@ import ipaddr from 'ipaddr.js'; import isLocalhost from 'is-localhost-ip'; import maxmind from 'maxmind'; import { UAParser } from 'ua-parser-js'; +import { getChinaRegionCode } from '@/lib/geo'; import { getIpAddress, stripPort } from '@/lib/ip'; import { safeDecodeURIComponent } from '@/lib/url'; @@ -11,43 +12,6 @@ const MAXMIND = 'maxmind'; const IP_LOCATION_API_URL = 'https://ip9.com.cn/get'; const IP_LOCATION_API_TIMEOUT = 2000; -const CHINA_REGION_CODES = { - 北京: 'BJ', - 天津: 'TJ', - 河北: 'HE', - 山西: 'SX', - 内蒙古: 'NM', - 辽宁: 'LN', - 吉林: 'JL', - 黑龙江: 'HL', - 上海: 'SH', - 江苏: 'JS', - 浙江: 'ZJ', - 安徽: 'AH', - 福建: 'FJ', - 江西: 'JX', - 山东: 'SD', - 河南: 'HA', - 湖北: 'HB', - 湖南: 'HN', - 广东: 'GD', - 广西: 'GX', - 海南: 'HI', - 重庆: 'CQ', - 四川: 'SC', - 贵州: 'GZ', - 云南: 'YN', - 西藏: 'XZ', - 陕西: 'SN', - 甘肃: 'GS', - 青海: 'QH', - 宁夏: 'NX', - 新疆: 'XJ', - 台湾: 'TW', - 香港: 'HK', - 澳门: 'MO', -}; - const PROVIDER_HEADERS = [ // Umami custom headers (cloud mode only) ...(process.env.CLOUD_MODE @@ -123,13 +87,6 @@ async function isLocalIp(ip: string) { } } -function getChinaRegionCode(province: string) { - const name = province?.trim(); - const region = Object.entries(CHINA_REGION_CODES).find(([key]) => name?.startsWith(key))?.[1]; - - return region ? getRegionCode('CN', region) : undefined; -} - async function getOnlineLocation(ip: string) { try { const url = new URL(process.env.IP_LOCATION_API_URL || IP_LOCATION_API_URL); diff --git a/src/lib/geo.test.ts b/src/lib/geo.test.ts new file mode 100644 index 000000000..37510eb46 --- /dev/null +++ b/src/lib/geo.test.ts @@ -0,0 +1,11 @@ +import { expect, test } from 'vitest'; +import { getChinaRegionCode, getRegionNames } from './geo'; + +test('getChinaRegionCode: converts Chinese province names to ISO codes', () => { + expect(getChinaRegionCode('福建省')).toBe('CN-FJ'); +}); + +test('getRegionNames: localizes Chinese regions for zh-CN', () => { + expect(getRegionNames('zh-CN')['CN-FJ']).toBe('福建'); + expect(getRegionNames('en-US')['CN-FJ']).toBe('Fujian'); +}); diff --git a/src/lib/geo.ts b/src/lib/geo.ts new file mode 100644 index 000000000..788554041 --- /dev/null +++ b/src/lib/geo.ts @@ -0,0 +1,57 @@ +import regions from '../../public/iso-3166-2.json'; + +export const CHINA_REGION_CODES = { + 北京: 'BJ', + 天津: 'TJ', + 河北: 'HE', + 山西: 'SX', + 内蒙古: 'NM', + 辽宁: 'LN', + 吉林: 'JL', + 黑龙江: 'HL', + 上海: 'SH', + 江苏: 'JS', + 浙江: 'ZJ', + 安徽: 'AH', + 福建: 'FJ', + 江西: 'JX', + 山东: 'SD', + 河南: 'HA', + 湖北: 'HB', + 湖南: 'HN', + 广东: 'GD', + 广西: 'GX', + 海南: 'HI', + 重庆: 'CQ', + 四川: 'SC', + 贵州: 'GZ', + 云南: 'YN', + 西藏: 'XZ', + 陕西: 'SN', + 甘肃: 'GS', + 青海: 'QH', + 宁夏: 'NX', + 新疆: 'XJ', + 台湾: 'TW', + 香港: 'HK', + 澳门: 'MO', +}; + +const CHINA_REGION_NAMES = Object.fromEntries( + Object.entries(CHINA_REGION_CODES).map(([name, code]) => [`CN-${code}`, name]), +); + +export function getChinaRegionCode(province: string) { + const name = province?.trim(); + const region = Object.entries(CHINA_REGION_CODES).find(([key]) => name?.startsWith(key))?.[1]; + + return region ? `CN-${region}` : undefined; +} + +export function getRegionNames(locale?: string): Record { + if (locale?.toLowerCase() === 'zh-cn') { + return { ...regions, ...CHINA_REGION_NAMES }; + } + + return regions; +}