补齐平台订阅、外部登录、CRM 同步与用户端页面;Nginx 转发用户端接口,登录页使用 Google 与 Apple 标志。 Co-authored-by: Cursor <cursoragent@cursor.com>
1032 行
40 KiB
Plaintext
1032 行
40 KiB
Plaintext
/**
|
||
* OmniCard AI 访客端多语言词典(镜像 admin/src/locale/omni.ts)
|
||
* 支持 zh-CN / en-US / ar-SA / es-ES / de-DE / fr-FR / ja-JP 与 RTL
|
||
*/
|
||
|
||
export type OmniLocale =
|
||
| 'zh-CN'
|
||
| 'en-US'
|
||
| 'ar-SA'
|
||
| 'es-ES'
|
||
| 'de-DE'
|
||
| 'fr-FR'
|
||
| 'ja-JP';
|
||
export type Direction = 'ltr' | 'rtl';
|
||
|
||
export interface LocaleMeta {
|
||
code: OmniLocale;
|
||
name: string;
|
||
dir: Direction;
|
||
}
|
||
|
||
export type OmniMessageKey =
|
||
| 'common.confirm'
|
||
| 'common.cancel'
|
||
| 'common.back'
|
||
| 'common.save'
|
||
| 'common.delete'
|
||
| 'common.edit'
|
||
| 'common.search'
|
||
| 'common.loading'
|
||
| 'common.success'
|
||
| 'common.error'
|
||
| 'common.empty'
|
||
| 'common.app_name'
|
||
| 'portal.preview_mode'
|
||
| 'card.save_contact'
|
||
| 'card.exchange'
|
||
| 'card.ai_chat'
|
||
| 'card.share'
|
||
| 'card.scan_nfc'
|
||
| 'card.view_profile'
|
||
| 'radar.online_visitor'
|
||
| 'radar.active_now'
|
||
| 'radar.visitor_trace'
|
||
| 'radar.lead_score'
|
||
| 'crm.contacts'
|
||
| 'crm.leads'
|
||
| 'crm.follow_up'
|
||
| 'portal.unavailable'
|
||
| 'portal.retry'
|
||
| 'portal.pronounce'
|
||
| 'portal.pronouncing'
|
||
| 'portal.whatsapp'
|
||
| 'portal.linkedin'
|
||
| 'portal.telegram'
|
||
| 'portal.twitter'
|
||
| 'portal.wechat'
|
||
| 'portal.line'
|
||
| 'portal.kakao'
|
||
| 'portal.email'
|
||
| 'portal.phone'
|
||
| 'portal.case'
|
||
| 'portal.article'
|
||
| 'portal.social'
|
||
| 'portal.video'
|
||
| 'portal.block'
|
||
| 'portal.contact_unset'
|
||
| 'portal.copied'
|
||
| 'portal.copied_link'
|
||
| 'portal.copied_whatsapp'
|
||
| 'portal.copied_linkedin'
|
||
| 'portal.copied_email'
|
||
| 'portal.copied_telegram'
|
||
| 'portal.copied_twitter'
|
||
| 'portal.copied_wechat'
|
||
| 'portal.copied_line'
|
||
| 'portal.copied_kakao'
|
||
| 'portal.collect'
|
||
| 'portal.collected'
|
||
| 'portal.appointment'
|
||
| 'portal.appointment_desc'
|
||
| 'portal.book_now'
|
||
| 'portal.google_cal'
|
||
| 'portal.outlook_cal'
|
||
| 'portal.ics_download'
|
||
| 'portal.copied_meeting_link'
|
||
| 'portal.appointment_form_title'
|
||
| 'portal.appointment_form_desc'
|
||
| 'portal.appointment_name'
|
||
| 'portal.appointment_contact'
|
||
| 'portal.appointment_company'
|
||
| 'portal.appointment_time'
|
||
| 'portal.appointment_time_video'
|
||
| 'portal.appointment_time_offline'
|
||
| 'portal.appointment_time_call'
|
||
| 'portal.appointment_notes'
|
||
| 'portal.appointment_notes_placeholder'
|
||
| 'portal.appointment_photos'
|
||
| 'portal.appointment_photos_tip'
|
||
| 'portal.appointment_submit'
|
||
| 'portal.appointment_submitting'
|
||
| 'portal.appointment_success_tip'
|
||
| 'portal.appointment_fill_required'
|
||
| 'portal.cookie_notice'
|
||
| 'portal.cookie_accept'
|
||
| 'portal.cookie_reject'
|
||
| 'tab.workplace'
|
||
| 'tab.card'
|
||
| 'tab.radar'
|
||
| 'tab.leads'
|
||
| 'tab.profile';
|
||
|
||
export interface OmniLocaleConfig {
|
||
code: OmniLocale;
|
||
name: string;
|
||
dir: Direction;
|
||
messages: Record<OmniMessageKey, string>;
|
||
}
|
||
|
||
export const omniLocales: Record<OmniLocale, OmniLocaleConfig> = {
|
||
'zh-CN': {
|
||
code: 'zh-CN',
|
||
name: '简体中文',
|
||
dir: 'ltr',
|
||
messages: {
|
||
'common.confirm': '确认',
|
||
'common.cancel': '取消',
|
||
'common.back': '返回',
|
||
'common.save': '保存',
|
||
'common.delete': '删除',
|
||
'common.edit': '编辑',
|
||
'common.search': '搜索',
|
||
'common.loading': '加载中...',
|
||
'common.success': '操作成功',
|
||
'common.error': '操作失败',
|
||
'common.empty': '暂无数据',
|
||
'common.app_name': 'OmniCard',
|
||
'portal.preview_mode': '预览中',
|
||
'card.save_contact': '保存到通讯录',
|
||
'card.exchange': '交换名片',
|
||
'card.ai_chat': '在线咨询',
|
||
'card.share': '分享名片',
|
||
'card.scan_nfc': 'NFC 感应',
|
||
'card.view_profile': '查看微官网',
|
||
'radar.online_visitor': '在线访客',
|
||
'radar.active_now': '当前活跃',
|
||
'radar.visitor_trace': '访问轨迹',
|
||
'radar.lead_score': '意向度评分',
|
||
'crm.contacts': '联系人列表',
|
||
'crm.leads': '客户管理',
|
||
'crm.follow_up': '跟进记录',
|
||
'portal.unavailable': '微官网暂不可用',
|
||
'portal.retry': '重新加载',
|
||
'portal.pronounce': '发音',
|
||
'portal.pronouncing': '播放中',
|
||
'portal.whatsapp': 'WhatsApp',
|
||
'portal.linkedin': 'LinkedIn',
|
||
'portal.telegram': 'Telegram',
|
||
'portal.twitter': 'X',
|
||
'portal.wechat': '微信',
|
||
'portal.line': 'LINE',
|
||
'portal.kakao': 'KakaoTalk',
|
||
'portal.email': '邮件',
|
||
'portal.phone': '电话',
|
||
'portal.case': '客户案例',
|
||
'portal.article': '专栏文章',
|
||
'portal.social': '社交媒体',
|
||
'portal.video': '视频演示',
|
||
'portal.block': '板块内容',
|
||
'portal.contact_unset': '该联系方式未设置',
|
||
'portal.copied': '已复制',
|
||
'portal.copied_link': '直链已复制',
|
||
'portal.copied_whatsapp': 'WhatsApp 号码已复制',
|
||
'portal.copied_linkedin': 'LinkedIn 链接已复制',
|
||
'portal.copied_email': '邮箱地址已复制',
|
||
'portal.copied_telegram': 'Telegram 账号已复制',
|
||
'portal.copied_twitter': 'X (Twitter) 链接已复制',
|
||
'portal.copied_wechat': '微信号已复制',
|
||
'portal.copied_line': 'LINE 链接已复制',
|
||
'portal.copied_kakao': 'KakaoTalk 链接已复制',
|
||
'portal.collect': '收入名片夹',
|
||
'portal.collected': '已收入',
|
||
'portal.appointment': '预约商谈',
|
||
'portal.appointment_desc': '预约 30 分钟视频会议或线下商谈',
|
||
'portal.book_now': '立即预约',
|
||
'portal.google_cal': 'Google 日历',
|
||
'portal.outlook_cal': 'Outlook 日历',
|
||
'portal.ics_download': '下载 ICS 文件',
|
||
'portal.copied_meeting_link': '日程邀请链接已复制',
|
||
'portal.appointment_form_title': '预约商务会谈',
|
||
'portal.appointment_form_desc': '填写沟通需求与期望时间',
|
||
'portal.appointment_name': '您的姓名',
|
||
'portal.appointment_contact': '联系电话 / WhatsApp / 微信',
|
||
'portal.appointment_company': '所属公司 (选填)',
|
||
'portal.appointment_time': '沟通形式与时间',
|
||
'portal.appointment_time_video': '视频会议 (30分钟)',
|
||
'portal.appointment_time_offline': '线下商谈 / 拜访',
|
||
'portal.appointment_time_call': '电话沟通',
|
||
'portal.appointment_notes': '合作需求与议题',
|
||
'portal.appointment_notes_placeholder': '请简述您的业务需求或合作意向',
|
||
'portal.appointment_photos': '相关材料或照片 (选填)',
|
||
'portal.appointment_photos_tip': '可上传名片、材料或样品照片,最多3张',
|
||
'portal.appointment_submit': '提交预约',
|
||
'portal.appointment_submitting': '提交中...',
|
||
'portal.appointment_success_tip': '预约已提交,将尽快与您联系',
|
||
'portal.appointment_fill_required': '请填写姓名和有效联系方式',
|
||
'portal.cookie_notice': '我们使用 Cookie 改善体验并分析访问。继续浏览前请确认是否同意。',
|
||
'portal.cookie_accept': '同意',
|
||
'portal.cookie_reject': '拒绝',
|
||
'tab.workplace': '工作台',
|
||
'tab.card': '名片',
|
||
'tab.radar': '雷达',
|
||
'tab.leads': '潜客',
|
||
'tab.profile': '我的',
|
||
},
|
||
},
|
||
'en-US': {
|
||
code: 'en-US',
|
||
name: 'English',
|
||
dir: 'ltr',
|
||
messages: {
|
||
'common.confirm': 'Confirm',
|
||
'common.cancel': 'Cancel',
|
||
'common.back': 'Back',
|
||
'common.save': 'Save',
|
||
'common.delete': 'Delete',
|
||
'common.edit': 'Edit',
|
||
'common.search': 'Search',
|
||
'common.loading': 'Loading...',
|
||
'common.success': 'Success',
|
||
'common.error': 'Error occurred',
|
||
'common.empty': 'No data available',
|
||
'common.app_name': 'OmniCard',
|
||
'portal.preview_mode': 'Preview',
|
||
'card.save_contact': 'Save Contact',
|
||
'card.exchange': 'Exchange Card',
|
||
'card.ai_chat': 'Inquire',
|
||
'card.share': 'Share Card',
|
||
'card.scan_nfc': 'NFC Tap',
|
||
'card.view_profile': 'View Profile',
|
||
'radar.online_visitor': 'Online Visitors',
|
||
'radar.active_now': 'Active Now',
|
||
'radar.visitor_trace': 'Visitor Trail',
|
||
'radar.lead_score': 'Lead Score',
|
||
'crm.contacts': 'Contacts',
|
||
'crm.leads': 'Leads',
|
||
'crm.follow_up': 'Follow-up',
|
||
'portal.unavailable': 'This page is currently unavailable',
|
||
'portal.retry': 'Reload',
|
||
'portal.pronounce': 'Pronounce',
|
||
'portal.pronouncing': 'Playing',
|
||
'portal.whatsapp': 'WhatsApp',
|
||
'portal.linkedin': 'LinkedIn',
|
||
'portal.telegram': 'Telegram',
|
||
'portal.twitter': 'X',
|
||
'portal.wechat': 'WeChat',
|
||
'portal.line': 'LINE',
|
||
'portal.kakao': 'KakaoTalk',
|
||
'portal.email': 'Email',
|
||
'portal.phone': 'Call',
|
||
'portal.case': 'Case Study',
|
||
'portal.article': 'Article',
|
||
'portal.social': 'Social Media',
|
||
'portal.video': 'Video',
|
||
'portal.block': 'Section',
|
||
'portal.contact_unset': 'This contact method is not configured',
|
||
'portal.copied': 'Copied',
|
||
'portal.copied_link': 'Link copied',
|
||
'portal.copied_whatsapp': 'WhatsApp link copied',
|
||
'portal.copied_linkedin': 'LinkedIn link copied',
|
||
'portal.copied_email': 'Email copied',
|
||
'portal.copied_telegram': 'Telegram link copied',
|
||
'portal.copied_twitter': 'X link copied',
|
||
'portal.copied_wechat': 'WeChat ID copied',
|
||
'portal.copied_line': 'LINE link copied',
|
||
'portal.copied_kakao': 'KakaoTalk link copied',
|
||
'portal.collect': 'Save to Hall',
|
||
'portal.collected': 'Saved to Hall',
|
||
'portal.appointment': 'Book Appointment',
|
||
'portal.appointment_desc': 'Book a 30-min video meeting or in-person talk',
|
||
'portal.book_now': 'Book Now',
|
||
'portal.google_cal': 'Google Calendar',
|
||
'portal.outlook_cal': 'Outlook Calendar',
|
||
'portal.ics_download': 'Download ICS File',
|
||
'portal.copied_meeting_link': 'Calendar link copied',
|
||
'portal.appointment_form_title': 'Book a Meeting',
|
||
'portal.appointment_form_desc': 'Share your meeting preferences and requirements',
|
||
'portal.appointment_name': 'Your Name',
|
||
'portal.appointment_contact': 'Phone / WhatsApp / Email',
|
||
'portal.appointment_company': 'Company (Optional)',
|
||
'portal.appointment_time': 'Meeting Format & Time',
|
||
'portal.appointment_time_video': 'Video Meeting (30 min)',
|
||
'portal.appointment_time_offline': 'In-Person Meeting',
|
||
'portal.appointment_time_call': 'Phone Call',
|
||
'portal.appointment_notes': 'Topics & Agenda',
|
||
'portal.appointment_notes_placeholder': 'Briefly describe your project or partnership goals...',
|
||
'portal.appointment_photos': 'Card / Photo Attachments (Optional)',
|
||
'portal.appointment_photos_tip': 'Upload business card, project brief or product sample (up to 3)',
|
||
'portal.appointment_submit': 'Submit Appointment',
|
||
'portal.appointment_submitting': 'Submitting...',
|
||
'portal.appointment_success_tip': 'Appointment submitted! We will contact you shortly.',
|
||
'portal.appointment_fill_required': 'Please provide your name and contact info',
|
||
'portal.cookie_notice': 'We use cookies to improve your experience and understand visits. Please choose before continuing.',
|
||
'portal.cookie_accept': 'Accept',
|
||
'portal.cookie_reject': 'Reject',
|
||
'tab.workplace': 'Workplace',
|
||
'tab.card': 'Card',
|
||
'tab.radar': 'Radar',
|
||
'tab.leads': 'Leads',
|
||
'tab.profile': 'Profile',
|
||
},
|
||
},
|
||
'ar-SA': {
|
||
code: 'ar-SA',
|
||
name: 'العربية',
|
||
dir: 'rtl',
|
||
messages: {
|
||
'common.confirm': 'تأكيد',
|
||
'common.cancel': 'إلغاء',
|
||
'common.back': 'رجوع',
|
||
'common.save': 'حفظ',
|
||
'common.delete': 'حذف',
|
||
'common.edit': 'تعديل',
|
||
'common.search': 'بحث',
|
||
'common.loading': 'جاري التحميل...',
|
||
'common.success': 'تمت العملية بنجاح',
|
||
'common.error': 'حدث خطأ',
|
||
'common.empty': 'لا توجد بيانات',
|
||
'common.app_name': 'OmniCard',
|
||
'portal.preview_mode': 'معاينة',
|
||
'card.save_contact': 'حفظ جهة الاتصال',
|
||
'card.exchange': 'تبادل البطاقات',
|
||
'card.ai_chat': 'استشارة',
|
||
'card.share': 'مشاركة البطاقة',
|
||
'card.scan_nfc': 'مسح NFC',
|
||
'card.view_profile': 'عرض الملف الشخصي',
|
||
'radar.online_visitor': 'الزوار الحاليون',
|
||
'radar.active_now': 'نشط الآن',
|
||
'radar.visitor_trace': 'مسار الزائر',
|
||
'radar.lead_score': 'درجة العميل المحتمل',
|
||
'crm.contacts': 'جهات الاتصال',
|
||
'crm.leads': 'العملاء',
|
||
'crm.follow_up': 'المتابعة',
|
||
'portal.unavailable': 'الصفحة غير متاحة حاليا',
|
||
'portal.retry': 'إعادة التحميل',
|
||
'portal.pronounce': 'الاستماع للنطق',
|
||
'portal.pronouncing': 'جار التشغيل',
|
||
'portal.whatsapp': 'واتساب',
|
||
'portal.linkedin': 'لينكد إن',
|
||
'portal.telegram': 'تيليجرام',
|
||
'portal.twitter': 'إكس',
|
||
'portal.wechat': 'وي تشات',
|
||
'portal.line': 'LINE',
|
||
'portal.kakao': 'KakaoTalk',
|
||
'portal.email': 'البريد',
|
||
'portal.phone': 'اتصال',
|
||
'portal.case': 'دراسات الحالة',
|
||
'portal.article': 'مقالات',
|
||
'portal.social': 'التواصل الاجتماعي',
|
||
'portal.video': 'فيديو',
|
||
'portal.block': 'محتوى',
|
||
'portal.contact_unset': 'لم يتم تعيين وسيلة التواصل',
|
||
'portal.copied': 'تم النسخ',
|
||
'portal.copied_link': 'تم نسخ الرابط',
|
||
'portal.copied_whatsapp': 'تم نسخ رابط واتساب',
|
||
'portal.copied_linkedin': 'تم نسخ رابط لينكد إن',
|
||
'portal.copied_email': 'تم نسخ البريد الإلكتروني',
|
||
'portal.copied_telegram': 'تم نسخ رابط تيليجرام',
|
||
'portal.copied_twitter': 'تم نسخ رابط إكس',
|
||
'portal.copied_wechat': 'تم نسخ معرف وي تشات',
|
||
'portal.copied_line': 'تم نسخ رابط LINE',
|
||
'portal.copied_kakao': 'تم نسخ رابط KakaoTalk',
|
||
'portal.collect': 'حفظ في القاعة',
|
||
'portal.collected': 'تم الحفظ في القاعة',
|
||
'portal.appointment': 'حجز موعد',
|
||
'portal.appointment_desc': 'احجز اجتماع فيديو عالمي لمدة 30 دقيقة أو محادثة شخصية',
|
||
'portal.book_now': 'احجز موعداً',
|
||
'portal.google_cal': 'تقويم Google',
|
||
'portal.outlook_cal': 'تقويم Outlook',
|
||
'portal.ics_download': 'تنزيل ملف التقويم (ICS)',
|
||
'portal.copied_meeting_link': 'تم نسخ رابط التقويم',
|
||
'portal.appointment_form_title': 'حجز موعد عمل',
|
||
'portal.appointment_form_desc': 'أرسل رغبتك ومتطلباتك إلى صاحب البطاقة مباشرة',
|
||
'portal.appointment_name': 'اسمك الكريم',
|
||
'portal.appointment_contact': 'رقم الهاتف / واتساب / البريد',
|
||
'portal.appointment_company': 'اسم الشركة (اختياري)',
|
||
'portal.appointment_time': 'طريقة / وقت الاجتماع المفضل',
|
||
'portal.appointment_time_video': 'فيديو عبر الإنترنت (30 دقيقة)',
|
||
'portal.appointment_time_offline': 'لقاء شخصي في المعرض',
|
||
'portal.appointment_time_call': 'مكالمة هاتفية سريعة',
|
||
'portal.appointment_notes': 'المتطلبات وموضوع النقاش',
|
||
'portal.appointment_notes_placeholder': 'صف بإيجاز احتياجاتك أو أهداف التعاون...',
|
||
'portal.appointment_photos': 'صور البطاقة أو متطلبات العمل (اختياري)',
|
||
'portal.appointment_photos_tip': 'يمكنك إرفاق بطاقة عملك أو متطلباتك (بحد أقصى 3 صور)',
|
||
'portal.appointment_submit': 'إرسال طلب الموعد',
|
||
'portal.appointment_submitting': 'جاري الإرسال...',
|
||
'portal.appointment_success_tip': 'تم إرسال طلبك بنجاح! سيتواصل معك صاحب البطاقة قريباً.',
|
||
'portal.appointment_fill_required': 'يرجى إدخال الاسم ومعلومات التواصل',
|
||
'portal.cookie_notice': 'نستخدم ملفات تعريف الارتباط لتحسين تجربتك وفهم الزيارات. يرجى الاختيار قبل المتابعة.',
|
||
'portal.cookie_accept': 'موافق',
|
||
'portal.cookie_reject': 'رفض',
|
||
'tab.workplace': 'المكتب',
|
||
'tab.card': 'بطاقتي',
|
||
'tab.radar': 'الرادار',
|
||
'tab.leads': 'العملاء',
|
||
'tab.profile': 'حسابي',
|
||
},
|
||
},
|
||
'es-ES': {
|
||
code: 'es-ES',
|
||
name: 'Español',
|
||
dir: 'ltr',
|
||
messages: {
|
||
'common.confirm': 'Confirmar',
|
||
'common.cancel': 'Cancelar',
|
||
'common.back': 'Volver',
|
||
'common.save': 'Guardar',
|
||
'common.delete': 'Eliminar',
|
||
'common.edit': 'Editar',
|
||
'common.search': 'Buscar',
|
||
'common.loading': 'Cargando...',
|
||
'common.success': 'Listo',
|
||
'common.error': 'Ha ocurrido un error',
|
||
'common.empty': 'No hay datos',
|
||
'common.app_name': 'OmniCard',
|
||
'portal.preview_mode': 'Vista previa',
|
||
'card.save_contact': 'Guardar contacto',
|
||
'card.exchange': 'Intercambiar tarjeta',
|
||
'card.ai_chat': 'Consulta',
|
||
'card.share': 'Compartir tarjeta',
|
||
'card.scan_nfc': 'Toque NFC',
|
||
'card.view_profile': 'Ver perfil',
|
||
'radar.online_visitor': 'Visitantes en línea',
|
||
'radar.active_now': 'Activos ahora',
|
||
'radar.visitor_trace': 'Recorrido del visitante',
|
||
'radar.lead_score': 'Puntuación de interés',
|
||
'crm.contacts': 'Contactos',
|
||
'crm.leads': 'Clientes',
|
||
'crm.follow_up': 'Seguimiento',
|
||
'portal.unavailable': 'Esta página no está disponible',
|
||
'portal.retry': 'Recargar',
|
||
'portal.pronounce': 'Pronunciar',
|
||
'portal.pronouncing': 'Reproduciendo',
|
||
'portal.whatsapp': 'WhatsApp',
|
||
'portal.linkedin': 'LinkedIn',
|
||
'portal.telegram': 'Telegram',
|
||
'portal.twitter': 'X',
|
||
'portal.wechat': 'WeChat',
|
||
'portal.line': 'LINE',
|
||
'portal.kakao': 'KakaoTalk',
|
||
'portal.email': 'Correo',
|
||
'portal.phone': 'Llamar',
|
||
'portal.case': 'Caso de éxito',
|
||
'portal.article': 'Artículo',
|
||
'portal.social': 'Redes sociales',
|
||
'portal.video': 'Vídeo',
|
||
'portal.block': 'Contenido',
|
||
'portal.contact_unset': 'Este medio de contacto no está configurado',
|
||
'portal.copied': 'Copiado',
|
||
'portal.copied_link': 'Enlace copiado',
|
||
'portal.copied_whatsapp': 'Enlace de WhatsApp copiado',
|
||
'portal.copied_linkedin': 'Enlace de LinkedIn copiado',
|
||
'portal.copied_email': 'Correo copiado',
|
||
'portal.copied_telegram': 'Enlace de Telegram copiado',
|
||
'portal.copied_twitter': 'Enlace de X copiado',
|
||
'portal.copied_wechat': 'ID de WeChat copiado',
|
||
'portal.copied_line': 'Enlace de LINE copiado',
|
||
'portal.copied_kakao': 'Enlace de KakaoTalk copiado',
|
||
'portal.collect': 'Guardar en el hall',
|
||
'portal.collected': 'Guardado en el hall',
|
||
'portal.appointment': 'Agendar Reunión',
|
||
'portal.appointment_desc': 'Reserva una reunión virtual de 30 min o charla presencial',
|
||
'portal.book_now': 'Agendar Cita',
|
||
'portal.google_cal': 'Google Calendar',
|
||
'portal.outlook_cal': 'Outlook Calendar',
|
||
'portal.ics_download': 'Descargar Archivo ICS',
|
||
'portal.copied_meeting_link': 'Enlace de calendario copiado',
|
||
'portal.appointment_form_title': 'Agendar Reunión de Negocios',
|
||
'portal.appointment_form_desc': 'Envía tus requisitos y propuesta directamente al titular de la tarjeta',
|
||
'portal.appointment_name': 'Tu Nombre',
|
||
'portal.appointment_contact': 'Teléfono / WhatsApp / Correo',
|
||
'portal.appointment_company': 'Empresa (Opcional)',
|
||
'portal.appointment_time': 'Formato / Horario Preferido',
|
||
'portal.appointment_time_video': 'Videollamada (30 min)',
|
||
'portal.appointment_time_offline': 'Reunión Presencial',
|
||
'portal.appointment_time_call': 'Llamada Rápida',
|
||
'portal.appointment_notes': 'Requisitos y Temas',
|
||
'portal.appointment_notes_placeholder': 'Describe brevemente tus necesidades o propuesta...',
|
||
'portal.appointment_photos': 'Fotos de tarjeta o requisitos (Opcional)',
|
||
'portal.appointment_photos_tip': 'Sube tu tarjeta de presentación o fotos del proyecto (hasta 3)',
|
||
'portal.appointment_submit': 'Enviar Solicitud',
|
||
'portal.appointment_submitting': 'Enviando...',
|
||
'portal.appointment_success_tip': '¡Solicitud enviada! El titular se pondrá en contacto pronto.',
|
||
'portal.appointment_fill_required': 'Por favor indica tu nombre y contacto',
|
||
'portal.cookie_notice': 'Usamos cookies para mejorar tu experiencia y entender las visitas. Elige antes de continuar.',
|
||
'portal.cookie_accept': 'Aceptar',
|
||
'portal.cookie_reject': 'Rechazar',
|
||
'tab.workplace': 'Panel',
|
||
'tab.card': 'Tarjeta',
|
||
'tab.radar': 'Radar',
|
||
'tab.leads': 'Clientes',
|
||
'tab.profile': 'Perfil',
|
||
},
|
||
},
|
||
'de-DE': {
|
||
code: 'de-DE',
|
||
name: 'Deutsch',
|
||
dir: 'ltr',
|
||
messages: {
|
||
'common.confirm': 'Bestätigen',
|
||
'common.cancel': 'Abbrechen',
|
||
'common.back': 'Zurück',
|
||
'common.save': 'Speichern',
|
||
'common.delete': 'Löschen',
|
||
'common.edit': 'Bearbeiten',
|
||
'common.search': 'Suchen',
|
||
'common.loading': 'Wird geladen...',
|
||
'common.success': 'Erfolgreich',
|
||
'common.error': 'Ein Fehler ist aufgetreten',
|
||
'common.empty': 'Keine Daten vorhanden',
|
||
'common.app_name': 'OmniCard',
|
||
'portal.preview_mode': 'Vorschau',
|
||
'card.save_contact': 'Kontakt speichern',
|
||
'card.exchange': 'Visitenkarte tauschen',
|
||
'card.ai_chat': 'Anfrage',
|
||
'card.share': 'Karte teilen',
|
||
'card.scan_nfc': 'NFC-Tipp',
|
||
'card.view_profile': 'Profil ansehen',
|
||
'radar.online_visitor': 'Online-Besucher',
|
||
'radar.active_now': 'Jetzt aktiv',
|
||
'radar.visitor_trace': 'Besucherpfad',
|
||
'radar.lead_score': 'Lead-Score',
|
||
'crm.contacts': 'Kontakte',
|
||
'crm.leads': 'Kunden',
|
||
'crm.follow_up': 'Nachverfolgung',
|
||
'portal.unavailable': 'Diese Seite ist nicht verfügbar',
|
||
'portal.retry': 'Neu laden',
|
||
'portal.pronounce': 'Aussprache',
|
||
'portal.pronouncing': 'Wird wiedergegeben',
|
||
'portal.whatsapp': 'WhatsApp',
|
||
'portal.linkedin': 'LinkedIn',
|
||
'portal.telegram': 'Telegram',
|
||
'portal.twitter': 'X',
|
||
'portal.wechat': 'WeChat',
|
||
'portal.line': 'LINE',
|
||
'portal.kakao': 'KakaoTalk',
|
||
'portal.email': 'E-Mail',
|
||
'portal.phone': 'Anrufen',
|
||
'portal.case': 'Fallstudie',
|
||
'portal.article': 'Einblick',
|
||
'portal.social': 'Social Media',
|
||
'portal.video': 'Video',
|
||
'portal.block': 'Inhalt',
|
||
'portal.contact_unset': 'Dieser Kontaktweg ist nicht hinterlegt',
|
||
'portal.copied': 'Kopiert',
|
||
'portal.copied_link': 'Link kopiert',
|
||
'portal.copied_whatsapp': 'WhatsApp-Link kopiert',
|
||
'portal.copied_linkedin': 'LinkedIn-Link kopiert',
|
||
'portal.copied_email': 'E-Mail kopiert',
|
||
'portal.copied_telegram': 'Telegram-Link kopiert',
|
||
'portal.copied_twitter': 'X-Link kopiert',
|
||
'portal.copied_wechat': 'WeChat-ID kopiert',
|
||
'portal.copied_line': 'LINE-Link kopiert',
|
||
'portal.copied_kakao': 'KakaoTalk-Link kopiert',
|
||
'portal.collect': 'In die Halle legen',
|
||
'portal.collected': 'In der Halle gespeichert',
|
||
'portal.appointment': 'Termin vereinbaren',
|
||
'portal.appointment_desc': 'Buchen Sie ein 30-minütiges globales Meeting',
|
||
'portal.book_now': 'Termin anfragen',
|
||
'portal.google_cal': 'Google Kalender',
|
||
'portal.outlook_cal': 'Outlook Kalender',
|
||
'portal.ics_download': 'ICS-Datei herunterladen',
|
||
'portal.copied_meeting_link': 'Kalenderlink kopiert',
|
||
'portal.appointment_form_title': 'Geschäftstermin anfragen',
|
||
'portal.appointment_form_desc': 'Senden Sie Ihre Anforderungen direkt an den Karteninhaber',
|
||
'portal.appointment_name': 'Ihr Name',
|
||
'portal.appointment_contact': 'Telefon / WhatsApp / E-Mail',
|
||
'portal.appointment_company': 'Unternehmen (optional)',
|
||
'portal.appointment_time': 'Bevorzugtes Format / Zeit',
|
||
'portal.appointment_time_video': 'Online-Meeting (30 Min.)',
|
||
'portal.appointment_time_offline': 'Persönliches Treffen',
|
||
'portal.appointment_time_call': 'Kurzer Telefonanruf',
|
||
'portal.appointment_notes': 'Themen & Anforderungen',
|
||
'portal.appointment_notes_placeholder': 'Beschreiben Sie kurz Ihr Vorhaben oder Ihre Fragen...',
|
||
'portal.appointment_photos': 'Visitenkarte / Projektfotos (Optional)',
|
||
'portal.appointment_photos_tip': 'Visitenkarte, Projektskizze oder Produktfotos hochladen (max. 3)',
|
||
'portal.appointment_submit': 'Termin anfragen',
|
||
'portal.appointment_submitting': 'Wird gesendet...',
|
||
'portal.appointment_success_tip': 'Anfrage gesendet! Der Karteninhaber meldet sich in Kürze.',
|
||
'portal.appointment_fill_required': 'Bitte Namen und Kontaktdaten angeben',
|
||
'portal.cookie_notice': 'Wir verwenden Cookies, um Ihr Erlebnis zu verbessern und Besuche zu verstehen. Bitte wählen Sie vor dem Fortfahren.',
|
||
'portal.cookie_accept': 'Akzeptieren',
|
||
'portal.cookie_reject': 'Ablehnen',
|
||
'tab.workplace': 'Cockpit',
|
||
'tab.card': 'Karte',
|
||
'tab.radar': 'Radar',
|
||
'tab.leads': 'Leads',
|
||
'tab.profile': 'Profil',
|
||
},
|
||
},
|
||
'fr-FR': {
|
||
code: 'fr-FR',
|
||
name: 'Français',
|
||
dir: 'ltr',
|
||
messages: {
|
||
'common.confirm': 'Confirmer',
|
||
'common.cancel': 'Annuler',
|
||
'common.back': 'Retour',
|
||
'common.save': 'Enregistrer',
|
||
'common.delete': 'Supprimer',
|
||
'common.edit': 'Modifier',
|
||
'common.search': 'Rechercher',
|
||
'common.loading': 'Chargement...',
|
||
'common.success': 'Terminé',
|
||
'common.error': 'Une erreur est survenue',
|
||
'common.empty': 'Aucune donnée',
|
||
'common.app_name': 'OmniCard',
|
||
'portal.preview_mode': 'Aperçu',
|
||
'card.save_contact': 'Enregistrer le contact',
|
||
'card.exchange': 'Échanger la carte',
|
||
'card.ai_chat': 'Demande',
|
||
'card.share': 'Partager la carte',
|
||
'card.scan_nfc': 'Toucher NFC',
|
||
'card.view_profile': 'Voir le profil',
|
||
'radar.online_visitor': 'Visiteurs en ligne',
|
||
'radar.active_now': 'Actifs maintenant',
|
||
'radar.visitor_trace': 'Parcours visiteur',
|
||
'radar.lead_score': 'Score d’intérêt',
|
||
'crm.contacts': 'Contacts',
|
||
'crm.leads': 'Clients',
|
||
'crm.follow_up': 'Suivi',
|
||
'portal.unavailable': 'Cette page est indisponible',
|
||
'portal.retry': 'Recharger',
|
||
'portal.pronounce': 'Prononcer',
|
||
'portal.pronouncing': 'Lecture en cours',
|
||
'portal.whatsapp': 'WhatsApp',
|
||
'portal.linkedin': 'LinkedIn',
|
||
'portal.telegram': 'Telegram',
|
||
'portal.twitter': 'X',
|
||
'portal.wechat': 'WeChat',
|
||
'portal.line': 'LINE',
|
||
'portal.kakao': 'KakaoTalk',
|
||
'portal.email': 'E-mail',
|
||
'portal.phone': 'Appeler',
|
||
'portal.case': 'Étude de cas',
|
||
'portal.article': 'Analyse',
|
||
'portal.social': 'Réseaux sociaux',
|
||
'portal.video': 'Vidéo',
|
||
'portal.block': 'Contenu',
|
||
'portal.contact_unset': 'Ce moyen de contact n’est pas renseigné',
|
||
'portal.copied': 'Copié',
|
||
'portal.copied_link': 'Lien copié',
|
||
'portal.copied_whatsapp': 'Lien WhatsApp copié',
|
||
'portal.copied_linkedin': 'Lien LinkedIn copié',
|
||
'portal.copied_email': 'E-mail copié',
|
||
'portal.copied_telegram': 'Lien Telegram copié',
|
||
'portal.copied_twitter': 'Lien X copié',
|
||
'portal.copied_wechat': 'Identifiant WeChat copié',
|
||
'portal.copied_line': 'Lien LINE copié',
|
||
'portal.copied_kakao': 'Lien KakaoTalk copié',
|
||
'portal.collect': 'Ajouter au hall',
|
||
'portal.collected': 'Ajouté au hall',
|
||
'portal.appointment': 'Prendre Rendez-vous',
|
||
'portal.appointment_desc': 'Réservez une réunion vidéo globale de 30 minutes',
|
||
'portal.book_now': 'Prendre RDV',
|
||
'portal.google_cal': 'Google Agenda',
|
||
'portal.outlook_cal': 'Outlook Calendrier',
|
||
'portal.ics_download': 'Télécharger le fichier ICS',
|
||
'portal.copied_meeting_link': 'Lien de calendrier copié',
|
||
'portal.appointment_form_title': 'Demande de Rendez-vous',
|
||
'portal.appointment_form_desc': 'Transmettez vos besoins directement au titulaire de la carte',
|
||
'portal.appointment_name': 'Votre Nom',
|
||
'portal.appointment_contact': 'Téléphone / WhatsApp / E-mail',
|
||
'portal.appointment_company': 'Société (Facultatif)',
|
||
'portal.appointment_time': 'Format / Créneau Souhaité',
|
||
'portal.appointment_time_video': 'Visio en ligne (30 min)',
|
||
'portal.appointment_time_offline': 'Rencontre en personne',
|
||
'portal.appointment_time_call': 'Appel rapide',
|
||
'portal.appointment_notes': 'Besoins & Sujets',
|
||
'portal.appointment_notes_placeholder': 'Décrivez brièvement votre projet ou vos attentes...',
|
||
'portal.appointment_photos': 'Carte de visite / Photos (Optionnel)',
|
||
'portal.appointment_photos_tip': 'Ajoutez votre carte ou photos du projet (jusqu\'à 3)',
|
||
'portal.appointment_submit': 'Envoyer la demande',
|
||
'portal.appointment_submitting': 'Envoi en cours...',
|
||
'portal.appointment_success_tip': 'Demande envoyée ! Le titulaire vous contactera sous peu.',
|
||
'portal.appointment_fill_required': 'Veuillez renseigner votre nom et vos coordonnées',
|
||
'portal.cookie_notice': 'Nous utilisons des cookies pour améliorer votre expérience et comprendre les visites. Merci de choisir avant de continuer.',
|
||
'portal.cookie_accept': 'Accepter',
|
||
'portal.cookie_reject': 'Refuser',
|
||
'tab.workplace': 'Tableau',
|
||
'tab.card': 'Carte',
|
||
'tab.radar': 'Radar',
|
||
'tab.leads': 'Contacts',
|
||
'tab.profile': 'Profil',
|
||
},
|
||
},
|
||
'ja-JP': {
|
||
code: 'ja-JP',
|
||
name: '日本語',
|
||
dir: 'ltr',
|
||
messages: {
|
||
'common.confirm': '確認',
|
||
'common.cancel': 'キャンセル',
|
||
'common.back': '戻る',
|
||
'common.save': '保存',
|
||
'common.delete': '削除',
|
||
'common.edit': '編集',
|
||
'common.search': '検索',
|
||
'common.loading': '読み込み中...',
|
||
'common.success': '完了しました',
|
||
'common.error': 'エラーが発生しました',
|
||
'common.empty': 'データがありません',
|
||
'common.app_name': 'OmniCard',
|
||
'portal.preview_mode': 'プレビュー',
|
||
'card.save_contact': '連絡先に保存',
|
||
'card.exchange': '名刺を交換',
|
||
'card.ai_chat': 'オンライン相談',
|
||
'card.share': '名刺をシェア',
|
||
'card.scan_nfc': 'NFC タップ',
|
||
'card.view_profile': 'プロフィールを見る',
|
||
'radar.online_visitor': 'オンライン訪問者',
|
||
'radar.active_now': '現在アクティブ',
|
||
'radar.visitor_trace': '訪問履歴',
|
||
'radar.lead_score': '関心度スコア',
|
||
'crm.contacts': '連絡先',
|
||
'crm.leads': '顧客',
|
||
'crm.follow_up': 'フォロー記録',
|
||
'portal.unavailable': 'このページは現在ご利用いただけません',
|
||
'portal.retry': '再読み込み',
|
||
'portal.pronounce': '発音',
|
||
'portal.pronouncing': '再生中',
|
||
'portal.whatsapp': 'WhatsApp',
|
||
'portal.linkedin': 'LinkedIn',
|
||
'portal.telegram': 'Telegram',
|
||
'portal.twitter': 'X',
|
||
'portal.wechat': 'WeChat',
|
||
'portal.line': 'LINE',
|
||
'portal.kakao': 'KakaoTalk',
|
||
'portal.email': 'メール',
|
||
'portal.phone': '電話する',
|
||
'portal.case': '導入事例',
|
||
'portal.article': 'インサイト',
|
||
'portal.social': 'ソーシャル',
|
||
'portal.video': '動画',
|
||
'portal.block': 'コンテンツ',
|
||
'portal.contact_unset': 'この連絡先は未設定です',
|
||
'portal.copied': 'コピーしました',
|
||
'portal.copied_link': 'リンクをコピーしました',
|
||
'portal.copied_whatsapp': 'WhatsApp のリンクをコピーしました',
|
||
'portal.copied_linkedin': 'LinkedIn のリンクをコピーしました',
|
||
'portal.copied_email': 'メールアドレスをコピーしました',
|
||
'portal.copied_telegram': 'Telegram のリンクをコピーしました',
|
||
'portal.copied_twitter': 'X のリンクをコピーしました',
|
||
'portal.copied_wechat': 'WeChat ID をコピーしました',
|
||
'portal.copied_line': 'LINE のリンクをコピーしました',
|
||
'portal.copied_kakao': 'KakaoTalk のリンクをコピーしました',
|
||
'portal.collect': 'ホールに保存',
|
||
'portal.collected': 'ホールに保存しました',
|
||
'portal.appointment': '日程を予約する',
|
||
'portal.appointment_desc': '30分間のオンライン面談または商谈を予約',
|
||
'portal.book_now': '予約・相談する',
|
||
'portal.google_cal': 'Google カレンダー',
|
||
'portal.outlook_cal': 'Outlook カレンダー',
|
||
'portal.ics_download': 'ICSファイルをダウンロード',
|
||
'portal.copied_meeting_link': 'カレンダーのリンクをコピーしました',
|
||
'portal.appointment_form_title': '商談・面談のご予約',
|
||
'portal.appointment_form_desc': 'ご相談内容やご要望を名刺所有者へ直接送信します',
|
||
'portal.appointment_name': 'お名前',
|
||
'portal.appointment_contact': '電話番号 / WhatsApp / メール',
|
||
'portal.appointment_company': '会社名・組織名(任意)',
|
||
'portal.appointment_time': 'ご希望の面談形式・時間',
|
||
'portal.appointment_time_video': 'オンライン面談(30分)',
|
||
'portal.appointment_time_offline': '対面・展示会での商談',
|
||
'portal.appointment_time_call': 'お電話でのクイック相談',
|
||
'portal.appointment_notes': 'ご相談内容・ご要望',
|
||
'portal.appointment_notes_placeholder': '事業内容やご興味のある点をご記入ください...',
|
||
'portal.appointment_photos': '名刺・資料写真(任意)',
|
||
'portal.appointment_photos_tip': '名刺や商品、仕様書の写真を最大3枚まで添付できます',
|
||
'portal.appointment_submit': '予約・相談を送信',
|
||
'portal.appointment_submitting': '送信中...',
|
||
'portal.appointment_success_tip': 'ご予約を送信しました。担当者より追ってご連絡いたします。',
|
||
'portal.appointment_fill_required': 'お名前とご連絡先を入力してください',
|
||
'portal.cookie_notice': 'Cookie を使用して体験を向上し、訪問状況を把握します。続行前にご選択ください。',
|
||
'portal.cookie_accept': '同意する',
|
||
'portal.cookie_reject': '拒否する',
|
||
'tab.workplace': 'ワーク',
|
||
'tab.card': '名刺',
|
||
'tab.radar': 'レーダー',
|
||
'tab.leads': '見込み客',
|
||
'tab.profile': 'マイ',
|
||
},
|
||
},
|
||
};
|
||
|
||
export const PORTAL_LOCALE_STORAGE_KEY = 'omni_locale';
|
||
|
||
export interface AppLocaleState {
|
||
current: OmniLocale;
|
||
isRtl: boolean;
|
||
dir: Direction;
|
||
}
|
||
|
||
export const appLocaleState: AppLocaleState = {
|
||
current: 'zh-CN',
|
||
isRtl: false,
|
||
dir: 'ltr',
|
||
};
|
||
|
||
let overrideLocale: OmniLocale | null = null;
|
||
|
||
function syncState(target: OmniLocale): void {
|
||
appLocaleState.current = target;
|
||
appLocaleState.isRtl = isRtlLocale(target);
|
||
appLocaleState.dir = appLocaleState.isRtl ? 'rtl' : 'ltr';
|
||
}
|
||
|
||
/**
|
||
* 将任意语言标识规范化为 7 种主流语言之一(回退 en-US 国际默认)
|
||
*/
|
||
export function normalizeLocale(raw: string): OmniLocale {
|
||
if (!raw || typeof raw !== 'string') {
|
||
return 'en-US';
|
||
}
|
||
const lower = raw.trim().toLowerCase();
|
||
if (lower.startsWith('zh')) {
|
||
return 'zh-CN';
|
||
}
|
||
if (lower.startsWith('ar')) {
|
||
return 'ar-SA';
|
||
}
|
||
if (lower.startsWith('es')) {
|
||
return 'es-ES';
|
||
}
|
||
if (lower.startsWith('de')) {
|
||
return 'de-DE';
|
||
}
|
||
if (lower.startsWith('fr')) {
|
||
return 'fr-FR';
|
||
}
|
||
if (lower.startsWith('ja')) {
|
||
return 'ja-JP';
|
||
}
|
||
if (lower.startsWith('en')) {
|
||
return 'en-US';
|
||
}
|
||
return 'en-US';
|
||
}
|
||
|
||
export function resolveAppLocale(raw: string, fallback?: string): OmniLocale {
|
||
if (!raw || !raw.trim()) {
|
||
return fallback ? normalizeLocale(fallback) : 'en-US';
|
||
}
|
||
return normalizeLocale(raw);
|
||
}
|
||
|
||
/**
|
||
* 将系统语言码映射为门户语言:zh → zh-CN,ar → ar-SA,
|
||
* es → es-ES,de → de-DE,fr → fr-FR,ja → ja-JP,其余 en-US
|
||
*/
|
||
export function resolveDeviceLocale(raw: string): OmniLocale {
|
||
return normalizeLocale(raw);
|
||
}
|
||
|
||
/**
|
||
* 根据访客的国家码映射主流语言或回退 fallback(默认 en-US)
|
||
*/
|
||
export function resolveGeoLocale(countryCode?: string, fallback: string = 'en-US'): OmniLocale {
|
||
if (!countryCode || !countryCode.trim()) {
|
||
return normalizeLocale(fallback);
|
||
}
|
||
const code = countryCode.trim().toUpperCase();
|
||
if (code === 'CN' || code === 'TW' || code === 'HK') {
|
||
return 'zh-CN';
|
||
}
|
||
if (code === 'SA' || code === 'AE' || code === 'EG') {
|
||
return 'ar-SA';
|
||
}
|
||
if (code === 'ES' || code === 'MX') {
|
||
return 'es-ES';
|
||
}
|
||
if (code === 'DE' || code === 'AT') {
|
||
return 'de-DE';
|
||
}
|
||
if (code === 'FR') {
|
||
return 'fr-FR';
|
||
}
|
||
if (code === 'JP') {
|
||
return 'ja-JP';
|
||
}
|
||
return normalizeLocale(fallback);
|
||
}
|
||
|
||
/**
|
||
* 判定语言是否为 RTL(如阿拉伯语 ar-SA、希伯来语 he-IL、波斯语 fa、乌尔都语 ur)
|
||
*/
|
||
export function isRtlLocale(lang: string): boolean {
|
||
if (!lang || typeof lang !== 'string') {
|
||
return false;
|
||
}
|
||
const code = lang.trim().toLowerCase();
|
||
if (
|
||
code.startsWith('ar') ||
|
||
code.startsWith('he') ||
|
||
code.startsWith('fa') ||
|
||
code.startsWith('ur')
|
||
) {
|
||
return true;
|
||
}
|
||
const item = (omniLocales as Record<string, OmniLocaleConfig | undefined>)[lang];
|
||
return item != null && item.dir === 'rtl';
|
||
}
|
||
|
||
function readDeviceLanguage(): string {
|
||
try {
|
||
const fromLocale = uni.getLocale();
|
||
if (fromLocale && fromLocale.trim() !== '') {
|
||
return fromLocale;
|
||
}
|
||
} catch (_e) {}
|
||
|
||
try {
|
||
const info = uni.getSystemInfoSync();
|
||
if (info && info.language && info.language.trim() !== '') {
|
||
return info.language;
|
||
}
|
||
} catch (_e) {}
|
||
|
||
return '';
|
||
}
|
||
|
||
/**
|
||
* 读取本地持久化语言
|
||
*/
|
||
function readStorageLanguage(): string {
|
||
try {
|
||
const stored = uni.getStorageSync(PORTAL_LOCALE_STORAGE_KEY) as string;
|
||
if (stored && typeof stored === 'string' && stored.trim() !== '') {
|
||
return stored.trim();
|
||
}
|
||
} catch (_e) {}
|
||
return '';
|
||
}
|
||
|
||
/**
|
||
* 读取当前检测语言。无信号时回退 zh-CN
|
||
*/
|
||
export function detectLocale(): OmniLocale {
|
||
if (overrideLocale != null) {
|
||
return overrideLocale;
|
||
}
|
||
const stored = readStorageLanguage();
|
||
if (stored) {
|
||
return normalizeLocale(stored);
|
||
}
|
||
const raw = readDeviceLanguage();
|
||
if (!raw) {
|
||
return 'zh-CN';
|
||
}
|
||
return resolveDeviceLocale(raw);
|
||
}
|
||
|
||
export function getCurrentLocale(): OmniLocale {
|
||
const current = detectLocale();
|
||
syncState(current);
|
||
return current;
|
||
}
|
||
|
||
/**
|
||
* 根据语言刷新底部原生 TabBar 5 大菜单标题 (工作台, 名片, 雷达, 潜客, 我的)
|
||
*/
|
||
export function updateTabBarTitles(locale?: OmniLocale): void {
|
||
const targetLocale = locale != null ? locale : getCurrentLocale();
|
||
const items: Array<{ index: number; key: OmniMessageKey }> = [
|
||
{ index: 0, key: 'tab.workplace' },
|
||
{ index: 1, key: 'tab.card' },
|
||
{ index: 2, key: 'tab.radar' },
|
||
{ index: 3, key: 'tab.leads' },
|
||
{ index: 4, key: 'tab.profile' },
|
||
];
|
||
|
||
for (let i = 0; i < items.length; i++) {
|
||
try {
|
||
if (typeof uni !== 'undefined' && typeof uni.setTabBarItem === 'function') {
|
||
uni.setTabBarItem({
|
||
index: items[i].index,
|
||
text: getOmniText(targetLocale, items[i].key),
|
||
});
|
||
}
|
||
} catch (_e) {}
|
||
}
|
||
}
|
||
|
||
export function setAppLocale(lang: string): void {
|
||
const normalized = normalizeLocale(lang);
|
||
overrideLocale = normalized;
|
||
syncState(normalized);
|
||
try {
|
||
uni.setStorageSync(PORTAL_LOCALE_STORAGE_KEY, normalized);
|
||
} catch (_e) {}
|
||
updateTabBarTitles(normalized);
|
||
try {
|
||
if (typeof uni !== 'undefined' && typeof uni.$emit === 'function') {
|
||
uni.$emit('omni_locale_changed', normalized);
|
||
}
|
||
} catch (_e) {}
|
||
}
|
||
|
||
export function initAppLocale(): OmniLocale {
|
||
const current = detectLocale();
|
||
syncState(current);
|
||
updateTabBarTitles(current);
|
||
return current;
|
||
}
|
||
|
||
export function setCurrentLocale(locale: OmniLocale): void {
|
||
setAppLocale(locale);
|
||
}
|
||
|
||
export function isRtl(locale: OmniLocale): boolean {
|
||
return isRtlLocale(locale);
|
||
}
|
||
|
||
export function getOmniText(locale: OmniLocale, key: OmniMessageKey): string {
|
||
const dict = omniLocales[locale] || omniLocales['en-US'];
|
||
return dict.messages[key] || omniLocales['en-US'].messages[key] || key;
|
||
}
|
||
|
||
// 模块加载时同步一次初始全局状态
|
||
try {
|
||
initAppLocale();
|
||
} catch (_e) {}
|