import { EMAIL_REGEX, EMBEDDED_EVENT_REGEX, EMBEDDED_MENTION_REGEX, EMOJI_REGEX, HASHTAG_REGEX, URL_REGEX, WS_URL_REGEX } from '@/constants' import { clsx, type ClassValue } from 'clsx' import { franc } from 'franc-min' import { twMerge } from 'tailwind-merge' export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } export function isSafari() { if (typeof window === 'undefined' || !window.navigator) return false const ua = window.navigator.userAgent const vendor = window.navigator.vendor return /Safari/.test(ua) && /Apple Computer/.test(vendor) && !/Chrome/.test(ua) } export function isAndroid() { if (typeof window === 'undefined' || !window.navigator) return false const ua = window.navigator.userAgent return /android/i.test(ua) } export function isTorBrowser() { if (typeof window === 'undefined' || !window.navigator) return false const ua = window.navigator.userAgent return /torbrowser/i.test(ua) } export function isTouchDevice() { if (typeof window === 'undefined' || !window.navigator) return false return 'ontouchstart' in window || navigator.maxTouchPoints > 0 } export function isInViewport(el: HTMLElement) { const rect = el.getBoundingClientRect() return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ) } export function isEmail(email: string) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) } export function isDevEnv() { return process.env.NODE_ENV === 'development' } export function detectLanguage(text?: string): string | null { if (!text) { return null } const cleanText = text .replace(URL_REGEX, '') .replace(WS_URL_REGEX, '') .replace(EMAIL_REGEX, '') .replace(EMBEDDED_MENTION_REGEX, '') .replace(EMBEDDED_EVENT_REGEX, '') .replace(HASHTAG_REGEX, '') .replace(EMOJI_REGEX, '') .trim() if (!cleanText) { return null } if (/[\u3040-\u309f\u30a0-\u30ff]/.test(cleanText)) { return 'ja' } if (/[\u0e00-\u0e7f]/.test(cleanText)) { return 'th' } if (/[\u4e00-\u9fff]/.test(cleanText)) { return 'zh' } if (/[\u0600-\u06ff]/.test(cleanText)) { return 'ar' } if (/[\u0590-\u05FF]/.test(cleanText)) { return 'fa' } if (/[\u0400-\u04ff]/.test(cleanText)) { return 'ru' } try { const detectedLang = franc(cleanText) const langMap: { [key: string]: string } = { ara: 'ar', // Arabic deu: 'de', // German eng: 'en', // English spa: 'es', // Spanish fas: 'fa', // Persian (Farsi) pes: 'fa', // Persian (alternative code) fra: 'fr', // French ita: 'it', // Italian jpn: 'ja', // Japanese pol: 'pl', // Polish por: 'pt', // Portuguese rus: 'ru', // Russian cmn: 'zh', // Chinese (Mandarin) zho: 'zh' // Chinese (alternative code) } const normalizedLang = langMap[detectedLang] if (!normalizedLang) { return 'und' } return normalizedLang } catch { return 'und' } }