@@ -1,5 +1,5 @@
|
|||||||
import { BROWSERS, OS_NAMES } from '@/lib/constants';
|
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 { useCountryNames } from './useCountryNames';
|
||||||
import { useLanguageNames } from './useLanguageNames';
|
import { useLanguageNames } from './useLanguageNames';
|
||||||
import { useLocale } from './useLocale';
|
import { useLocale } from './useLocale';
|
||||||
@@ -10,6 +10,7 @@ export function useFormat() {
|
|||||||
const { locale } = useLocale();
|
const { locale } = useLocale();
|
||||||
const { countryNames } = useCountryNames(locale);
|
const { countryNames } = useCountryNames(locale);
|
||||||
const { languageNames } = useLanguageNames(locale);
|
const { languageNames } = useLanguageNames(locale);
|
||||||
|
const regionNames = getRegionNames(locale);
|
||||||
|
|
||||||
const formatOS = (value: string): string => {
|
const formatOS = (value: string): string => {
|
||||||
return OS_NAMES[value] || value;
|
return OS_NAMES[value] || value;
|
||||||
@@ -29,7 +30,7 @@ export function useFormat() {
|
|||||||
|
|
||||||
const formatRegion = (value?: string): string => {
|
const formatRegion = (value?: string): string => {
|
||||||
const [country] = value?.split('-') || [];
|
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 => {
|
const formatCity = (value: string, country?: string): string => {
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import regions from '../../../public/iso-3166-2.json';
|
import { getRegionNames } from '@/lib/geo';
|
||||||
import { useCountryNames } from './useCountryNames';
|
import { useCountryNames } from './useCountryNames';
|
||||||
|
|
||||||
export function useRegionNames(locale: string) {
|
export function useRegionNames(locale: string) {
|
||||||
const { countryNames } = useCountryNames(locale);
|
const { countryNames } = useCountryNames(locale);
|
||||||
|
const regions = getRegionNames(locale);
|
||||||
|
|
||||||
const getRegionName = (regionCode: string, countryCode?: string) => {
|
const getRegionName = (regionCode: string, countryCode?: string) => {
|
||||||
if (!countryCode) {
|
if (!countryCode) {
|
||||||
|
|||||||
+1
-44
@@ -4,6 +4,7 @@ import ipaddr from 'ipaddr.js';
|
|||||||
import isLocalhost from 'is-localhost-ip';
|
import isLocalhost from 'is-localhost-ip';
|
||||||
import maxmind from 'maxmind';
|
import maxmind from 'maxmind';
|
||||||
import { UAParser } from 'ua-parser-js';
|
import { UAParser } from 'ua-parser-js';
|
||||||
|
import { getChinaRegionCode } from '@/lib/geo';
|
||||||
import { getIpAddress, stripPort } from '@/lib/ip';
|
import { getIpAddress, stripPort } from '@/lib/ip';
|
||||||
import { safeDecodeURIComponent } from '@/lib/url';
|
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_URL = 'https://ip9.com.cn/get';
|
||||||
const IP_LOCATION_API_TIMEOUT = 2000;
|
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 = [
|
const PROVIDER_HEADERS = [
|
||||||
// Umami custom headers (cloud mode only)
|
// Umami custom headers (cloud mode only)
|
||||||
...(process.env.CLOUD_MODE
|
...(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) {
|
async function getOnlineLocation(ip: string) {
|
||||||
try {
|
try {
|
||||||
const url = new URL(process.env.IP_LOCATION_API_URL || IP_LOCATION_API_URL);
|
const url = new URL(process.env.IP_LOCATION_API_URL || IP_LOCATION_API_URL);
|
||||||
|
|||||||
@@ -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');
|
||||||
|
});
|
||||||
@@ -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<string, string> {
|
||||||
|
if (locale?.toLowerCase() === 'zh-cn') {
|
||||||
|
return { ...regions, ...CHINA_REGION_NAMES };
|
||||||
|
}
|
||||||
|
|
||||||
|
return regions;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user