diff --git a/lib/core/translations/language/ar_sa.dart b/lib/core/translations/language/ar_sa.dart index d8a24f8f8..561cff270 100644 --- a/lib/core/translations/language/ar_sa.dart +++ b/lib/core/translations/language/ar_sa.dart @@ -1159,4 +1159,113 @@ const Map arSA = { "justNow": "الآن", "minutesAgo": "منذ @minutes دقيقة", "yesterday": "أمس", + // Guide overlay keys (placeholders in English) + "sayXiaoYanHint": "Say \"Xiaoyan Xiaoyan\" to the mic", + "imHere": "I’m here~", + "guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Xiaoyan”.", + "aiReplyCompleted": "Xiaoyan has finished the reply!", + "aiThinking": "Xiaoyan is thinking…", + "guideAwakenSuccess": "Great! Xiaoyan is awake—ask it to help.", + "confirmInput": "Confirm Input", + "guideClickSendPrefix": "Tap send, ", + "guideWeatherStart": "Tell Xiaoyan: “What’s the weather today?”", + "guideWeatherInput": "What’s the weather today?", + "guideWeatherSend": "Xiaoyan will report the weather in real time", + "guideWeatherEnd": "Xiaoyan can report weather live—try other commands", + "guideMusicStart": "Tell Xiaoyan: “Play some rock music”", + "guideMusicInput": "Play some rock music", + "guideMusicSend": "Xiaoyan will find music for you", + "guideMusicEnd": "Xiaoyan found music—try other commands", + "guideNavStart": "Tell Xiaoyan: “Navigate to Shenzhen Airport”", + "guideNavInput": "Navigate to Shenzhen Airport", + "guideNavSend": "Xiaoyan will plan the route", + "guideNavEnd": "Navigation set—try other commands", + "guideMeetingStart": + "Tell Xiaoyan: “Create a meeting reminder for 3pm tomorrow”", + "guideMeetingInput": "Create a meeting reminder for 3pm tomorrow", + "guideMeetingSend": "Xiaoyan will create a meeting reminder", + "guideMeetingEnd": "Reminder created—try other commands", + "guidePhoneStart": "Tell Xiaoyan: “Call Mom”", + "guidePhoneInput": "Call Mom", + "guidePhoneSend": "Xiaoyan will make the call", + "guidePhoneEnd": "Call placed—try other commands", + "guideSmsStart": "Tell Xiaoyan: “Send Dad a text: I’ll be home for dinner”", + "guideSmsInput": "Text Dad: I’ll be home for dinner", + "guideSmsSend": "Xiaoyan will send the message", + "guideSmsEnd": "Message sent—voice control is convenient", + // Goods pages common footer (placeholders) + 'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans', + 'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About', + 'copyrightVoiTrans': '© 2025 VoiTrans', + + // Meeting goods page (placeholders) + 'meetingHeaderDesc1': + 'Audio recording, transcription, keyword search, and auto summary.', + 'meetingHeaderDesc2': + 'Suitable for business meetings, class notes, and interview minutes.', + 'meetingAutoRecording': 'Auto recording and segmentation', + 'meetingSpeakerTagging': 'Speaker labeling', + 'meetingLongAudioTranscription': 'Long audio transcription', + 'meetingKeyPointSummary': 'Key point extraction', + 'meetingTopicNameSearch': 'Search by topic/name', + 'meetingTimelineJump': 'Timeline jump', + 'meetingExportSummary': 'Export minutes', + 'meetingMultiPlatformShare': 'Share across platforms', + 'meetingDisclaimer': + 'Use in quiet environments; performance depends on microphone and network.', + + // Translation goods page (placeholders) + 'tradeHeaderDesc1': + 'Real-time simultaneous interpretation and text translation with low-latency voice.', + 'tradeHeaderDesc2': 'Suitable for travel, business, speeches, and teaching.', + 'translateZhEn': 'Chinese-English translation', + 'lowLatencyVoiceBroadcast': 'Low-latency voice broadcast', + 'multiLangTextTranslation': 'Multilingual text translation', + 'termOptimizationContextPreserve': + 'Terminology optimization and context preservation', + 'lexiconTourBusinessLife': 'Travel/Business/Life lexicons', + 'personalVocabularyMemory': 'Personal vocabulary memory', + 'conversationSubtitleLargeText': 'Conversation subtitles / Large-text mode', + 'colorHighContrast': 'High color contrast', + 'tradeDisclaimer': + 'Translation performance depends on microphone, network latency, and ambient noise.', + + // VIP goods page (placeholders) + 'benefitsOverview': 'Benefits overview', + 'higherQuota': 'Higher usage quota', + 'lowerUnitPrice': 'Lower unit price', + 'priorityService': 'Priority service', + 'exclusiveSupportChannel': 'Dedicated support channel', + 'fastResponse': 'Fast issue response', + 'eventsAndDiscounts': 'Events and discounts', + 'memberExclusiveEvents': 'Member-exclusive events', + 'longTermDiscountPlan': 'Long-term discount plan', + 'generalPrivileges': 'General privileges', + 'earlyAccessNewFeatures': 'Early access to new features', + 'crossDeviceSync': 'Cross-device sync', + 'vipDisclaimer': + 'Actual benefits depend on the package details and may change with versions.', + // Goods names by id + 'ai_001_name': 'الذكاء الاصطناعي الأساسي 100', + 'ai_002_name': 'الذكاء الاصطناعي الأساسي 500', + 'ai_003_name': 'الذكاء الاصطناعي الأساسي 1000', + 'meet_001_name': 'اجتماع أساسي 100', + 'meet_002_name': 'اجتماع أساسي 500', + 'meet_003_name': 'اجتماع أساسي 1000', + 'trade_001_name': 'ترجمة أساسية 100', + 'trade_002_name': 'ترجمة أساسية 500', + 'trade_003_name': 'ترجمة أساسية 1000', + // Goods descriptions by id + 'ai_001_desc': + 'يشمل 100 استخدام. الوصول إلى ميزات الذكاء الاصطناعي الأساسية.', + 'ai_002_desc': + 'يشمل 500 استخدام. الوصول إلى ميزات الذكاء الاصطناعي الأساسية.', + 'ai_003_desc': + 'يشمل 1000 استخدام. الوصول إلى ميزات الذكاء الاصطناعي الأساسية.', + 'meet_001_desc': 'يشمل 100 تسجيل/نسخ لاجتماعات.', + 'meet_002_desc': 'يشمل 500 تسجيل/نسخ لاجتماعات.', + 'meet_003_desc': 'يشمل 1000 تسجيل/نسخ لاجتماعات.', + 'trade_001_desc': 'يشمل 100 ترجمة (صوت/نص).', + 'trade_002_desc': 'يشمل 500 ترجمة (صوت/نص).', + 'trade_003_desc': 'يشمل 1000 ترجمة (صوت/نص).', }; diff --git a/lib/core/translations/language/de_de.dart b/lib/core/translations/language/de_de.dart index f5bdbc994..378044786 100644 --- a/lib/core/translations/language/de_de.dart +++ b/lib/core/translations/language/de_de.dart @@ -880,4 +880,82 @@ const Map deDE = { "乌尔都语": "Urdu", "波斯语": "Persisch", "斯瓦希里语": "Swahili", + // Guide overlay keys (placeholders in English) + "sayXiaoYanHint": "Say \"Xiaoyan Xiaoyan\" to the mic", + "imHere": "I’m here~", + "guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Xiaoyan”.", + "aiReplyCompleted": "Xiaoyan has finished the reply!", + "aiThinking": "Xiaoyan is thinking…", + "guideAwakenSuccess": "Great! Xiaoyan is awake—ask it to help.", + "confirmInput": "Confirm Input", + "guideClickSendPrefix": "Tap send, ", + "guideWeatherStart": "Tell Xiaoyan: “What’s the weather today?”", + "guideWeatherInput": "What’s the weather today?", + "guideWeatherSend": "Xiaoyan will report the weather in real time", + "guideWeatherEnd": "Xiaoyan can report weather live—try other commands", + "guideMusicStart": "Tell Xiaoyan: “Play some rock music”", + "guideMusicInput": "Play some rock music", + "guideMusicSend": "Xiaoyan will find music for you", + "guideMusicEnd": "Xiaoyan found music—try other commands", + "guideNavStart": "Tell Xiaoyan: “Navigate to Shenzhen Airport”", + "guideNavInput": "Navigate to Shenzhen Airport", + "guideNavSend": "Xiaoyan will plan the route", + "guideNavEnd": "Navigation set—try other commands", + "guideMeetingStart": "Tell Xiaoyan: “Create a meeting reminder for 3pm tomorrow”", + "guideMeetingInput": "Create a meeting reminder for 3pm tomorrow", + "guideMeetingSend": "Xiaoyan will create a meeting reminder", + "guideMeetingEnd": "Reminder created—try other commands", + "guidePhoneStart": "Tell Xiaoyan: “Call Mom”", + "guidePhoneInput": "Call Mom", + "guidePhoneSend": "Xiaoyan will make the call", + "guidePhoneEnd": "Call placed—try other commands", + "guideSmsStart": "Tell Xiaoyan: “Send Dad a text: I’ll be home for dinner”", + "guideSmsInput": "Text Dad: I’ll be home for dinner", + "guideSmsSend": "Xiaoyan will send the message", + "guideSmsEnd": "Message sent—voice control is convenient", + // Goods pages common footer (placeholders) + 'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans', + 'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About', + 'copyrightVoiTrans': '© 2025 VoiTrans', + + // Meeting goods page (placeholders) + 'meetingHeaderDesc1': 'Audio recording, transcription, keyword search, and auto summary.', + 'meetingHeaderDesc2': 'Suitable for business meetings, class notes, and interview minutes.', + 'meetingAutoRecording': 'Auto recording and segmentation', + 'meetingSpeakerTagging': 'Speaker labeling', + 'meetingLongAudioTranscription': 'Long audio transcription', + 'meetingKeyPointSummary': 'Key point extraction', + 'meetingTopicNameSearch': 'Search by topic/name', + 'meetingTimelineJump': 'Timeline jump', + 'meetingExportSummary': 'Export minutes', + 'meetingMultiPlatformShare': 'Share across platforms', + 'meetingDisclaimer': 'Use in quiet environments; performance depends on microphone and network.', + + // Translation goods page (placeholders) + 'tradeHeaderDesc1': 'Real-time simultaneous interpretation and text translation with low-latency voice.', + 'tradeHeaderDesc2': 'Suitable for travel, business, speeches, and teaching.', + 'translateZhEn': 'Chinese-English translation', + 'lowLatencyVoiceBroadcast': 'Low-latency voice broadcast', + 'multiLangTextTranslation': 'Multilingual text translation', + 'termOptimizationContextPreserve': 'Terminology optimization and context preservation', + 'lexiconTourBusinessLife': 'Travel/Business/Life lexicons', + 'personalVocabularyMemory': 'Personal vocabulary memory', + 'conversationSubtitleLargeText': 'Conversation subtitles / Large-text mode', + 'colorHighContrast': 'High color contrast', + 'tradeDisclaimer': 'Translation performance depends on microphone, network latency, and ambient noise.', + + // VIP goods page (placeholders) + 'benefitsOverview': 'Benefits overview', + 'higherQuota': 'Higher usage quota', + 'lowerUnitPrice': 'Lower unit price', + 'priorityService': 'Priority service', + 'exclusiveSupportChannel': 'Dedicated support channel', + 'fastResponse': 'Fast issue response', + 'eventsAndDiscounts': 'Events and discounts', + 'memberExclusiveEvents': 'Member-exclusive events', + 'longTermDiscountPlan': 'Long-term discount plan', + 'generalPrivileges': 'General privileges', + 'earlyAccessNewFeatures': 'Early access to new features', + 'crossDeviceSync': 'Cross-device sync', + 'vipDisclaimer': 'Actual benefits depend on the package details and may change with versions.', }; diff --git a/lib/core/translations/language/en_us.dart b/lib/core/translations/language/en_us.dart index a19fc113a..1ea7da229 100644 --- a/lib/core/translations/language/en_us.dart +++ b/lib/core/translations/language/en_us.dart @@ -197,6 +197,165 @@ const Map enUS = { "popularFunction": "Popular Features", "tryNow": "Try Now", + // Goods screens (AI/Translation/Meeting) + 'availablePackages': 'Available Packages', + 'remainingQuota': 'Remaining Quota', + 'totalCount': 'Total Count', + 'remaining': 'Remaining', + 'featureDescription': 'Feature Description', + // AI feature cards + 'musicAndRecommendation': 'Music & Recommendation', + 'navigationAndRoutes': 'Navigation & Routes', + 'nearbySearch': 'Nearby Search', + 'newsInformation': 'News', + 'communicationAssistant': 'Communication Assistant', + // Translation feature cards + 'realtimeTranscription': 'Real-time Transcription', + // 'textTranslation' exists + 'sceneLexicon': 'Scenario Glossary', + 'subtitleDisplay': 'Subtitles', + // Meeting feature cards + 'meetingRecording': 'Meeting Recording', + 'transcriptionAndSummary': 'Transcription & Summary', + 'keywordSearch': 'Keyword Search', + 'collaborationSharing': 'Collaboration & Sharing', + // Goods names by id + 'ai_001_name': 'AI Basic 100', + 'ai_002_name': 'AI Basic 500', + 'ai_003_name': 'AI Basic 1000', + 'meet_001_name': 'Meeting Basic 100', + 'meet_002_name': 'Meeting Basic 500', + 'meet_003_name': 'Meeting Basic 1000', + 'trade_001_name': 'Translation Basic 100', + 'trade_002_name': 'Translation Basic 500', + 'trade_003_name': 'Translation Basic 1000', + + // Goods descriptions by id + 'ai_001_desc': 'Includes 100 uses. Access core AI features.', + 'ai_002_desc': 'Includes 500 uses. Access core AI features.', + 'ai_003_desc': 'Includes 1000 uses. Access core AI features.', + 'meet_001_desc': 'Includes 100 meeting recordings/transcriptions.', + 'meet_002_desc': 'Includes 500 meeting recordings/transcriptions.', + 'meet_003_desc': 'Includes 1000 meeting recordings/transcriptions.', + 'trade_001_desc': 'Includes 100 translations (voice/text).', + 'trade_002_desc': 'Includes 500 translations (voice/text).', + 'trade_003_desc': 'Includes 1000 translations (voice/text).', + + // Goods pages common footer + 'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans', + 'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About', + 'copyrightVoiTrans': '© 2025 VoiTrans', + + // Meeting goods page descriptions + 'meetingHeaderDesc1': + 'Audio recording, transcription, keyword search, and auto summary to boost meeting efficiency.', + 'meetingHeaderDesc2': + 'Suitable for business meetings, class notes, and interview minutes.', + 'meetingAutoRecording': 'Auto recording and segmentation', + 'meetingSpeakerTagging': 'Speaker labeling', + 'meetingLongAudioTranscription': 'Long audio transcription', + 'meetingKeyPointSummary': 'Key point extraction', + 'meetingTopicNameSearch': 'Search by topic/name', + 'meetingTimelineJump': 'Timeline jump', + 'meetingExportSummary': 'Export minutes', + 'meetingMultiPlatformShare': 'Share across platforms', + 'meetingDisclaimer': + 'Use in quiet environments; performance depends on microphone and network.', + + // Translation goods page descriptions + 'tradeHeaderDesc1': + 'Real-time simultaneous interpretation and text translation with low-latency voice.', + 'tradeHeaderDesc2': + 'Suitable for travel, business, speeches, and teaching.', + 'translateZhEn': 'Chinese-English translation', + 'lowLatencyVoiceBroadcast': 'Low-latency voice broadcast', + 'multiLangTextTranslation': 'Multilingual text translation', + 'termOptimizationContextPreserve': 'Terminology optimization and context preservation', + 'lexiconTourBusinessLife': 'Travel/Business/Life lexicons', + 'personalVocabularyMemory': 'Personal vocabulary memory', + 'conversationSubtitleLargeText': 'Conversation subtitles / Large-text mode', + 'colorHighContrast': 'High color contrast', + 'tradeDisclaimer': + 'Translation performance depends on microphone, network latency, and ambient noise.', + + // AI goods page descriptions + 'aiHeaderDesc1': + 'Longer conversation quota, more tool calls, extended context length.', + 'aiHeaderDesc2': + 'Suitable for agent Q&A, summarization, analysis, and task execution.', + 'musicSearchPlaybackControl': 'Music library search and playback control', + 'smartPlaylistAndSimilarRecommendations': + 'Smart playlist and similar song recommendations', + 'routePlanningAndCongestionAvoidance': + 'Route planning and congestion avoidance', + 'voiceBroadcastAndWaypoints': 'Voice broadcast and waypoint settings', + 'realTimeWeatherForecast': 'Real-time weather and forecast', + 'clothingAdviceAndTravelReminders': 'Clothing advice and travel reminders', + 'poiSearchFoodGasParking': 'POI search: dining / gas / parking', + 'ratingsHoursAndDirectRoutes': + 'Ratings, business hours, and direct routing', + 'hotNewsAndTopicOverview': 'Hot news and topic overview', + 'longArticleSummariesAndKeyPoints': + 'Long-article summaries and key points', + 'helpCallAndSMS': 'Help with calls and SMS', + 'templatedMessagesAndScheduleReminders': + 'Template messages and schedule reminders', + 'aiDisclaimer': + 'Features depend on device permissions, service availability, and network conditions.', + + // VIP goods page + 'benefitsOverview': 'Benefits overview', + 'higherQuota': 'Higher usage quota', + 'lowerUnitPrice': 'Lower unit price', + 'priorityService': 'Priority service', + 'exclusiveSupportChannel': 'Dedicated support channel', + 'fastResponse': 'Fast issue response', + 'eventsAndDiscounts': 'Events and discounts', + 'memberExclusiveEvents': 'Member-exclusive events', + 'longTermDiscountPlan': 'Long-term discount plan', + 'generalPrivileges': 'General privileges', + 'earlyAccessNewFeatures': 'Early access to new features', + 'crossDeviceSync': 'Cross-device sync', + 'vipDisclaimer': + 'Actual benefits depend on the package details and may change with versions.', + + // Onboarding / Guide + 'skip': 'Skip', + 'next': 'Next', + 'sayXiaoYanHint': 'Say "Xiaoyan Xiaoyan" to the mic', + 'imHere': 'I’m here~', + 'guideWelcomeWakeAI': 'Welcome to Voitrans! First, wake your AI “Xiaoyan”.', + 'aiReplyCompleted': 'Xiaoyan has finished the reply!', + 'aiThinking': 'Xiaoyan is thinking…', + 'guideAwakenSuccess': 'Great! Xiaoyan is awake—ask it to help.', + 'confirmInput': 'Confirm Input', + 'guideClickSendPrefix': 'Tap send, ', + // AI steps + 'guideWeatherStart': 'Tell Xiaoyan: “What’s the weather today?”', + 'guideWeatherInput': 'What’s the weather today?', + 'guideWeatherSend': 'Xiaoyan will report the weather in real time', + 'guideWeatherEnd': 'Xiaoyan can report weather live—try other commands', + 'guideMusicStart': 'Tell Xiaoyan: “Play some rock music”', + 'guideMusicInput': 'Play some rock music', + 'guideMusicSend': 'Xiaoyan will find music for you', + 'guideMusicEnd': 'Xiaoyan found music—try other commands', + 'guideNavStart': 'Tell Xiaoyan: “Navigate to Shenzhen Airport”', + 'guideNavInput': 'Navigate to Shenzhen Airport', + 'guideNavSend': 'Xiaoyan will plan the route', + 'guideNavEnd': 'Navigation set—try other commands', + 'guideMeetingStart': 'Tell Xiaoyan: “Create a meeting reminder for 3pm tomorrow”', + 'guideMeetingInput': 'Create a meeting reminder for 3pm tomorrow', + 'guideMeetingSend': 'Xiaoyan will create a meeting reminder', + 'guideMeetingEnd': 'Reminder created—try other commands', + 'guidePhoneStart': 'Tell Xiaoyan: “Call Mom”', + 'guidePhoneInput': 'Call Mom', + 'guidePhoneSend': 'Xiaoyan will make the call', + 'guidePhoneEnd': 'Call placed—try other commands', + 'guideSmsStart': 'Tell Xiaoyan: “Send Dad a text: I’ll be home for dinner”', + 'guideSmsInput': 'Text Dad: I’ll be home for dinner', + 'guideSmsSend': 'Xiaoyan will send the message', + 'guideSmsEnd': 'Message sent—voice control is convenient', + // 商务会议助手页 "startMeeting": "Start Meeting", 'edit': 'Edit', @@ -1053,7 +1212,7 @@ const Map enUS = { "autoInputCode": "Auto Input Code", "skipBinding": "Skip Binding", "rescan": "Rescan", - "skip": "Skip", + "verifyingDevice": "Verifying device...", "confirmBinding": "Confirm Binding", "associatingDevice": "Associating device...", diff --git a/lib/core/translations/language/es_es.dart b/lib/core/translations/language/es_es.dart index 6ccc9dae1..b49042841 100644 --- a/lib/core/translations/language/es_es.dart +++ b/lib/core/translations/language/es_es.dart @@ -874,4 +874,38 @@ const Map esES = { "乌尔都语": "Urdu", "波斯语": "Persa", "斯瓦希里语": "Suajili", + // Guide overlay keys (placeholders in English) + "sayXiaoYanHint": "Say \"Xiaoyan Xiaoyan\" to the mic", + "imHere": "I’m here~", + "guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Xiaoyan”.", + "aiReplyCompleted": "Xiaoyan has finished the reply!", + "aiThinking": "Xiaoyan is thinking…", + "guideAwakenSuccess": "Great! Xiaoyan is awake—ask it to help.", + "confirmInput": "Confirm Input", + "guideClickSendPrefix": "Tap send, ", + "guideWeatherStart": "Tell Xiaoyan: “What’s the weather today?”", + "guideWeatherInput": "What’s the weather today?", + "guideWeatherSend": "Xiaoyan will report the weather in real time", + "guideWeatherEnd": "Xiaoyan can report weather live—try other commands", + "guideMusicStart": "Tell Xiaoyan: “Play some rock music”", + "guideMusicInput": "Play some rock music", + "guideMusicSend": "Xiaoyan will find music for you", + "guideMusicEnd": "Xiaoyan found music—try other commands", + "guideNavStart": "Tell Xiaoyan: “Navigate to Shenzhen Airport”", + "guideNavInput": "Navigate to Shenzhen Airport", + "guideNavSend": "Xiaoyan will plan the route", + "guideNavEnd": "Navigation set—try other commands", + "guideMeetingStart": + "Tell Xiaoyan: “Create a meeting reminder for 3pm tomorrow”", + "guideMeetingInput": "Create a meeting reminder for 3pm tomorrow", + "guideMeetingSend": "Xiaoyan will create a meeting reminder", + "guideMeetingEnd": "Reminder created—try other commands", + "guidePhoneStart": "Tell Xiaoyan: “Call Mom”", + "guidePhoneInput": "Call Mom", + "guidePhoneSend": "Xiaoyan will make the call", + "guidePhoneEnd": "Call placed—try other commands", + "guideSmsStart": "Tell Xiaoyan: “Send Dad a text: I’ll be home for dinner”", + "guideSmsInput": "Text Dad: I’ll be home for dinner", + "guideSmsSend": "Xiaoyan will send the message", + "guideSmsEnd": "Message sent—voice control is convenient", }; diff --git a/lib/core/translations/language/fr_fr.dart b/lib/core/translations/language/fr_fr.dart index ad0f7c7a7..8b64b9629 100644 --- a/lib/core/translations/language/fr_fr.dart +++ b/lib/core/translations/language/fr_fr.dart @@ -883,4 +883,37 @@ const Map frFR = { "乌尔都语": "Ourdou", "波斯语": "Persan", "斯瓦希里语": "Swahili", + // Guide overlay keys (placeholders in English) + "sayXiaoYanHint": "Say \"Xiaoyan Xiaoyan\" to the mic", + "imHere": "I’m here~", + "guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Xiaoyan”.", + "aiReplyCompleted": "Xiaoyan has finished the reply!", + "aiThinking": "Xiaoyan is thinking…", + "guideAwakenSuccess": "Great! Xiaoyan is awake—ask it to help.", + "confirmInput": "Confirm Input", + "guideClickSendPrefix": "Tap send, ", + "guideWeatherStart": "Tell Xiaoyan: “What’s the weather today?”", + "guideWeatherInput": "What’s the weather today?", + "guideWeatherSend": "Xiaoyan will report the weather in real time", + "guideWeatherEnd": "Xiaoyan can report weather live—try other commands", + "guideMusicStart": "Tell Xiaoyan: “Play some rock music”", + "guideMusicInput": "Play some rock music", + "guideMusicSend": "Xiaoyan will find music for you", + "guideMusicEnd": "Xiaoyan found music—try other commands", + "guideNavStart": "Tell Xiaoyan: “Navigate to Shenzhen Airport”", + "guideNavInput": "Navigate to Shenzhen Airport", + "guideNavSend": "Xiaoyan will plan the route", + "guideNavEnd": "Navigation set—try other commands", + "guideMeetingStart": "Tell Xiaoyan: “Create a meeting reminder for 3pm tomorrow”", + "guideMeetingInput": "Create a meeting reminder for 3pm tomorrow", + "guideMeetingSend": "Xiaoyan will create a meeting reminder", + "guideMeetingEnd": "Reminder created—try other commands", + "guidePhoneStart": "Tell Xiaoyan: “Call Mom”", + "guidePhoneInput": "Call Mom", + "guidePhoneSend": "Xiaoyan will make the call", + "guidePhoneEnd": "Call placed—try other commands", + "guideSmsStart": "Tell Xiaoyan: “Send Dad a text: I’ll be home for dinner”", + "guideSmsInput": "Text Dad: I’ll be home for dinner", + "guideSmsSend": "Xiaoyan will send the message", + "guideSmsEnd": "Message sent—voice control is convenient", }; diff --git a/lib/core/translations/language/hi_in.dart b/lib/core/translations/language/hi_in.dart index 58c9c48bb..1d745b64a 100644 --- a/lib/core/translations/language/hi_in.dart +++ b/lib/core/translations/language/hi_in.dart @@ -848,4 +848,110 @@ const Map hiIN = { "乌尔都语": "उर्दू", "波斯语": "फारसी", "斯瓦希里语": "स्वाहिली", + // Guide overlay keys (placeholders in English) + "sayXiaoYanHint": "Say \"Xiaoyan Xiaoyan\" to the mic", + "imHere": "I’m here~", + "guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Xiaoyan”.", + "aiReplyCompleted": "Xiaoyan has finished the reply!", + "aiThinking": "Xiaoyan is thinking…", + "guideAwakenSuccess": "Great! Xiaoyan is awake—ask it to help.", + "confirmInput": "Confirm Input", + "guideClickSendPrefix": "Tap send, ", + "guideWeatherStart": "Tell Xiaoyan: “What’s the weather today?”", + "guideWeatherInput": "What’s the weather today?", + "guideWeatherSend": "Xiaoyan will report the weather in real time", + "guideWeatherEnd": "Xiaoyan can report weather live—try other commands", + "guideMusicStart": "Tell Xiaoyan: “Play some rock music”", + "guideMusicInput": "Play some rock music", + "guideMusicSend": "Xiaoyan will find music for you", + "guideMusicEnd": "Xiaoyan found music—try other commands", + "guideNavStart": "Tell Xiaoyan: “Navigate to Shenzhen Airport”", + "guideNavInput": "Navigate to Shenzhen Airport", + "guideNavSend": "Xiaoyan will plan the route", + "guideNavEnd": "Navigation set—try other commands", + "guideMeetingStart": + "Tell Xiaoyan: “Create a meeting reminder for 3pm tomorrow”", + "guideMeetingInput": "Create a meeting reminder for 3pm tomorrow", + "guideMeetingSend": "Xiaoyan will create a meeting reminder", + "guideMeetingEnd": "Reminder created—try other commands", + "guidePhoneStart": "Tell Xiaoyan: “Call Mom”", + "guidePhoneInput": "Call Mom", + "guidePhoneSend": "Xiaoyan will make the call", + "guidePhoneEnd": "Call placed—try other commands", + "guideSmsStart": "Tell Xiaoyan: “Send Dad a text: I’ll be home for dinner”", + "guideSmsInput": "Text Dad: I’ll be home for dinner", + "guideSmsSend": "Xiaoyan will send the message", + "guideSmsEnd": "Message sent—voice control is convenient", + // Goods pages common footer (placeholders) + 'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans', + 'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About', + 'copyrightVoiTrans': '© 2025 VoiTrans', + + // Meeting goods page (placeholders) + 'meetingHeaderDesc1': + 'Audio recording, transcription, keyword search, and auto summary.', + 'meetingHeaderDesc2': + 'Suitable for business meetings, class notes, and interview minutes.', + 'meetingAutoRecording': 'Auto recording and segmentation', + 'meetingSpeakerTagging': 'Speaker labeling', + 'meetingLongAudioTranscription': 'Long audio transcription', + 'meetingKeyPointSummary': 'Key point extraction', + 'meetingTopicNameSearch': 'Search by topic/name', + 'meetingTimelineJump': 'Timeline jump', + 'meetingExportSummary': 'Export minutes', + 'meetingMultiPlatformShare': 'Share across platforms', + 'meetingDisclaimer': + 'Use in quiet environments; performance depends on microphone and network.', + + // Translation goods page (placeholders) + 'tradeHeaderDesc1': + 'Real-time simultaneous interpretation and text translation with low-latency voice.', + 'tradeHeaderDesc2': 'Suitable for travel, business, speeches, and teaching.', + 'translateZhEn': 'Chinese-English translation', + 'lowLatencyVoiceBroadcast': 'Low-latency voice broadcast', + 'multiLangTextTranslation': 'Multilingual text translation', + 'termOptimizationContextPreserve': + 'Terminology optimization and context preservation', + 'lexiconTourBusinessLife': 'Travel/Business/Life lexicons', + 'personalVocabularyMemory': 'Personal vocabulary memory', + 'conversationSubtitleLargeText': 'Conversation subtitles / Large-text mode', + 'colorHighContrast': 'High color contrast', + 'tradeDisclaimer': + 'Translation performance depends on microphone, network latency, and ambient noise.', + + // VIP goods page (placeholders) + 'benefitsOverview': 'Benefits overview', + 'higherQuota': 'Higher usage quota', + 'lowerUnitPrice': 'Lower unit price', + 'priorityService': 'Priority service', + 'exclusiveSupportChannel': 'Dedicated support channel', + 'fastResponse': 'Fast issue response', + 'eventsAndDiscounts': 'Events and discounts', + 'memberExclusiveEvents': 'Member-exclusive events', + 'longTermDiscountPlan': 'Long-term discount plan', + 'generalPrivileges': 'General privileges', + 'earlyAccessNewFeatures': 'Early access to new features', + 'crossDeviceSync': 'Cross-device sync', + 'vipDisclaimer': + 'Actual benefits depend on the package details and may change with versions.', + // Goods names by id + 'ai_001_name': 'एआई बेसिक 100', + 'ai_002_name': 'एआई बेसिक 500', + 'ai_003_name': 'एआई बेसिक 1000', + 'meet_001_name': 'मीटिंग बेसिक 100', + 'meet_002_name': 'मीटिंग बेसिक 500', + 'meet_003_name': 'मीटिंग बेसिक 1000', + 'trade_001_name': 'अनुवाद बेसिक 100', + 'trade_002_name': 'अनुवाद बेसिक 500', + 'trade_003_name': 'अनुवाद बेसिक 1000', + // Goods descriptions by id + 'ai_001_desc': '100 उपयोग शामिल। मुख्य AI सुविधाओं की पहुँच।', + 'ai_002_desc': '500 उपयोग शामिल। मुख्य AI सुविधाओं की पहुँच।', + 'ai_003_desc': '1000 उपयोग शामिल। मुख्य AI सुविधाओं की पहुँच।', + 'meet_001_desc': '100 बैठक रिकॉर्डिंग/ट्रांसक्रिप्शन शामिल।', + 'meet_002_desc': '500 बैठक रिकॉर्डिंग/ट्रांसक्रिप्शन शामिल।', + 'meet_003_desc': '1000 बैठक रिकॉर्डिंग/ट्रांसक्रिप्शन शामिल।', + 'trade_001_desc': '100 अनुवाद (वॉयस/टेक्स्ट) शामिल।', + 'trade_002_desc': '500 अनुवाद (वॉयस/टेक्स्ट) शामिल।', + 'trade_003_desc': '1000 अनुवाद (वॉयस/टेक्स्ट) शामिल।', }; diff --git a/lib/core/translations/language/it_it.dart b/lib/core/translations/language/it_it.dart index 07a2e32f8..5c542f335 100644 --- a/lib/core/translations/language/it_it.dart +++ b/lib/core/translations/language/it_it.dart @@ -869,4 +869,82 @@ const Map itIT = { "乌尔都语": "Urdu", "波斯语": "Persiano", "斯瓦希里语": "Swahili", + // Guide overlay keys (placeholders in English) + "sayXiaoYanHint": "Say \"Xiaoyan Xiaoyan\" to the mic", + "imHere": "I’m here~", + "guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Xiaoyan”.", + "aiReplyCompleted": "Xiaoyan has finished the reply!", + "aiThinking": "Xiaoyan is thinking…", + "guideAwakenSuccess": "Great! Xiaoyan is awake—ask it to help.", + "confirmInput": "Confirm Input", + "guideClickSendPrefix": "Tap send, ", + "guideWeatherStart": "Tell Xiaoyan: “What’s the weather today?”", + "guideWeatherInput": "What’s the weather today?", + "guideWeatherSend": "Xiaoyan will report the weather in real time", + "guideWeatherEnd": "Xiaoyan can report weather live—try other commands", + "guideMusicStart": "Tell Xiaoyan: “Play some rock music”", + "guideMusicInput": "Play some rock music", + "guideMusicSend": "Xiaoyan will find music for you", + "guideMusicEnd": "Xiaoyan found music—try other commands", + "guideNavStart": "Tell Xiaoyan: “Navigate to Shenzhen Airport”", + "guideNavInput": "Navigate to Shenzhen Airport", + "guideNavSend": "Xiaoyan will plan the route", + "guideNavEnd": "Navigation set—try other commands", + "guideMeetingStart": "Tell Xiaoyan: “Create a meeting reminder for 3pm tomorrow”", + "guideMeetingInput": "Create a meeting reminder for 3pm tomorrow", + "guideMeetingSend": "Xiaoyan will create a meeting reminder", + "guideMeetingEnd": "Reminder created—try other commands", + "guidePhoneStart": "Tell Xiaoyan: “Call Mom”", + "guidePhoneInput": "Call Mom", + "guidePhoneSend": "Xiaoyan will make the call", + "guidePhoneEnd": "Call placed—try other commands", + "guideSmsStart": "Tell Xiaoyan: “Send Dad a text: I’ll be home for dinner”", + "guideSmsInput": "Text Dad: I’ll be home for dinner", + "guideSmsSend": "Xiaoyan will send the message", + "guideSmsEnd": "Message sent—voice control is convenient", + // Goods pages common footer (placeholders) + 'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans', + 'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About', + 'copyrightVoiTrans': '© 2025 VoiTrans', + + // Meeting goods page (placeholders) + 'meetingHeaderDesc1': 'Audio recording, transcription, keyword search, and auto summary.', + 'meetingHeaderDesc2': 'Suitable for business meetings, class notes, and interview minutes.', + 'meetingAutoRecording': 'Auto recording and segmentation', + 'meetingSpeakerTagging': 'Speaker labeling', + 'meetingLongAudioTranscription': 'Long audio transcription', + 'meetingKeyPointSummary': 'Key point extraction', + 'meetingTopicNameSearch': 'Search by topic/name', + 'meetingTimelineJump': 'Timeline jump', + 'meetingExportSummary': 'Export minutes', + 'meetingMultiPlatformShare': 'Share across platforms', + 'meetingDisclaimer': 'Use in quiet environments; performance depends on microphone and network.', + + // Translation goods page (placeholders) + 'tradeHeaderDesc1': 'Real-time simultaneous interpretation and text translation with low-latency voice.', + 'tradeHeaderDesc2': 'Suitable for travel, business, speeches, and teaching.', + 'translateZhEn': 'Chinese-English translation', + 'lowLatencyVoiceBroadcast': 'Low-latency voice broadcast', + 'multiLangTextTranslation': 'Multilingual text translation', + 'termOptimizationContextPreserve': 'Terminology optimization and context preservation', + 'lexiconTourBusinessLife': 'Travel/Business/Life lexicons', + 'personalVocabularyMemory': 'Personal vocabulary memory', + 'conversationSubtitleLargeText': 'Conversation subtitles / Large-text mode', + 'colorHighContrast': 'High color contrast', + 'tradeDisclaimer': 'Translation performance depends on microphone, network latency, and ambient noise.', + + // VIP goods page (placeholders) + 'benefitsOverview': 'Benefits overview', + 'higherQuota': 'Higher usage quota', + 'lowerUnitPrice': 'Lower unit price', + 'priorityService': 'Priority service', + 'exclusiveSupportChannel': 'Dedicated support channel', + 'fastResponse': 'Fast issue response', + 'eventsAndDiscounts': 'Events and discounts', + 'memberExclusiveEvents': 'Member-exclusive events', + 'longTermDiscountPlan': 'Long-term discount plan', + 'generalPrivileges': 'General privileges', + 'earlyAccessNewFeatures': 'Early access to new features', + 'crossDeviceSync': 'Cross-device sync', + 'vipDisclaimer': 'Actual benefits depend on the package details and may change with versions.', }; diff --git a/lib/core/translations/language/ja_jp.dart b/lib/core/translations/language/ja_jp.dart index 360a0207c..4f27b6aa2 100644 --- a/lib/core/translations/language/ja_jp.dart +++ b/lib/core/translations/language/ja_jp.dart @@ -797,4 +797,38 @@ const Map jaJP = { "乌尔都语": "ウルドゥー語", "波斯语": "ペルシャ語", "斯瓦希里语": "スワヒリ語", + // Guide overlay keys (placeholders in English) + "sayXiaoYanHint": "Say \"Xiaoyan Xiaoyan\" to the mic", + "imHere": "I’m here~", + "guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Xiaoyan”.", + "aiReplyCompleted": "Xiaoyan has finished the reply!", + "aiThinking": "Xiaoyan is thinking…", + "guideAwakenSuccess": "Great! Xiaoyan is awake—ask it to help.", + "confirmInput": "Confirm Input", + "guideClickSendPrefix": "Tap send, ", + "guideWeatherStart": "Tell Xiaoyan: “What’s the weather today?”", + "guideWeatherInput": "What’s the weather today?", + "guideWeatherSend": "Xiaoyan will report the weather in real time", + "guideWeatherEnd": "Xiaoyan can report weather live—try other commands", + "guideMusicStart": "Tell Xiaoyan: “Play some rock music”", + "guideMusicInput": "Play some rock music", + "guideMusicSend": "Xiaoyan will find music for you", + "guideMusicEnd": "Xiaoyan found music—try other commands", + "guideNavStart": "Tell Xiaoyan: “Navigate to Shenzhen Airport”", + "guideNavInput": "Navigate to Shenzhen Airport", + "guideNavSend": "Xiaoyan will plan the route", + "guideNavEnd": "Navigation set—try other commands", + "guideMeetingStart": + "Tell Xiaoyan: “Create a meeting reminder for 3pm tomorrow”", + "guideMeetingInput": "Create a meeting reminder for 3pm tomorrow", + "guideMeetingSend": "Xiaoyan will create a meeting reminder", + "guideMeetingEnd": "Reminder created—try other commands", + "guidePhoneStart": "Tell Xiaoyan: “Call Mom”", + "guidePhoneInput": "Call Mom", + "guidePhoneSend": "Xiaoyan will make the call", + "guidePhoneEnd": "Call placed—try other commands", + "guideSmsStart": "Tell Xiaoyan: “Send Dad a text: I’ll be home for dinner”", + "guideSmsInput": "Text Dad: I’ll be home for dinner", + "guideSmsSend": "Xiaoyan will send the message", + "guideSmsEnd": "Message sent—voice control is convenient", }; diff --git a/lib/core/translations/language/ko_kr.dart b/lib/core/translations/language/ko_kr.dart index 2b1c2122e..4959af0e1 100644 --- a/lib/core/translations/language/ko_kr.dart +++ b/lib/core/translations/language/ko_kr.dart @@ -784,4 +784,82 @@ const Map koKR = { "乌尔都语": "우르두어", "波斯语": "페르시아어", "斯瓦希里语": "스와힐리어", + // Guide overlay keys (placeholders in English) + "sayXiaoYanHint": "Say \"Xiaoyan Xiaoyan\" to the mic", + "imHere": "I’m here~", + "guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Xiaoyan”.", + "aiReplyCompleted": "Xiaoyan has finished the reply!", + "aiThinking": "Xiaoyan is thinking…", + "guideAwakenSuccess": "Great! Xiaoyan is awake—ask it to help.", + "confirmInput": "Confirm Input", + "guideClickSendPrefix": "Tap send, ", + "guideWeatherStart": "Tell Xiaoyan: “What’s the weather today?”", + "guideWeatherInput": "What’s the weather today?", + "guideWeatherSend": "Xiaoyan will report the weather in real time", + "guideWeatherEnd": "Xiaoyan can report weather live—try other commands", + "guideMusicStart": "Tell Xiaoyan: “Play some rock music”", + "guideMusicInput": "Play some rock music", + "guideMusicSend": "Xiaoyan will find music for you", + "guideMusicEnd": "Xiaoyan found music—try other commands", + "guideNavStart": "Tell Xiaoyan: “Navigate to Shenzhen Airport”", + "guideNavInput": "Navigate to Shenzhen Airport", + "guideNavSend": "Xiaoyan will plan the route", + "guideNavEnd": "Navigation set—try other commands", + "guideMeetingStart": "Tell Xiaoyan: “Create a meeting reminder for 3pm tomorrow”", + "guideMeetingInput": "Create a meeting reminder for 3pm tomorrow", + "guideMeetingSend": "Xiaoyan will create a meeting reminder", + "guideMeetingEnd": "Reminder created—try other commands", + "guidePhoneStart": "Tell Xiaoyan: “Call Mom”", + "guidePhoneInput": "Call Mom", + "guidePhoneSend": "Xiaoyan will make the call", + "guidePhoneEnd": "Call placed—try other commands", + "guideSmsStart": "Tell Xiaoyan: “Send Dad a text: I’ll be home for dinner”", + "guideSmsInput": "Text Dad: I’ll be home for dinner", + "guideSmsSend": "Xiaoyan will send the message", + "guideSmsEnd": "Message sent—voice control is convenient", + // Goods pages common footer (placeholders) + 'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans', + 'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About', + 'copyrightVoiTrans': '© 2025 VoiTrans', + + // Meeting goods page (placeholders) + 'meetingHeaderDesc1': 'Audio recording, transcription, keyword search, and auto summary.', + 'meetingHeaderDesc2': 'Suitable for business meetings, class notes, and interview minutes.', + 'meetingAutoRecording': 'Auto recording and segmentation', + 'meetingSpeakerTagging': 'Speaker labeling', + 'meetingLongAudioTranscription': 'Long audio transcription', + 'meetingKeyPointSummary': 'Key point extraction', + 'meetingTopicNameSearch': 'Search by topic/name', + 'meetingTimelineJump': 'Timeline jump', + 'meetingExportSummary': 'Export minutes', + 'meetingMultiPlatformShare': 'Share across platforms', + 'meetingDisclaimer': 'Use in quiet environments; performance depends on microphone and network.', + + // Translation goods page (placeholders) + 'tradeHeaderDesc1': 'Real-time simultaneous interpretation and text translation with low-latency voice.', + 'tradeHeaderDesc2': 'Suitable for travel, business, speeches, and teaching.', + 'translateZhEn': 'Chinese-English translation', + 'lowLatencyVoiceBroadcast': 'Low-latency voice broadcast', + 'multiLangTextTranslation': 'Multilingual text translation', + 'termOptimizationContextPreserve': 'Terminology optimization and context preservation', + 'lexiconTourBusinessLife': 'Travel/Business/Life lexicons', + 'personalVocabularyMemory': 'Personal vocabulary memory', + 'conversationSubtitleLargeText': 'Conversation subtitles / Large-text mode', + 'colorHighContrast': 'High color contrast', + 'tradeDisclaimer': 'Translation performance depends on microphone, network latency, and ambient noise.', + + // VIP goods page (placeholders) + 'benefitsOverview': 'Benefits overview', + 'higherQuota': 'Higher usage quota', + 'lowerUnitPrice': 'Lower unit price', + 'priorityService': 'Priority service', + 'exclusiveSupportChannel': 'Dedicated support channel', + 'fastResponse': 'Fast issue response', + 'eventsAndDiscounts': 'Events and discounts', + 'memberExclusiveEvents': 'Member-exclusive events', + 'longTermDiscountPlan': 'Long-term discount plan', + 'generalPrivileges': 'General privileges', + 'earlyAccessNewFeatures': 'Early access to new features', + 'crossDeviceSync': 'Cross-device sync', + 'vipDisclaimer': 'Actual benefits depend on the package details and may change with versions.', }; diff --git a/lib/core/translations/language/pt_pt.dart b/lib/core/translations/language/pt_pt.dart index 14eadd866..4ca7b3ab4 100644 --- a/lib/core/translations/language/pt_pt.dart +++ b/lib/core/translations/language/pt_pt.dart @@ -863,4 +863,82 @@ const Map ptPT = { "乌尔都语": "Urdu", "波斯语": "Persa", "斯瓦希里语": "Suaíli", + // Guide overlay keys (placeholders in English) + "sayXiaoYanHint": "Say \"Xiaoyan Xiaoyan\" to the mic", + "imHere": "I’m here~", + "guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Xiaoyan”.", + "aiReplyCompleted": "Xiaoyan has finished the reply!", + "aiThinking": "Xiaoyan is thinking…", + "guideAwakenSuccess": "Great! Xiaoyan is awake—ask it to help.", + "confirmInput": "Confirm Input", + "guideClickSendPrefix": "Tap send, ", + "guideWeatherStart": "Tell Xiaoyan: “What’s the weather today?”", + "guideWeatherInput": "What’s the weather today?", + "guideWeatherSend": "Xiaoyan will report the weather in real time", + "guideWeatherEnd": "Xiaoyan can report weather live—try other commands", + "guideMusicStart": "Tell Xiaoyan: “Play some rock music”", + "guideMusicInput": "Play some rock music", + "guideMusicSend": "Xiaoyan will find music for you", + "guideMusicEnd": "Xiaoyan found music—try other commands", + "guideNavStart": "Tell Xiaoyan: “Navigate to Shenzhen Airport”", + "guideNavInput": "Navigate to Shenzhen Airport", + "guideNavSend": "Xiaoyan will plan the route", + "guideNavEnd": "Navigation set—try other commands", + "guideMeetingStart": "Tell Xiaoyan: “Create a meeting reminder for 3pm tomorrow”", + "guideMeetingInput": "Create a meeting reminder for 3pm tomorrow", + "guideMeetingSend": "Xiaoyan will create a meeting reminder", + "guideMeetingEnd": "Reminder created—try other commands", + "guidePhoneStart": "Tell Xiaoyan: “Call Mom”", + "guidePhoneInput": "Call Mom", + "guidePhoneSend": "Xiaoyan will make the call", + "guidePhoneEnd": "Call placed—try other commands", + "guideSmsStart": "Tell Xiaoyan: “Send Dad a text: I’ll be home for dinner”", + "guideSmsInput": "Text Dad: I’ll be home for dinner", + "guideSmsSend": "Xiaoyan will send the message", + "guideSmsEnd": "Message sent—voice control is convenient", + // Goods pages common footer (placeholders) + 'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans', + 'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About', + 'copyrightVoiTrans': '© 2025 VoiTrans', + + // Meeting goods page (placeholders) + 'meetingHeaderDesc1': 'Audio recording, transcription, keyword search, and auto summary.', + 'meetingHeaderDesc2': 'Suitable for business meetings, class notes, and interview minutes.', + 'meetingAutoRecording': 'Auto recording and segmentation', + 'meetingSpeakerTagging': 'Speaker labeling', + 'meetingLongAudioTranscription': 'Long audio transcription', + 'meetingKeyPointSummary': 'Key point extraction', + 'meetingTopicNameSearch': 'Search by topic/name', + 'meetingTimelineJump': 'Timeline jump', + 'meetingExportSummary': 'Export minutes', + 'meetingMultiPlatformShare': 'Share across platforms', + 'meetingDisclaimer': 'Use in quiet environments; performance depends on microphone and network.', + + // Translation goods page (placeholders) + 'tradeHeaderDesc1': 'Real-time simultaneous interpretation and text translation with low-latency voice.', + 'tradeHeaderDesc2': 'Suitable for travel, business, speeches, and teaching.', + 'translateZhEn': 'Chinese-English translation', + 'lowLatencyVoiceBroadcast': 'Low-latency voice broadcast', + 'multiLangTextTranslation': 'Multilingual text translation', + 'termOptimizationContextPreserve': 'Terminology optimization and context preservation', + 'lexiconTourBusinessLife': 'Travel/Business/Life lexicons', + 'personalVocabularyMemory': 'Personal vocabulary memory', + 'conversationSubtitleLargeText': 'Conversation subtitles / Large-text mode', + 'colorHighContrast': 'High color contrast', + 'tradeDisclaimer': 'Translation performance depends on microphone, network latency, and ambient noise.', + + // VIP goods page (placeholders) + 'benefitsOverview': 'Benefits overview', + 'higherQuota': 'Higher usage quota', + 'lowerUnitPrice': 'Lower unit price', + 'priorityService': 'Priority service', + 'exclusiveSupportChannel': 'Dedicated support channel', + 'fastResponse': 'Fast issue response', + 'eventsAndDiscounts': 'Events and discounts', + 'memberExclusiveEvents': 'Member-exclusive events', + 'longTermDiscountPlan': 'Long-term discount plan', + 'generalPrivileges': 'General privileges', + 'earlyAccessNewFeatures': 'Early access to new features', + 'crossDeviceSync': 'Cross-device sync', + 'vipDisclaimer': 'Actual benefits depend on the package details and may change with versions.', }; diff --git a/lib/core/translations/language/ru_ru.dart b/lib/core/translations/language/ru_ru.dart index 6d6603e5d..11c95cd0f 100644 --- a/lib/core/translations/language/ru_ru.dart +++ b/lib/core/translations/language/ru_ru.dart @@ -856,4 +856,82 @@ const Map ruRU = { "乌尔都语": "Урду", "波斯语": "Персидский", "斯瓦希里语": "Суахили", + // Guide overlay keys (placeholders in English) + "sayXiaoYanHint": "Say \"Xiaoyan Xiaoyan\" to the mic", + "imHere": "I’m here~", + "guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Xiaoyan”.", + "aiReplyCompleted": "Xiaoyan has finished the reply!", + "aiThinking": "Xiaoyan is thinking…", + "guideAwakenSuccess": "Great! Xiaoyan is awake—ask it to help.", + "confirmInput": "Confirm Input", + "guideClickSendPrefix": "Tap send, ", + "guideWeatherStart": "Tell Xiaoyan: “What’s the weather today?”", + "guideWeatherInput": "What’s the weather today?", + "guideWeatherSend": "Xiaoyan will report the weather in real time", + "guideWeatherEnd": "Xiaoyan can report weather live—try other commands", + "guideMusicStart": "Tell Xiaoyan: “Play some rock music”", + "guideMusicInput": "Play some rock music", + "guideMusicSend": "Xiaoyan will find music for you", + "guideMusicEnd": "Xiaoyan found music—try other commands", + "guideNavStart": "Tell Xiaoyan: “Navigate to Shenzhen Airport”", + "guideNavInput": "Navigate to Shenzhen Airport", + "guideNavSend": "Xiaoyan will plan the route", + "guideNavEnd": "Navigation set—try other commands", + "guideMeetingStart": "Tell Xiaoyan: “Create a meeting reminder for 3pm tomorrow”", + "guideMeetingInput": "Create a meeting reminder for 3pm tomorrow", + "guideMeetingSend": "Xiaoyan will create a meeting reminder", + "guideMeetingEnd": "Reminder created—try other commands", + "guidePhoneStart": "Tell Xiaoyan: “Call Mom”", + "guidePhoneInput": "Call Mom", + "guidePhoneSend": "Xiaoyan will make the call", + "guidePhoneEnd": "Call placed—try other commands", + "guideSmsStart": "Tell Xiaoyan: “Send Dad a text: I’ll be home for dinner”", + "guideSmsInput": "Text Dad: I’ll be home for dinner", + "guideSmsSend": "Xiaoyan will send the message", + "guideSmsEnd": "Message sent—voice control is convenient", + // Goods pages common footer (placeholders) + 'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans', + 'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About', + 'copyrightVoiTrans': '© 2025 VoiTrans', + + // Meeting goods page (placeholders) + 'meetingHeaderDesc1': 'Audio recording, transcription, keyword search, and auto summary.', + 'meetingHeaderDesc2': 'Suitable for business meetings, class notes, and interview minutes.', + 'meetingAutoRecording': 'Auto recording and segmentation', + 'meetingSpeakerTagging': 'Speaker labeling', + 'meetingLongAudioTranscription': 'Long audio transcription', + 'meetingKeyPointSummary': 'Key point extraction', + 'meetingTopicNameSearch': 'Search by topic/name', + 'meetingTimelineJump': 'Timeline jump', + 'meetingExportSummary': 'Export minutes', + 'meetingMultiPlatformShare': 'Share across platforms', + 'meetingDisclaimer': 'Use in quiet environments; performance depends on microphone and network.', + + // Translation goods page (placeholders) + 'tradeHeaderDesc1': 'Real-time simultaneous interpretation and text translation with low-latency voice.', + 'tradeHeaderDesc2': 'Suitable for travel, business, speeches, and teaching.', + 'translateZhEn': 'Chinese-English translation', + 'lowLatencyVoiceBroadcast': 'Low-latency voice broadcast', + 'multiLangTextTranslation': 'Multilingual text translation', + 'termOptimizationContextPreserve': 'Terminology optimization and context preservation', + 'lexiconTourBusinessLife': 'Travel/Business/Life lexicons', + 'personalVocabularyMemory': 'Personal vocabulary memory', + 'conversationSubtitleLargeText': 'Conversation subtitles / Large-text mode', + 'colorHighContrast': 'High color contrast', + 'tradeDisclaimer': 'Translation performance depends on microphone, network latency, and ambient noise.', + + // VIP goods page (placeholders) + 'benefitsOverview': 'Benefits overview', + 'higherQuota': 'Higher usage quota', + 'lowerUnitPrice': 'Lower unit price', + 'priorityService': 'Priority service', + 'exclusiveSupportChannel': 'Dedicated support channel', + 'fastResponse': 'Fast issue response', + 'eventsAndDiscounts': 'Events and discounts', + 'memberExclusiveEvents': 'Member-exclusive events', + 'longTermDiscountPlan': 'Long-term discount plan', + 'generalPrivileges': 'General privileges', + 'earlyAccessNewFeatures': 'Early access to new features', + 'crossDeviceSync': 'Cross-device sync', + 'vipDisclaimer': 'Actual benefits depend on the package details and may change with versions.', }; diff --git a/lib/core/translations/language/zh_cn.dart b/lib/core/translations/language/zh_cn.dart index 5fb101114..4360198c9 100644 --- a/lib/core/translations/language/zh_cn.dart +++ b/lib/core/translations/language/zh_cn.dart @@ -191,6 +191,87 @@ const Map zhCN = { "popularFunction": "热门功能场景", "tryNow": "立即尝试", + // 商品页面(AI/翻译/会议) + 'availablePackages': '可购买套餐', + 'remainingQuota': '剩余额度', + 'totalCount': '总次数', + 'remaining': '剩余', + 'featureDescription': '功能说明', + // AI 功能卡片 + 'musicAndRecommendation': '听歌与推荐', + 'navigationAndRoutes': '导航与路线', + 'nearbySearch': '附近搜索', + 'newsInformation': '新闻资讯', + 'communicationAssistant': '通讯助手', + // 翻译功能卡片 + 'realtimeTranscription': '实时同传', + // 'textTranslation' 已存在 + 'sceneLexicon': '场景词库', + 'subtitleDisplay': '字幕显示', + // 会议功能卡片 + 'meetingRecording': '会议记录', + 'transcriptionAndSummary': '转写与总结', + 'keywordSearch': '关键词检索', + 'collaborationSharing': '协同分享', + // 商品名称(按ID) + 'ai_001_name': 'AI基础 100 次', + 'ai_002_name': 'AI基础 500 次', + 'ai_003_name': 'AI基础 1000 次', + 'meet_001_name': '会议基础 100 次', + 'meet_002_name': '会议基础 500 次', + 'meet_003_name': '会议基础 1000 次', + 'trade_001_name': '翻译基础 100 次', + 'trade_002_name': '翻译基础 500 次', + 'trade_003_name': '翻译基础 1000 次', + + // 商品描述(按ID) + 'ai_001_desc': '含 100 次使用,覆盖核心 AI 功能', + 'ai_002_desc': '含 500 次使用,覆盖核心 AI 功能', + 'ai_003_desc': '含 1000 次使用,覆盖核心 AI 功能', + 'meet_001_desc': '含 100 次会议录音/转写', + 'meet_002_desc': '含 500 次会议录音/转写', + 'meet_003_desc': '含 1000 次会议录音/转写', + 'trade_001_desc': '含 100 次翻译(语音/文本)', + 'trade_002_desc': '含 500 次翻译(语音/文本)', + 'trade_003_desc': '含 1000 次翻译(语音/文本)', + + // 新手引导 / Onboarding + 'skip': '跳过', + 'next': '下一步', + 'sayXiaoYanHint': '对着麦克风说:“小言小言”', + 'imHere': '我在呢~', + 'guideWelcomeWakeAI': '欢迎使用Voitrans!首先,让我们唤醒你的专属 AI—— 小言', + 'aiReplyCompleted': '小言已经完成了回答!', + 'aiThinking': '小言正在思考中~', + 'guideAwakenSuccess': '太棒了!你已成功唤醒小言,接下来试试让它帮你做件事吧', + 'confirmInput': '确定输入', + 'guideClickSendPrefix': '点击发送,', + // AI 引导步骤 + 'guideWeatherStart': '对小言说:“今天天气怎么样”', + 'guideWeatherInput': '今天天气怎么样', + 'guideWeatherSend': '小言会为你实时为你播报天气', + 'guideWeatherEnd': '小言能实时为你播报天气,试试其他指令吧', + 'guideMusicStart': '对小言说:“请播放一组摇滚乐”', + 'guideMusicInput': '请播放一组摇滚乐', + 'guideMusicSend': '小言会为你搜寻到一组音乐', + 'guideMusicEnd': '小言已成功为您搜寻到一组音乐,试试其他指令吧', + 'guideNavStart': '对小言说:“导航到深圳机场”', + 'guideNavInput': '导航到深圳机场', + 'guideNavSend': '小言会为你规划路线', + 'guideNavEnd': '小言已成功为您导航到深圳机场,试试其他指令吧', + 'guideMeetingStart': '对小言说:“明天下午3点创建会议提醒”', + 'guideMeetingInput': '明天下午3点创建会议提醒', + 'guideMeetingSend': '小言会为你创建会议提醒', + 'guideMeetingEnd': '小言已成功为您创建会议提醒,试试其他指令吧', + 'guidePhoneStart': '对小言说:“拨打妈妈的电话”', + 'guidePhoneInput': '拨打妈妈的电话', + 'guidePhoneSend': '小言会为你拨打电话', + 'guidePhoneEnd': '小言已成功为您拨打电话,试试其他指令吧', + 'guideSmsStart': '对小言说:“给爸爸发短信说晚上回家吃饭”', + 'guideSmsInput': '给爸爸发短信说晚上回家吃饭', + 'guideSmsSend': '小言会为你发送短信', + 'guideSmsEnd': '短信已发送,语音操控更便捷', + // 商务会议助手页 "startMeeting": "开始会议", 'edit': '编辑', @@ -968,7 +1049,7 @@ const Map zhCN = { "autoInputCode": "自动输入代码", "skipBinding": "跳过绑定", "rescan": "重新扫描", - "skip": "跳过", + "verifyingDevice": "正在验证设备...", "confirmBinding": "确认绑定", "associatingDevice": "正在关联设备...", @@ -1118,4 +1199,67 @@ const Map zhCN = { //补充 "insufficientIntegral": "积分不足", + + // 商品页通用页脚 + 'appNameProvider': '应用名称:VoiTrans · 服务提供:VoiTrans', + 'moreInfoViewInSettingsAbout': '更多信息请前往 设置 > 关于 查看', + 'copyrightVoiTrans': '© 2025 VoiTrans', + + // 会议商品页描述 + 'meetingHeaderDesc1': '录音转写、关键词检索与自动总结,提升会议效率。', + 'meetingHeaderDesc2': '适用于商务会议、课堂笔记、访谈纪要等场景。', + 'meetingAutoRecording': '自动录音与分段', + 'meetingSpeakerTagging': '讲话人标注', + 'meetingLongAudioTranscription': '长音频转写', + 'meetingKeyPointSummary': '关键要点提炼', + 'meetingTopicNameSearch': '按主题/人名检索', + 'meetingTimelineJump': '时间线跳转', + 'meetingExportSummary': '导出纪要', + 'meetingMultiPlatformShare': '多平台分享', + 'meetingDisclaimer': '建议在安静环境使用,效果受麦克风与网络影响,具体以实际表现为准。', + + // 同传/翻译商品页描述 + 'tradeHeaderDesc1': '多语种实时同传与文本翻译,低延时语音播报。', + 'tradeHeaderDesc2': '适用于出行、商务、演讲与教学等场景。', + 'translateZhEn': '中英互译', + 'lowLatencyVoiceBroadcast': '低延时语音播报', + 'multiLangTextTranslation': '多语种文本翻译', + 'termOptimizationContextPreserve': '术语优化与语境保持', + 'lexiconTourBusinessLife': '旅游/商务/生活词库', + 'personalVocabularyMemory': '专属词汇记忆', + 'conversationSubtitleLargeText': '对话字幕/大字模式', + 'colorHighContrast': '颜色高对比度', + 'tradeDisclaimer': '翻译效果受麦克风、网络时延与环境噪声影响,具体以实际表现为准。', + + // AI 商品页描述 + 'aiHeaderDesc1': '更长对话额度、更多工具调用、更强上下文长度支持。', + 'aiHeaderDesc2': '适用于智能体问答、总结分析、任务执行等场景。', + 'musicSearchPlaybackControl': '检索曲库、播放控制', + 'smartPlaylistAndSimilarRecommendations': '智能推荐歌单与相似歌曲', + 'routePlanningAndCongestionAvoidance': '路线规划与拥堵规避', + 'voiceBroadcastAndWaypoints': '语音播报与途径点设置', + 'realTimeWeatherForecast': '实时天气与预报', + 'clothingAdviceAndTravelReminders': '穿衣建议与出行提醒', + 'poiSearchFoodGasParking': '餐饮/加油/停车等地点检索', + 'ratingsHoursAndDirectRoutes': '评分、营业时间与路线直达', + 'hotNewsAndTopicOverview': '热点快讯与专题速览', + 'longArticleSummariesAndKeyPoints': '长文总结与要点提炼', + 'helpCallAndSMS': '帮忙拨打电话与发短信', + 'templatedMessagesAndScheduleReminders': '模板消息与日程提醒', + 'aiDisclaimer': '以上功能受设备权限、服务可用性与网络状况影响,具体以实际表现为准。', + + // 会员商品页 + 'benefitsOverview': '权益总览', + 'higherQuota': '更高使用额度', + 'lowerUnitPrice': '更低单价', + 'priorityService': '优先服务', + 'exclusiveSupportChannel': '专属客服通道', + 'fastResponse': '问题快速响应', + 'eventsAndDiscounts': '活动与折扣', + 'memberExclusiveEvents': '会员专属活动', + 'longTermDiscountPlan': '长期优惠计划', + 'generalPrivileges': '通用特权', + 'earlyAccessNewFeatures': '新功能优先体验', + 'crossDeviceSync': '跨设备同步', + 'vipDisclaimer': '具体权益以实际套餐说明为准,可能随版本迭代调整。', }; diff --git a/lib/core/translations/language/zh_hk.dart b/lib/core/translations/language/zh_hk.dart index 2a2c7fbfd..8e16a47d4 100644 --- a/lib/core/translations/language/zh_hk.dart +++ b/lib/core/translations/language/zh_hk.dart @@ -189,6 +189,27 @@ const Map zhHK = { "aiSingerInfo": "用你喜歡的歌手聲音演唱任何歌曲,甚至是你自己創作的歌曲", "popularFunction": "熱門功能場景", "tryNow": "立即嘗試", + // 商品名稱(按ID) + 'ai_001_name': 'AI基礎 100 次', + 'ai_002_name': 'AI基礎 500 次', + 'ai_003_name': 'AI基礎 1000 次', + 'meet_001_name': '會議基礎 100 次', + 'meet_002_name': '會議基礎 500 次', + 'meet_003_name': '會議基礎 1000 次', + 'trade_001_name': '翻譯基礎 100 次', + 'trade_002_name': '翻譯基礎 500 次', + 'trade_003_name': '翻譯基礎 1000 次', + + // 商品描述(按ID) + 'ai_001_desc': '含 100 次使用,涵蓋核心 AI 功能', + 'ai_002_desc': '含 500 次使用,涵蓋核心 AI 功能', + 'ai_003_desc': '含 1000 次使用,涵蓋核心 AI 功能', + 'meet_001_desc': '含 100 次會議錄音/轉寫', + 'meet_002_desc': '含 500 次會議錄音/轉寫', + 'meet_003_desc': '含 1000 次會議錄音/轉寫', + 'trade_001_desc': '含 100 次翻譯(語音/文本)', + 'trade_002_desc': '含 500 次翻譯(語音/文本)', + 'trade_003_desc': '含 1000 次翻譯(語音/文本)', // 商務會議助手頁 "startMeeting": "開始會議", @@ -787,4 +808,99 @@ const Map zhHK = { "乌尔都语": "烏爾都語", "波斯语": "波斯語", "斯瓦希里语": "斯瓦希里語", + // Guide overlay keys (placeholders in English) + "sayXiaoYanHint": "Say \"Xiaoyan Xiaoyan\" to the mic", + "imHere": "I’m here~", + "guideWelcomeWakeAI": "Welcome to Voitrans! First, wake your AI “Xiaoyan”.", + "aiReplyCompleted": "Xiaoyan has finished the reply!", + "aiThinking": "Xiaoyan is thinking…", + "guideAwakenSuccess": "Great! Xiaoyan is awake—ask it to help.", + "confirmInput": "Confirm Input", + "guideClickSendPrefix": "Tap send, ", + "guideWeatherStart": "Tell Xiaoyan: “What’s the weather today?”", + "guideWeatherInput": "What’s the weather today?", + "guideWeatherSend": "Xiaoyan will report the weather in real time", + "guideWeatherEnd": "Xiaoyan can report weather live—try other commands", + "guideMusicStart": "Tell Xiaoyan: “Play some rock music”", + "guideMusicInput": "Play some rock music", + "guideMusicSend": "Xiaoyan will find music for you", + "guideMusicEnd": "Xiaoyan found music—try other commands", + "guideNavStart": "Tell Xiaoyan: “Navigate to Shenzhen Airport”", + "guideNavInput": "Navigate to Shenzhen Airport", + "guideNavSend": "Xiaoyan will plan the route", + "guideNavEnd": "Navigation set—try other commands", + "guideMeetingStart": "Tell Xiaoyan: “Create a meeting reminder for 3pm tomorrow”", + "guideMeetingInput": "Create a meeting reminder for 3pm tomorrow", + "guideMeetingSend": "Xiaoyan will create a meeting reminder", + "guideMeetingEnd": "Reminder created—try other commands", + "guidePhoneStart": "Tell Xiaoyan: “Call Mom”", + "guidePhoneInput": "Call Mom", + "guidePhoneSend": "Xiaoyan will make the call", + "guidePhoneEnd": "Call placed—try other commands", + "guideSmsStart": "Tell Xiaoyan: “Send Dad a text: I’ll be home for dinner”", + "guideSmsInput": "Text Dad: I’ll be home for dinner", + "guideSmsSend": "Xiaoyan will send the message", + "guideSmsEnd": "Message sent—voice control is convenient", + // Goods pages common footer (placeholders) + 'appNameProvider': '應用名稱:VoiTrans · 服務提供:VoiTrans', + 'moreInfoViewInSettingsAbout': '更多信息請前往 設置 > 關於 查看', + 'copyrightVoiTrans': '© 2025 VoiTrans', + + // Meeting goods page (placeholders) + 'meetingHeaderDesc1': '錄音轉寫、關鍵詞檢索與自動總結,提升會議效率。', + 'meetingHeaderDesc2': '適用於商務會議、課堂筆記、訪談紀要等場景。', + 'meetingAutoRecording': '自動錄音與分段', + 'meetingSpeakerTagging': '講話人標注', + 'meetingLongAudioTranscription': '長音頻轉寫', + 'meetingKeyPointSummary': '關鍵要點提煉', + 'meetingTopicNameSearch': '按主題/人名檢索', + 'meetingTimelineJump': '時間線跳轉', + 'meetingExportSummary': '導出紀要', + 'meetingMultiPlatformShare': '多平台分享', + 'meetingDisclaimer': '建議在安靜環境使用,效果受麥克風與網絡影響,具體以實際表現為準。', + + // Translation goods page (placeholders) + 'tradeHeaderDesc1': '多語種實時同傳與文本翻譯,低延時語音播報。', + 'tradeHeaderDesc2': '適用於出行、商務、演講與教學等場景。', + 'translateZhEn': '中英互譯', + 'lowLatencyVoiceBroadcast': '低延時語音播報', + 'multiLangTextTranslation': '多語種文本翻譯', + 'termOptimizationContextPreserve': '術語優化與語境保持', + 'lexiconTourBusinessLife': '旅遊/商務/生活詞庫', + 'personalVocabularyMemory': '專屬詞彙記憶', + 'conversationSubtitleLargeText': '對話字幕/大字模式', + 'colorHighContrast': '顏色高對比度', + 'tradeDisclaimer': '翻譯效果受麥克風、網絡時延與環境噪聲影響,具體以實際表現為準。', + + // AI 商品頁描述(佔位) + 'aiHeaderDesc1': '更長對話額度、更多工具調用、更強上下文長度支持。', + 'aiHeaderDesc2': '適用於智能體問答、總結分析、任務執行等場景。', + 'musicSearchPlaybackControl': '檢索曲庫、播放控制', + 'smartPlaylistAndSimilarRecommendations': '智能推薦歌單與相似歌曲', + 'routePlanningAndCongestionAvoidance': '路線規劃與擁堵規避', + 'voiceBroadcastAndWaypoints': '語音播報與途徑點設置', + 'realTimeWeatherForecast': '實時天氣與預報', + 'clothingAdviceAndTravelReminders': '穿衣建議與出行提醒', + 'poiSearchFoodGasParking': '餐飲/加油/停車等地點檢索', + 'ratingsHoursAndDirectRoutes': '評分、營業時間與路線直達', + 'hotNewsAndTopicOverview': '熱點快訊與專題速覽', + 'longArticleSummariesAndKeyPoints': '長文總結與要點提煉', + 'helpCallAndSMS': '幫忙撥打電話與發短信', + 'templatedMessagesAndScheduleReminders': '模板消息與日程提醒', + 'aiDisclaimer': '以上功能受設備權限、服務可用性與網絡狀況影響,具體以實際表現為準。', + + // VIP goods page (placeholders) + 'benefitsOverview': '權益總覽', + 'higherQuota': '更高使用額度', + 'lowerUnitPrice': '更低單價', + 'priorityService': '優先服務', + 'exclusiveSupportChannel': '專屬客服通道', + 'fastResponse': '問題快速響應', + 'eventsAndDiscounts': '活動與折扣', + 'memberExclusiveEvents': '會員專屬活動', + 'longTermDiscountPlan': '長期優惠計劃', + 'generalPrivileges': '通用特權', + 'earlyAccessNewFeatures': '新功能優先體驗', + 'crossDeviceSync': '跨設備同步', + 'vipDisclaimer': '具體權益以實際套餐說明為準,可能隨版本迭代調整。', }; diff --git a/lib/core/widgets/intro_overlay_builder.dart b/lib/core/widgets/intro_overlay_builder.dart index 22b52a81a..882ae9f80 100644 --- a/lib/core/widgets/intro_overlay_builder.dart +++ b/lib/core/widgets/intro_overlay_builder.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_intro/flutter_intro.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; import 'package:lottie/lottie.dart'; class IntroOverlayBuilder { @@ -19,7 +20,7 @@ class IntroOverlayBuilder { static Widget homeBuilder( StepWidgetParams params, bool isWakeup, { - String title = '对着麦克风说:“小言小言”', + String title = 'sayXiaoYanHint', Function? onNext, }) { return Column( @@ -29,7 +30,7 @@ class IntroOverlayBuilder { margin: EdgeInsets.only(top: ScreenUtil().statusBarHeight), alignment: Alignment.centerRight, child: _button( - '跳过', + 'skip'.tr, () { params.onFinish(); }, @@ -47,7 +48,7 @@ class IntroOverlayBuilder { Padding( padding: EdgeInsets.only(bottom: 10.w), child: Text( - isWakeup ? '我在呢~' : title, + isWakeup ? 'imHere'.tr : title.tr, style: TextStyle( fontSize: 15.sp, color: Colors.white, @@ -57,7 +58,7 @@ class IntroOverlayBuilder { ), if (onNext != null) _button( - '下一步', + 'next'.tr, () { params.onNext!(); onNext(); @@ -70,7 +71,7 @@ class IntroOverlayBuilder { static Widget aiBuilder( StepWidgetParams params, String text, { - String buttonText = '下一步', + String buttonText = 'next', bool alignment = true, Function? onNext, Function? onFinish, @@ -92,7 +93,7 @@ class IntroOverlayBuilder { margin: EdgeInsets.only(top: ScreenUtil().statusBarHeight), alignment: Alignment.centerRight, child: _button( - '跳过', + 'skip'.tr, () { params.onFinish(); }, @@ -125,7 +126,7 @@ class IntroOverlayBuilder { Padding( padding: EdgeInsets.only(top: 10.w, left: 3, right: 3), child: _button( - buttonText, + buttonText.tr, () { params.onNext!(); onNext(); @@ -136,7 +137,7 @@ class IntroOverlayBuilder { Padding( padding: EdgeInsets.only(top: 10.w, left: 3, right: 3), child: _button( - buttonText, + buttonText.tr, () { params.onFinish(); onFinish(); diff --git a/lib/data/models/user_Info.dart b/lib/data/models/user_Info.dart index 861d1604a..4f3bc195b 100644 --- a/lib/data/models/user_Info.dart +++ b/lib/data/models/user_Info.dart @@ -45,7 +45,7 @@ class User { String phonemac; String password; int viplv = 0; //添加会员等级字段,0表示普通用户 - int viptime = 0; // 会员到期/剩余时间(秒/毫秒,按后端定义) + int vipexptime = 0; // 会员到期/剩余时间(秒/毫秒,按后端定义) int aichatintegral = 0; // ai聊天积分 int aichattotalintegral = 0; // ai聊天总积分 int tradeintegral = 0; // 翻译积分 @@ -67,7 +67,7 @@ class User { required this.phonemac, required this.password, required this.viplv, - required this.viptime, + required this.vipexptime, required this.aichatintegral, required this.aichattotalintegral, required this.tradeintegral, @@ -96,7 +96,7 @@ class User { phonemac: (userData?['phonemac'] as String?) ?? '', password: (userData?['password'] as String?) ?? '', viplv: (userData?['viplv'] as int?) ?? 0, // 提供默认值 - viptime: (userData?['viptime'] as int?) ?? 0, // 提供默认值 + vipexptime: (userData?['vipexptime'] as int?) ?? 0, // 提供默认值 aichatintegral: (userData?['aichatintegral'] as int?) ?? 0, aichattotalintegral: (userData?['aichattotalintegral'] as int?) ?? 0, @@ -130,7 +130,7 @@ class User { phonemac: (userData?['phonemac'] as String?) ?? '', password: (userData?['password'] as String?) ?? '', viplv: (userData?['viplv'] as int?) ?? 0, // 提供默认值 - viptime: (userData?['viptime'] as int?) ?? 0, // 提供默认值 + vipexptime: (userData?['vipexptime'] as int?) ?? 0, // 提供默认值 aichatintegral: (userData?['aichatintegral'] as int?) ?? 0, aichattotalintegral: (userData?['aichattotalintegral'] as int?) ?? 0, tradeintegral: (userData?['tradeintegral'] as int?) ?? 0, @@ -156,7 +156,7 @@ class User { phonemac = user['phonemac'] as String? ?? phonemac; password = user['password'] as String? ?? password; viplv = user['viplv'] as int? ?? viplv; - viptime = user['viptime'] as int? ?? viptime; + vipexptime = user['vipexptime'] as int? ?? vipexptime; aichatintegral = user['aichatintegral'] as int? ?? aichatintegral; aichattotalintegral = user['aichattotalintegral'] as int? ?? aichattotalintegral; @@ -183,7 +183,7 @@ class User { 'phonemac': phonemac, 'password': password, 'viplv': viplv, - 'viptime': viptime, + 'vipexptime': vipexptime, 'aichatintegral': aichatintegral, 'aichattotalintegral': aichattotalintegral, 'tradeintegral': tradeintegral, diff --git a/lib/data/services/network/api.dart b/lib/data/services/network/api.dart index e405bd87f..988af2e72 100644 --- a/lib/data/services/network/api.dart +++ b/lib/data/services/network/api.dart @@ -182,19 +182,10 @@ class Api { } //询问订单 - static payaskorder([params]) { + static payverifyorder([params]) { return DioManager().request( NWMethod.post, - '/api/home/pay_askorder', - params: params, - ); - } - - //内购收据验证 - static payiapverify([params]) { - return DioManager().request( - NWMethod.post, - '/api/home/pay_iapverify', + '/api/home/pay_verifyorder', params: params, ); } diff --git a/lib/data/services/novice_guide_service.dart b/lib/data/services/novice_guide_service.dart index f7617114f..7fbcefecf 100644 --- a/lib/data/services/novice_guide_service.dart +++ b/lib/data/services/novice_guide_service.dart @@ -23,10 +23,10 @@ class NoviceGuideService extends GetxService { List aiStepsList = [ { - 'start': '对小言说:“今天天气怎么样”', - 'input': '今天天气怎么样', - 'send': '小言会为你实时为你播报天气', - 'end': '小言能实时为你播报天气,试试其他指令吧', + 'startKey': 'guideWeatherStart', + 'inputKey': 'guideWeatherInput', + 'sendKey': 'guideWeatherSend', + 'endKey': 'guideWeatherEnd', 'method': () async { // 天气查询需要位置权限 await PermissionUtil.instance.requestPermission( @@ -39,17 +39,17 @@ class NoviceGuideService extends GetxService { }, }, { - 'start': '对小言说:“请播放一组摇滚乐”', - 'input': '请播放一组摇滚乐', - 'send': '小言会为你搜寻到一组音乐', - 'end': '小言已成功为您搜寻到一组音乐,试试其他指令吧', + 'startKey': 'guideMusicStart', + 'inputKey': 'guideMusicInput', + 'sendKey': 'guideMusicSend', + 'endKey': 'guideMusicEnd', 'method': () async {}, }, { - 'start': '对小言说:“导航到深圳机场”', - 'input': '导航到深圳机场', - 'send': '小言会为你规划路线', - 'end': '小言已成功为您导航到深圳机场,试试其他指令吧', + 'startKey': 'guideNavStart', + 'inputKey': 'guideNavInput', + 'sendKey': 'guideNavSend', + 'endKey': 'guideNavEnd', 'method': () async { // 导航功能需要位置权限 await PermissionUtil.instance.requestPermission( @@ -62,10 +62,10 @@ class NoviceGuideService extends GetxService { }, }, { - 'start': '对小言说:“明天下午3点创建会议提醒”', - 'input': '明天下午3点创建会议提醒', - 'send': '小言会为你创建会议提醒', - 'end': '小言已成功为您创建会议提醒,试试其他指令吧', + 'startKey': 'guideMeetingStart', + 'inputKey': 'guideMeetingInput', + 'sendKey': 'guideMeetingSend', + 'endKey': 'guideMeetingEnd', 'method': () async { //创建会议提醒需要日历权限 await PermissionUtil.instance.requestPermission( @@ -78,10 +78,10 @@ class NoviceGuideService extends GetxService { }, }, { - 'start': '对小言说:“拨打妈妈的电话”', - 'input': '拨打妈妈的电话', - 'send': '小言会为你拨打电话', - 'end': '小言已成功为您拨打电话,试试其他指令吧', + 'startKey': 'guidePhoneStart', + 'inputKey': 'guidePhoneInput', + 'sendKey': 'guidePhoneSend', + 'endKey': 'guidePhoneEnd', 'method': () async { if (Platform.isAndroid) { // 拨打电话需要电话权限 @@ -103,10 +103,10 @@ class NoviceGuideService extends GetxService { }, }, { - 'start': '对小言说:“给爸爸发短信说晚上回家吃饭’”', - 'input': '给爸爸发短信说晚上回家吃饭’', - 'send': '小言会为你发送短信', - 'end': '短信已发送,语音操控更便捷', + 'startKey': 'guideSmsStart', + 'inputKey': 'guideSmsInput', + 'sendKey': 'guideSmsSend', + 'endKey': 'guideSmsEnd', 'method': () async { if (Platform.isAndroid) { // 发送短信需要短信权限 diff --git a/lib/data/services/pay_service.dart b/lib/data/services/pay_service.dart index bbe89c42b..dedc2cae8 100644 --- a/lib/data/services/pay_service.dart +++ b/lib/data/services/pay_service.dart @@ -54,7 +54,7 @@ class PayService extends GetxService { /// 初始化支付宝SDK Future _initAlipay() async { try { - // 检查支付宝是否安装 - 修复用法 + // 检查支付宝是否安x装 - 修复用法 final isInstalled = await _tobias.isAliPayInstalled; print('支付宝是否安装: $isInstalled'); } catch (e) { @@ -99,8 +99,11 @@ class PayService extends GetxService { print('[IAP] 待查询商品ID: $id'); } // 仅在非 Web 平台执行;平台信息用于日志 - await _initIAP(); final platform = _platformString(); + if (!iapAvailable.value) { + final available = await _inAppPurchase.isAvailable(); + iapAvailable.value = available; + } if (!iapAvailable.value) { print('[IAP-$platform] 当前平台内购不可用,无法查询商品。'); return; @@ -108,7 +111,9 @@ class PayService extends GetxService { print('[IAP-$platform] 开始查询商品,IDs=${productIds.join(', ')}'); final resp = await _inAppPurchase.queryProductDetails(productIds); if (resp.error != null) { - print('[IAP-$platform] 查询错误: ${resp.error}'); + final err = resp.error!; + print( + '[IAP-$platform] 查询错误: code=${err.code}, source=${err.source}, message=${err.message}, details=${err.details}'); } if (resp.productDetails.isEmpty) { print('[IAP-$platform] 未返回任何商品。notFound=${resp.notFoundIDs}'); @@ -132,7 +137,9 @@ class PayService extends GetxService { print('[IAP] 开始查询单个商品: id="$pid"'); final resp = await _inAppPurchase.queryProductDetails({pid}); if (resp.error != null) { - print('[IAP] 查询商品失败: ${resp.error}'); + final err = resp.error!; + print( + '[IAP] 查询商品失败: code=${err.code}, source=${err.source}, message=${err.message}, details=${err.details}'); } if (resp.productDetails.isEmpty) { print('[IAP] 查询结果为空。notFound=${resp.notFoundIDs}'); @@ -187,31 +194,43 @@ class PayService extends GetxService { if (isSubscription) { print('[IAP-android] 订阅商品(ENV),使用 buyNonConsumable'); final gpParam = GooglePlayPurchaseParam(productDetails: product); + print( + '[IAP-android] 调用 buyNonConsumable 参数: productId=${product.id}'); ok = await _inAppPurchase.buyNonConsumable(purchaseParam: gpParam); + print('[IAP-android] buyNonConsumable 返回: $ok'); } else { // 普通一次性/消耗型商品,使用 buyConsumable final purchaseParam = PurchaseParam(productDetails: product); + print( + '[IAP-android] 调用 buyConsumable 参数: productId=${product.id} autoConsume=true'); ok = await _inAppPurchase.buyConsumable( purchaseParam: purchaseParam, autoConsume: true, ); + print('[IAP-android] buyConsumable 返回: $ok'); } } else { // iOS 或非订阅商品,按消耗型处理(如需支持 iOS 订阅,可通过 ENV 切换调用 buyNonConsumable) final purchaseParam = PurchaseParam(productDetails: product); + print( + '[IAP-ios] 调用 buyConsumable 参数: productId=${product.id} autoConsume=true'); ok = await _inAppPurchase.buyConsumable( purchaseParam: purchaseParam, autoConsume: true, ); + print('[IAP-ios] buyConsumable 返回: $ok'); } if (!ok) { onResult?.call(false, '无法发起内购'); + print('[IAP] 发起内购失败:平台=${_platformString()} productId=${product.id}'); } else { onResult?.call(true, '已发起内购,请完成支付'); + print('[IAP] 已发起内购:等待购买流回调(可能受旧交易阻塞或商店限制)'); } return ok; } catch (e) { onResult?.call(false, '发起内购失败: $e'); + print('[IAP] 发起内购异常: $e'); return false; } } @@ -232,41 +251,59 @@ class PayService extends GetxService { _iapOnResult?.call(false, details.error?.message ?? '支付错误'); break; case PurchaseStatus.purchased: + final txId = details.purchaseID ?? ''; + final ok = await _verifyIapWithServer(details); + if (!ok) { + print( + '[IAP] 验证失败 purchased txId=${details.purchaseID} product=${details.productID}'); + _iapOnResult?.call(false, details.error?.message ?? '支付错误'); + } + if (ok) { + try { + await _inAppPurchase.completePurchase(details); + print('[IAP] 完成交易 purchased txId=${details.purchaseID}'); + _iapOnResult?.call(true, details.error?.message ?? '支付成功'); + } catch (e, st) { + print('[IAP] 完成交易异常 purchased txId=${details.purchaseID} err=$e'); + print('[IAP] 完成交易异常堆栈 purchased $st'); + } + } + + break; case PurchaseStatus.restored: - // 完成购买并进行服务端收据验证 - try { - await _verifyIapWithServer(details); - } catch (e) { - _iapOnResult?.call(false, '收据验证失败: $e'); + final txId = details.purchaseID ?? ''; + final ok = await _verifyIapWithServer(details); + if (!ok) { + print( + '[IAP] 验证失败 restored(silent) txId=${details.purchaseID} product=${details.productID}'); + _iapOnResult?.call(false, details.error?.message ?? '支付错误'); + } + if (ok) { + try { + await _inAppPurchase.completePurchase(details); + _iapOnResult?.call(true, details.error?.message ?? '支付成功'); + print('[IAP] 完成交易 restored(silent) txId=${details.purchaseID}'); + } catch (e, st) { + print( + '[IAP] 完成交易异常 restored(silent) txId=${details.purchaseID} err=$e'); + print('[IAP] 完成交易异常堆栈 restored(silent) $st'); + } } break; case PurchaseStatus.canceled: _iapOnResult?.call(false, '已取消支付'); + print('[IAP] 用户取消支付 product=${details.productID}'); break; } - if (details.pendingCompletePurchase) { - try { - await _inAppPurchase.completePurchase(details); - } catch (_) {} - } } } - Future _verifyIapWithServer(PurchaseDetails details) async { - final platform = _platformString(); - final verificationData = - details.verificationData.serverVerificationData ?? ''; - final transactionId = details.purchaseID ?? ''; - final params = { - 'platform': platform, - 'product_id': details.productID, - 'transaction_id': transactionId, - 'server_verification_data': verificationData, - }; + Future _verifyIapWithServer(PurchaseDetails details) async { try { - final resp = await Api.payiapverify(params); - // 兼容多种返回结构,优先拿到用户信息 + final params = await buildIapAskParams(); + final resp = await Api.payverifyorder(params); Map? user; + Map? order; if (resp is Map) { if (resp['user'] is Map) { user = resp['user'] as Map; @@ -274,15 +311,32 @@ class PayService extends GetxService { (resp['data']['user'] is Map)) { user = resp['data']['user'] as Map; } + if (resp['order'] is Map) { + order = resp['order'] as Map; + } else if (resp['data'] is Map && + (resp['data']['order'] is Map)) { + order = resp['data']['order'] as Map; + } } - if (user != null) { + final int? status = order != null + ? (order['status'] is int + ? order['status'] as int + : int.tryParse('${order['status']}')) + : null; + final bool ok = status == 1 || user != null; + if (ok && user != null) { User.instance.updateUserInfo(user); - _iapOnResult?.call(true, '支付成功'); - } else { - _iapOnResult?.call(true, '支付成功,额度将稍后刷新'); } + if (!ok) { + final code = (resp is Map) ? resp['code'] : null; + final msg = (resp is Map) ? (resp['message'] ?? resp['msg']) : null; + print( + '[IAP] 验证失败详情 status=$status code=$code msg=$msg order_id=${params['order_id']}'); + } + return ok; } catch (e) { - _iapOnResult?.call(false, '服务器验证异常: $e'); + print('[IAP] 服务器验证异常: $e'); + return false; } } @@ -360,6 +414,41 @@ class PayService extends GetxService { } } + /// 解析 Apple 的真实商品ID(支持环境前缀/后缀或显式映射) + /// 优先级:显式映射(APP_IOS_IAP_ID_MAP JSON) > 前缀(APP_IOS_IAP_PREFIX) > 后缀(APP_IOS_IAP_SUFFIX) > 原始ID + /// 示例: + /// - APP_IOS_IAP_PREFIX=com.voitrans. + /// - APP_IOS_IAP_ID_MAP={"ai_001":"com.voitrans.ai001","ai_002":"com.voitrans.ai002"} + String resolveAppleProductId(String backendId) { + final raw = backendId.trim(); + Map? mapped; + try { + final jsonStr = dotenv.env['APP_IOS_IAP_ID_MAP']; + if (jsonStr != null && jsonStr.isNotEmpty) { + mapped = json.decode(jsonStr) as Map; + } + } catch (e) { + print('[IAP-ios] 解析 APP_IOS_IAP_ID_MAP 失败: $e'); + } + if (mapped != null) { + final m = mapped[raw]; + if (m is String && m.trim().isNotEmpty) { + final resolved = m.trim(); + print('[IAP-ios] 使用映射ID: $raw -> $resolved'); + return resolved; + } + } + final prefix = dotenv.env['APP_IOS_IAP_PREFIX'] ?? ''; + final suffix = dotenv.env['APP_IOS_IAP_SUFFIX'] ?? ''; + final resolved = '${prefix}${raw}${suffix}'; + if (resolved != raw) { + print('[IAP-ios] 使用前后缀ID: $raw -> $resolved'); + } else { + print('[IAP-ios] 未配置映射/前缀,使用原始ID: $raw'); + } + return resolved; + } + /// 发起 Apple 内购 Future processApplePayment({ required String productId, @@ -369,9 +458,17 @@ class PayService extends GetxService { onResult?.call(false, '当前平台不支持 Apple 内购'); return false; } - // 重新初始化内购,避免早期可用性判断为 false - await _initIAP(); - return _processIapPayment(productId: productId, onResult: onResult); + if (!iapAvailable.value) { + await _initIAP(); + if (!iapAvailable.value) { + onResult?.call(false, '内购不可用'); + return false; + } + } + // 解析为 App Store 的真实商品ID + final iosId = resolveAppleProductId(productId); + print('[IAP-ios] 准备使用商品ID购买: backend="$productId" -> store="$iosId"'); + return _processIapPayment(productId: iosId, onResult: onResult); } /// 发起 Google Play 内购 @@ -383,8 +480,13 @@ class PayService extends GetxService { onResult?.call(false, '当前平台不支持 Google 内购'); return false; } - // 重新初始化内购,避免早期可用性判断为 false - await _initIAP(); + if (!iapAvailable.value) { + await _initIAP(); + if (!iapAvailable.value) { + onResult?.call(false, '内购不可用'); + return false; + } + } return _processIapPayment(productId: productId, onResult: onResult); } diff --git a/lib/modules/agent/views/agent_view.dart b/lib/modules/agent/views/agent_view.dart index b7484a4bc..22662ad94 100644 --- a/lib/modules/agent/views/agent_view.dart +++ b/lib/modules/agent/views/agent_view.dart @@ -276,8 +276,8 @@ class _AgentViewState extends State with WidgetsBindingObserver { params, false, title: controller.newAIReplyCompleted.value - ? '小言已经完成了回答!' - : '小言正在思考中~', + ? 'aiReplyCompleted'.tr + : 'aiThinking'.tr, onNext: controller.newAIReplyCompleted.value ? () {} : null, ), ); @@ -326,15 +326,18 @@ class _AgentViewState extends State with WidgetsBindingObserver { getOverlayPosition: IntroOverlayBuilder.overlayPosition, overlayBuilder: (params) { - return IntroOverlayBuilder.aiBuilder( - params, - controller.noviceGuideService.aiStepsList[ - controller.noviceGuideService - .aiStep]['end'], - onFinish: () async { - if (controller - .noviceGuideService.aiStep < - 5) { + return IntroOverlayBuilder.aiBuilder( + params, + controller + .noviceGuideService + .aiStepsList[controller + .noviceGuideService.aiStep] + ['endKey'] + .tr, + onFinish: () async { + if (controller + .noviceGuideService.aiStep < + 5) { await Future.delayed(const Duration( milliseconds: 300)); controller @@ -622,23 +625,29 @@ class _AgentViewState extends State with WidgetsBindingObserver { return IntroOverlayBuilder.aiBuilder( params, controller - .noviceGuideService.aiStepsList[ - controller.noviceGuideService - .aiStep]['start'], - buttonText: '确定输入', + .noviceGuideService + .aiStepsList[controller + .noviceGuideService.aiStep] + ['startKey'] + .tr, + buttonText: 'confirmInput'.tr, onNext: () { controller.textController.text = - controller.noviceGuideService - .aiStepsList[ - controller.noviceGuideService - .aiStep]['input']; + controller + .noviceGuideService + .aiStepsList[controller + .noviceGuideService + .aiStep]['inputKey'] + .tr; }, onTap: () { controller.textController.text = - controller.noviceGuideService - .aiStepsList[ - controller.noviceGuideService - .aiStep]['input']; + controller + .noviceGuideService + .aiStepsList[controller + .noviceGuideService + .aiStep]['inputKey'] + .tr; params.onNext!(); }, ); @@ -862,13 +871,13 @@ class _AgentViewState extends State with WidgetsBindingObserver { overlayBuilder: (params) { return IntroOverlayBuilder.aiBuilder( params, - '点击发送,${controller.noviceGuideService.aiStepsList[controller.noviceGuideService.aiStep]['send']}', + '${'guideClickSendPrefix'.tr}${controller.noviceGuideService.aiStepsList[controller.noviceGuideService.aiStep]['sendKey'].tr}', alignment: false, onTap: () async { await controller .noviceGuideService.aiStepsList[ controller.noviceGuideService - .aiStep]['method'](); + .aiStep]['method'](); params.onNext!(); controller.sendMessage(); }, diff --git a/lib/modules/goods/controllers/goods_base_controller.dart b/lib/modules/goods/controllers/goods_base_controller.dart index 846b35dc6..74d9aeb30 100644 --- a/lib/modules/goods/controllers/goods_base_controller.dart +++ b/lib/modules/goods/controllers/goods_base_controller.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:voitrans/data/models/user_Info.dart'; -import '../../../routes/app_routes.dart'; import '../../../data/services/pay_service.dart'; import '../../../data/services/version_update_service.dart'; import '../../../data/models/goods.dart'; @@ -17,6 +16,8 @@ abstract class GoodsBaseController extends GetxController { final RxList items = [].obs; final RxBool loading = false.obs; final RxString error = ''.obs; + final RxBool isPaying = false.obs; + Timer? _payingTimeoutTimer; late final PayService _payService = Get.find(); StreamSubscription? _deeplinkSub; @@ -34,6 +35,8 @@ abstract class GoodsBaseController extends GetxController { void onClose() { _deeplinkSub?.cancel(); _deeplinkSub = null; + _payingTimeoutTimer?.cancel(); + _payingTimeoutTimer = null; super.onClose(); } @@ -43,6 +46,8 @@ abstract class GoodsBaseController extends GetxController { try { final list = await fetchProducts(); items.assignAll(list); + // iOS 环境下,在页面加载后批量查询当前商品的 IAP 详情,便于排查 StoreKit 可用商品 + await _debugQueryIapProductsIfIos(); } catch (e) { error.value = e.toString(); } finally { @@ -53,6 +58,30 @@ abstract class GoodsBaseController extends GetxController { /// 子类实现:返回商品列表(统一使用 DBGoods) Future> fetchProducts(); + /// iOS 批量查询当前页面商品的 IAP 详情(仅真机 iOS 生效,Web/Android 跳过) + Future _debugQueryIapProductsIfIos() async { + try { + final isIOS = GetPlatform.isIOS && !kIsWeb; + if (!isIOS) return; + + // 收集页面商品ID;若为空,使用预设的基础套餐ID进行测试 + final ids = items + .map((e) => (e.id ?? '').trim()) + .where((id) => id.isNotEmpty) + .toSet(); + if (ids.isEmpty) { + ids.addAll({ + 'ai_001', + }); + } + + print('[IAP-ios] 批量查询页面商品IDs: ${ids.join(', ')}'); + await _payService.debugQueryProducts(ids); + } catch (e) { + print('[IAP-ios] 批量查询异常: $e'); + } + } + /// 统一入口:根据后端配置决定是否弹出支付方式选择面板 Future purchase(DBGoods item) async { // 读取渠道配置 @@ -480,9 +509,15 @@ abstract class GoodsBaseController extends GetxController { onResult?.call(false, '创建 Apple 订单失败'); return false; } + isPaying.value = true; + _startPayingTimeout(); // 使用商品id作为内购的 productId(与后台保持一致) final productId = item.id; + // 解析为 App Store 的真实商品ID(支持前缀/映射) + final iosProductId = _payService.resolveAppleProductId(productId); + // 调试:在发起购买前先查询并打印该商品的内购详情/错误,便于定位问题 + await _payService.debugQueryProducts({iosProductId}); return _payService.processApplePayment( productId: productId, onResult: (success, msg) { @@ -490,6 +525,8 @@ abstract class GoodsBaseController extends GetxController { onResult?.call(success, msg); if (!success) { _showPayResultDialog(false, msg); + isPaying.value = false; + _cancelPayingTimeout(); } else { // 支付成功或额度待刷新时弹窗,其余阶段用轻提示 final showDialog = msg.contains('支付成功'); @@ -497,6 +534,8 @@ abstract class GoodsBaseController extends GetxController { _showPayResultDialog(true, msg); // 仅在支付成功阶段,携带校验参数主动查询订单 _askOrderWithIapVerification(); + isPaying.value = false; + _cancelPayingTimeout(); } else { Get.snackbar('提示', msg, snackPosition: SnackPosition.BOTTOM, @@ -507,6 +546,8 @@ abstract class GoodsBaseController extends GetxController { ); } catch (e) { onResult?.call(false, 'Apple 内购异常: $e'); + isPaying.value = false; + _cancelPayingTimeout(); return false; } } @@ -526,6 +567,8 @@ abstract class GoodsBaseController extends GetxController { onResult?.call(false, '创建 Google 订单失败'); return false; } + isPaying.value = true; + _startPayingTimeout(); // 使用商品id作为内购的 productId(与后台保持一致) final productId = item.id; @@ -537,12 +580,16 @@ abstract class GoodsBaseController extends GetxController { onResult?.call(success, msg); if (!success) { _showPayResultDialog(false, msg); + isPaying.value = false; + _cancelPayingTimeout(); } else { final showDialog = msg.contains('支付成功'); if (showDialog) { _showPayResultDialog(true, msg); // 仅在支付成功阶段,携带校验参数主动查询订单 _askOrderWithIapVerification(); + isPaying.value = false; + _cancelPayingTimeout(); } else { Get.snackbar('提示', msg, snackPosition: SnackPosition.BOTTOM, @@ -553,6 +600,8 @@ abstract class GoodsBaseController extends GetxController { ); } catch (e) { onResult?.call(false, 'Google 内购异常: $e'); + isPaying.value = false; + _cancelPayingTimeout(); return false; } } @@ -590,7 +639,7 @@ abstract class GoodsBaseController extends GetxController { try { // 简单轮询回查,避免回调延迟 for (int i = 0; i < retries; i++) { - final resp = await Api.payaskorder({'order_id': orderId}); + final resp = await Api.payverifyorder({'order_id': orderId}); print("查询订单 resp: $resp"); final order = resp?['order'] as Map?; final user = resp?['user'] as Map?; @@ -625,7 +674,7 @@ abstract class GoodsBaseController extends GetxController { Future _askOrderWithIapVerification() async { try { final params = await _payService.buildIapAskParams(); - final resp = await Api.payaskorder(params); + final resp = await Api.payverifyorder(params); print('[IAP] 主动查询订单 resp: $resp'); final order = resp?['order'] as Map?; final user = resp?['user'] as Map?; @@ -731,6 +780,19 @@ abstract class GoodsBaseController extends GetxController { ); } + void _startPayingTimeout({int seconds = 30}) { + _payingTimeoutTimer?.cancel(); + _payingTimeoutTimer = Timer(Duration(seconds: seconds), () { + isPaying.value = false; + _payingTimeoutTimer = null; + }); + } + + void _cancelPayingTimeout() { + _payingTimeoutTimer?.cancel(); + _payingTimeoutTimer = null; + } + /// 指定 PayPal 支付(创建订单并打开授权链接) Future payPaypal(DBGoods item, {PaymentResultCallback? onResult}) async { diff --git a/lib/modules/goods/utils/goods_i18n.dart b/lib/modules/goods/utils/goods_i18n.dart new file mode 100644 index 000000000..796caa477 --- /dev/null +++ b/lib/modules/goods/utils/goods_i18n.dart @@ -0,0 +1,63 @@ +import 'package:get/get.dart'; +import 'package:voitrans/data/models/goods.dart'; + +/// 商品名称本地化 +/// 优先根据商品ID映射到本地化名称;若无映射,则回退到后端提供的名称 +String localizedGoodsName(DBGoods item) { + final id = (item.id ?? '').trim(); + + switch (id) { + case 'ai_001': + return 'ai_001_name'.tr; + case 'ai_002': + return 'ai_002_name'.tr; + case 'ai_003': + return 'ai_003_name'.tr; + case 'meet_001': + return 'meet_001_name'.tr; + case 'meet_002': + return 'meet_002_name'.tr; + case 'meet_003': + return 'meet_003_name'.tr; + case 'trade_001': + return 'trade_001_name'.tr; + case 'trade_002': + return 'trade_002_name'.tr; + case 'trade_003': + return 'trade_003_name'.tr; + // 可在此补充其他商品ID的映射,如:translate_001、meet_001 等 + default: + final name = (item.name ?? '').trim(); + return name.isNotEmpty ? name : 'unknown'.tr; + } +} + +/// 商品描述本地化 +/// 优先根据商品ID映射到本地化描述;若无映射,则回退到后端提供的描述 +String localizedGoodsDesc(DBGoods item) { + final id = (item.id ?? '').trim(); + + switch (id) { + case 'ai_001': + return 'ai_001_desc'.tr; + case 'ai_002': + return 'ai_002_desc'.tr; + case 'ai_003': + return 'ai_003_desc'.tr; + case 'meet_001': + return 'meet_001_desc'.tr; + case 'meet_002': + return 'meet_002_desc'.tr; + case 'meet_003': + return 'meet_003_desc'.tr; + case 'trade_001': + return 'trade_001_desc'.tr; + case 'trade_002': + return 'trade_002_desc'.tr; + case 'trade_003': + return 'trade_003_desc'.tr; + default: + final desc = (item.desc ?? '').trim(); + return desc.isNotEmpty ? desc : ''; + } +} diff --git a/lib/modules/goods/views/goodsai_view.dart b/lib/modules/goods/views/goodsai_view.dart index edc1cf688..f6a1cfd0f 100644 --- a/lib/modules/goods/views/goodsai_view.dart +++ b/lib/modules/goods/views/goodsai_view.dart @@ -5,6 +5,7 @@ import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import '../../../data/models/goods.dart'; import '../../../data/models/user_Info.dart'; import '../controllers/goodsai_controller.dart'; +import '../utils/goods_i18n.dart'; class GoodsaiView extends GetView { const GoodsaiView({super.key}); @@ -31,37 +32,54 @@ class GoodsaiView extends GetView { body: Obx(() { // 访问刷新信号以建立依赖关系:用户信息变化时触发重建 final _ = User.refreshTick.value; + Widget content; if (controller.loading.value) { - return const Center(child: CircularProgressIndicator()); - } - if (controller.error.isNotEmpty) { - return Center(child: Text(controller.error.value)); + content = const Center(child: CircularProgressIndicator()); + } else if (controller.error.isNotEmpty) { + content = Center(child: Text(controller.error.value)); + } else { + content = ListView( + padding: EdgeInsets.all(16.w), + children: [ + _buildHeader(isDarkMode), + SizedBox(height: 12.h), + _buildUsageCard(isDarkMode), + SizedBox(height: 16.h), + Text( + 'availablePackages'.tr, + style: TextStyle( + fontSize: 16.sp, + fontWeight: FontWeight.w600, + color: isDarkMode ? Colors.white : Colors.black, + ), + ), + SizedBox(height: 8.h), + ...controller.items.map((item) => Padding( + padding: EdgeInsets.only(bottom: 12.h), + child: _buildCard(item, isDarkMode), + )), + SizedBox(height: 16.h), + _buildFeaturesSection(isDarkMode), + SizedBox(height: 16.h), + _buildFooterSection(isDarkMode), + ], + ); } - - return ListView( - padding: EdgeInsets.all(16.w), + return Stack( children: [ - _buildHeader(isDarkMode), - SizedBox(height: 12.h), - _buildUsageCard(isDarkMode), - SizedBox(height: 16.h), - Text( - '可购买套餐', - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - color: isDarkMode ? Colors.white : Colors.black, + content, + if (controller.isPaying.value) + Positioned.fill( + child: AbsorbPointer( + absorbing: true, + child: Container( + color: Colors.black.withOpacity(0.35), + child: const Center( + child: CircularProgressIndicator(), + ), + ), + ), ), - ), - SizedBox(height: 8.h), - ...controller.items.map((item) => Padding( - padding: EdgeInsets.only(bottom: 12.h), - child: _buildCard(item, isDarkMode), - )), - SizedBox(height: 16.h), - _buildFeaturesSection(isDarkMode), - SizedBox(height: 16.h), - _buildFooterSection(isDarkMode), ], ); }), @@ -105,7 +123,7 @@ class GoodsaiView extends GetView { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'AI 功能', + 'aiFunction'.tr, style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.w700, @@ -114,7 +132,7 @@ class GoodsaiView extends GetView { ), SizedBox(height: 6.h), Text( - '更长对话额度、更多工具调用、更强上下文长度支持。', + 'aiHeaderDesc1'.tr, style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[700], @@ -122,7 +140,7 @@ class GoodsaiView extends GetView { ), SizedBox(height: 4.h), Text( - '适用于智能体问答、总结分析、任务执行等场景。', + 'aiHeaderDesc2'.tr, style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[700], @@ -172,7 +190,7 @@ class GoodsaiView extends GetView { color: isDarkMode ? Colors.blue[300]! : Colors.blue[600]!), SizedBox(width: 8.w), Text( - '剩余额度', + 'remainingQuota'.tr, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, @@ -194,14 +212,14 @@ class GoodsaiView extends GetView { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - '总次数:$totalAi', + '${'totalCount'.tr}:$totalAi', style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[700], ), ), Text( - '剩余:$remainAi', + '${'remaining'.tr}:$remainAi', style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[700], @@ -221,7 +239,7 @@ class GoodsaiView extends GetView { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '功能说明', + 'featureDescription'.tr, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, @@ -242,10 +260,10 @@ class GoodsaiView extends GetView { return _buildFeatureCard( isDarkMode, icon: Icons.music_note, - title: '听歌与推荐', + title: 'musicAndRecommendation'.tr, lines: [ - '检索曲库、播放控制', - '智能推荐歌单与相似歌曲', + 'musicSearchPlaybackControl'.tr, + 'smartPlaylistAndSimilarRecommendations'.tr, ], colorSeed: Colors.purple, ); @@ -253,10 +271,10 @@ class GoodsaiView extends GetView { return _buildFeatureCard( isDarkMode, icon: Icons.navigation, - title: '导航与路线', + title: 'navigationAndRoutes'.tr, lines: [ - '路线规划与拥堵规避', - '语音播报与途径点设置', + 'routePlanningAndCongestionAvoidance'.tr, + 'voiceBroadcastAndWaypoints'.tr, ], colorSeed: Colors.orange, ); @@ -264,10 +282,10 @@ class GoodsaiView extends GetView { return _buildFeatureCard( isDarkMode, icon: Icons.wb_sunny, - title: '天气查询', + title: 'weatherQuery'.tr, lines: [ - '实时天气与预报', - '穿衣建议与出行提醒', + 'realTimeWeatherForecast'.tr, + 'clothingAdviceAndTravelReminders'.tr, ], colorSeed: Colors.blue, ); @@ -275,10 +293,10 @@ class GoodsaiView extends GetView { return _buildFeatureCard( isDarkMode, icon: Icons.place, - title: '附近搜索', + title: 'nearbySearch'.tr, lines: [ - '餐饮/加油/停车等地点检索', - '评分、营业时间与路线直达', + 'poiSearchFoodGasParking'.tr, + 'ratingsHoursAndDirectRoutes'.tr, ], colorSeed: Colors.green, ); @@ -286,10 +304,10 @@ class GoodsaiView extends GetView { return _buildFeatureCard( isDarkMode, icon: Icons.newspaper, - title: '新闻资讯', + title: 'newsInformation'.tr, lines: [ - '热点快讯与专题速览', - '长文总结与要点提炼', + 'hotNewsAndTopicOverview'.tr, + 'longArticleSummariesAndKeyPoints'.tr, ], colorSeed: Colors.indigo, ); @@ -297,10 +315,10 @@ class GoodsaiView extends GetView { return _buildFeatureCard( isDarkMode, icon: Icons.call, - title: '通讯助手', + title: 'communicationAssistant'.tr, lines: [ - '帮忙拨打电话与发短信', - '模板消息与日程提醒', + 'helpCallAndSMS'.tr, + 'templatedMessagesAndScheduleReminders'.tr, ], colorSeed: Colors.teal, ); @@ -309,7 +327,7 @@ class GoodsaiView extends GetView { ), SizedBox(height: 12.h), Text( - '以上功能受设备权限、服务可用性与网络状况影响,具体以实际表现为准。', + 'aiDisclaimer'.tr, style: TextStyle(fontSize: 12.sp, color: subColor), ), ], @@ -329,19 +347,19 @@ class GoodsaiView extends GetView { ), SizedBox(height: 8.h), Text( - '应用名称:VoiTrans · 服务提供:VoiTrans', + 'appNameProvider'.tr, textAlign: TextAlign.center, style: TextStyle(fontSize: 11.sp, color: subColor), ), SizedBox(height: 4.h), Text( - '更多信息请前往 设置 > 关于 查看', + 'moreInfoViewInSettingsAbout'.tr, textAlign: TextAlign.center, style: TextStyle(fontSize: 11.sp, color: subColor), ), SizedBox(height: 4.h), Text( - '© 2025 VoiTrans', + 'copyrightVoiTrans'.tr, textAlign: TextAlign.center, style: TextStyle(fontSize: 11.sp, color: subColor), ), @@ -460,14 +478,14 @@ class GoodsaiView extends GetView { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(item.name, + Text(localizedGoodsName(item), style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, color: isDarkMode ? Colors.white : Colors.black, )), SizedBox(height: 4.h), - Text(item.desc, + Text(localizedGoodsDesc(item), style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[600], @@ -495,7 +513,7 @@ class GoodsaiView extends GetView { borderRadius: BorderRadius.circular(20.r), ), child: Text( - '购买', + 'purchase'.tr, style: TextStyle(fontSize: 12.sp, color: Colors.white), ), ), diff --git a/lib/modules/goods/views/goodsmeet_view.dart b/lib/modules/goods/views/goodsmeet_view.dart index 2bedfd040..e32c2dfb4 100644 --- a/lib/modules/goods/views/goodsmeet_view.dart +++ b/lib/modules/goods/views/goodsmeet_view.dart @@ -4,6 +4,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:voitrans/data/models/goods.dart'; import '../../../data/models/user_Info.dart'; import '../controllers/goodsmeet_controller.dart'; +import '../utils/goods_i18n.dart'; class GoodsmeetView extends GetView { const GoodsmeetView({super.key}); @@ -99,7 +100,7 @@ class GoodsmeetView extends GetView { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '会议助手', + 'conferenceAssistant'.tr, style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.w700, @@ -108,7 +109,7 @@ class GoodsmeetView extends GetView { ), SizedBox(height: 6.h), Text( - '录音转写、关键词检索与自动总结,提升会议效率。', + 'meetingHeaderDesc1'.tr, style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[700], @@ -116,7 +117,7 @@ class GoodsmeetView extends GetView { ), SizedBox(height: 4.h), Text( - '适用于商务会议、课堂笔记、访谈纪要等场景。', + 'meetingHeaderDesc2'.tr, style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[700], @@ -164,7 +165,7 @@ class GoodsmeetView extends GetView { color: isDarkMode ? Colors.blue[300]! : Colors.blue[600]!), SizedBox(width: 8.w), Text( - '剩余额度', + 'remainingQuota'.tr, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, @@ -186,14 +187,14 @@ class GoodsmeetView extends GetView { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - '总次数:$totalAi', + '${'totalCount'.tr}:$totalAi', style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[700], ), ), Text( - '剩余:$remainAi', + '${'remaining'.tr}:$remainAi', style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[700], @@ -241,14 +242,14 @@ class GoodsmeetView extends GetView { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(item.name, + Text(localizedGoodsName(item), style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, color: isDarkMode ? Colors.white : Colors.black, )), SizedBox(height: 4.h), - Text(item.desc, + Text(localizedGoodsDesc(item), style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[600], @@ -276,7 +277,7 @@ class GoodsmeetView extends GetView { borderRadius: BorderRadius.circular(20.r), ), child: Text( - '购买', + 'purchase'.tr, style: TextStyle(fontSize: 12.sp, color: Colors.white), ), ), @@ -295,7 +296,7 @@ class GoodsmeetView extends GetView { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '功能说明', + 'featureDescription'.tr, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, @@ -312,36 +313,42 @@ class GoodsmeetView extends GetView { _buildFeatureCard( isDarkMode, icon: Icons.mic, - title: '会议记录', - lines: ['自动录音与分段', '讲话人标注'], + title: 'meetingRecording'.tr, + lines: ['meetingAutoRecording'.tr, 'meetingSpeakerTagging'.tr], colorSeed: Colors.pink, ), _buildFeatureCard( isDarkMode, icon: Icons.summarize, - title: '转写与总结', - lines: ['长音频转写', '关键要点提炼'], + title: 'transcriptionAndSummary'.tr, + lines: [ + 'meetingLongAudioTranscription'.tr, + 'meetingKeyPointSummary'.tr + ], colorSeed: Colors.blue, ), _buildFeatureCard( isDarkMode, icon: Icons.search, - title: '关键词检索', - lines: ['按主题/人名检索', '时间线跳转'], + title: 'keywordSearch'.tr, + lines: ['meetingTopicNameSearch'.tr, 'meetingTimelineJump'.tr], colorSeed: Colors.indigo, ), _buildFeatureCard( isDarkMode, icon: Icons.share, - title: '协同分享', - lines: ['导出纪要', '多平台分享'], + title: 'collaborationSharing'.tr, + lines: [ + 'meetingExportSummary'.tr, + 'meetingMultiPlatformShare'.tr + ], colorSeed: Colors.teal, ), ], ), SizedBox(height: 12.h), Text( - '建议在安静环境使用,效果受麦克风与网络影响,具体以实际表现为准。', + 'meetingDisclaimer'.tr, style: TextStyle(fontSize: 12.sp, color: subColor), ), ], @@ -428,19 +435,19 @@ class GoodsmeetView extends GetView { ), SizedBox(height: 8.h), Text( - '应用名称:VoiTrans · 服务提供:VoiTrans', + 'appNameProvider'.tr, textAlign: TextAlign.center, style: TextStyle(fontSize: 11.sp, color: subColor), ), SizedBox(height: 4.h), Text( - '更多信息请前往 设置 > 关于 查看', + 'moreInfoViewInSettingsAbout'.tr, textAlign: TextAlign.center, style: TextStyle(fontSize: 11.sp, color: subColor), ), SizedBox(height: 4.h), Text( - '© 2025 VoiTrans', + 'copyrightVoiTrans'.tr, textAlign: TextAlign.center, style: TextStyle(fontSize: 11.sp, color: subColor), ), diff --git a/lib/modules/goods/views/goodstrade_view.dart b/lib/modules/goods/views/goodstrade_view.dart index e501aecaa..e454f8e63 100644 --- a/lib/modules/goods/views/goodstrade_view.dart +++ b/lib/modules/goods/views/goodstrade_view.dart @@ -4,6 +4,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:voitrans/data/models/goods.dart'; import '../../../data/models/user_Info.dart'; import '../controllers/goodstrade_controller.dart'; +import '../utils/goods_i18n.dart'; class GoodstradeView extends GetView { const GoodstradeView({super.key}); @@ -99,7 +100,7 @@ class GoodstradeView extends GetView { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '翻译功能', + 'simultaneousTranslation'.tr, style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.w700, @@ -108,7 +109,7 @@ class GoodstradeView extends GetView { ), SizedBox(height: 6.h), Text( - '多语种实时同传与文本翻译,低延时语音播报。', + 'tradeHeaderDesc1'.tr, style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[700], @@ -116,7 +117,7 @@ class GoodstradeView extends GetView { ), SizedBox(height: 4.h), Text( - '适用于出行、商务、演讲与教学等场景。', + 'tradeHeaderDesc2'.tr, style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[700], @@ -164,7 +165,7 @@ class GoodstradeView extends GetView { color: isDarkMode ? Colors.blue[300]! : Colors.blue[600]!), SizedBox(width: 8.w), Text( - '剩余额度', + 'remainingQuota'.tr, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, @@ -186,14 +187,14 @@ class GoodstradeView extends GetView { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - '总次数:$totalAi', + '${'totalCount'.tr}:$totalAi', style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[700], ), ), Text( - '剩余:$remainAi', + '${'remaining'.tr}:$remainAi', style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[700], @@ -241,14 +242,14 @@ class GoodstradeView extends GetView { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(item.name, + Text(localizedGoodsName(item), style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, color: isDarkMode ? Colors.white : Colors.black, )), SizedBox(height: 4.h), - Text(item.desc, + Text(localizedGoodsDesc(item), style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[600], @@ -276,7 +277,7 @@ class GoodstradeView extends GetView { borderRadius: BorderRadius.circular(20.r), ), child: Text( - '购买', + 'purchase'.tr, style: TextStyle(fontSize: 12.sp, color: Colors.white), ), ), @@ -295,7 +296,7 @@ class GoodstradeView extends GetView { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '功能说明', + 'featureDescription'.tr, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, @@ -312,36 +313,45 @@ class GoodstradeView extends GetView { _buildFeatureCard( isDarkMode, icon: Icons.translate, - title: '实时同传', - lines: ['中英互译', '低延时语音播报'], + title: 'realtimeTranscription'.tr, + lines: ['translateZhEn'.tr, 'lowLatencyVoiceBroadcast'.tr], colorSeed: Colors.indigo, ), _buildFeatureCard( isDarkMode, icon: Icons.text_snippet, - title: '文本翻译', - lines: ['多语种文本翻译', '术语优化与语境保持'], + title: 'textTranslation'.tr, + lines: [ + 'multiLangTextTranslation'.tr, + 'termOptimizationContextPreserve'.tr + ], colorSeed: Colors.blue, ), _buildFeatureCard( isDarkMode, icon: Icons.library_books, - title: '场景词库', - lines: ['旅游/商务/生活词库', '专属词汇记忆'], + title: 'sceneLexicon'.tr, + lines: [ + 'lexiconTourBusinessLife'.tr, + 'personalVocabularyMemory'.tr + ], colorSeed: Colors.teal, ), _buildFeatureCard( isDarkMode, icon: Icons.subtitles, - title: '字幕显示', - lines: ['对话字幕/大字模式', '颜色高对比度'], + title: 'subtitleDisplay'.tr, + lines: [ + 'conversationSubtitleLargeText'.tr, + 'colorHighContrast'.tr + ], colorSeed: Colors.purple, ), ], ), SizedBox(height: 12.h), Text( - '翻译效果受麦克风、网络时延与环境噪声影响,具体以实际表现为准。', + 'tradeDisclaimer'.tr, style: TextStyle(fontSize: 12.sp, color: subColor), ), ], @@ -428,19 +438,19 @@ class GoodstradeView extends GetView { ), SizedBox(height: 8.h), Text( - '应用名称:VoiTrans · 服务提供:VoiTrans', + 'appNameProvider'.tr, textAlign: TextAlign.center, style: TextStyle(fontSize: 11.sp, color: subColor), ), SizedBox(height: 4.h), Text( - '更多信息请前往 设置 > 关于 查看', + 'moreInfoViewInSettingsAbout'.tr, textAlign: TextAlign.center, style: TextStyle(fontSize: 11.sp, color: subColor), ), SizedBox(height: 4.h), Text( - '© 2025 VoiTrans', + 'copyrightVoiTrans'.tr, textAlign: TextAlign.center, style: TextStyle(fontSize: 11.sp, color: subColor), ), diff --git a/lib/modules/goods/views/goodsvip_view.dart b/lib/modules/goods/views/goodsvip_view.dart index 5a5f55896..e4fbff0dd 100644 --- a/lib/modules/goods/views/goodsvip_view.dart +++ b/lib/modules/goods/views/goodsvip_view.dart @@ -3,6 +3,7 @@ import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:voitrans/data/models/goods.dart'; import '../controllers/goodsvip_controller.dart'; +import '../utils/goods_i18n.dart'; class GoodsvipView extends GetView { const GoodsvipView({super.key}); @@ -27,26 +28,44 @@ class GoodsvipView extends GetView { centerTitle: true, ), body: Obx(() { + Widget content; if (controller.loading.value) { - return const Center(child: CircularProgressIndicator()); + content = const Center(child: CircularProgressIndicator()); + } else if (controller.error.isNotEmpty) { + content = Center(child: Text(controller.error.value)); + } else { + content = ListView.separated( + padding: EdgeInsets.all(16.w), + itemCount: controller.items.length + 2, + separatorBuilder: (_, __) => SizedBox(height: 12.h), + itemBuilder: (_, index) { + if (index < controller.items.length) { + final item = controller.items[index]; + return _buildGoodsCard(item, isDarkMode); + } + if (index == controller.items.length) { + return _buildFeaturesSection(isDarkMode); + } + return _buildFooterSection(isDarkMode); + }, + ); } - if (controller.error.isNotEmpty) { - return Center(child: Text(controller.error.value)); - } - return ListView.separated( - padding: EdgeInsets.all(16.w), - itemCount: controller.items.length + 2, - separatorBuilder: (_, __) => SizedBox(height: 12.h), - itemBuilder: (_, index) { - if (index < controller.items.length) { - final item = controller.items[index]; - return _buildGoodsCard(item, isDarkMode); - } - if (index == controller.items.length) { - return _buildFeaturesSection(isDarkMode); - } - return _buildFooterSection(isDarkMode); - }, + return Stack( + children: [ + content, + if (controller.isPaying.value) + Positioned.fill( + child: AbsorbPointer( + absorbing: true, + child: Container( + color: Colors.black.withOpacity(0.35), + child: const Center( + child: CircularProgressIndicator(), + ), + ), + ), + ), + ], ); }), ); @@ -94,7 +113,7 @@ class GoodsvipView extends GetView { color: isDarkMode ? Colors.white : Colors.black, )), SizedBox(height: 4.h), - Text(item.desc, + Text(localizedGoodsDesc(item), style: TextStyle( fontSize: 12.sp, color: isDarkMode ? Colors.white70 : Colors.grey[600], @@ -123,7 +142,7 @@ class GoodsvipView extends GetView { borderRadius: BorderRadius.circular(20.r), ), child: Text( - '购买', + 'purchase'.tr, style: TextStyle( fontSize: 12.sp, color: Colors.white, @@ -145,7 +164,7 @@ class GoodsvipView extends GetView { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '功能说明', + 'featureDescription'.tr, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, @@ -162,36 +181,36 @@ class GoodsvipView extends GetView { _buildFeatureCard( isDarkMode, icon: Icons.workspace_premium, - title: '权益总览', - lines: ['更高使用额度', '更低单价'], + title: 'benefitsOverview'.tr, + lines: ['higherQuota'.tr, 'lowerUnitPrice'.tr], colorSeed: Colors.amber, ), _buildFeatureCard( isDarkMode, icon: Icons.support_agent, - title: '优先服务', - lines: ['专属客服通道', '问题快速响应'], + title: 'priorityService'.tr, + lines: ['exclusiveSupportChannel'.tr, 'fastResponse'.tr], colorSeed: Colors.purple, ), _buildFeatureCard( isDarkMode, icon: Icons.local_offer, - title: '活动与折扣', - lines: ['会员专属活动', '长期优惠计划'], + title: 'eventsAndDiscounts'.tr, + lines: ['memberExclusiveEvents'.tr, 'longTermDiscountPlan'.tr], colorSeed: Colors.indigo, ), _buildFeatureCard( isDarkMode, icon: Icons.auto_awesome, - title: '通用特权', - lines: ['新功能优先体验', '跨设备同步'], + title: 'generalPrivileges'.tr, + lines: ['earlyAccessNewFeatures'.tr, 'crossDeviceSync'.tr], colorSeed: Colors.teal, ), ], ), SizedBox(height: 12.h), Text( - '具体权益以实际套餐说明为准,可能随版本迭代调整。', + 'vipDisclaimer'.tr, style: TextStyle(fontSize: 12.sp, color: subColor), ), ], @@ -257,7 +276,8 @@ class GoodsvipView extends GetView { SizedBox(height: 8.h), ...lines.map((l) => Padding( padding: EdgeInsets.only(bottom: 4.h), - child: Text(l, style: TextStyle(fontSize: 12.sp, color: subColor)), + child: + Text(l, style: TextStyle(fontSize: 12.sp, color: subColor)), )), ], ), @@ -273,24 +293,23 @@ class GoodsvipView extends GetView { children: [ SizedBox( width: double.infinity, - child: - Divider(color: isDarkMode ? Colors.white24 : Colors.black12), + child: Divider(color: isDarkMode ? Colors.white24 : Colors.black12), ), SizedBox(height: 8.h), Text( - '应用名称:VoiTrans · 服务提供:VoiTrans', + 'appNameProvider'.tr, textAlign: TextAlign.center, style: TextStyle(fontSize: 11.sp, color: subColor), ), SizedBox(height: 4.h), Text( - '更多信息请前往 设置 > 关于 查看', + 'moreInfoViewInSettingsAbout'.tr, textAlign: TextAlign.center, style: TextStyle(fontSize: 11.sp, color: subColor), ), SizedBox(height: 4.h), Text( - '© 2025 VoiTrans', + 'copyrightVoiTrans'.tr, textAlign: TextAlign.center, style: TextStyle(fontSize: 11.sp, color: subColor), ), diff --git a/lib/modules/home/views/home_view.dart b/lib/modules/home/views/home_view.dart index 6be0315bd..9e7ca2838 100644 --- a/lib/modules/home/views/home_view.dart +++ b/lib/modules/home/views/home_view.dart @@ -101,7 +101,7 @@ class HomeView extends GetView { overlayBuilder: (params) { return IntroOverlayBuilder.aiBuilder( params, - '欢迎使用Voitrans!首先,让我们唤醒你的专属 AI—— 小言', + 'guideWelcomeWakeAI'.tr, onNext: () { controller.noviceGuideService.startWakeupListen(); }, @@ -812,7 +812,7 @@ class HomeView extends GetView { overlayBuilder: (params) { return IntroOverlayBuilder.aiBuilder( params, - '太棒了!你已成功唤醒小言,接下来试试让它帮你做件事吧', + 'guideAwakenSuccess'.tr, onTap: () { params.onFinish(); controller.exploreAIFeatures(); diff --git a/lib/modules/settings/views/settings_view.dart b/lib/modules/settings/views/settings_view.dart index febe0493c..c814ac4de 100644 --- a/lib/modules/settings/views/settings_view.dart +++ b/lib/modules/settings/views/settings_view.dart @@ -248,7 +248,7 @@ class SettingsView extends GetView { children: [ _buildCategoryItem( icon: Icons.workspace_premium, - label: 'Vip', + label: 'premiumMember'.tr, iconBg: isDarkMode ? Colors.amber[900]!.withOpacity(0.3) : Colors.amber[100]!, @@ -257,7 +257,7 @@ class SettingsView extends GetView { ), _buildCategoryItem( icon: Icons.translate, - label: 'Translation', + label: 'interpretation'.tr, iconBg: isDarkMode ? Colors.indigo[900]!.withOpacity(0.3) : Colors.indigo[100]!, @@ -266,7 +266,7 @@ class SettingsView extends GetView { ), _buildCategoryItem( icon: Icons.file_open, - label: "Meet", + label: 'conferenceAssistant'.tr, iconBg: isDarkMode ? Colors.pink[900]!.withOpacity(0.3) : Colors.pink[100]!, @@ -275,7 +275,7 @@ class SettingsView extends GetView { ), _buildCategoryItem( icon: Icons.smart_toy, - label: "AI", + label: 'aiFunction'.tr, iconBg: isDarkMode ? Colors.teal[900]!.withOpacity(0.3) : Colors.teal[100]!, diff --git a/pubspec.yaml b/pubspec.yaml index 26889ffc7..670d31152 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: voitrans description: "Voitrans - AI Voice Assistant." publish_to: "none" -version: 1.0.18+57 +version: 1.0.20+62 environment: sdk: ">=3.3.0 <4.0.0"