From b87a1080c75a35d15f03555c18fbb0afb34cc1ea Mon Sep 17 00:00:00 2001 From: ischanx Date: Mon, 22 Jun 2026 00:50:29 +0800 Subject: [PATCH 1/8] feat(start): add i18n infrastructure --- apps/start/package.json | 5 +- .../src/components/full-page-error-state.tsx | 11 +- .../components/full-page-loading-state.tsx | 11 +- .../src/components/i18n-language-sync.tsx | 33 + apps/start/src/components/language-toggle.tsx | 52 + apps/start/src/components/providers.tsx | 34 +- apps/start/src/i18n/index.ts | 38 + apps/start/src/i18n/locales.ts | 43 + apps/start/src/i18n/resources/en.json | 1822 +++++++++++++++++ apps/start/src/i18n/resources/zh-CN.json | 1822 +++++++++++++++++ apps/start/src/i18n/resources/zh-TW.json | 1822 +++++++++++++++++ apps/start/src/router.tsx | 23 +- apps/start/src/routes/__root.tsx | 21 +- pnpm-lock.yaml | 221 +- 14 files changed, 5912 insertions(+), 46 deletions(-) create mode 100644 apps/start/src/components/i18n-language-sync.tsx create mode 100644 apps/start/src/components/language-toggle.tsx create mode 100644 apps/start/src/i18n/index.ts create mode 100644 apps/start/src/i18n/locales.ts create mode 100644 apps/start/src/i18n/resources/en.json create mode 100644 apps/start/src/i18n/resources/zh-CN.json create mode 100644 apps/start/src/i18n/resources/zh-TW.json diff --git a/apps/start/package.json b/apps/start/package.json index 1714f66bc..e292f1bbd 100644 --- a/apps/start/package.json +++ b/apps/start/package.json @@ -109,6 +109,8 @@ "flag-icons": "^7.1.0", "framer-motion": "^11.0.28", "hamburger-react": "^2.5.0", + "i18next": "^26.3.1", + "i18next-browser-languagedetector": "^8.2.1", "input-otp": "^1.2.4", "javascript-time-ago": "^2.5.9", "katex": "^0.16.21", @@ -132,6 +134,7 @@ "react-dom": "catalog:", "react-grid-layout": "^1.5.2", "react-hook-form": "^7.50.1", + "react-i18next": "^17.0.8", "react-in-viewport": "1.0.0-beta.8", "react-markdown": "^10.1.0", "react-redux": "^8.1.3", @@ -190,4 +193,4 @@ "web-vitals": "^4.2.4", "wrangler": "4.85.0" } -} \ No newline at end of file +} diff --git a/apps/start/src/components/full-page-error-state.tsx b/apps/start/src/components/full-page-error-state.tsx index c04c8ba55..204c3fa81 100644 --- a/apps/start/src/components/full-page-error-state.tsx +++ b/apps/start/src/components/full-page-error-state.tsx @@ -1,19 +1,22 @@ import { ServerCrashIcon } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { FullPageEmptyState } from './full-page-empty-state'; export const FullPageErrorState = ({ - title = 'Error...', - description = 'Something went wrong...', + title, + description, children, }: { title?: string; description?: string; children?: React.ReactNode }) => { + const { t } = useTranslation(); + return ( - {description} + {description ?? t('ui.error_description')} {children &&
{children}
}
); diff --git a/apps/start/src/components/full-page-loading-state.tsx b/apps/start/src/components/full-page-loading-state.tsx index aeefc2bf4..f3189f5ba 100644 --- a/apps/start/src/components/full-page-loading-state.tsx +++ b/apps/start/src/components/full-page-loading-state.tsx @@ -1,17 +1,20 @@ import type { LucideIcon } from 'lucide-react'; import { Loader2Icon } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { FullPageEmptyState } from './full-page-empty-state'; const FullPageLoadingState = ({ - title = 'Fetching...', - description = 'Please wait while we fetch your data...', + title, + description, }: { title?: string; description?: string }) => { + const { t } = useTranslation(); + return ( ( diff --git a/apps/start/src/components/i18n-language-sync.tsx b/apps/start/src/components/i18n-language-sync.tsx new file mode 100644 index 000000000..644fc09fa --- /dev/null +++ b/apps/start/src/components/i18n-language-sync.tsx @@ -0,0 +1,33 @@ +import { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import { normalizeLanguage } from '@/i18n/locales'; + +function getInitialClientLanguage() { + const storedLanguage = window.localStorage.getItem('openpanel-language'); + if (storedLanguage) { + return normalizeLanguage(storedLanguage); + } + + return normalizeLanguage(window.navigator.language); +} + +export function I18nLanguageSync() { + const { i18n } = useTranslation(); + + useEffect(() => { + const language = getInitialClientLanguage(); + void i18n.changeLanguage(language); + document.documentElement.lang = language; + }, [i18n]); + + useEffect(() => { + const handleLanguageChanged = (language: string) => { + document.documentElement.lang = normalizeLanguage(language); + }; + + i18n.on('languageChanged', handleLanguageChanged); + return () => i18n.off('languageChanged', handleLanguageChanged); + }, [i18n]); + + return null; +} diff --git a/apps/start/src/components/language-toggle.tsx b/apps/start/src/components/language-toggle.tsx new file mode 100644 index 000000000..170b7aeb5 --- /dev/null +++ b/apps/start/src/components/language-toggle.tsx @@ -0,0 +1,52 @@ +import { CheckIcon, LanguagesIcon } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; +import { + languageLabels, + normalizeLanguage, + supportedLanguages, +} from '@/i18n/locales'; +import { cn } from '@/lib/utils'; + +export function LanguageToggle({ className }: { className?: string }) { + const { i18n, t } = useTranslation(); + const currentLanguage = normalizeLanguage( + i18n.resolvedLanguage ?? i18n.language + ); + + return ( + + + + + + {supportedLanguages.map((language) => ( + { + window.localStorage.setItem('openpanel-language', language); + document.documentElement.lang = language; + void i18n.changeLanguage(language); + }} + > + {languageLabels[language]} + {currentLanguage === language && } + + ))} + + + ); +} diff --git a/apps/start/src/components/providers.tsx b/apps/start/src/components/providers.tsx index d75cf1cfd..6d914c9f8 100644 --- a/apps/start/src/components/providers.tsx +++ b/apps/start/src/components/providers.tsx @@ -7,8 +7,11 @@ import type { AppStore } from '@/redux'; import makeStore from '@/redux'; import { NuqsAdapter } from 'nuqs/adapters/tanstack-router'; import { useRef } from 'react'; +import { I18nextProvider } from 'react-i18next'; import { Provider as ReduxProvider } from 'react-redux'; import { Toaster } from 'sonner'; +import i18n from '@/i18n'; +import { I18nLanguageSync } from './i18n-language-sync'; import { ThemeProvider } from './theme-provider'; export function Providers({ children }: { children: React.ReactNode }) { @@ -19,20 +22,23 @@ export function Providers({ children }: { children: React.ReactNode }) { return ( - - - - - - {children} - - - - - - - - + + + + + + + + {children} + + + + + + + + + ); } diff --git a/apps/start/src/i18n/index.ts b/apps/start/src/i18n/index.ts new file mode 100644 index 000000000..3c0e83320 --- /dev/null +++ b/apps/start/src/i18n/index.ts @@ -0,0 +1,38 @@ +import i18n from 'i18next'; +import LanguageDetector from 'i18next-browser-languagedetector'; +import { initReactI18next } from 'react-i18next'; +import en from './resources/en.json'; +import zhCN from './resources/zh-CN.json'; +import zhTW from './resources/zh-TW.json'; +import { + defaultLanguage, + normalizeLanguage, +} from './locales'; + +void i18n + .use(LanguageDetector) + .use(initReactI18next) + .init({ + resources: { + en: { translation: en }, + 'zh-CN': { translation: zhCN }, + 'zh-TW': { translation: zhTW }, + }, + fallbackLng: defaultLanguage, + load: 'currentOnly', + interpolation: { + escapeValue: false, + }, + detection: { + order: ['localStorage', 'navigator', 'htmlTag'], + caches: ['localStorage'], + lookupLocalStorage: 'openpanel-language', + convertDetectedLanguage: normalizeLanguage, + }, + }); + +if (import.meta.env.DEV && typeof window !== 'undefined') { + Object.assign(window, { __openpanelI18n: i18n }); +} + +export default i18n; diff --git a/apps/start/src/i18n/locales.ts b/apps/start/src/i18n/locales.ts new file mode 100644 index 000000000..c76f66a22 --- /dev/null +++ b/apps/start/src/i18n/locales.ts @@ -0,0 +1,43 @@ +export const supportedLanguages = ['en', 'zh-CN', 'zh-TW'] as const; + +export type SupportedLanguage = (typeof supportedLanguages)[number]; + +export const defaultLanguage: SupportedLanguage = 'en'; + +export const languageLabels: Record = { + en: 'English', + 'zh-CN': '简体中文', + 'zh-TW': '繁體中文', +}; + +export function isSupportedLanguage( + language: string | undefined +): language is SupportedLanguage { + return supportedLanguages.includes(language as SupportedLanguage); +} + +export function normalizeLanguage(language: string | undefined) { + if (!language) { + return defaultLanguage; + } + + if (isSupportedLanguage(language)) { + return language; + } + + const normalized = language.toLowerCase(); + if ( + normalized.startsWith('zh-tw') || + normalized.startsWith('zh-hk') || + normalized.startsWith('zh-mo') || + normalized.includes('hant') + ) { + return 'zh-TW'; + } + + if (normalized.startsWith('zh')) { + return 'zh-CN'; + } + + return defaultLanguage; +} diff --git a/apps/start/src/i18n/resources/en.json b/apps/start/src/i18n/resources/en.json new file mode 100644 index 000000000..fb4b07765 --- /dev/null +++ b/apps/start/src/i18n/resources/en.json @@ -0,0 +1,1822 @@ +{ + "common": { + "language": "Language", + "loading": "Loading", + "theme": "Theme", + "profile": "Profile", + "account": "Account", + "logout": "Logout", + "go_home": "Go to home", + "go_back_home": "Go back to home", + "or": "OR", + "cancel": "Cancel", + "continue": "Continue", + "save": "Save", + "delete": "Delete" + }, + "sidebar": { + "docs": "Docs", + "support_us": "Support Us", + "pay_what_you_want": "Pay What You Want", + "organization": "Organization", + "analytics": "Analytics", + "manage": "Manage", + "overview": "Overview", + "dashboards": "Dashboards", + "insights": "Insights", + "pages": "Pages", + "seo": "SEO", + "realtime": "Realtime", + "events": "Events", + "sessions": "Sessions", + "profiles": "Profiles", + "groups": "Groups", + "cohorts": "Cohorts", + "settings": "Settings", + "references": "References", + "notifications": "Notifications", + "back_to_workspace": "Back to workspace", + "projects": "Projects", + "billing": "Billing", + "members": "Members", + "integrations": "Integrations", + "give_feedback": "Give feedback", + "open_ai_chat": "Open AI chat", + "action_create_report": "Create report", + "action_create_reference": "Create reference", + "action_ask_ai": "Ask AI", + "action_create_dashboard": "Create dashboard", + "action_create_notification_rule": "Create notification rule", + "action_create_project": "Create a project", + "action_invite_user": "Invite a user", + "action_add_integration": "Add integration" + }, + "errors": { + "no_access": "No access", + "something_went_wrong": "Something went wrong", + "page_not_found": "Page not found", + "page_not_found_description": "The page you're looking for doesn't exist or has moved." + }, + "auth": { + "sign_in": "Sign in", + "no_account": "Don't have an account?", + "create_one_today": "Create one today", + "error": "Error", + "correlation_id": "Correlation ID: {{id}}", + "contact_support": "Contact us if you have any issues.", + "self_hosted_analytics": "Self-hosted analytics", + "open_panel_cloud": "OpenPanel Cloud", + "mixpanel_alternative": "Mixpanel alternative", + "posthog_alternative": "Posthog alternative", + "open_source_analytics": "Open source analytics", + "email": "Email", + "password": "Password", + "first_name": "First name", + "last_name": "Last name", + "confirm_password": "Confirm password", + "new_password": "New password", + "sign_in_with_google": "Sign in with Google", + "sign_up_with_google": "Sign up with Google", + "sign_in_with_github": "Sign in with Github", + "sign_up_with_github": "Sign up with Github", + "used_last_time": "Used last time", + "successfully_signed_in": "Successfully signed in", + "successfully_signed_up": "Successfully signed up", + "forgot_password": "Forgot password?", + "create_account": "Create account", + "reset_password": "Reset password", + "reset_your_password": "Reset your password", + "password_reset_successfully": "Password reset successfully", + "already_have_account": "Already have an account?", + "missing_reset_password_token": "Missing reset password token", + "two_factor_authentication": "Two-factor authentication", + "totp_description": "Enter the 6-digit code from your authenticator app.", + "recovery_code_description": "Enter one of your recovery codes. Each code can be used only once.", + "verify": "Verify", + "signed_in": "Signed in", + "use_recovery_code": "Use a recovery code instead", + "use_authenticator_app": "Use authenticator app instead", + "sign_in_with_different_account": "Sign in with a different account", + "start_tracking": "Start tracking in minutes", + "accept_terms_prefix": "By creating an account you accept the", + "terms_of_service": "Terms of Service", + "terms_connector": "and", + "privacy_policy": "Privacy Policy", + "invitation_to": "Invitation to {{organization}}", + "invitation_description": "After you have created your account, you will be added to the organization.", + "invitation_expired": "Invitation to {{organization}} has expired", + "invitation_expired_description": "The invitation has expired. Please contact the organization owner to get a new invitation.", + "trial_benefits": "No credit card required · Free 30-day trial · Cancel anytime", + "sign_up_with_email": "Sign up with email", + "incorrect_password": "Incorrect password", + "share_locked_title": "{{type}} is locked", + "share_password_description": "Please enter the correct password to access this {{type}}", + "share_type_overview": "Overview", + "share_type_dashboard": "Dashboard", + "share_type_report": "Report", + "enter_password": "Enter your password", + "get_access": "Get access", + "request_password_reset": "Request password reset", + "your_email_address": "Your email address", + "reset_email_sent": "You should receive an email shortly!", + "login_panel_alternative_title": "Best open-source alternative", + "login_panel_alternative_description": "Mixpanel too expensive, Google Analytics has no privacy, Amplitude old and boring", + "login_panel_reliable_title": "Fast and reliable", + "login_panel_reliable_description": "Never miss a beat with our real-time analytics", + "login_panel_simple_title": "Easy to use", + "login_panel_simple_description": "Compared to other tools we have kept it simple", + "login_panel_privacy_title": "Privacy by default", + "login_panel_privacy_description": "We have built our platform with privacy at its heart", + "login_panel_open_source_title": "Open source", + "login_panel_open_source_description": "You can inspect the code and self-host if you choose" + }, + "chat": { + "new_chat": "New chat", + "conversations": "Conversations", + "no_conversations": "No conversations yet. Start typing to create one.", + "untitled_chat": "Untitled chat", + "new_conversation": "New conversation", + "close_chat": "Close chat", + "confirm_delete": "Confirm delete", + "delete_conversation": "Delete conversation", + "click_again_to_confirm": "Click again to confirm", + "delete": "Delete", + "ask_anything_placeholder": "Ask anything about your data...", + "ask_ai_placeholder": "Ask AI anything...", + "send_to_ai": "Send to AI", + "keyboard_shortcut": "Keyboard shortcut: Cmd+J", + "stop_generating": "Stop generating", + "send_message": "Send message", + "thinking": "Thinking...", + "generic_error": "Something went wrong. Try again.", + "scroll_to_bottom": "Scroll to bottom", + "latest": "Latest", + "tool_failed": "Tool failed", + "thought": "Thought", + "ai_not_configured": "AI chat isn't configured", + "ai_not_configured_setup_prefix": "Set", + "ai_not_configured_setup_between": "and/or", + "ai_not_configured_setup_suffix": "on the API service to enable AI chat, then restart it.", + "ai_not_configured_description": "The model picker shows only providers with a configured key.", + "view_setup_docs": "View setup docs", + "empty_no_context_headline": "Ask about your data", + "empty_no_context_description": "I can answer questions about your analytics, generate reports, and dig into users, sessions, or pages.", + "empty_no_context_prompt_what_happened_yesterday": "What happened yesterday?", + "empty_no_context_prompt_last_seven_days_traffic": "Show me last 7 days of traffic", + "empty_no_context_prompt_highest_bounce_rate": "Which pages have the highest bounce rate?", + "empty_overview_headline": "Ask about this overview", + "empty_overview_description": "I can explain trends, compare periods, or filter the page. Try a question or pick a starter.", + "empty_overview_prompt_compare_previous_period": "What changed compared to the previous period?", + "empty_overview_prompt_filter_mobile_only": "Filter to mobile only", + "empty_overview_prompt_last_seven_days_traffic": "Show me last 7 days of traffic", + "empty_overview_prompt_top_referrers": "Which referrers drove the most sessions?", + "empty_insights_headline": "Explore your insights", + "empty_insights_description": "I can explain why an insight fired, find related ones, or walk you through the most important.", + "empty_insights_prompt_most_important": "What are the most important insights right now?", + "empty_insights_prompt_biggest_anomaly": "Explain the biggest anomaly this week", + "empty_insights_prompt_device_trends": "Any insights related to device trends?", + "empty_pages_headline": "Ask about your pages", + "empty_pages_description": "I can rank pages by performance, find declining ones, or identify entry/exit patterns.", + "empty_pages_prompt_declining_pages": "Which pages are declining vs last month?", + "empty_pages_prompt_highest_bounce_rate": "Show pages with the highest bounce rate", + "empty_pages_prompt_top_entry_pages": "Top entry pages in the last 7 days", + "empty_pages_prompt_underperforming_seo": "Find pages with underperforming SEO", + "empty_seo_headline": "Dig into your SEO", + "empty_seo_description": "I can surface high-opportunity queries, check for cannibalization, and correlate SEO with on-site engagement.", + "empty_seo_prompt_page_two_queries": "Queries on page 2 with high impressions (easy wins)", + "empty_seo_prompt_query_cannibalization": "Any query cannibalization I should fix?", + "empty_seo_prompt_gsc_clicks_bounce_hard": "Which pages bring GSC clicks but bounce hard?", + "empty_seo_prompt_top_seo_queries": "Top SEO queries last 30 days", + "empty_events_headline": "Analyze your events", + "empty_events_description": "I can analyze distribution, correlate events, and drill into properties.", + "empty_events_prompt_events_together": "Which events often happen together?", + "empty_events_prompt_distribution_by_country": "Analyze event distribution by country", + "empty_events_prompt_signup_events_only": "Filter to signup events only", + "empty_events_prompt_common_properties": "What are the most common event properties?", + "empty_profile_detail_headline": "Ask about this user", + "empty_profile_detail_description": "I can summarize this profile, build a journey, or compare them to the average user.", + "empty_profile_detail_prompt_user_journey": "Tell me about this user's journey", + "empty_profile_detail_prompt_compare_average": "How does this user compare to average?", + "empty_profile_detail_prompt_last_session": "What was their last session?", + "empty_profile_detail_prompt_unusual_behavior": "Do they have unusual behavior?", + "empty_session_detail_headline": "Ask about this session", + "empty_session_detail_description": "I can walk through the path, compare to typical sessions, or explain the referrer context.", + "empty_session_detail_prompt_walk_through": "Walk me through this session", + "empty_session_detail_prompt_compare_typical": "How does this compare to typical sessions?", + "empty_session_detail_prompt_traffic_source": "Where did this traffic come from?", + "empty_session_detail_prompt_similar_sessions": "Are there similar sessions today?", + "empty_group_detail_headline": "Ask about this group", + "empty_group_detail_description": "I can show metrics, list members, and compare to peer groups.", + "empty_group_detail_prompt_summarize_activity": "Summarize this group's activity", + "empty_group_detail_prompt_compare_groups": "Compare to other groups", + "empty_group_detail_prompt_active_members": "Who are the most active members?", + "empty_group_detail_prompt_engagement_trend": "What's this group's engagement trend?", + "empty_report_editor_headline": "Edit this report with me", + "empty_report_editor_description": "I can preview changes, suggest breakdowns, or compare to the previous period.", + "empty_report_editor_prompt_useful_breakdowns": "Suggest useful breakdowns for this report", + "empty_report_editor_prompt_compare_previous_period": "Compare to the previous period", + "empty_report_editor_prompt_find_anomalies": "Find anomalies in the current data", + "empty_report_editor_prompt_country_breakdown": "Add a country breakdown", + "empty_dashboard_headline": "Ask about this dashboard", + "empty_dashboard_description": "I can summarize every report on this dashboard at once, flag what changed, or zoom into a single chart.", + "empty_dashboard_prompt_summarize_dashboard": "Summarize this dashboard", + "empty_dashboard_prompt_underperforming": "What's underperforming here?", + "empty_dashboard_prompt_compare_previous_period": "Compare this dashboard to the previous period", + "empty_dashboard_prompt_biggest_change": "Which report has the biggest change?", + "empty_default_context_headline": "Ask about your data", + "empty_default_context_description": "I can answer questions about the page you're viewing, generate reports, and dig into specific users, sessions, or pages.", + "empty_default_context_prompt_visitor_count": "What's our visitor count this week?", + "empty_default_context_prompt_top_traffic_sources": "Top traffic sources right now", + "empty_default_context_prompt_top_pages_bounce_rate": "Show me top pages by bounce rate", + "tool_working": "Working", + "tool_result_empty": "No result.", + "tool_result_view_raw_output": "View raw output", + "tool_result_item_count_one": "{{count}} item", + "tool_result_item_count_other": "{{count}} items", + "table_showing_limited_rows": "Showing {{shown}} of {{total}}", + "table_truncated_suffix": "(truncated)", + "ui_apply_date_range_summary": "date range: {{value}}", + "ui_apply_interval_summary": "interval: {{value}}", + "ui_apply_filters_summary": "filters", + "ui_apply_applied_summary": "Applied {{summary}}", + "ui_apply_cleared_property_filters": "Cleared property filters", + "ui_apply_applied_filters": "Applied filters: {{summary}}", + "ui_apply_cleared_event_filter": "Cleared event-name filter", + "ui_apply_filtered_events_one": "Filtered to event: {{names}}", + "ui_apply_filtered_events_other": "Filtered to events: {{names}}", + "tool_fallback_verb_list": "Looking up", + "tool_fallback_verb_get": "Loading", + "tool_fallback_verb_find": "Finding", + "tool_fallback_verb_query": "Querying", + "tool_fallback_verb_analyze": "Analyzing", + "tool_fallback_verb_compare": "Comparing", + "tool_fallback_verb_correlate": "Correlating", + "tool_fallback_verb_explain": "Explaining", + "tool_fallback_verb_suggest": "Suggesting", + "tool_fallback_verb_preview": "Previewing", + "tool_fallback_verb_generate": "Generating", + "tool_fallback_verb_apply": "Applying", + "tool_fallback_verb_set": "Updating", + "tool_fallback_verb_gsc": "Loading SEO", + "tool_fallback_verb_running": "Running", + "tool_list_event_names_active": "Looking up event names", + "tool_list_event_names_done": "Event names", + "tool_list_event_properties_active": "Looking up properties", + "tool_list_event_properties_done": "Event properties", + "tool_get_event_property_values_active": "Loading property values", + "tool_get_event_property_values_done": "Property values", + "tool_list_dashboards_active": "Loading dashboards", + "tool_list_dashboards_done": "Dashboards", + "tool_list_reports_active": "Loading reports", + "tool_list_reports_done": "Reports", + "tool_get_report_data_active": "Running report", + "tool_get_report_data_done": "Report", + "tool_generate_report_active": "Building report", + "tool_generate_report_done": "Report", + "tool_get_analytics_overview_active": "Loading overview", + "tool_get_analytics_overview_done": "Overview", + "tool_get_top_pages_active": "Loading top pages", + "tool_get_top_pages_done": "Top pages", + "tool_get_top_referrers_active": "Loading top referrers", + "tool_get_top_referrers_done": "Top referrers", + "tool_get_country_breakdown_active": "Loading geo breakdown", + "tool_get_country_breakdown_done": "Geo breakdown", + "tool_get_device_breakdown_active": "Loading device breakdown", + "tool_get_device_breakdown_done": "Device breakdown", + "tool_get_rolling_active_users_active": "Loading active users", + "tool_get_rolling_active_users_done": "Active users", + "tool_get_funnel_active": "Building funnel", + "tool_get_funnel_done": "Funnel", + "tool_get_retention_cohort_active": "Building retention cohort", + "tool_get_retention_cohort_done": "Retention", + "tool_get_user_flow_active": "Building user flow", + "tool_get_user_flow_done": "User flow", + "tool_query_events_active": "Querying events", + "tool_query_events_done": "Events", + "tool_query_sessions_active": "Querying sessions", + "tool_query_sessions_done": "Sessions", + "tool_find_profiles_active": "Finding profiles", + "tool_find_profiles_done": "Profiles", + "tool_get_profile_full_active": "Loading profile", + "tool_get_profile_full_done": "Profile", + "tool_get_profile_events_active": "Loading profile events", + "tool_get_profile_events_done": "Profile events", + "tool_get_profile_sessions_active": "Loading profile sessions", + "tool_get_profile_sessions_done": "Profile sessions", + "tool_get_profile_metrics_active": "Loading profile metrics", + "tool_get_profile_metrics_done": "Profile metrics", + "tool_get_profile_journey_active": "Loading user journey", + "tool_get_profile_journey_done": "User journey", + "tool_get_profile_groups_active": "Loading profile groups", + "tool_get_profile_groups_done": "Profile groups", + "tool_compare_profile_to_average_active": "Comparing to average", + "tool_compare_profile_to_average_done": "Profile comparison", + "tool_get_session_full_active": "Loading session", + "tool_get_session_full_done": "Session", + "tool_get_session_path_active": "Loading session path", + "tool_get_session_path_done": "Session path", + "tool_get_session_events_active": "Loading session events", + "tool_get_session_events_done": "Session events", + "tool_get_similar_sessions_active": "Finding similar sessions", + "tool_get_similar_sessions_done": "Similar sessions", + "tool_compare_session_to_typical_active": "Comparing to typical", + "tool_compare_session_to_typical_done": "Session comparison", + "tool_get_session_referrer_context_active": "Loading referrer context", + "tool_get_session_referrer_context_done": "Referrer context", + "tool_get_session_replay_summary_active": "Loading session replay", + "tool_get_session_replay_summary_done": "Session replay", + "tool_get_page_performance_active": "Loading page performance", + "tool_get_page_performance_done": "Page performance", + "tool_get_page_conversions_active": "Loading page conversions", + "tool_get_page_conversions_done": "Page conversions", + "tool_get_entry_exit_pages_active": "Loading entry/exit pages", + "tool_get_entry_exit_pages_done": "Entry/exit pages", + "tool_find_declining_pages_active": "Finding declining pages", + "tool_find_declining_pages_done": "Declining pages", + "tool_gsc_get_overview_active": "Loading SEO overview", + "tool_gsc_get_overview_done": "SEO overview", + "tool_gsc_get_top_queries_active": "Loading top queries", + "tool_gsc_get_top_queries_done": "Top queries", + "tool_gsc_get_top_pages_active": "Loading top SEO pages", + "tool_gsc_get_top_pages_done": "Top SEO pages", + "tool_gsc_get_query_details_active": "Loading query details", + "tool_gsc_get_query_details_done": "Query details", + "tool_gsc_get_page_details_active": "Loading page details", + "tool_gsc_get_page_details_done": "Page details", + "tool_gsc_get_query_opportunities_active": "Finding query opportunities", + "tool_gsc_get_query_opportunities_done": "Query opportunities", + "tool_gsc_get_cannibalization_active": "Checking cannibalization", + "tool_gsc_get_cannibalization_done": "Cannibalization", + "tool_correlate_seo_with_traffic_active": "Correlating SEO with traffic", + "tool_correlate_seo_with_traffic_done": "SEO/traffic correlation", + "tool_analyze_event_distribution_active": "Analyzing event distribution", + "tool_analyze_event_distribution_done": "Event distribution", + "tool_correlate_events_active": "Correlating events", + "tool_correlate_events_done": "Event correlation", + "tool_get_event_property_distribution_active": "Loading property distribution", + "tool_get_event_property_distribution_done": "Property distribution", + "tool_list_properties_for_event_active": "Loading properties", + "tool_list_properties_for_event_done": "Event properties", + "tool_list_insights_active": "Loading insights", + "tool_list_insights_done": "Insights", + "tool_explain_insight_active": "Loading insight", + "tool_explain_insight_done": "Insight", + "tool_find_related_insights_active": "Finding related insights", + "tool_find_related_insights_done": "Related insights", + "tool_get_group_full_active": "Loading group", + "tool_get_group_full_done": "Group", + "tool_get_group_members_active": "Loading group members", + "tool_get_group_members_done": "Group members", + "tool_get_group_events_active": "Loading group events", + "tool_get_group_events_done": "Group events", + "tool_get_group_metrics_active": "Loading group metrics", + "tool_get_group_metrics_done": "Group metrics", + "tool_compare_groups_active": "Comparing groups", + "tool_compare_groups_done": "Group comparison", + "tool_preview_report_with_changes_active": "Previewing changes", + "tool_preview_report_with_changes_done": "Report preview", + "tool_suggest_breakdowns_active": "Suggesting breakdowns", + "tool_suggest_breakdowns_done": "Breakdown suggestions", + "tool_compare_to_previous_period_active": "Comparing to previous period", + "tool_compare_to_previous_period_done": "Period comparison", + "tool_find_anomalies_in_current_report_active": "Finding anomalies", + "tool_find_anomalies_in_current_report_done": "Anomalies", + "tool_explain_filter_impact_active": "Analyzing filter impact", + "tool_explain_filter_impact_done": "Filter impact", + "tool_apply_filters_active": "Applying date range", + "tool_apply_filters_done": "Date range updated", + "tool_set_property_filters_active": "Applying filters", + "tool_set_property_filters_done": "Filters updated", + "tool_set_event_names_filter_active": "Applying event filter", + "tool_set_event_names_filter_done": "Event filter updated", + "tool_list_references_active": "Loading references", + "tool_list_references_done": "References", + "tool_get_references_around_active": "Checking references around this date", + "tool_get_references_around_done": "Nearby references", + "resize_drawer": "Resize chat drawer", + "select_model": "Select model", + "result_no_profile": "No profile", + "result_profile": "Profile", + "result_sessions": "Sessions", + "result_total_events": "Total events", + "result_avg_session": "Avg session", + "result_minutes": "{{value}} min", + "result_bounce_rate": "Bounce rate", + "result_revenue": "Revenue", + "result_open_profile": "Open profile →", + "result_no_data": "No data", + "result_report": "Report", + "result_no_renderable_report_config": "Report data returned but no renderable config.", + "result_chart_report_title": "{{chart}} report", + "result_open_in_dashboard": "Open in dashboard →", + "result_funnel_title": "Funnel: {{steps}}", + "result_day_active_users": "{{count}}-day active users", + "result_active_users_title": "{{label}} — last {{count}} days", + "result_chart_type_linear": "Line chart", + "result_chart_type_bar": "Bar chart", + "result_chart_type_area": "Area chart", + "result_chart_type_pie": "Pie chart", + "result_chart_type_funnel": "Funnel", + "result_chart_type_metric": "Metric", + "result_chart_type_retention": "Retention", + "result_chart_type_histogram": "Histogram", + "result_chart_type_sankey": "Sankey", + "result_chart_type_map": "Map", + "result_chart_type_conversion": "Conversion" + }, + "ui": { + "click_to_copy": "Click to copy", + "copied_to_clipboard": "Copied to clipboard", + "error_title": "Error...", + "error_description": "Something went wrong...", + "fetching": "Fetching...", + "fetching_description": "Please wait while we fetch your data...", + "toggle_fullscreen": "Toggle fullscreen", + "exit_full_screen": "Exit full screen", + "json_editor_invalid_json_syntax": "Invalid JSON syntax", + "json_editor_invalid_syntax": "Invalid {{language}}. Please check your syntax.", + "powered_by": "Powered by", + "try_it_for_free_today": "Try it for free today!", + "time_window": "Time window", + "time_window_30min": "Last 30 minutes", + "time_window_last_hour": "Last hour", + "time_window_last_24h": "Last 24 hours", + "time_window_today": "Today", + "time_window_yesterday": "Yesterday", + "time_window_7d": "Last 7 days", + "time_window_30d": "Last 30 days", + "time_window_3m": "Last 3 months", + "time_window_6m": "Last 6 months", + "time_window_12m": "Last 12 months", + "time_window_month_to_date": "Month to date", + "time_window_last_month": "Last month", + "time_window_year_to_date": "Year to date", + "time_window_last_year": "Last year", + "time_window_custom": "Custom", + "last_days": "Last days", + "custom_date_filter_days_aria_label": "Number of days for custom date filter", + "x_days": "X days", + "no_match": "No match", + "search_item": "Search item...", + "search": "Search", + "create_value": "Create \"{{value}}\"", + "pick_value": "Pick '{{value}}'", + "nothing_selected": "Nothing selected", + "search_event": "Search event...", + "any_events": "Any events", + "command_palette": "Command Palette", + "command_palette_description": "Search for a command to run..." + }, + "clients": { + "field_client_id": "Client ID", + "field_secret": "Secret", + "field_mcp_token": "MCP Token", + "secret_help": "You will only need the secret if you want to send server events.", + "mcp_token_help": "Use this token to authenticate with the MCP server (base64 encoded client ID and secret).", + "action_save_credentials": "Save credentials", + "get_started_title": "Get started!", + "get_started_read_our": "Read our", + "get_started_suffix": "to get started. Easy peasy!", + "column_name": "Name", + "column_created_at": "Created at", + "revoke_success_title": "Success", + "revoke_success_description": "Client revoked, incoming requests will be rejected.", + "action_copy_client_id": "Copy client ID", + "action_edit": "Edit", + "action_revoke": "Revoke", + "revoke_confirm_title": "Revoke client", + "revoke_confirm_description": "Are you sure you want to revoke this client? This action cannot be undone." + }, + "integrations": { + "slack_name": "Slack", + "slack_description": "Get notified in Slack when something important happens in OpenPanel.", + "slack_logo_alt": "Slack logo", + "discord_name": "Discord", + "discord_description": "Send OpenPanel notifications to a Discord channel.", + "discord_logo_alt": "Discord logo", + "webhook_name": "Webhook", + "webhook_description": "Send OpenPanel events to any HTTP endpoint.", + "action_connect": "Connect", + "action_create": "Create", + "action_update": "Update", + "action_delete": "Delete", + "action_edit": "Edit", + "action_test_connection": "Test connection", + "action_add_header": "Add header", + "status_connected": "Connected", + "empty_installed_title": "No integrations yet", + "empty_installed_description": "Integrations allow you to connect your systems to OpenPanel. You can add them in the available integrations section.", + "delete_confirm_title": "Delete {{name}}?", + "delete_confirm_description": "This action cannot be undone.", + "modal_title": "Create an integration", + "success_integration_saved": "Integration saved", + "success_test_notification_sent": "Test notification sent", + "error_create_failed": "Failed to create integration", + "error_validation": "Validation error", + "error_webhook_url_required": "Webhook URL is required", + "error_test_notification_failed": "Failed to send test notification", + "error_invalid_javascript_template": "Invalid JavaScript template", + "field_name": "Name", + "field_url": "URL", + "field_discord_webhook_url": "Discord webhook URL", + "field_headers": "Headers", + "field_payload_format": "Payload format", + "field_javascript_transform": "JavaScript transform", + "slack_name_placeholder": "Eg. My personal Slack", + "discord_name_placeholder": "Eg. My personal Discord", + "webhook_name_placeholder": "Eg. Zapier webhook", + "headers_help": "Add custom HTTP headers to include with webhook requests", + "header_name_placeholder": "Header name", + "header_value_placeholder": "Header value", + "payload_format_help": "Choose how to format the webhook payload", + "payload_format_placeholder": "Select format", + "payload_format_message": "Message", + "payload_format_javascript": "JavaScript", + "javascript_transform_help": "Write a JavaScript function that transforms the event payload. The function receives payload as a parameter and should return an object.", + "available_payload_title": "Available in payload:", + "payload_name_description": "Event name", + "payload_profile_id_description": "User profile ID", + "payload_properties_description": "Full properties object", + "payload_nested_property_description": "Nested property value", + "payload_profile_property_description": "Profile property", + "payload_more_fields": "and more...", + "available_helpers_title": "Available helpers:", + "example_title": "Example:", + "security_title": "Security:", + "security_description": "Network calls, file system access, and other dangerous operations are blocked.", + "page_title": "Integrations", + "page_description": "Manage your integrations here", + "tab_installed": "Installed", + "tab_available": "Available" + }, + "cohorts": { + "add_event_criteria": "Add event criteria", + "add_property_filter": "Add property filter", + "all": "All", + "all_of_these_events": "All of these events", + "all_of_these_properties": "All of these properties", + "any": "Any", + "any_of_these_events": "Any of these events", + "any_of_these_properties": "Any of these properties", + "at_least": "At least", + "at_most": "At most", + "between": "Between", + "capped_notice": "Capped at 10,000 members - consider narrowing the criteria.", + "cohort": "Cohort", + "cohort_deleted": "Cohort deleted.", + "cohort_refresh_queued": "Cohort refresh queued.", + "create_cohort": "Create cohort", + "created": "Created", + "delete": "Delete", + "delete_cohort": "Delete cohort", + "delete_confirm_description": "Are you sure you want to delete this cohort? This action cannot be undone.", + "delete_named_confirm_description": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.", + "description": "Create and manage user segments based on events and properties", + "download": "Download", + "download_members_failed": "Failed to download cohort members", + "edit": "Edit", + "empty_description": "You have not created any cohorts for this project yet", + "empty_title": "No cohorts", + "event": "Event", + "event_based": "Event-based", + "event_filters": "Event Filters", + "events": "Events", + "events_last_30_days": "Events last 30 days ({{count}})", + "exactly": "Exactly", + "frequency": "Frequency", + "last": "Last", + "last_computed": "Last computed", + "match": "Match", + "member_count_one": "{{count}} member", + "member_count_other": "{{count}} members", + "members": "Members", + "no_events_yet": "No events yet", + "not_computed_notice": "This cohort hasn't been computed yet. Membership will appear within a minute.", + "not_found": "Cohort not found", + "operator": "Operator", + "overview": "Overview", + "period": "Period", + "period_180_days": "180 days", + "period_30_days": "30 days", + "period_365_days": "365 days", + "period_7_days": "7 days", + "period_90_days": "90 days", + "property_based": "Property-based", + "refresh": "Refresh", + "select_event_placeholder": "Select event...", + "since": "Since", + "static": "Static", + "success": "Success", + "timeframe": "Timeframe", + "times": "times", + "title": "Cohorts", + "to": "to", + "type": "Type", + "updated_at": "Updated {{date}}" + }, + "filters": { + "add_filter": "Add filter", + "cohort": "Cohort", + "filters": "Filters", + "group_property": "Group · {{property}}", + "no": "No", + "pick_cohort": "pick cohort", + "profile_property": "Profile · {{property}}", + "remove_filter": "Remove filter", + "session_bounced": "Bounced", + "session_duration": "Duration", + "session_events": "Events", + "session_performed_event": "Performed event", + "session_revenue": "Revenue", + "session_screen_views": "Screen views", + "yes": "Yes" + }, + "events": { + "page_title": "Events", + "page_description": "Paginate through your events, conversions and overall stats", + "tab_events": "Events", + "tab_conversions": "Conversions", + "tab_stats": "Stats", + "column_created_at": "Created at", + "column_name": "Name", + "column_profile": "Profile", + "column_session_id": "Session ID", + "column_device_id": "Device ID", + "column_country": "Country", + "column_os": "OS", + "column_browser": "Browser", + "column_groups": "Groups", + "column_properties": "Properties", + "screen_label": "Screen:", + "visit_label": "Visit:", + "route_name": "Route: {{path}}", + "unknown_profile": "Unknown", + "anonymous_profile": "Anonymous", + "more_properties_count_one": "{{count}} more item", + "more_properties_count_other": "{{count}} more items", + "empty_title": "No events", + "empty_description": "Start sending events and you'll see them here", + "date_range": "Date range", + "listening": "Listening", + "new_events_suffix": "new events", + "listening_to_new_events": "Listening to new events", + "click_to_refresh": "Click to refresh", + "all_events": "All events", + "events_per_day": "Events per day", + "event_distribution": "Event distribution" + }, + "groups": { + "page_title": "Groups", + "page_description": "Groups represent companies, teams, or other entities that events belong to.", + "group_page_title": "Group", + "group_events_title": "Group events", + "group_members_title": "Group members", + "add_group": "Add group", + "all_types": "All types", + "empty_title": "No groups found", + "empty_description": "Groups represent companies, teams, or other entities that events belong to.", + "search_placeholder": "Search groups...", + "column_name": "Name", + "column_id": "ID", + "column_type": "Type", + "column_members": "Members", + "column_last_active": "Last active", + "column_created": "Created", + "total_members": "Total members", + "new_members_count": "+{{count}} new", + "new_members_last_30_days": "New members last 30 days", + "no_data_yet": "No data yet", + "tab_overview": "Overview", + "tab_members": "Members", + "tab_events": "Events", + "group_not_found": "Group not found", + "edit": "Edit", + "delete": "Delete", + "delete_group": "Delete group", + "delete_group_confirm": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.", + "total_events": "Total Events", + "unique_members": "Unique Members", + "first_seen": "First Seen", + "last_seen": "Last Seen", + "group_information": "Group Information", + "field_id": "id", + "field_name": "name", + "field_type": "type", + "field_created_at": "createdAt" + }, + "settings": { + "project_not_found": "Project not found", + "project_settings_title": "Project settings", + "project_settings_description": "Manage your project settings here", + "tab_details": "Details", + "tab_events": "Events", + "tab_clients_api_keys": "Clients / API keys", + "tab_tracking_script": "Tracking script", + "tab_mcp": "MCP", + "tab_widgets": "Widgets", + "tab_imports": "Imports", + "tab_google_search": "Google Search", + "details_title": "Details", + "details_name_label": "Name", + "details_domain_label": "Domain", + "details_allowed_domains_label": "Allowed domains", + "details_add_domain_placeholder": "Add a domain", + "details_allow_all_domains": "Allow all domains", + "details_cross_domain_label": "Cross domain support", + "details_cross_domain_enable": "Enable cross domain support", + "details_cross_domain_description": "This will let you track users across multiple domains", + "details_revenue_tracking_label": "Revenue tracking", + "details_unsafe_revenue_enable": "Allow \"unsafe\" revenue tracking", + "details_unsafe_revenue_description": "With this enabled, you can track revenue from client code.", + "details_updated_toast": "Project updated", + "details_domain_required": "Please add a domain", + "details_cors_required": "Please add at least one cors domain", + "filters_title": "Exclude events", + "filters_description": "Exclude events from being tracked by adding filters.", + "filters_select_event_placeholder": "Select event name...", + "filters_add_property_filter": "Add property filter", + "filters_ip_addresses_label": "IP addresses", + "filters_ip_addresses_placeholder": "Exclude IP addresses", + "filters_profile_ids_label": "Profile IDs", + "filters_profile_ids_placeholder": "Exclude Profile IDs", + "filters_event_rules_label": "Event rules", + "filters_add_event_rule": "Add event rule", + "filters_updated_toast": "Project filters updated", + "delete_account_title": "Delete account", + "delete_account_description": "Deleting your account will permanently remove your personal data. Organizations you created that have no other admin will also be deleted, along with their projects and events.", + "delete_account_subscription_block_title": "Cancel your subscriptions first", + "delete_account_subscription_block_description": "These organizations you created have an active subscription. Cancel each one before deleting your account:", + "delete_project_title": "Delete Project", + "delete_project_description": "Deleting your project will remove it from your organization and all of its data. It'll be permanently deleted after 24 hours.", + "delete_project_scheduled_toast": "Project is scheduled for deletion", + "delete_project_cancelled_toast": "Project deletion cancelled", + "delete_project_scheduled_title": "Project scheduled for deletion", + "delete_project_scheduled_prefix": "This project will be deleted on", + "delete_project_scheduled_suffix": "Any event associated with this project will be deleted.", + "delete_project_org_scheduled_notice": "The whole organization is scheduled for deletion. To keep this project, cancel the deletion from the organization settings.", + "delete_project_cancel_button": "Cancel deletion", + "delete_project_confirm_text": "Are you sure you want to delete this project?", + "delete_organization_title": "Delete Organization", + "delete_organization_description": "Deleting this organization will remove it and all of its projects and their data. It will be permanently deleted after 24 hours.", + "delete_organization_cancelled_toast": "Organization deletion cancelled", + "delete_organization_scheduled_title": "Organization scheduled for deletion", + "delete_organization_scheduled_prefix": "This organization will be deleted on", + "delete_organization_scheduled_suffix": "All of its projects and their events will be deleted.", + "delete_organization_subscription_block_title": "Cancel your subscription first", + "delete_organization_subscription_block_description": "This organization has an active subscription. Cancel it from the billing settings before you delete the organization.", + "invite_mail_column": "Mail", + "invite_email_label": "Email", + "invite_search_email_placeholder": "Search email", + "invite_role_column": "Role", + "invite_created_column": "Created", + "invite_access_column": "Access", + "invite_revoked_toast": "Invite for {{email}} revoked", + "invite_revoke_failed_toast": "Failed to revoke invite for {{email}}", + "invite_copy_link": "Copy invite link", + "invite_revoke": "Revoke invite", + "invite_unknown_project": "Unknown", + "invite_all_projects": "All projects", + "invite_user_button": "Invite user", + "members_name_column": "Name", + "members_email_column": "Email", + "members_search_email_placeholder": "Search email", + "members_role_column": "Role", + "members_created_column": "Created", + "members_access_column": "Access", + "members_all_projects": "All projects", + "members_removed_toast": "{{name}} has been removed from the organization", + "members_remove_failed_toast": "Failed to remove {{name}} from the organization", + "members_edit_access": "Edit access", + "members_remove_member": "Remove member", + "tracking_select_client_placeholder": "Select client", + "tracking_copy_button": "Copy", + "tracking_framework_prompt": "Or pick a framework below to get started.", + "tracking_missing_framework": "Missing a framework?", + "tracking_let_us_know": "Let us know!", + "gsc_title": "Google Search Console", + "gsc_connect_description": "Connect your Google Search Console property to import search performance data.", + "gsc_authorize_description": "You will be redirected to Google to authorize access. Only read-only access to Search Console data is requested.", + "gsc_connect_button": "Connect Google Search Console", + "gsc_initiate_failed_toast": "Failed to initiate Google Search Console connection", + "gsc_site_connected_toast": "Site connected", + "gsc_backfill_started_toast": "Backfill of 6 months of data has started.", + "gsc_select_failed_toast": "Failed to select site", + "gsc_disconnected_toast": "Disconnected from Google Search Console", + "gsc_disconnect_failed_toast": "Failed to disconnect", + "gsc_select_property_title": "Select a property", + "gsc_select_property_description": "Choose which Google Search Console property to connect to this project.", + "gsc_no_properties": "No Search Console properties found for this Google account.", + "gsc_select_property_placeholder": "Select a property...", + "gsc_connect_property_button": "Connect property", + "gsc_cancel_button": "Cancel", + "gsc_connected_description": "Connected to Google Search Console.", + "gsc_authorization_expired": "Authorization expired", + "gsc_authorization_expired_description": "Your Google Search Console authorization has expired or been revoked. Please reconnect to continue syncing data.", + "gsc_reconnect_button": "Reconnect Google Search Console", + "gsc_disconnect_button": "Disconnect", + "gsc_property_label": "Property", + "gsc_backfill_label": "Backfill", + "gsc_last_synced_label": "Last synced", + "gsc_last_error_label": "Last error", + "imports_deleted_toast": "Import deleted", + "imports_deleted_description": "The import has been successfully deleted.", + "imports_retried_toast": "Import retried", + "imports_retried_description": "The import has been queued for processing again.", + "imports_import_data_button": "Import Data", + "imports_history_title": "Import History", + "imports_provider_column": "Provider", + "imports_created_column": "Created", + "imports_status_column": "Status", + "imports_progress_column": "Progress", + "imports_config_column": "Config", + "imports_actions_column": "Actions", + "imports_empty_title": "No imports yet", + "imports_empty_description": "Your import history will appear here.", + "imports_estimated_events_tooltip": "Estimated number of events. Can be inaccurate depending on the provider.", + "imports_config_badge": "Config", + "imports_retry_button": "Retry", + "imports_delete_button": "Delete", + "mcp_title": "MCP Server", + "mcp_description": "Connect any MCP-compatible AI client (Claude, Cursor, Windsurf, …) to your OpenPanel data. The server is read-only and exposes 38 tools for querying events, sessions, profiles, funnels, retention and more.", + "mcp_endpoint_label": "Endpoint", + "mcp_token_help_prefix": "Replace", + "mcp_token_help_middle": "with", + "mcp_token_help_suffix": "You can also pass it as an", + "mcp_token_help_suffix_2": "header instead of a query param.", + "mcp_need_token_title": "Need a token?", + "mcp_need_token_description_prefix": "Only", + "mcp_need_token_description_middle": "and", + "mcp_need_token_description_suffix": "clients can authenticate with MCP. Create one and copy the MCP token from the success screen — it's only shown once.", + "mcp_create_client_button": "Create MCP client", + "mcp_configure_client_title": "Configure your AI client", + "mcp_config_file_label": "Config file:", + "mcp_read_docs_button": "Read the full MCP docs", + "mcp_claude_desktop_description_prefix": "Add the following block to", + "mcp_claude_desktop_description_suffix": "You can open it from", + "mcp_claude_desktop_settings_path": "Settings → Developer → Edit Config", + "mcp_claude_code_description_prefix": "Run this once in your terminal. The token can also be passed as a header via", + "mcp_cursor_description_prefix": "Add the server to your global config at", + "mcp_cursor_description_suffix": "or your project config at", + "mcp_windsurf_description_prefix": "Add the server to", + "mcp_windsurf_description_suffix": "Windsurf accepts both", + "mcp_vscode_description_prefix": "Add the server to", + "mcp_vscode_description_suffix": "in your workspace, or to your user-level MCP config.", + "mcp_raycast_description_prefix": "Copy the JSON below, then run the", + "mcp_raycast_install_server": "Install Server", + "mcp_raycast_description_suffix": "command in Raycast — it auto-fills the form from your clipboard.", + "widgets_enabled_toast": "Widget enabled", + "widgets_disabled_toast": "Widget disabled", + "widgets_update_failed_toast": "Failed to update widget", + "widgets_options_updated_toast": "Widget options updated", + "widgets_options_update_failed_toast": "Failed to update options", + "widgets_realtime_title": "Realtime Widget", + "widgets_realtime_description": "Embed a realtime visitor counter widget on your website. The widget shows live visitor count, activity histogram, top countries, referrers and paths.", + "widgets_options_title": "Widget Options", + "widgets_show_referrers": "Show Referrers", + "widgets_show_countries": "Show Countries", + "widgets_show_paths": "Show Paths", + "widgets_url_title": "Widget URL", + "widgets_realtime_url_description": "Direct link to the widget. You can open this in a new tab or embed it.", + "widgets_embed_code_title": "Embed Code", + "widgets_embed_code_description": "Copy this code and paste it into your website HTML where you want the widget to appear.", + "widgets_preview_title": "Preview", + "widgets_open_new_tab": "Open in new tab", + "widgets_counter_title": "Counter Widget", + "widgets_counter_description": "A compact live visitor counter badge you can embed anywhere. Shows the current number of unique visitors with a live indicator.", + "widgets_counter_url_description": "Direct link to the counter widget.", + "widgets_badge_title": "Analytics Badge", + "widgets_badge_description": "A Product Hunt-style badge showing your 30-day unique visitor count. Perfect for showcasing your analytics powered by OpenPanel.", + "widgets_badge_url_description": "Direct link to the analytics badge widget.", + "mcp_windsurf_url_connector": "and", + "widgets_realtime_preview_title": "Realtime Widget Preview", + "widgets_counter_preview_title": "Counter Widget Preview", + "widgets_badge_preview_title": "Analytics Badge Preview", + "imports_provider_umami_description": "Import your analytics data from Umami", + "imports_provider_mixpanel_description": "Import your analytics data from Mixpanel API", + "imports_provider_amplitude_description": "Import your analytics data from an Amplitude export" + }, + "projects": { + "metric_three_month_diff": "3M DIFF", + "metric_revenue": "Revenue", + "metric_three_months": "3M", + "metric_thirty_days": "30D", + "metric_twenty_four_hours": "24H", + "chart_sessions": "Sessions", + "chart_revenue": "Revenue", + "chart_no_activity_title": "No activity yet", + "chart_no_activity_description": "Sessions will show up here once tracking starts.", + "projects": "Projects", + "select_project": "Select project", + "all_projects": "All projects", + "create_new_project": "Create new project", + "organizations": "Organizations", + "new_organization": "New organization", + "project_mapper_optional": "Project Mapper (Optional)", + "add_mapping": "Add Mapping", + "project_mapper_description": "Map source project IDs to your OpenPanel projects. If you skip mapping all data will be imported to your current project.", + "project_mapper_from_label": "From (Source Project ID)", + "project_mapper_from_placeholder": "e.g., abc123", + "project_mapper_to_label": "To (OpenPanel Project)" + }, + "pages": { + "page_title": "Pages", + "page_description": "Access all your pages here", + "search_placeholder": "Search pages", + "empty_title": "No pages", + "empty_description": "Integrate our web SDK to your site to get pages here.", + "empty_search_description": "No pages found matching \"{{search}}\"", + "column_page": "Page", + "column_trend": "Trend", + "column_views": "Views", + "column_sessions": "Sessions", + "column_bounce": "Bounce", + "column_duration": "Duration", + "column_impressions": "Impr.", + "column_ctr": "CTR", + "column_clicks": "Clicks", + "new_label": "new", + "views_sessions": "Views & Sessions", + "trend_upward": "Upward trend", + "trend_downward": "Downward trend", + "trend_stable": "Stable trend" + }, + "profiles": { + "page_title": "Profiles", + "page_description": "If you haven't called identify your profiles will be anonymous", + "tab_identified": "Identified", + "tab_anonymous": "Anonymous", + "tab_power_users": "Power users", + "search_placeholder": "Search profiles", + "filters_title": "Profile filters", + "empty_title": "No profiles", + "empty_description": "Looks like you haven't identified any profiles yet.", + "column_name": "Name", + "column_referrer": "Referrer", + "column_country": "Country", + "column_os": "OS", + "column_browser": "Browser", + "column_model": "Model", + "column_first_seen": "First seen", + "column_last_seen": "Last seen", + "column_groups": "Groups", + "column_events": "Events", + "most_visited_pages": "Most visited pages", + "no_pages_visited_yet": "No pages visited yet", + "popular_events": "Popular events", + "no_events_yet": "No events yet", + "latest_events": "Latest Events", + "all": "All", + "activity": "Activity", + "activity_events_count_one": "{{count}} event", + "activity_events_count_other": "{{count}} events", + "no_activity": "No activity", + "groups": "Groups", + "events": "Events", + "page_views": "Page views", + "events_per_day": "Events per day", + "metric_total_events": "Total Events", + "metric_sessions": "Sessions", + "metric_page_views": "Page Views", + "metric_avg_events_per_session": "Avg Events/Session", + "metric_bounce_rate": "Bounce Rate", + "metric_session_duration_avg": "Session Duration (Avg)", + "metric_session_duration_p90": "Session Duration (P90)", + "metric_first_seen": "First seen", + "metric_last_seen": "Last seen", + "metric_days_active": "Days Active", + "metric_conversion_events": "Conversion Events", + "metric_avg_time_between_sessions": "Avg Time Between Sessions (h)", + "metric_revenue": "Revenue", + "profile_information": "Profile Information", + "tab_profile": "Profile", + "tab_properties": "Properties", + "yes": "Yes", + "no": "No", + "no_properties_found": "No properties found" + }, + "sessions": { + "page_title": "Sessions", + "page_description": "Access all your sessions here", + "search_placeholder": "Search sessions by path, referrer...", + "filters_title": "Session filters", + "empty_title": "No sessions found", + "empty_description": "Looks like you haven't inserted any events yet.", + "column_started": "Started", + "column_session_id": "Session ID", + "column_profile": "Profile", + "column_entry_page": "Entry Page", + "column_exit_page": "Exit Page", + "column_duration": "Duration", + "column_bounce": "Bounce", + "column_referrer": "Referrer", + "column_location": "Location", + "column_os": "OS", + "column_browser": "Browser", + "column_device": "Device", + "column_page_views": "Page views", + "column_events": "Events", + "column_revenue": "Revenue", + "column_device_id": "Device ID", + "column_groups": "Groups", + "view_replay": "View replay", + "yes": "Yes", + "no": "No", + "detail_title": "Session: {{id}}", + "detail_visited_pages": "Visited pages", + "detail_event_distribution": "Event distribution", + "detail_session_info": "Session info", + "detail_profile": "Profile", + "detail_groups": "Groups", + "detail_events": "Events", + "detail_no_events": "No events found", + "replay_pause": "Pause", + "replay_play": "Play", + "replay_timeline": "Timeline", + "replay_events_empty": "Events will appear as the replay plays.", + "replay_player_load_failed": "Failed to load replay player.", + "replay_events_at_time_one": "{{count}} event at {{time}}", + "replay_events_at_time_other": "{{count}} events at {{time}}", + "replay_event_at_time": "{{event}} at {{time}}", + "exit_fullscreen": "Exit fullscreen", + "enter_fullscreen": "Enter fullscreen", + "loading_session_replay": "Loading session replay", + "no_replay_data": "No replay data available for this session." + }, + "dashboards": { + "page_title": "Dashboards", + "page_description": "Access all your dashboards here", + "dashboard": "Dashboard", + "empty_title": "No dashboards", + "empty_description": "You have not created any dashboards for this project yet", + "create_dashboard": "Create dashboard", + "force_delete": "Force delete", + "success": "Success", + "delete_success": "Dashboard deleted.", + "more": "more", + "detail_description": "View and manage your reports", + "search_reports_placeholder": "Search reports...", + "create_report": "Create report", + "report": "Report", + "share_dashboard": "Share dashboard", + "reset_layout": "Reset layout", + "reset_layout_confirm": "Are you sure you want to reset the layout to default? This will clear all custom positioning and sizing.", + "delete_dashboard": "Delete dashboard", + "delete_dashboard_confirm": "Are you sure you want to delete this dashboard? All your reports will be deleted!", + "no_reports_title": "No reports", + "no_reports_description": "You can visualize your data with a report", + "no_matching_reports_title": "No matching reports", + "no_matching_reports_description": "No reports match \"{{search}}\". Try a different search.", + "report_delete_success": "Report deleted", + "report_duplicate_success": "Report duplicated", + "layout_reset_success": "Layout reset to default", + "edit": "Edit", + "delete": "Delete" + }, + "insights": { + "page_title": "Insights", + "page_description": "Discover trends and changes in your analytics", + "search_placeholder": "Search insights...", + "time_window_placeholder": "Time Window", + "all_windows": "All Windows", + "yesterday": "Yesterday", + "seven_days": "7 Days", + "thirty_days": "30 Days", + "severity_placeholder": "Severity", + "all_severity": "All Severity", + "severe": "Severe", + "moderate": "Moderate", + "low": "Low", + "no_severity": "No Severity", + "direction_placeholder": "Direction", + "all_directions": "All Directions", + "increasing": "Increasing", + "decreasing": "Decreasing", + "flat": "Flat", + "sort_placeholder": "Sort by", + "sort_impact_high_low": "Impact (High → Low)", + "sort_impact_low_high": "Impact (Low → High)", + "sort_severity_high_low": "Severity (High → Low)", + "sort_severity_low_high": "Severity (Low → High)", + "sort_most_recent": "Most Recent", + "empty_title": "No insights found", + "empty_filtered_description": "Try adjusting your filters to see more insights.", + "empty_description": "Insights will appear here as trends are detected in your analytics.", + "module_geo": "Geographic", + "module_devices": "Devices", + "module_referrers": "Referrers", + "module_entry_pages": "Entry Pages", + "module_page_trends": "Page Trends", + "module_exit_pages": "Exit Pages", + "module_traffic_anomalies": "Anomalies", + "metric_share": "Share", + "metric_pageviews": "Pageviews", + "metric_sessions": "Sessions", + "count_one": "insight", + "count_other": "insights", + "showing_count": "Showing {{count}} of {{total}} insights" + }, + "share": { + "not_found_title": "Share not found", + "report_not_found_description": "The report you are looking for does not exist.", + "dashboard_not_found_description": "The dashboard you are looking for does not exist.", + "overview_not_found_description": "The overview you are looking for does not exist.", + "report": "Report", + "no_reports": "No reports" + }, + "seo": { + "page_title": "SEO", + "page_description": "Google Search Console data", + "empty_title": "No SEO data yet", + "empty_description": "Connect Google Search Console to track your search impressions, clicks, and keyword rankings.", + "connect_gsc": "Connect Google Search Console", + "performance_description": "Search performance for {{siteUrl}}", + "metric_clicks": "Clicks", + "metric_impressions": "Impressions", + "metric_avg_ctr": "Avg CTR", + "metric_avg_position": "Avg Position", + "key_page": "Page", + "key_query": "Query", + "search_pages": "Search pages", + "search_queries": "Search queries", + "top_pages": "Top pages", + "top_queries": "Top queries", + "search_engines": "Search engines", + "ai_referrals": "AI referrals", + "no_search_traffic": "No search traffic in this period", + "no_ai_traffic": "No AI traffic in this period", + "chart_clicks_impressions": "Clicks & Impressions", + "other_source": "Others", + "metric_ctr": "CTR", + "metric_impressions_short": "Impr.", + "metric_position_short": "Pos.", + "search": "Search", + "zero_results": "0 results", + "results_range": "{{start}}-{{end}} of {{total}}", + "search_keywords": "Search keywords", + "keyword_cannibalization": "Keyword Cannibalization", + "pages_count": "{{count}} pages", + "impressions_avg_ctr_summary": "{{impressions}} impr · {{ctr}}% avg CTR", + "cannibalization_advice_prefix": "These pages all rank for", + "cannibalization_advice_suffix": ". Consider consolidating weaker pages into the top-ranking one to concentrate link equity and avoid splitting clicks.", + "page_metrics_summary": "pos {{position}} · {{ctr}}% CTR · {{impressions}} impr", + "ctr_vs_position": "CTR vs Position", + "your_ctr": "Your CTR", + "your_avg_ctr": "Your avg CTR", + "benchmark": "Benchmark", + "position_number": "Position #{{position}}", + "lower_is_better": "Lower is better", + "insight_low_ctr": "Low CTR", + "insight_near_page_one": "Near page 1", + "insight_low_visibility": "Low visibility", + "insight_high_bounce": "High bounce", + "insight_low_ctr_headline": "Ranking #{{position}} but only {{ctr}}% CTR", + "insight_low_ctr_suggestion": "You are on page 1 but people rarely click. Rewrite your title tag and meta description to be more compelling and match search intent.", + "insight_near_page_one_headline": "Position {{position}} — one push from page 1", + "insight_near_page_one_suggestion": "A content refresh, more internal links, or a few backlinks could move this into the top 10 and dramatically increase clicks.", + "insight_invisible_clicks_headline": "{{impressions}} impressions but only {{clicks}} clicks", + "insight_invisible_clicks_suggestion": "Google shows this page a lot, but it almost never gets clicked. Consider whether the page targets the right queries or if a different format (e.g. listicle, how-to) would perform better.", + "insight_high_bounce_headline": "{{bounceRate}}% bounce rate on a page with {{sessions}} sessions", + "insight_high_bounce_suggestion": "Visitors are leaving without engaging. Check if the page delivers on its title/meta promise, improve page speed, and make sure key content is above the fold.", + "insight_high_bounce_no_gsc_headline": "{{bounceRate}}% bounce rate with {{sessions}} sessions", + "insight_high_bounce_no_gsc_suggestion": "High bounce rate with no search visibility. Review content quality and check if the page is indexed and targeting the right keywords.", + "metrics_position_impressions_ctr": "Pos {{position}} · {{impressions}} impr · {{ctr}}% CTR", + "metrics_position_impressions_clicks": "Pos {{position}} · {{impressions}} impr · {{clicks}} clicks", + "metrics_impressions_clicks_position": "{{impressions}} impr · {{clicks}} clicks · Pos {{position}}", + "metrics_bounce_sessions_impressions": "{{bounceRate}}% bounce · {{sessions}} sessions · {{impressions}} impr", + "metrics_bounce_sessions": "{{bounceRate}}% bounce · {{sessions}} sessions", + "opportunities": "Opportunities" + }, + "realtime": { + "geo_title": "Geo", + "paths_title": "Paths", + "referrals_title": "Referrals", + "column_country_city": "Country / City", + "column_duration": "Duration", + "column_events": "Events", + "column_sessions": "Sessions", + "column_path": "Path", + "column_referrer": "Referrer", + "not_set": "(Not set)", + "active_users": "Active users", + "referrers_label": "Referrers:", + "unique_visitors_last_30_min": "Unique visitors last 30 min", + "more": "more", + "no_active_sessions": "No active sessions", + "map_cluster_title": "Realtime cluster", + "map_sessions_count_one": "{{count}} session", + "map_sessions_count_other": "{{count}} sessions", + "map_profiles_count_one": "{{count}} profile", + "map_profiles_count_other": "{{count}} profiles", + "map_locations": "Locations", + "map_countries": "Countries", + "map_cities": "Cities", + "map_top_referrers": "Top referrers", + "map_top_events": "Top events", + "map_top_paths": "Top paths", + "map_recent_sessions": "Recent sessions", + "no_data": "No data", + "unknown_location": "Unknown", + "no_recent_sessions": "No recent sessions", + "map_details_load_failed": "Could not load badge details." + }, + "notifications": { + "page_title": "Notifications", + "page_description": "See notifications and manage the rules that decide when to notify you.", + "tab_notifications": "Notifications", + "tab_rules": "Rules", + "rules_empty_title": "No rules yet", + "rules_empty_description": "You have not created any rules yet. Create a rule to start getting notifications.", + "action_add_rule": "Add Rule", + "action_delete": "Delete", + "action_edit": "Edit", + "rule_any_event": "Any event", + "rule_deleted_success": "Rule deleted", + "rule_events_prefix": "Get notified when", + "rule_events_suffix": "occurs", + "rule_funnel_description": "Get notified when a session has completed this funnel", + "delete_rule_confirm_title": "Delete {{name}}?", + "delete_rule_confirm_description": "This action cannot be undone.", + "column_title": "Title", + "column_message": "Message", + "column_integration": "Integration", + "column_rule": "Rule", + "column_country": "Country", + "column_os": "OS", + "column_browser": "Browser", + "column_profile": "Profile", + "column_created_at": "Created at", + "search_placeholder": "Search" + }, + "onboarding": { + "page_title": "Onboarding", + "project_title": "Project", + "step_create_account": "Create an account", + "step_create_project": "Create a project", + "step_connect_data": "Connect your data", + "step_verify": "Verify", + "action_login": "Login", + "action_skip_onboarding": "Skip onboarding", + "action_skip_for_now": "Skip for now", + "action_next": "Next", + "action_back": "Back", + "action_copy": "Copy", + "action_save": "Save", + "action_your_dashboard": "Your dashboard", + "skip_confirm_title": "Skip onboarding?", + "skip_confirm_description": "Are you sure you want to skip onboarding? Since you do not have any projects, you will be logged out.", + "project_create_new_workspace": "Create new workspace", + "project_use_existing_workspace": "Use existing workspace", + "project_workspace_name_help": "This is the name of your workspace. It can be anything you like.", + "project_workspace_name_placeholder": "Eg. The Music Company", + "project_select_timezone": "Select timezone", + "project_select_workspace": "Select workspace", + "project_name_placeholder": "Eg. The Music App", + "project_tracking_label": "What are you tracking?", + "project_type_website": "Website", + "project_type_app": "App", + "project_type_backend": "Backend / API", + "project_tracking_required": "At least one type must be selected", + "project_domain_allowed_prefix": "All events from", + "project_domain_allowed_suffix": "will be allowed. Do you want to allow any other?", + "field_workspace_name": "Workspace name", + "field_timezone": "Timezone", + "field_workspace": "Workspace", + "field_first_project_name": "Your first project name", + "field_domain": "Domain", + "field_allowed_domains": "Allowed domains", + "field_client_id": "Client ID", + "field_client_secret": "Client secret", + "allowed_domains_placeholder": "Accept events from these domains", + "allowed_domains_any_tag": "Accept events from any domains", + "connect_project_missing_title": "No project found", + "connect_project_missing_description": "The project you are looking for does not exist. Please reload the page.", + "connect_client_credentials_title": "Client credentials", + "connect_quick_start_title": "Quick start", + "connect_pick_framework": "Or pick a framework below to get started.", + "connect_missing_framework": "Missing a framework?", + "connect_let_us_know": "Let us know!", + "verify_project_not_found": "Project not found", + "verify_client_not_found": "Client not found", + "verify_connected_title": "Successfully connected", + "verify_waiting_title": "Waiting for events", + "verify_waiting_description": "Verify that your implementation works.", + "verify_more_events_one": "{{count}} more event", + "verify_more_events_other": "{{count}} more events", + "verify_allowed_domains_updated": "Allowed domains updated", + "verify_faq_no_events_title": "No events received?", + "verify_faq_intro": "Don't worry, this happens to everyone. Here are a few things you can check:", + "verify_faq_client_id_title": "Ensure client ID is correct", + "verify_faq_client_id_prefix": "For web tracking, the", + "verify_faq_client_id_suffix": "in your snippet must match this project. Copy it here if needed:", + "verify_faq_domain_title": "Correct domain configured", + "verify_faq_domain_description": "For websites it is important that the domain is correctly configured. We authenticate requests based on the domain. Update allowed domains below:", + "verify_faq_client_secret_title": "Wrong client secret", + "verify_faq_client_secret_prefix": "For app and backend events you need the correct", + "verify_faq_client_secret_suffix": ". Copy it here if needed. Never use the client secret in web or client-side code; it would expose your credentials.", + "verify_support_prefix": "Still have issues? Join our", + "verify_support_discord": "discord channel", + "verify_support_email_prefix": "or email us at", + "verify_support_suffix": "and we will help you out.", + "verify_personal_curl_title": "Personal curl example", + "testimonial_thomas_quote": "OpenPanel is BY FAR the best open-source analytics I've ever seen. Better UX/UI, many more features, and incredible support from the founder.", + "testimonial_julien_quote": "After testing several product analytics tools, we chose OpenPanel and we are very satisfied. Profiles and Conversion Events are our favorite features.", + "testimonial_piotr_quote": "The Overview tab is great - it has everything I need. The UI is beautiful, clean, modern, very pleasing to the eye.", + "testimonial_selfhost_quote": "After paying a lot to PostHog for years, OpenPanel gives us the same - in many ways better - analytics while keeping full ownership of our data. We don't want to run any business without OpenPanel anymore.", + "testimonial_selfhost_author": "Self-hosting user" + }, + "organization": { + "not_found": "Organization not found", + "details_title": "Details", + "name_label": "Name", + "timezone_label": "Timezone", + "timezone_placeholder": "Select timezone", + "toast_updated": "Organization updated", + "toast_updated_description": "Your organization has been updated.", + "settings_page_title": "Workspace settings", + "settings_page_description": "Manage your workspace settings here", + "projects_empty_title": "No projects found", + "projects_empty_admin_description": "Create your first project to get started with analytics.", + "projects_empty_member_description": "You do not have access to any projects in this organization yet. Ask an admin to grant you access.", + "create_project": "Create project", + "projects_page_title": "Projects", + "projects_page_description": "All your projects in this workspace", + "search_projects": "Search projects", + "feedback_prompt_title": "Share Your Feedback", + "feedback_prompt_subtitle": "Help us improve OpenPanel with your insights", + "feedback_prompt_description": "Your feedback helps us build features you actually need. Share your thoughts, report bugs, or suggest improvements", + "feedback_prompt_cta": "Give Feedback", + "supporter_prompt_title": "Support OpenPanel", + "supporter_prompt_subtitle": "Help us build the future of open analytics", + "supporter_prompt_cta": "Become a Supporter", + "supporter_prompt_footer": "Starting at $20/month • Cancel anytime •", + "supporter_prompt_learn_more": "Learn more", + "supporter_perk_docker_title": "Latest Docker Images", + "supporter_perk_docker_description": "Bleeding-edge builds on every commit", + "supporter_perk_support_title": "Prioritized Support", + "supporter_perk_support_description": "Get help faster with priority Discord support", + "supporter_perk_requests_title": "Feature Requests", + "supporter_perk_requests_description": "Your ideas get prioritized in our roadmap", + "supporter_perk_discord_role_title": "Exclusive Discord Role", + "supporter_perk_discord_role_description": "Special badge and recognition in our community", + "supporter_perk_early_access_title": "Early Access", + "supporter_perk_early_access_description": "Try new features before public release", + "supporter_perk_impact_title": "Direct Impact", + "supporter_perk_impact_description": "Your support directly funds development" + }, + "account": { + "page_title": "Your account", + "tab_profile": "Profile", + "tab_email_preferences": "Email preferences", + "tab_two_factor": "Two-factor auth", + "profile_title": "Profile", + "email_label": "Email", + "first_name_label": "First name", + "last_name_label": "Last name", + "toast_profile_updated": "Profile updated", + "toast_profile_updated_description": "Your profile has been updated.", + "email_preferences_title": "Email Preferences", + "email_preferences_description": "Choose which types of emails you want to receive. Uncheck a category to stop receiving those emails.", + "toast_email_preferences_updated": "Email preferences updated", + "toast_email_preferences_updated_description": "Your email preferences have been saved.", + "email_category_onboarding": "Onboarding", + "email_category_onboarding_description": "Get started tips and guidance emails", + "email_category_billing": "Billing", + "email_category_billing_description": "Subscription updates and payment reminders", + "two_factor_title": "Two-factor authentication", + "two_factor_description": "Protect your account with an authenticator app (Google Authenticator, 1Password, Authy, etc.). You'll be asked for a 6-digit code each time you sign in with email and password.", + "two_factor_not_available": "Two-factor authentication is not available.", + "two_factor_not_available_description": "Your account signs in with Google or GitHub, which handle two-factor authentication in their account settings. Enable it in your provider's security settings.", + "two_factor_disabled": "Two-factor authentication is disabled.", + "two_factor_enable": "Enable", + "two_factor_enabled": "Two-factor authentication is enabled.", + "two_factor_enabled_meta": "Enabled {{date}} · {{count}} recovery code remaining", + "two_factor_regenerate_recovery_codes": "Regenerate recovery codes", + "two_factor_disable": "Disable", + "two_factor_enabled_meta_one": "Enabled {{date}} · {{count}} recovery code remaining", + "two_factor_enabled_meta_other": "Enabled {{date}} · {{count}} recovery codes remaining" + }, + "members": { + "page_title": "Members", + "page_description": "Manage your members here", + "tab_members": "Members", + "tab_invitations": "Invitations" + }, + "billing": { + "page_title": "Billing", + "page_description": "Manage your billing here", + "interval_month": "month", + "interval_year": "year", + "customer_portal": "Customer portal", + "free_trial_badge": "Free trial", + "no_active_plan_badge": "No active plan", + "days_left": "{{count}} day left", + "trial_ends_description": "Your trial ends on {{date}}. When it ends, your dashboards pause until you choose a plan — your data keeps flowing in.", + "choose_plan_title": "Choose a plan", + "toast_subscription_updated": "Subscription updated", + "toast_subscription_updated_description": "It might take a few seconds to update", + "toast_subscription_canceled": "Subscription canceled", + "plan_cancel_subscription": "Cancel subscription", + "plan_reactivate_subscription": "Reactivate subscription", + "plan_change_subscription": "Change subscription", + "plan_pay_with_polar": "Pay with Polar", + "plan_current_usage": "Your current usage is {{count}} out of {{limit}} events.", + "plan_downgrade_limit_notice": "You cannot downgrade if your usage exceeds the limit of the new plan.", + "plan_switch_to_monthly": "Switch to monthly", + "plan_switch_to_yearly_prefix": "Switch to yearly and get", + "plan_switch_to_yearly_discount": "2 months for free", + "plan_monthly": "Monthly", + "plan_yearly": "Yearly", + "status_subscription_renews_on": "Your subscription renews on {{date}}", + "status_trial_ends_on": "Your trial ends on {{date}}", + "status_trial_ended": "Your free trial has ended.", + "status_subscription_will_cancel_on": "Your subscription will be canceled on {{date}}", + "status_subscription_canceled_on": "Your subscription was canceled on {{date}}", + "status_subscription_canceled": "Your subscription was canceled", + "status_payment_failed": "Your last payment failed — please update your payment method.", + "status_subscription_unpaid": "Your subscription is unpaid.", + "status_subscription_incomplete": "Your subscription setup is incomplete.", + "status_subscription_expired_on": "Your subscription expired on {{date}}", + "status_subscription_expired": "Your subscription expired", + "usage_title": "Usage", + "usage_loading_error": "Issues loading usage data", + "usage_empty": "No usage data yet", + "usage_period": "Period", + "usage_left_to_use": "Left to use", + "usage_events_count": "Events count", + "usage_limit": "Limit", + "usage_subscription": "Subscription", + "usage_no_active_subscription": "No active subscription", + "usage_events_last_30_days": "Events from last 30 days", + "usage_weekly_events": "Weekly Events", + "usage_daily_events": "Daily Events", + "usage_unknown_date": "Unknown date", + "usage_events_this_week": "Events this week", + "usage_events_this_day": "Events this day", + "usage_total_events": "Total Events", + "usage_your_events_count": "Your events count", + "usage_your_tier_limit": "Your tier limit", + "faq_title": "Frequently asked questions", + "faq_free_tier_question": "Does OpenPanel have a free tier?", + "faq_free_tier_answer_trial": "For our Cloud plan we offer a 30 days free trial, this is mostly for you to be able to try out OpenPanel before committing to a paid plan.", + "faq_free_tier_answer_self_host": "OpenPanel is also open-source and you can self-host it for free!", + "faq_free_tier_answer_why_title": "Why does OpenPanel not have a free tier?", + "faq_free_tier_answer_why_body": "We want to make sure that OpenPanel is used by people who are serious about using it. We also need to invest time and resources to maintain the platform and provide support to our users.", + "faq_exceeds_limit_question": "What happens if my site exceeds the limit?", + "faq_exceeds_limit_answer": "You will not see any new events in OpenPanel until your next billing period. If this happens 2 months in a row, we'll advice you to upgrade your plan.", + "faq_cancel_subscription_question": "What happens if I cancel my subscription?", + "faq_cancel_subscription_answer_access": "If you cancel your subscription, you will still have access to OpenPanel until the end of your current billing period. You can reactivate your subscription at any time.", + "faq_cancel_subscription_answer_data": "After your current billing period ends, you will not get access to new data.", + "faq_cancel_subscription_answer_note": "NOTE: If your account has been inactive for 3 months, we'll delete your events.", + "faq_billing_information_question": "How do I change my billing information?", + "faq_billing_information_answer": "You can change your billing information by clicking the \"Customer portal\" button in the billing section.", + "faq_custom_plan_question": "We need a custom plan, can you help us?", + "faq_custom_plan_answer": "Yes, we can help you with that. Please contact us at hello@openpanel.dev to request a quote.", + "prompt_trial_ended_badge": "Trial ended", + "prompt_trial_ended_title": "Your 30 days are up", + "prompt_trial_ended_lead": "Thanks for trying OpenPanel. Everything you set up is still here: your projects, your reports, and every event you tracked. Pick a plan and your dashboards are live again in about a minute.", + "prompt_trial_ended_date_label": "Trial ended", + "prompt_trial_ended_cta": "Continue with {{plan}} for {{price}}/month", + "prompt_trial_ended_note": "We keep collecting your incoming events for now, so nothing is lost while you decide.", + "prompt_expired_badge": "Subscription ended", + "prompt_expired_title": "Your data is right where you left it", + "prompt_expired_lead": "Your subscription ended, but we haven't deleted anything. Reactivate and your dashboards, reports, and events are back immediately.", + "prompt_expired_date_label": "Subscription ended", + "prompt_expired_cta": "Reactivate with {{plan}} for {{price}}/month", + "prompt_unpaid_badge": "Payment issue", + "prompt_unpaid_title": "Your last payment didn't go through", + "prompt_unpaid_lead": "Usually it's an expired card or a bank block, and it takes a minute to fix. Update your payment method and your dashboards come straight back. Your data hasn't gone anywhere.", + "prompt_unpaid_date_label": "Paid through", + "prompt_unpaid_cta": "Update payment method", + "prompt_free_plan_badge": "Plan change", + "prompt_free_plan_title": "We retired the free plan", + "prompt_free_plan_lead": "We'd rather run a small, sustainable service than a free one we can't support properly. Paid plans start at $2.5/month and your data carries over as-is.", + "prompt_free_plan_date_label": "Subscription ended", + "prompt_free_plan_cta": "Continue with {{plan}} for {{price}}/month", + "prompt_custom_plan_cta": "Get a custom plan", + "prompt_events_tracked_label": "Events tracked, all safe and stored", + "prompt_usage_recommendation_prefix": "Based on your usage, the", + "prompt_usage_recommendation_suffix": "plan covers you: up to {{events}} events per month for {{price}}.", + "prompt_custom_plan_description": "Your usage is above our standard plans, so let's set you up with a custom one.", + "prompt_see_all_plans": "See all plans", + "prompt_questions_email": "Questions? Email us", + "prompt_feature_plans_start": "Plans start at $2.5/month", + "prompt_feature_unlimited": "Unlimited reports, members and projects", + "prompt_feature_funnels": "Advanced funnels and conversions", + "prompt_feature_realtime": "Real-time analytics", + "prompt_feature_kpis": "Track KPIs and custom events", + "prompt_feature_privacy": "Privacy-focused and GDPR compliant", + "prompt_feature_revenue": "Revenue tracking", + "prompt_feature_gsc": "Google Search Console integration", + "days_left_one": "{{count}} day left", + "days_left_other": "{{count}} days left" + }, + "overview": { + "filters": "Filters", + "cohort": "Cohort", + "in_cohort": "In cohort", + "not_in_cohort": "Not in cohort", + "operator": "Operator", + "pick_cohort": "pick cohort", + "pick_value": "pick value", + "remove_filter": "Remove filter", + "refreshed_data": "Refreshed data", + "unique_visitors_last_5_minutes": "{{count}} unique visitors last 5 minutes", + "public": "Public", + "private": "Private", + "make_public": "Make public", + "make_private": "Make private", + "view": "View", + "switch_to_chart_view": "Switch to chart view", + "switch_to_table_view": "Switch to table view", + "more": "More", + "search": "Search", + "search_ellipsis": "Search...", + "search_column": "Search {{column}}...", + "search_pages": "Search pages...", + "column_name": "Name", + "no_results_found": "No results found", + "no_data_available": "No data available", + "not_set": "Not set", + "direct_not_set": "Direct / Not set", + "and_more_items_one": "and {{count}} more item", + "and_more_items_other": "and {{count}} more items", + "total": "Total", + "loading_map": "Loading map...", + "error_loading_map": "Error loading map", + "last_30_min": "Last 30 min", + "live_30_min": "Live · 30 min", + "geo_data_provided_by": "Geo data provided by", + "map": "Map", + "top_column": "Top {{column}}", + "unique_visitors": "Unique Visitors", + "sessions": "Sessions", + "sessions_short": "Sess.", + "pageviews": "Pageviews", + "views": "Views", + "pages_per_session": "Pages per session", + "bounce_rate": "Bounce Rate", + "session_duration": "Session Duration", + "revenue": "Revenue", + "toggle_mock_revenue": "Toggle mock revenue (dev only)", + "mock_revenue": "Mock revenue", + "mock_revenue_on": "Mock revenue on", + "user_journey": "User Journey", + "steps_count": "{{count}} Steps", + "no_journey_data_available": "No journey data available", + "step_number": "Step {{step}}", + "share": "Share", + "percent_of_total": "% of total", + "percent_of_source": "% of source", + "user_journey_description": "Shows the most common paths users take through your application", + "day_mon_short": "Mon", + "day_tue_short": "Tue", + "day_wed_short": "Wed", + "day_thu_short": "Thu", + "day_fri_short": "Fri", + "day_sat_short": "Sat", + "day_sun_short": "Sun", + "day_monday": "Monday", + "day_tuesday": "Tuesday", + "day_wednesday": "Wednesday", + "day_thursday": "Thursday", + "day_friday": "Friday", + "day_saturday": "Saturday", + "day_sunday": "Sunday", + "path": "Path", + "bot": "Bot", + "date": "Date", + "event": "Event", + "count": "Count", + "device": "Device", + "devices": "Devices", + "browser": "Browser", + "browser_version": "Browser Version", + "version": "Version", + "os": "OS", + "os_version": "OS Version", + "brand": "Brand", + "brands": "Brands", + "model": "Model", + "models": "Models", + "top_devices": "Top devices", + "top_browser": "Top browser", + "top_browser_version": "Top Browser Version", + "top_os": "Top OS", + "top_os_version": "Top OS version", + "top_brands": "Top Brands", + "top_models": "Top Models", + "countries": "Countries", + "regions": "Regions", + "cities": "Cities", + "top_countries": "Top countries", + "top_regions": "Top regions", + "top_cities": "Top cities", + "refs": "Refs", + "urls": "Urls", + "types": "Types", + "source": "Source", + "medium": "Medium", + "campaign": "Campaign", + "term": "Term", + "content": "Content", + "top_sources": "Top sources", + "top_urls": "Top urls", + "top_types": "Top types", + "utm_source": "UTM Source", + "utm_medium": "UTM Medium", + "utm_campaign": "UTM Campaign", + "utm_term": "UTM Term", + "utm_content": "UTM Content", + "top_pages": "Top Pages", + "pages": "Pages", + "entry_pages": "Entry Pages", + "exit_pages": "Exit Pages", + "entries": "Entries", + "exits": "Exits", + "hide_domain": "Hide domain", + "show_domain": "Show domain", + "events": "Events", + "conversions": "Conversions", + "link_out": "Link out", + "column_country": "Country", + "column_region": "Region", + "column_city": "City", + "column_browser": "Browser", + "column_brand": "Brand", + "column_os": "OS", + "column_device": "Device", + "column_browser_version": "Browser version", + "column_os_version": "OS version", + "column_model": "Model", + "column_referrer": "Referrer", + "column_referrer_name": "Referrer name", + "column_referrer_type": "Referrer type", + "column_utm_source": "UTM source", + "column_utm_medium": "UTM medium", + "column_utm_campaign": "UTM campaign", + "column_utm_term": "UTM term", + "column_utm_content": "UTM content", + "column_countries": "Countries", + "column_regions": "Regions", + "column_cities": "Cities", + "column_browsers": "Browsers", + "column_brands": "Brands", + "column_oss": "OSs", + "column_devices": "Devices", + "column_browser_versions": "Browser versions", + "column_os_versions": "OS versions", + "column_models": "Models", + "column_referrers": "Referrers", + "column_referrer_names": "Referrer names", + "column_referrer_types": "Referrer types", + "column_utm_sources": "UTM sources", + "column_utm_mediums": "UTM mediums", + "column_utm_campaigns": "UTM campaigns", + "column_utm_terms": "UTM terms", + "column_utm_contents": "UTM contents", + "and_more_items": "and {{count}} more items" + }, + "reports": { + "page_title": "Reports", + "report": "Report", + "success": "Success", + "report_updated": "Report updated.", + "update": "Update", + "save": "Save", + "available_charts": "Available charts", + "available_metrics": "Available metrics", + "custom_dates": "Custom dates", + "duplicate": "Duplicate", + "delete": "Delete", + "settings": "Settings", + "compare_to_previous_period": "Compare to previous period", + "criteria": "Criteria", + "select_criteria": "Select criteria", + "criteria_on_or_after": "On or After", + "criteria_on": "On", + "unit": "Unit", + "unit_count": "Count", + "funnel_group": "Funnel Group", + "default_session": "Default: Session", + "session": "Session", + "profile": "Profile", + "funnel_window": "Funnel Window", + "default_24h": "Default: 24h", + "mode": "Mode", + "select_mode": "Select mode", + "mode_after": "After", + "mode_before": "Before", + "mode_between": "Between", + "steps": "Steps", + "default_5": "Default: 5", + "exclude_events": "Exclude Events", + "select_events_to_exclude": "Select events to exclude", + "include_events": "Include events", + "leave_empty_to_include_all": "Leave empty to include all", + "stack_series": "Stack series", + "metrics": "Metrics", + "formula_placeholder": "eg: A+B", + "hide_series_from_chart": "Hide series {{series}} from chart", + "select_event": "Select event", + "display_name": "Display name", + "add_formula": "Add Formula", + "add_filter": "Add filter", + "property_value": "Property: {{property}}", + "select_property": "Select property", + "breakdown": "Breakdown", + "cohorts": "Cohorts", + "select_breakdown": "Select breakdown", + "global_filters": "Global filters", + "global_filters_description": "Applied to every series in this report.", + "done": "Done", + "invalid_number": "Not a valid number", + "invalid_date": "Not a valid date", + "invalid_boolean": "Use \"true\" or \"false\"", + "yes": "Yes", + "no": "No", + "yes_no": "Yes / No", + "select": "Select...", + "in_cohort": "In cohort", + "not_in_cohort": "Not in cohort", + "operator": "Operator", + "select_cohorts": "Select cohorts...", + "value_type": "Value type", + "share": "Share", + "pick_events": "Pick events", + "unnamed_report": "Unnamed Report", + "search": "Search", + "session_bounced": "Bounced", + "session_bounced_description": "Single-pageview session", + "session_screen_views": "Screen views", + "session_screen_views_description": "Number of screen views in the session", + "session_events": "Events", + "session_events_description": "Total events in the session", + "session_duration": "Duration", + "session_duration_description": "Session length in milliseconds", + "session_revenue": "Revenue", + "session_revenue_description": "Revenue attributed to the session", + "session_performed_event": "Performed event", + "session_performed_event_description": "Session contains an event named X", + "event_properties": "Event properties", + "profile_properties": "Profile properties", + "group_properties": "Group properties", + "all_cohorts": "All cohorts", + "session_metrics": "Session metrics" + }, + "report_chart": { + "start_here": "Start here", + "ready_when_you_are": "Ready when you're", + "pick_event_to_start": "Pick at least one event to start visualizing", + "no_data": "No data", + "chart_load_error": "There was an error loading this chart.", + "loading_slow": "Stay calm, it's coming", + "search_placeholder": "Search...", + "grouped": "Grouped", + "flat": "Flat", + "unselect_all": "Unselect All", + "filter_by_name": "Filter by name", + "sort_count_high_low": "Count (High to Low)", + "sort_count_low_high": "Count (Low to High)", + "sort_name_a_z": "Name (A to Z)", + "sort_name_z_a": "Name (Z to A)", + "sort_percentage_high_low": "Percentage (High to Low)", + "sort_percentage_low_high": "Percentage (Low to High)", + "date": "Date", + "total_profiles": "Total profiles", + "retention_rate": "Retention Rate", + "retained_users": "Retained Users", + "total_users": "Total Users", + "select_two_events": "Select 2 events", + "retention_requires_two_events": "We need two events to determine the retention rate.", + "conversion": "Conversion", + "serie": "Serie", + "avg_rate": "Avg Rate", + "total": "Total", + "conversions": "Conversions", + "view_users": "View Users", + "add_reference": "Add Reference", + "summary_flow": "Flow", + "summary_average_conversion_rate": "Average conversion rate", + "summary_total_conversions": "Total conversions", + "summary_previous_average_conversion_rate": "Previous period average conversion rate", + "summary_previous_total_conversions": "Previous period total conversions", + "summary_best_breakdown_average": "Best breakdown (avg)", + "summary_worst_breakdown_average": "Worst breakdown (avg)", + "summary_breakdown_with_rate": "{{breakdown}} with {{rate}}", + "summary_best_conversion_rate": "Best conversion rate", + "summary_worst_conversion_rate": "Worst conversion rate", + "summary_rate_on_breakdown_at_date": "{{rate}} on {{breakdown}} at {{date}}", + "summary_rate_at_date": "{{rate}} at {{date}}", + "completed": "Completed", + "dropoff_hint": "dropped after this event. Improve this step and your conversion rate will likely increase.", + "most_dropoffs_after": "Most dropoffs after", + "event": "Event", + "dropped_after": "Dropped after", + "view_users_completed_step": "View users who completed this step", + "current": "Current", + "previous": "Previous", + "improvement": "Improvement", + "decline": "Decline", + "no_change": "No change" + } +} diff --git a/apps/start/src/i18n/resources/zh-CN.json b/apps/start/src/i18n/resources/zh-CN.json new file mode 100644 index 000000000..a687ff827 --- /dev/null +++ b/apps/start/src/i18n/resources/zh-CN.json @@ -0,0 +1,1822 @@ +{ + "common": { + "language": "语言", + "loading": "加载中", + "theme": "主题", + "profile": "个人资料", + "account": "账号", + "logout": "退出登录", + "go_home": "回到首页", + "go_back_home": "返回首页", + "or": "或", + "cancel": "取消", + "continue": "继续", + "save": "保存", + "delete": "删除" + }, + "sidebar": { + "docs": "文档", + "support_us": "支持我们", + "pay_what_you_want": "随心赞助", + "organization": "组织", + "analytics": "分析", + "manage": "管理", + "overview": "概览", + "dashboards": "看板", + "insights": "洞察", + "pages": "页面", + "seo": "SEO", + "realtime": "实时", + "events": "事件", + "sessions": "会话", + "profiles": "用户档案", + "groups": "分组", + "cohorts": "群组", + "settings": "设置", + "references": "引用", + "notifications": "通知", + "back_to_workspace": "返回工作区", + "projects": "项目", + "billing": "账单", + "members": "成员", + "integrations": "集成", + "give_feedback": "反馈", + "open_ai_chat": "打开 AI 对话", + "action_create_report": "创建报告", + "action_create_reference": "创建引用", + "action_ask_ai": "询问 AI", + "action_create_dashboard": "创建看板", + "action_create_notification_rule": "创建通知规则", + "action_create_project": "创建项目", + "action_invite_user": "邀请用户", + "action_add_integration": "添加集成" + }, + "errors": { + "no_access": "无访问权限", + "something_went_wrong": "出了点问题", + "page_not_found": "页面不存在", + "page_not_found_description": "你要访问的页面不存在或已经移动。" + }, + "auth": { + "sign_in": "登录", + "no_account": "还没有账号?", + "create_one_today": "立即创建", + "error": "错误", + "correlation_id": "关联 ID:{{id}}", + "contact_support": "如果遇到问题,请联系我们。", + "self_hosted_analytics": "自托管分析", + "open_panel_cloud": "OpenPanel 云服务", + "mixpanel_alternative": "Mixpanel 替代方案", + "posthog_alternative": "PostHog 替代方案", + "open_source_analytics": "开源分析", + "email": "邮箱", + "password": "密码", + "first_name": "名字", + "last_name": "姓氏", + "confirm_password": "确认密码", + "new_password": "新密码", + "sign_in_with_google": "使用 Google 登录", + "sign_up_with_google": "使用 Google 注册", + "sign_in_with_github": "使用 GitHub 登录", + "sign_up_with_github": "使用 GitHub 注册", + "used_last_time": "上次使用", + "successfully_signed_in": "登录成功", + "successfully_signed_up": "注册成功", + "forgot_password": "忘记密码?", + "create_account": "创建账号", + "reset_password": "重置密码", + "reset_your_password": "重置你的密码", + "password_reset_successfully": "密码重置成功", + "already_have_account": "已有账号?", + "missing_reset_password_token": "缺少重置密码令牌", + "two_factor_authentication": "双重身份验证", + "totp_description": "请输入身份验证器应用中的 6 位验证码。", + "recovery_code_description": "请输入一个恢复代码。每个代码只能使用一次。", + "verify": "验证", + "signed_in": "已登录", + "use_recovery_code": "改用恢复代码", + "use_authenticator_app": "改用身份验证器应用", + "sign_in_with_different_account": "使用其他账号登录", + "start_tracking": "几分钟内开始追踪", + "accept_terms_prefix": "创建账号即表示你接受", + "terms_of_service": "服务条款", + "terms_connector": "和", + "privacy_policy": "隐私政策", + "invitation_to": "加入 {{organization}} 的邀请", + "invitation_description": "创建账号后,你会被加入该组织。", + "invitation_expired": "加入 {{organization}} 的邀请已过期", + "invitation_expired_description": "该邀请已过期。请联系组织所有者获取新的邀请。", + "trial_benefits": "无需信用卡 · 免费试用 30 天 · 可随时取消", + "sign_up_with_email": "使用邮箱注册", + "incorrect_password": "密码错误", + "share_locked_title": "{{type}} 已锁定", + "share_password_description": "请输入正确密码以访问此{{type}}", + "share_type_overview": "概览", + "share_type_dashboard": "看板", + "share_type_report": "报告", + "enter_password": "输入你的密码", + "get_access": "获取访问权限", + "request_password_reset": "请求重置密码", + "your_email_address": "你的邮箱地址", + "reset_email_sent": "你很快会收到一封邮件!", + "login_panel_alternative_title": "最佳开源替代方案", + "login_panel_alternative_description": "Mixpanel 太贵,Google Analytics 隐私不足,Amplitude 陈旧乏味。", + "login_panel_reliable_title": "快速且可靠", + "login_panel_reliable_description": "通过实时分析掌握每一次变化。", + "login_panel_simple_title": "简单易用", + "login_panel_simple_description": "相比其他工具,我们把体验保持得足够简单。", + "login_panel_privacy_title": "默认保护隐私", + "login_panel_privacy_description": "我们从一开始就把隐私作为平台核心。", + "login_panel_open_source_title": "开源", + "login_panel_open_source_description": "你可以检查代码,也可以选择自托管。" + }, + "chat": { + "new_chat": "新对话", + "conversations": "对话", + "no_conversations": "还没有对话。开始输入即可创建。", + "untitled_chat": "未命名对话", + "new_conversation": "新建对话", + "close_chat": "关闭对话", + "confirm_delete": "确认删除", + "delete_conversation": "删除对话", + "click_again_to_confirm": "再次点击以确认", + "delete": "删除", + "ask_anything_placeholder": "询问任何关于数据的问题...", + "ask_ai_placeholder": "向 AI 提问...", + "send_to_ai": "发送给 AI", + "keyboard_shortcut": "键盘快捷键:Cmd+J", + "stop_generating": "停止生成", + "send_message": "发送消息", + "thinking": "正在思考...", + "generic_error": "出现了问题。请重试。", + "scroll_to_bottom": "滚动到底部", + "latest": "最新", + "tool_failed": "工具执行失败", + "thought": "思考过程", + "ai_not_configured": "尚未配置 AI 对话", + "ai_not_configured_setup_prefix": "请在 API 服务中设置", + "ai_not_configured_setup_between": "和/或", + "ai_not_configured_setup_suffix": "以启用 AI 对话,然后重启服务。", + "ai_not_configured_description": "模型选择器只会显示已配置密钥的提供商。", + "view_setup_docs": "查看配置文档", + "empty_no_context_headline": "询问你的数据", + "empty_no_context_description": "我可以回答分析数据相关问题、生成报告,并深入查看用户、会话或页面。", + "empty_no_context_prompt_what_happened_yesterday": "昨天发生了什么?", + "empty_no_context_prompt_last_seven_days_traffic": "显示最近 7 天的流量", + "empty_no_context_prompt_highest_bounce_rate": "哪些页面跳出率最高?", + "empty_overview_headline": "询问此概览", + "empty_overview_description": "我可以解释趋势、对比周期或筛选页面。直接提问,或选择一个起始问题。", + "empty_overview_prompt_compare_previous_period": "与上一周期相比有什么变化?", + "empty_overview_prompt_filter_mobile_only": "仅筛选移动端", + "empty_overview_prompt_last_seven_days_traffic": "显示最近 7 天的流量", + "empty_overview_prompt_top_referrers": "哪些来源带来了最多会话?", + "empty_insights_headline": "探索你的洞察", + "empty_insights_description": "我可以解释洞察触发原因、查找相关洞察,或带你查看最重要的内容。", + "empty_insights_prompt_most_important": "当前最重要的洞察有哪些?", + "empty_insights_prompt_biggest_anomaly": "解释本周最大的异常", + "empty_insights_prompt_device_trends": "有没有与设备趋势相关的洞察?", + "empty_pages_headline": "询问你的页面", + "empty_pages_description": "我可以按表现排序页面、找出下滑页面,或识别入口和退出模式。", + "empty_pages_prompt_declining_pages": "哪些页面相比上月在下滑?", + "empty_pages_prompt_highest_bounce_rate": "显示跳出率最高的页面", + "empty_pages_prompt_top_entry_pages": "最近 7 天的主要入口页", + "empty_pages_prompt_underperforming_seo": "找出 SEO 表现不佳的页面", + "empty_seo_headline": "深入分析 SEO", + "empty_seo_description": "我可以找出高机会查询、检查关键词内耗,并关联 SEO 与站内互动。", + "empty_seo_prompt_page_two_queries": "曝光高但位于第 2 页的查询(容易优化)", + "empty_seo_prompt_query_cannibalization": "有没有需要修复的查询内耗?", + "empty_seo_prompt_gsc_clicks_bounce_hard": "哪些页面带来 GSC 点击但跳出很高?", + "empty_seo_prompt_top_seo_queries": "最近 30 天的热门 SEO 查询", + "empty_events_headline": "分析你的事件", + "empty_events_description": "我可以分析分布、关联事件,并深入查看属性。", + "empty_events_prompt_events_together": "哪些事件经常一起发生?", + "empty_events_prompt_distribution_by_country": "按国家分析事件分布", + "empty_events_prompt_signup_events_only": "只筛选注册事件", + "empty_events_prompt_common_properties": "最常见的事件属性有哪些?", + "empty_profile_detail_headline": "询问此用户", + "empty_profile_detail_description": "我可以总结此用户档案、构建用户旅程,或将其与平均用户对比。", + "empty_profile_detail_prompt_user_journey": "告诉我这个用户的旅程", + "empty_profile_detail_prompt_compare_average": "此用户与平均水平相比如何?", + "empty_profile_detail_prompt_last_session": "他的最后一次会话是什么?", + "empty_profile_detail_prompt_unusual_behavior": "他有没有异常行为?", + "empty_session_detail_headline": "询问此会话", + "empty_session_detail_description": "我可以梳理访问路径、对比典型会话,或解释来源上下文。", + "empty_session_detail_prompt_walk_through": "带我浏览这个会话", + "empty_session_detail_prompt_compare_typical": "这与典型会话相比如何?", + "empty_session_detail_prompt_traffic_source": "这些流量来自哪里?", + "empty_session_detail_prompt_similar_sessions": "今天还有类似会话吗?", + "empty_group_detail_headline": "询问此分组", + "empty_group_detail_description": "我可以展示指标、列出成员,并与相似分组对比。", + "empty_group_detail_prompt_summarize_activity": "总结此分组的活动", + "empty_group_detail_prompt_compare_groups": "与其他分组对比", + "empty_group_detail_prompt_active_members": "最活跃的成员是谁?", + "empty_group_detail_prompt_engagement_trend": "此分组的互动趋势如何?", + "empty_report_editor_headline": "和我一起编辑此报告", + "empty_report_editor_description": "我可以预览更改、建议拆分维度,或与上一周期对比。", + "empty_report_editor_prompt_useful_breakdowns": "为此报告建议有用的拆分维度", + "empty_report_editor_prompt_compare_previous_period": "与上一周期对比", + "empty_report_editor_prompt_find_anomalies": "查找当前数据中的异常", + "empty_report_editor_prompt_country_breakdown": "添加国家拆分", + "empty_dashboard_headline": "询问此看板", + "empty_dashboard_description": "我可以一次性总结看板上的所有报告、标记变化,或深入查看单个图表。", + "empty_dashboard_prompt_summarize_dashboard": "总结此看板", + "empty_dashboard_prompt_underperforming": "这里哪些表现不佳?", + "empty_dashboard_prompt_compare_previous_period": "将此看板与上一周期对比", + "empty_dashboard_prompt_biggest_change": "哪份报告变化最大?", + "empty_default_context_headline": "询问你的数据", + "empty_default_context_description": "我可以回答你正在查看页面的相关问题、生成报告,并深入查看特定用户、会话或页面。", + "empty_default_context_prompt_visitor_count": "本周访客数是多少?", + "empty_default_context_prompt_top_traffic_sources": "当前主要流量来源", + "empty_default_context_prompt_top_pages_bounce_rate": "按跳出率显示热门页面", + "tool_working": "正在处理", + "tool_result_empty": "无结果。", + "tool_result_view_raw_output": "查看原始输出", + "tool_result_item_count_one": "{{count}} 项", + "tool_result_item_count_other": "{{count}} 项", + "table_showing_limited_rows": "显示 {{shown}} / {{total}} 条", + "table_truncated_suffix": "(已截断)", + "ui_apply_date_range_summary": "日期范围:{{value}}", + "ui_apply_interval_summary": "间隔:{{value}}", + "ui_apply_filters_summary": "筛选条件", + "ui_apply_applied_summary": "已应用 {{summary}}", + "ui_apply_cleared_property_filters": "已清除属性筛选", + "ui_apply_applied_filters": "已应用筛选:{{summary}}", + "ui_apply_cleared_event_filter": "已清除事件名称筛选", + "ui_apply_filtered_events_one": "已筛选到事件:{{names}}", + "ui_apply_filtered_events_other": "已筛选到事件:{{names}}", + "tool_fallback_verb_list": "正在查找", + "tool_fallback_verb_get": "正在加载", + "tool_fallback_verb_find": "正在查找", + "tool_fallback_verb_query": "正在查询", + "tool_fallback_verb_analyze": "正在分析", + "tool_fallback_verb_compare": "正在对比", + "tool_fallback_verb_correlate": "正在关联", + "tool_fallback_verb_explain": "正在解释", + "tool_fallback_verb_suggest": "正在建议", + "tool_fallback_verb_preview": "正在预览", + "tool_fallback_verb_generate": "正在生成", + "tool_fallback_verb_apply": "正在应用", + "tool_fallback_verb_set": "正在更新", + "tool_fallback_verb_gsc": "正在加载 SEO", + "tool_fallback_verb_running": "正在运行", + "tool_list_event_names_active": "正在查找事件名称", + "tool_list_event_names_done": "事件名称", + "tool_list_event_properties_active": "正在查找属性", + "tool_list_event_properties_done": "事件属性", + "tool_get_event_property_values_active": "正在加载属性值", + "tool_get_event_property_values_done": "属性值", + "tool_list_dashboards_active": "正在加载看板", + "tool_list_dashboards_done": "看板", + "tool_list_reports_active": "正在加载报告", + "tool_list_reports_done": "报告", + "tool_get_report_data_active": "正在运行报告", + "tool_get_report_data_done": "报告", + "tool_generate_report_active": "正在生成报告", + "tool_generate_report_done": "报告", + "tool_get_analytics_overview_active": "正在加载概览", + "tool_get_analytics_overview_done": "概览", + "tool_get_top_pages_active": "正在加载热门页面", + "tool_get_top_pages_done": "热门页面", + "tool_get_top_referrers_active": "正在加载热门来源", + "tool_get_top_referrers_done": "热门来源", + "tool_get_country_breakdown_active": "正在加载地理拆分", + "tool_get_country_breakdown_done": "地理拆分", + "tool_get_device_breakdown_active": "正在加载设备拆分", + "tool_get_device_breakdown_done": "设备拆分", + "tool_get_rolling_active_users_active": "正在加载活跃用户", + "tool_get_rolling_active_users_done": "活跃用户", + "tool_get_funnel_active": "正在构建漏斗", + "tool_get_funnel_done": "漏斗", + "tool_get_retention_cohort_active": "正在构建留存群组", + "tool_get_retention_cohort_done": "留存", + "tool_get_user_flow_active": "正在构建用户流", + "tool_get_user_flow_done": "用户流", + "tool_query_events_active": "正在查询事件", + "tool_query_events_done": "事件", + "tool_query_sessions_active": "正在查询会话", + "tool_query_sessions_done": "会话", + "tool_find_profiles_active": "正在查找用户档案", + "tool_find_profiles_done": "用户档案", + "tool_get_profile_full_active": "正在加载用户档案", + "tool_get_profile_full_done": "用户档案", + "tool_get_profile_events_active": "正在加载用户事件", + "tool_get_profile_events_done": "用户事件", + "tool_get_profile_sessions_active": "正在加载用户会话", + "tool_get_profile_sessions_done": "用户会话", + "tool_get_profile_metrics_active": "正在加载用户指标", + "tool_get_profile_metrics_done": "用户指标", + "tool_get_profile_journey_active": "正在加载用户旅程", + "tool_get_profile_journey_done": "用户旅程", + "tool_get_profile_groups_active": "正在加载用户分组", + "tool_get_profile_groups_done": "用户分组", + "tool_compare_profile_to_average_active": "正在与平均水平对比", + "tool_compare_profile_to_average_done": "用户对比", + "tool_get_session_full_active": "正在加载会话", + "tool_get_session_full_done": "会话", + "tool_get_session_path_active": "正在加载会话路径", + "tool_get_session_path_done": "会话路径", + "tool_get_session_events_active": "正在加载会话事件", + "tool_get_session_events_done": "会话事件", + "tool_get_similar_sessions_active": "正在查找相似会话", + "tool_get_similar_sessions_done": "相似会话", + "tool_compare_session_to_typical_active": "正在与典型会话对比", + "tool_compare_session_to_typical_done": "会话对比", + "tool_get_session_referrer_context_active": "正在加载来源上下文", + "tool_get_session_referrer_context_done": "来源上下文", + "tool_get_session_replay_summary_active": "正在加载会话回放", + "tool_get_session_replay_summary_done": "会话回放", + "tool_get_page_performance_active": "正在加载页面表现", + "tool_get_page_performance_done": "页面表现", + "tool_get_page_conversions_active": "正在加载页面转化", + "tool_get_page_conversions_done": "页面转化", + "tool_get_entry_exit_pages_active": "正在加载入口/退出页面", + "tool_get_entry_exit_pages_done": "入口/退出页面", + "tool_find_declining_pages_active": "正在查找下滑页面", + "tool_find_declining_pages_done": "下滑页面", + "tool_gsc_get_overview_active": "正在加载 SEO 概览", + "tool_gsc_get_overview_done": "SEO 概览", + "tool_gsc_get_top_queries_active": "正在加载热门查询", + "tool_gsc_get_top_queries_done": "热门查询", + "tool_gsc_get_top_pages_active": "正在加载热门 SEO 页面", + "tool_gsc_get_top_pages_done": "热门 SEO 页面", + "tool_gsc_get_query_details_active": "正在加载查询详情", + "tool_gsc_get_query_details_done": "查询详情", + "tool_gsc_get_page_details_active": "正在加载页面详情", + "tool_gsc_get_page_details_done": "页面详情", + "tool_gsc_get_query_opportunities_active": "正在查找查询机会", + "tool_gsc_get_query_opportunities_done": "查询机会", + "tool_gsc_get_cannibalization_active": "正在检查关键词内耗", + "tool_gsc_get_cannibalization_done": "关键词内耗", + "tool_correlate_seo_with_traffic_active": "正在关联 SEO 与流量", + "tool_correlate_seo_with_traffic_done": "SEO/流量关联", + "tool_analyze_event_distribution_active": "正在分析事件分布", + "tool_analyze_event_distribution_done": "事件分布", + "tool_correlate_events_active": "正在关联事件", + "tool_correlate_events_done": "事件关联", + "tool_get_event_property_distribution_active": "正在加载属性分布", + "tool_get_event_property_distribution_done": "属性分布", + "tool_list_properties_for_event_active": "正在加载属性", + "tool_list_properties_for_event_done": "事件属性", + "tool_list_insights_active": "正在加载洞察", + "tool_list_insights_done": "洞察", + "tool_explain_insight_active": "正在加载洞察", + "tool_explain_insight_done": "洞察", + "tool_find_related_insights_active": "正在查找相关洞察", + "tool_find_related_insights_done": "相关洞察", + "tool_get_group_full_active": "正在加载分组", + "tool_get_group_full_done": "分组", + "tool_get_group_members_active": "正在加载分组成员", + "tool_get_group_members_done": "分组成员", + "tool_get_group_events_active": "正在加载分组事件", + "tool_get_group_events_done": "分组事件", + "tool_get_group_metrics_active": "正在加载分组指标", + "tool_get_group_metrics_done": "分组指标", + "tool_compare_groups_active": "正在对比分组", + "tool_compare_groups_done": "分组对比", + "tool_preview_report_with_changes_active": "正在预览更改", + "tool_preview_report_with_changes_done": "报告预览", + "tool_suggest_breakdowns_active": "正在建议拆分维度", + "tool_suggest_breakdowns_done": "拆分建议", + "tool_compare_to_previous_period_active": "正在与上一周期对比", + "tool_compare_to_previous_period_done": "周期对比", + "tool_find_anomalies_in_current_report_active": "正在查找异常", + "tool_find_anomalies_in_current_report_done": "异常", + "tool_explain_filter_impact_active": "正在分析筛选影响", + "tool_explain_filter_impact_done": "筛选影响", + "tool_apply_filters_active": "正在应用日期范围", + "tool_apply_filters_done": "日期范围已更新", + "tool_set_property_filters_active": "正在应用筛选", + "tool_set_property_filters_done": "筛选已更新", + "tool_set_event_names_filter_active": "正在应用事件筛选", + "tool_set_event_names_filter_done": "事件筛选已更新", + "tool_list_references_active": "正在加载引用", + "tool_list_references_done": "引用", + "tool_get_references_around_active": "正在检查此日期附近的引用", + "tool_get_references_around_done": "附近引用", + "resize_drawer": "调整对话抽屉宽度", + "select_model": "选择模型", + "result_no_profile": "无用户档案", + "result_profile": "用户档案", + "result_sessions": "会话", + "result_total_events": "事件总数", + "result_avg_session": "平均会话", + "result_minutes": "{{value}} 分钟", + "result_bounce_rate": "跳出率", + "result_revenue": "收入", + "result_open_profile": "打开用户档案 →", + "result_no_data": "无数据", + "result_report": "报告", + "result_no_renderable_report_config": "报告返回了数据,但没有可渲染配置。", + "result_chart_report_title": "{{chart}}报告", + "result_open_in_dashboard": "在看板中打开 →", + "result_funnel_title": "漏斗:{{steps}}", + "result_day_active_users": "{{count}} 天活跃用户", + "result_active_users_title": "{{label}} — 最近 {{count}} 天", + "result_chart_type_linear": "折线图", + "result_chart_type_bar": "柱状图", + "result_chart_type_area": "面积图", + "result_chart_type_pie": "饼图", + "result_chart_type_funnel": "漏斗", + "result_chart_type_metric": "指标", + "result_chart_type_retention": "留存", + "result_chart_type_histogram": "直方图", + "result_chart_type_sankey": "桑基图", + "result_chart_type_map": "地图", + "result_chart_type_conversion": "转化" + }, + "ui": { + "click_to_copy": "点击复制", + "copied_to_clipboard": "已复制到剪贴板", + "error_title": "错误...", + "error_description": "出现了问题...", + "fetching": "正在获取...", + "fetching_description": "请稍候,正在获取你的数据...", + "toggle_fullscreen": "切换全屏", + "exit_full_screen": "退出全屏", + "json_editor_invalid_json_syntax": "JSON 语法无效", + "json_editor_invalid_syntax": "{{language}} 无效。请检查语法。", + "powered_by": "由", + "try_it_for_free_today": "今天免费试用!", + "time_window": "时间窗口", + "time_window_30min": "最近 30 分钟", + "time_window_last_hour": "最近 1 小时", + "time_window_last_24h": "最近 24 小时", + "time_window_today": "今天", + "time_window_yesterday": "昨天", + "time_window_7d": "最近 7 天", + "time_window_30d": "最近 30 天", + "time_window_3m": "最近 3 个月", + "time_window_6m": "最近 6 个月", + "time_window_12m": "最近 12 个月", + "time_window_month_to_date": "本月至今", + "time_window_last_month": "上个月", + "time_window_year_to_date": "今年至今", + "time_window_last_year": "去年", + "time_window_custom": "自定义", + "last_days": "最近天数", + "custom_date_filter_days_aria_label": "自定义日期筛选的天数", + "x_days": "X 天", + "no_match": "无匹配项", + "search_item": "搜索项目...", + "search": "搜索", + "create_value": "创建“{{value}}”", + "pick_value": "选择“{{value}}”", + "nothing_selected": "未选择任何项", + "search_event": "搜索事件...", + "any_events": "任意事件", + "command_palette": "命令面板", + "command_palette_description": "搜索要运行的命令..." + }, + "clients": { + "field_client_id": "客户端 ID", + "field_secret": "密钥", + "field_mcp_token": "MCP 令牌", + "secret_help": "只有在发送服务端事件时才需要使用密钥。", + "mcp_token_help": "使用此令牌向 MCP 服务器进行身份验证(客户端 ID 和密钥的 base64 编码)。", + "action_save_credentials": "保存凭证", + "get_started_title": "开始使用!", + "get_started_read_our": "阅读我们的", + "get_started_suffix": "开始接入。很简单!", + "column_name": "名称", + "column_created_at": "创建时间", + "revoke_success_title": "成功", + "revoke_success_description": "客户端已撤销,传入请求将被拒绝。", + "action_copy_client_id": "复制客户端 ID", + "action_edit": "编辑", + "action_revoke": "撤销", + "revoke_confirm_title": "撤销客户端", + "revoke_confirm_description": "确定要撤销此客户端吗?此操作无法撤销。" + }, + "integrations": { + "slack_name": "Slack", + "slack_description": "当 OpenPanel 中发生重要事件时,在 Slack 中接收通知。", + "slack_logo_alt": "Slack 标志", + "discord_name": "Discord", + "discord_description": "将 OpenPanel 通知发送到 Discord 频道。", + "discord_logo_alt": "Discord 标志", + "webhook_name": "Webhook", + "webhook_description": "将 OpenPanel 事件发送到任意 HTTP 端点。", + "action_connect": "连接", + "action_create": "创建", + "action_update": "更新", + "action_delete": "删除", + "action_edit": "编辑", + "action_test_connection": "测试连接", + "action_add_header": "添加请求头", + "status_connected": "已连接", + "empty_installed_title": "还没有集成", + "empty_installed_description": "集成可将你的系统连接到 OpenPanel。你可以在可用集成区域中添加。", + "delete_confirm_title": "删除 {{name}}?", + "delete_confirm_description": "此操作无法撤销。", + "modal_title": "创建集成", + "success_integration_saved": "集成已保存", + "success_test_notification_sent": "测试通知已发送", + "error_create_failed": "创建集成失败", + "error_validation": "验证错误", + "error_webhook_url_required": "Webhook URL 为必填项", + "error_test_notification_failed": "发送测试通知失败", + "error_invalid_javascript_template": "无效的 JavaScript 模板", + "field_name": "名称", + "field_url": "URL", + "field_discord_webhook_url": "Discord Webhook URL", + "field_headers": "请求头", + "field_payload_format": "载荷格式", + "field_javascript_transform": "JavaScript 转换", + "slack_name_placeholder": "例如:我的个人 Slack", + "discord_name_placeholder": "例如:我的个人 Discord", + "webhook_name_placeholder": "例如:Zapier webhook", + "headers_help": "添加自定义 HTTP 请求头,并随 webhook 请求一起发送", + "header_name_placeholder": "请求头名称", + "header_value_placeholder": "请求头值", + "payload_format_help": "选择 webhook 载荷的格式化方式", + "payload_format_placeholder": "选择格式", + "payload_format_message": "消息", + "payload_format_javascript": "JavaScript", + "javascript_transform_help": "编写一个用于转换事件载荷的 JavaScript 函数。该函数接收 payload 作为参数,并应返回一个对象。", + "available_payload_title": "payload 中可用:", + "payload_name_description": "事件名称", + "payload_profile_id_description": "用户档案 ID", + "payload_properties_description": "完整属性对象", + "payload_nested_property_description": "嵌套属性值", + "payload_profile_property_description": "用户档案属性", + "payload_more_fields": "以及更多...", + "available_helpers_title": "可用辅助对象:", + "example_title": "示例:", + "security_title": "安全:", + "security_description": "网络调用、文件系统访问和其他危险操作已被阻止。", + "page_title": "集成", + "page_description": "在这里管理你的集成", + "tab_installed": "已安装", + "tab_available": "可用" + }, + "cohorts": { + "add_event_criteria": "添加事件条件", + "add_property_filter": "添加属性筛选", + "all": "全部", + "all_of_these_events": "匹配所有这些事件", + "all_of_these_properties": "匹配所有这些属性", + "any": "任一", + "any_of_these_events": "匹配任一这些事件", + "any_of_these_properties": "匹配任一这些属性", + "at_least": "至少", + "at_most": "至多", + "between": "介于", + "capped_notice": "成员数上限为 10,000,请考虑缩小条件范围。", + "cohort": "群组", + "cohort_deleted": "群组已删除。", + "cohort_refresh_queued": "群组刷新已排队。", + "create_cohort": "创建群组", + "created": "创建时间", + "delete": "删除", + "delete_cohort": "删除群组", + "delete_confirm_description": "确定要删除这个群组吗?此操作无法撤销。", + "delete_named_confirm_description": "确定要删除“{{name}}”吗?此操作无法撤销。", + "description": "根据事件和属性创建并管理用户分群", + "download": "下载", + "download_members_failed": "下载群组成员失败", + "edit": "编辑", + "empty_description": "你还没有为此项目创建任何群组", + "empty_title": "暂无群组", + "event": "事件", + "event_based": "基于事件", + "event_filters": "事件筛选", + "events": "事件", + "events_last_30_days": "过去 30 天事件({{count}})", + "exactly": "恰好", + "frequency": "频次", + "last": "最近", + "last_computed": "上次计算", + "match": "匹配", + "member_count_one": "{{count}} 位成员", + "member_count_other": "{{count}} 位成员", + "members": "成员", + "no_events_yet": "暂无事件", + "not_computed_notice": "此群组尚未完成计算。成员将在一分钟内显示。", + "not_found": "未找到群组", + "operator": "运算符", + "overview": "概览", + "period": "周期", + "period_180_days": "180 天", + "period_30_days": "30 天", + "period_365_days": "365 天", + "period_7_days": "7 天", + "period_90_days": "90 天", + "property_based": "基于属性", + "refresh": "刷新", + "select_event_placeholder": "选择事件...", + "since": "自", + "static": "静态", + "success": "成功", + "timeframe": "时间范围", + "times": "次", + "title": "群组", + "to": "至", + "type": "类型", + "updated_at": "更新于 {{date}}" + }, + "filters": { + "add_filter": "添加筛选", + "cohort": "群组", + "filters": "筛选", + "group_property": "用户组 · {{property}}", + "no": "否", + "pick_cohort": "选择群组", + "profile_property": "用户 · {{property}}", + "remove_filter": "移除筛选", + "session_bounced": "跳出", + "session_duration": "时长", + "session_events": "事件", + "session_performed_event": "执行过事件", + "session_revenue": "收入", + "session_screen_views": "屏幕浏览", + "yes": "是" + }, + "events": { + "page_title": "事件", + "page_description": "分页查看你的事件、转化和整体统计", + "tab_events": "事件", + "tab_conversions": "转化", + "tab_stats": "统计", + "column_created_at": "创建时间", + "column_name": "名称", + "column_profile": "用户档案", + "column_session_id": "会话 ID", + "column_device_id": "设备 ID", + "column_country": "国家", + "column_os": "操作系统", + "column_browser": "浏览器", + "column_groups": "分组", + "column_properties": "属性", + "screen_label": "页面:", + "visit_label": "访问:", + "route_name": "路由:{{path}}", + "unknown_profile": "未知", + "anonymous_profile": "匿名", + "more_properties_count_one": "还有 {{count}} 项", + "more_properties_count_other": "还有 {{count}} 项", + "empty_title": "暂无事件", + "empty_description": "开始发送事件后,它们会显示在这里", + "date_range": "日期范围", + "listening": "监听中", + "new_events_suffix": "个新事件", + "listening_to_new_events": "正在监听新事件", + "click_to_refresh": "点击刷新", + "all_events": "所有事件", + "events_per_day": "每日事件数", + "event_distribution": "事件分布" + }, + "groups": { + "page_title": "分组", + "page_description": "分组代表事件所属的公司、团队或其他实体。", + "group_page_title": "分组", + "group_events_title": "分组事件", + "group_members_title": "分组成员", + "add_group": "添加分组", + "all_types": "所有类型", + "empty_title": "未找到分组", + "empty_description": "分组代表事件所属的公司、团队或其他实体。", + "search_placeholder": "搜索分组...", + "column_name": "名称", + "column_id": "ID", + "column_type": "类型", + "column_members": "成员", + "column_last_active": "最后活跃", + "column_created": "创建时间", + "total_members": "总成员数", + "new_members_count": "+{{count}} 新增", + "new_members_last_30_days": "最近 30 天新增成员", + "no_data_yet": "暂无数据", + "tab_overview": "概览", + "tab_members": "成员", + "tab_events": "事件", + "group_not_found": "未找到分组", + "edit": "编辑", + "delete": "删除", + "delete_group": "删除分组", + "delete_group_confirm": "确定要删除“{{name}}”吗?此操作无法撤销。", + "total_events": "事件总数", + "unique_members": "唯一成员", + "first_seen": "首次出现", + "last_seen": "最后出现", + "group_information": "分组信息", + "field_id": "id", + "field_name": "name", + "field_type": "type", + "field_created_at": "createdAt" + }, + "settings": { + "project_not_found": "未找到项目", + "project_settings_title": "项目设置", + "project_settings_description": "在这里管理项目设置", + "tab_details": "详情", + "tab_events": "事件", + "tab_clients_api_keys": "客户端 / API 密钥", + "tab_tracking_script": "追踪脚本", + "tab_mcp": "MCP", + "tab_widgets": "小组件", + "tab_imports": "导入", + "tab_google_search": "Google 搜索", + "details_title": "详情", + "details_name_label": "名称", + "details_domain_label": "域名", + "details_allowed_domains_label": "允许的域名", + "details_add_domain_placeholder": "添加域名", + "details_allow_all_domains": "允许所有域名", + "details_cross_domain_label": "跨域支持", + "details_cross_domain_enable": "启用跨域支持", + "details_cross_domain_description": "这会让你可以跨多个域名追踪用户", + "details_revenue_tracking_label": "收入追踪", + "details_unsafe_revenue_enable": "允许“非安全”收入追踪", + "details_unsafe_revenue_description": "启用后,你可以从客户端代码追踪收入。", + "details_updated_toast": "项目已更新", + "details_domain_required": "请添加域名", + "details_cors_required": "请至少添加一个 CORS 域名", + "filters_title": "排除事件", + "filters_description": "通过添加筛选条件,排除不需要追踪的事件。", + "filters_select_event_placeholder": "选择事件名称...", + "filters_add_property_filter": "添加属性筛选", + "filters_ip_addresses_label": "IP 地址", + "filters_ip_addresses_placeholder": "排除 IP 地址", + "filters_profile_ids_label": "用户档案 ID", + "filters_profile_ids_placeholder": "排除用户档案 ID", + "filters_event_rules_label": "事件规则", + "filters_add_event_rule": "添加事件规则", + "filters_updated_toast": "项目筛选条件已更新", + "delete_account_title": "删除账号", + "delete_account_description": "删除账号会永久移除你的个人数据。你创建且没有其他管理员的组织也会被删除,包括其中的项目和事件。", + "delete_account_subscription_block_title": "请先取消订阅", + "delete_account_subscription_block_description": "你创建的这些组织有活跃订阅。删除账号前,请逐一取消:", + "delete_project_title": "删除项目", + "delete_project_description": "删除项目会将其从组织中移除,并删除所有相关数据。它会在 24 小时后被永久删除。", + "delete_project_scheduled_toast": "项目已安排删除", + "delete_project_cancelled_toast": "项目删除已取消", + "delete_project_scheduled_title": "项目已安排删除", + "delete_project_scheduled_prefix": "此项目将删除于", + "delete_project_scheduled_suffix": "与此项目相关的所有事件都会被删除。", + "delete_project_org_scheduled_notice": "整个组织已安排删除。若要保留此项目,请在组织设置中取消删除。", + "delete_project_cancel_button": "取消删除", + "delete_project_confirm_text": "确定要删除此项目吗?", + "delete_organization_title": "删除组织", + "delete_organization_description": "删除此组织会移除它以及所有项目和相关数据。它会在 24 小时后被永久删除。", + "delete_organization_cancelled_toast": "组织删除已取消", + "delete_organization_scheduled_title": "组织已安排删除", + "delete_organization_scheduled_prefix": "此组织将删除于", + "delete_organization_scheduled_suffix": "其中所有项目及其事件都会被删除。", + "delete_organization_subscription_block_title": "请先取消订阅", + "delete_organization_subscription_block_description": "此组织有活跃订阅。删除组织前,请先在账单设置中取消订阅。", + "invite_mail_column": "邮箱", + "invite_email_label": "邮箱", + "invite_search_email_placeholder": "搜索邮箱", + "invite_role_column": "角色", + "invite_created_column": "创建时间", + "invite_access_column": "访问权限", + "invite_revoked_toast": "{{email}} 的邀请已撤销", + "invite_revoke_failed_toast": "撤销 {{email}} 的邀请失败", + "invite_copy_link": "复制邀请链接", + "invite_revoke": "撤销邀请", + "invite_unknown_project": "未知", + "invite_all_projects": "所有项目", + "invite_user_button": "邀请用户", + "members_name_column": "姓名", + "members_email_column": "邮箱", + "members_search_email_placeholder": "搜索邮箱", + "members_role_column": "角色", + "members_created_column": "创建时间", + "members_access_column": "访问权限", + "members_all_projects": "所有项目", + "members_removed_toast": "{{name}} 已从组织中移除", + "members_remove_failed_toast": "从组织中移除 {{name}} 失败", + "members_edit_access": "编辑访问权限", + "members_remove_member": "移除成员", + "tracking_select_client_placeholder": "选择客户端", + "tracking_copy_button": "复制", + "tracking_framework_prompt": "或者选择下面的框架开始。", + "tracking_missing_framework": "缺少某个框架?", + "tracking_let_us_know": "告诉我们!", + "gsc_title": "Google Search Console", + "gsc_connect_description": "连接你的 Google Search Console 媒体资源,以导入搜索表现数据。", + "gsc_authorize_description": "你将被重定向到 Google 进行授权。我们只会请求 Search Console 数据的只读访问权限。", + "gsc_connect_button": "连接 Google Search Console", + "gsc_initiate_failed_toast": "无法发起 Google Search Console 连接", + "gsc_site_connected_toast": "站点已连接", + "gsc_backfill_started_toast": "已开始回填 6 个月的数据。", + "gsc_select_failed_toast": "选择站点失败", + "gsc_disconnected_toast": "已断开 Google Search Console 连接", + "gsc_disconnect_failed_toast": "断开连接失败", + "gsc_select_property_title": "选择媒体资源", + "gsc_select_property_description": "选择要连接到此项目的 Google Search Console 媒体资源。", + "gsc_no_properties": "此 Google 账号下没有找到 Search Console 媒体资源。", + "gsc_select_property_placeholder": "选择媒体资源...", + "gsc_connect_property_button": "连接媒体资源", + "gsc_cancel_button": "取消", + "gsc_connected_description": "已连接到 Google Search Console。", + "gsc_authorization_expired": "授权已过期", + "gsc_authorization_expired_description": "你的 Google Search Console 授权已过期或被撤销。请重新连接以继续同步数据。", + "gsc_reconnect_button": "重新连接 Google Search Console", + "gsc_disconnect_button": "断开连接", + "gsc_property_label": "媒体资源", + "gsc_backfill_label": "回填", + "gsc_last_synced_label": "上次同步", + "gsc_last_error_label": "上次错误", + "imports_deleted_toast": "导入已删除", + "imports_deleted_description": "导入已成功删除。", + "imports_retried_toast": "已重试导入", + "imports_retried_description": "导入已重新加入处理队列。", + "imports_import_data_button": "导入数据", + "imports_history_title": "导入历史", + "imports_provider_column": "提供方", + "imports_created_column": "创建时间", + "imports_status_column": "状态", + "imports_progress_column": "进度", + "imports_config_column": "配置", + "imports_actions_column": "操作", + "imports_empty_title": "还没有导入", + "imports_empty_description": "你的导入历史会显示在这里。", + "imports_estimated_events_tooltip": "事件数量为估算值,可能因提供方而不准确。", + "imports_config_badge": "配置", + "imports_retry_button": "重试", + "imports_delete_button": "删除", + "mcp_title": "MCP 服务器", + "mcp_description": "将任何兼容 MCP 的 AI 客户端(Claude、Cursor、Windsurf 等)连接到你的 OpenPanel 数据。服务器为只读,并提供 38 个工具用于查询事件、会话、用户档案、漏斗、留存等数据。", + "mcp_endpoint_label": "端点", + "mcp_token_help_prefix": "将", + "mcp_token_help_middle": "替换为", + "mcp_token_help_suffix": "你也可以把它作为", + "mcp_token_help_suffix_2": "请求头传入,而不是使用查询参数。", + "mcp_need_token_title": "需要令牌?", + "mcp_need_token_description_prefix": "只有", + "mcp_need_token_description_middle": "和", + "mcp_need_token_description_suffix": "客户端可以通过 MCP 认证。创建一个客户端,并从成功页面复制 MCP 令牌。它只会显示一次。", + "mcp_create_client_button": "创建 MCP 客户端", + "mcp_configure_client_title": "配置你的 AI 客户端", + "mcp_config_file_label": "配置文件:", + "mcp_read_docs_button": "阅读完整 MCP 文档", + "mcp_claude_desktop_description_prefix": "将以下配置块添加到", + "mcp_claude_desktop_description_suffix": "你可以从这里打开它:", + "mcp_claude_desktop_settings_path": "设置 → 开发者 → 编辑配置", + "mcp_claude_code_description_prefix": "在终端中运行一次。令牌也可以通过此请求头传入:", + "mcp_cursor_description_prefix": "将服务器添加到你的全局配置", + "mcp_cursor_description_suffix": "或项目配置", + "mcp_windsurf_description_prefix": "将服务器添加到", + "mcp_windsurf_description_suffix": "Windsurf 同时接受", + "mcp_vscode_description_prefix": "将服务器添加到工作区中的", + "mcp_vscode_description_suffix": ",或添加到你的用户级 MCP 配置。", + "mcp_raycast_description_prefix": "复制下面的 JSON,然后在 Raycast 中运行", + "mcp_raycast_install_server": "Install Server", + "mcp_raycast_description_suffix": "命令,它会从剪贴板自动填充表单。", + "widgets_enabled_toast": "小组件已启用", + "widgets_disabled_toast": "小组件已停用", + "widgets_update_failed_toast": "更新小组件失败", + "widgets_options_updated_toast": "小组件选项已更新", + "widgets_options_update_failed_toast": "更新选项失败", + "widgets_realtime_title": "实时小组件", + "widgets_realtime_description": "在你的网站上嵌入实时访客计数小组件。它会显示实时访客数、活动直方图、热门国家、来源和路径。", + "widgets_options_title": "小组件选项", + "widgets_show_referrers": "显示来源", + "widgets_show_countries": "显示国家", + "widgets_show_paths": "显示路径", + "widgets_url_title": "小组件 URL", + "widgets_realtime_url_description": "小组件的直接链接。你可以在新标签页打开,或将其嵌入。", + "widgets_embed_code_title": "嵌入代码", + "widgets_embed_code_description": "复制此代码,并粘贴到你希望显示小组件的网站 HTML 中。", + "widgets_preview_title": "预览", + "widgets_open_new_tab": "在新标签页打开", + "widgets_counter_title": "计数器小组件", + "widgets_counter_description": "一个可嵌入任意位置的紧凑实时访客计数徽章。显示当前唯一访客数,并带有实时指示器。", + "widgets_counter_url_description": "计数器小组件的直接链接。", + "widgets_badge_title": "Analytics 徽章", + "widgets_badge_description": "类似 Product Hunt 的徽章,显示你的 30 天唯一访客数。适合展示由 OpenPanel 提供支持的分析数据。", + "widgets_badge_url_description": "Analytics 徽章小组件的直接链接。", + "mcp_windsurf_url_connector": "和", + "widgets_realtime_preview_title": "实时小组件预览", + "widgets_counter_preview_title": "计数器小组件预览", + "widgets_badge_preview_title": "Analytics 徽章预览", + "imports_provider_umami_description": "从 Umami 导入你的分析数据", + "imports_provider_mixpanel_description": "从 Mixpanel API 导入你的分析数据", + "imports_provider_amplitude_description": "从 Amplitude 导出文件导入你的分析数据" + }, + "projects": { + "metric_three_month_diff": "3 个月差异", + "metric_revenue": "收入", + "metric_three_months": "3 个月", + "metric_thirty_days": "30 天", + "metric_twenty_four_hours": "24 小时", + "chart_sessions": "会话", + "chart_revenue": "收入", + "chart_no_activity_title": "还没有活动", + "chart_no_activity_description": "追踪开始后,会话会显示在这里。", + "projects": "项目", + "select_project": "选择项目", + "all_projects": "所有项目", + "create_new_project": "创建新项目", + "organizations": "组织", + "new_organization": "新建组织", + "project_mapper_optional": "项目映射(可选)", + "add_mapping": "添加映射", + "project_mapper_description": "将源项目 ID 映射到你的 OpenPanel 项目。如果跳过映射,所有数据都会导入当前项目。", + "project_mapper_from_label": "来源(源项目 ID)", + "project_mapper_from_placeholder": "例如:abc123", + "project_mapper_to_label": "目标(OpenPanel 项目)" + }, + "pages": { + "page_title": "页面", + "page_description": "在这里查看你的所有页面", + "search_placeholder": "搜索页面", + "empty_title": "暂无页面", + "empty_description": "将我们的 Web SDK 集成到你的网站后,页面数据会显示在这里。", + "empty_search_description": "没有找到匹配“{{search}}”的页面", + "column_page": "页面", + "column_trend": "趋势", + "column_views": "浏览量", + "column_sessions": "会话", + "column_bounce": "跳出", + "column_duration": "时长", + "column_impressions": "展示", + "column_ctr": "CTR", + "column_clicks": "点击", + "new_label": "新增", + "views_sessions": "浏览量与会话", + "trend_upward": "上升趋势", + "trend_downward": "下降趋势", + "trend_stable": "稳定趋势" + }, + "profiles": { + "page_title": "用户档案", + "page_description": "如果还没有调用 identify,你的用户档案会保持匿名", + "tab_identified": "已识别", + "tab_anonymous": "匿名", + "tab_power_users": "高活跃用户", + "search_placeholder": "搜索用户档案", + "filters_title": "用户档案筛选", + "empty_title": "暂无用户档案", + "empty_description": "看起来你还没有识别任何用户档案。", + "column_name": "名称", + "column_referrer": "来源", + "column_country": "国家/地区", + "column_os": "操作系统", + "column_browser": "浏览器", + "column_model": "型号", + "column_first_seen": "首次出现", + "column_last_seen": "最后出现", + "column_groups": "分组", + "column_events": "事件", + "most_visited_pages": "访问最多的页面", + "no_pages_visited_yet": "还没有访问过页面", + "popular_events": "热门事件", + "no_events_yet": "还没有事件", + "latest_events": "最新事件", + "all": "全部", + "activity": "活跃度", + "activity_events_count_one": "{{count}} 个事件", + "activity_events_count_other": "{{count}} 个事件", + "no_activity": "没有活动", + "groups": "分组", + "events": "事件", + "page_views": "页面浏览", + "events_per_day": "每日事件", + "metric_total_events": "总事件数", + "metric_sessions": "会话", + "metric_page_views": "页面浏览", + "metric_avg_events_per_session": "平均事件/会话", + "metric_bounce_rate": "跳出率", + "metric_session_duration_avg": "平均会话时长", + "metric_session_duration_p90": "P90 会话时长", + "metric_first_seen": "首次出现", + "metric_last_seen": "最后出现", + "metric_days_active": "活跃天数", + "metric_conversion_events": "转化事件", + "metric_avg_time_between_sessions": "平均会话间隔(小时)", + "metric_revenue": "收入", + "profile_information": "用户档案信息", + "tab_profile": "用户档案", + "tab_properties": "属性", + "yes": "是", + "no": "否", + "no_properties_found": "未找到属性" + }, + "sessions": { + "page_title": "会话", + "page_description": "在这里查看你的所有会话", + "search_placeholder": "按路径、来源搜索会话...", + "filters_title": "会话筛选", + "empty_title": "未找到会话", + "empty_description": "看起来你还没有写入任何事件。", + "column_started": "开始时间", + "column_session_id": "会话 ID", + "column_profile": "用户档案", + "column_entry_page": "入口页面", + "column_exit_page": "退出页面", + "column_duration": "时长", + "column_bounce": "跳出", + "column_referrer": "来源", + "column_location": "位置", + "column_os": "操作系统", + "column_browser": "浏览器", + "column_device": "设备", + "column_page_views": "页面浏览", + "column_events": "事件", + "column_revenue": "收入", + "column_device_id": "设备 ID", + "column_groups": "分组", + "view_replay": "查看回放", + "yes": "是", + "no": "否", + "detail_title": "会话:{{id}}", + "detail_visited_pages": "访问过的页面", + "detail_event_distribution": "事件分布", + "detail_session_info": "会话信息", + "detail_profile": "用户档案", + "detail_groups": "分组", + "detail_events": "事件", + "detail_no_events": "未找到事件", + "replay_pause": "暂停", + "replay_play": "播放", + "replay_timeline": "时间线", + "replay_events_empty": "事件会随着回放播放显示在这里。", + "replay_player_load_failed": "无法加载会话回放播放器。", + "replay_events_at_time_one": "{{time}} 有 {{count}} 个事件", + "replay_events_at_time_other": "{{time}} 有 {{count}} 个事件", + "replay_event_at_time": "{{event}} 在 {{time}}", + "exit_fullscreen": "退出全屏", + "enter_fullscreen": "进入全屏", + "loading_session_replay": "正在加载会话回放", + "no_replay_data": "此会话没有可用的回放数据。" + }, + "dashboards": { + "page_title": "仪表盘", + "page_description": "在这里查看你的所有仪表盘", + "dashboard": "仪表盘", + "empty_title": "暂无仪表盘", + "empty_description": "你还没有为这个项目创建任何仪表盘", + "create_dashboard": "创建仪表盘", + "force_delete": "强制删除", + "success": "成功", + "delete_success": "仪表盘已删除。", + "more": "更多", + "detail_description": "查看并管理你的报表", + "search_reports_placeholder": "搜索报表...", + "create_report": "创建报表", + "report": "报表", + "share_dashboard": "分享仪表盘", + "reset_layout": "重置布局", + "reset_layout_confirm": "确定要将布局重置为默认吗?这会清除所有自定义位置和尺寸。", + "delete_dashboard": "删除仪表盘", + "delete_dashboard_confirm": "确定要删除这个仪表盘吗?其中所有报表都会被删除!", + "no_reports_title": "暂无报表", + "no_reports_description": "你可以用报表来可视化数据", + "no_matching_reports_title": "没有匹配的报表", + "no_matching_reports_description": "没有报表匹配“{{search}}”。请尝试其他搜索。", + "report_delete_success": "报表已删除", + "report_duplicate_success": "报表已复制", + "layout_reset_success": "布局已重置为默认", + "edit": "编辑", + "delete": "删除" + }, + "insights": { + "page_title": "洞察", + "page_description": "发现分析数据中的趋势和变化", + "search_placeholder": "搜索洞察...", + "time_window_placeholder": "时间窗口", + "all_windows": "所有窗口", + "yesterday": "昨天", + "seven_days": "7 天", + "thirty_days": "30 天", + "severity_placeholder": "严重程度", + "all_severity": "所有严重程度", + "severe": "严重", + "moderate": "中等", + "low": "低", + "no_severity": "无严重程度", + "direction_placeholder": "方向", + "all_directions": "所有方向", + "increasing": "上升", + "decreasing": "下降", + "flat": "持平", + "sort_placeholder": "排序方式", + "sort_impact_high_low": "影响(高 → 低)", + "sort_impact_low_high": "影响(低 → 高)", + "sort_severity_high_low": "严重程度(高 → 低)", + "sort_severity_low_high": "严重程度(低 → 高)", + "sort_most_recent": "最新", + "empty_title": "未找到洞察", + "empty_filtered_description": "尝试调整筛选条件查看更多洞察。", + "empty_description": "检测到分析趋势后,洞察会显示在这里。", + "module_geo": "地理位置", + "module_devices": "设备", + "module_referrers": "来源", + "module_entry_pages": "入口页面", + "module_page_trends": "页面趋势", + "module_exit_pages": "退出页面", + "module_traffic_anomalies": "异常", + "metric_share": "占比", + "metric_pageviews": "页面浏览量", + "metric_sessions": "会话", + "count_one": "条洞察", + "count_other": "条洞察", + "showing_count": "显示 {{count}} / {{total}} 条洞察" + }, + "share": { + "not_found_title": "未找到分享", + "report_not_found_description": "你要查找的报表不存在。", + "dashboard_not_found_description": "你要查找的仪表盘不存在。", + "overview_not_found_description": "你要查找的概览不存在。", + "report": "报表", + "no_reports": "暂无报表" + }, + "seo": { + "page_title": "SEO", + "page_description": "Google Search Console 数据", + "empty_title": "暂无 SEO 数据", + "empty_description": "连接 Google Search Console 以跟踪搜索展示、点击和关键词排名。", + "connect_gsc": "连接 Google Search Console", + "performance_description": "{{siteUrl}} 的搜索表现", + "metric_clicks": "点击", + "metric_impressions": "展示", + "metric_avg_ctr": "平均 CTR", + "metric_avg_position": "平均排名", + "key_page": "页面", + "key_query": "查询", + "search_pages": "搜索页面", + "search_queries": "搜索查询", + "top_pages": "热门页面", + "top_queries": "热门查询", + "search_engines": "搜索引擎", + "ai_referrals": "AI 来源", + "no_search_traffic": "此时间段没有搜索流量", + "no_ai_traffic": "此时间段没有 AI 流量", + "chart_clicks_impressions": "点击与展示", + "other_source": "其他", + "metric_ctr": "CTR", + "metric_impressions_short": "展示", + "metric_position_short": "排名", + "search": "搜索", + "zero_results": "0 个结果", + "results_range": "{{start}}-{{end}} / {{total}}", + "search_keywords": "搜索关键词", + "keyword_cannibalization": "关键词蚕食", + "pages_count": "{{count}} 个页面", + "impressions_avg_ctr_summary": "{{impressions}} 展示 · {{ctr}}% 平均 CTR", + "cannibalization_advice_prefix": "这些页面都在竞争", + "cannibalization_advice_suffix": "。建议将较弱页面合并到排名最高的页面,集中链接权重并避免分散点击。", + "page_metrics_summary": "排名 {{position}} · {{ctr}}% CTR · {{impressions}} 展示", + "ctr_vs_position": "CTR 与排名", + "your_ctr": "你的 CTR", + "your_avg_ctr": "你的平均 CTR", + "benchmark": "基准", + "position_number": "排名 #{{position}}", + "lower_is_better": "数值越低越好", + "insight_low_ctr": "低 CTR", + "insight_near_page_one": "接近第一页", + "insight_low_visibility": "低可见度", + "insight_high_bounce": "高跳出", + "insight_low_ctr_headline": "排名 #{{position}},但 CTR 只有 {{ctr}}%", + "insight_low_ctr_suggestion": "你已经在第一页,但用户很少点击。重写标题标签和 meta 描述,让它们更有吸引力并匹配搜索意图。", + "insight_near_page_one_headline": "排名 {{position}},再推进一步就到第一页", + "insight_near_page_one_suggestion": "刷新内容、增加内部链接,或获取少量反向链接,可能把它推入前 10 并显著提升点击。", + "insight_invisible_clicks_headline": "{{impressions}} 次展示,但只有 {{clicks}} 次点击", + "insight_invisible_clicks_suggestion": "Google 经常展示这个页面,但它几乎没有获得点击。检查页面是否瞄准了正确查询,或是否需要换成更合适的内容形式(例如列表、教程)。", + "insight_high_bounce_headline": "有 {{sessions}} 次会话的页面跳出率为 {{bounceRate}}%", + "insight_high_bounce_suggestion": "访客没有互动就离开了。检查页面是否兑现标题/meta 的承诺,优化页面速度,并确保关键内容出现在首屏。", + "insight_high_bounce_no_gsc_headline": "{{sessions}} 次会话,跳出率 {{bounceRate}}%", + "insight_high_bounce_no_gsc_suggestion": "跳出率高且没有搜索可见度。检查内容质量,并确认页面已被索引且瞄准了正确关键词。", + "metrics_position_impressions_ctr": "排名 {{position}} · {{impressions}} 展示 · {{ctr}}% CTR", + "metrics_position_impressions_clicks": "排名 {{position}} · {{impressions}} 展示 · {{clicks}} 点击", + "metrics_impressions_clicks_position": "{{impressions}} 展示 · {{clicks}} 点击 · 排名 {{position}}", + "metrics_bounce_sessions_impressions": "{{bounceRate}}% 跳出 · {{sessions}} 会话 · {{impressions}} 展示", + "metrics_bounce_sessions": "{{bounceRate}}% 跳出 · {{sessions}} 会话", + "opportunities": "机会点" + }, + "realtime": { + "geo_title": "地理", + "paths_title": "路径", + "referrals_title": "来源", + "column_country_city": "国家/城市", + "column_duration": "时长", + "column_events": "事件", + "column_sessions": "会话", + "column_path": "路径", + "column_referrer": "来源", + "not_set": "(未设置)", + "active_users": "活跃用户", + "referrers_label": "来源:", + "unique_visitors_last_30_min": "最近 30 分钟独立访客", + "more": "更多", + "no_active_sessions": "暂无活跃会话", + "map_cluster_title": "实时聚合", + "map_sessions_count_one": "{{count}} 个会话", + "map_sessions_count_other": "{{count}} 个会话", + "map_profiles_count_one": "{{count}} 个用户档案", + "map_profiles_count_other": "{{count}} 个用户档案", + "map_locations": "位置", + "map_countries": "国家/地区", + "map_cities": "城市", + "map_top_referrers": "热门来源", + "map_top_events": "热门事件", + "map_top_paths": "热门路径", + "map_recent_sessions": "最近会话", + "no_data": "暂无数据", + "unknown_location": "未知", + "no_recent_sessions": "暂无最近会话", + "map_details_load_failed": "无法加载标记详情。" + }, + "notifications": { + "page_title": "通知", + "page_description": "查看通知,并管理决定何时提醒你的规则。", + "tab_notifications": "通知", + "tab_rules": "规则", + "rules_empty_title": "还没有规则", + "rules_empty_description": "你还没有创建任何规则。创建一条规则即可开始接收通知。", + "action_add_rule": "添加规则", + "action_delete": "删除", + "action_edit": "编辑", + "rule_any_event": "任意事件", + "rule_deleted_success": "规则已删除", + "rule_events_prefix": "当以下事件", + "rule_events_suffix": "发生时通知我", + "rule_funnel_description": "当某个会话完成此漏斗时通知我", + "delete_rule_confirm_title": "删除 {{name}}?", + "delete_rule_confirm_description": "此操作无法撤销。", + "column_title": "标题", + "column_message": "消息", + "column_integration": "集成", + "column_rule": "规则", + "column_country": "国家/地区", + "column_os": "操作系统", + "column_browser": "浏览器", + "column_profile": "用户档案", + "column_created_at": "创建时间", + "search_placeholder": "搜索" + }, + "onboarding": { + "page_title": "引导流程", + "project_title": "项目", + "step_create_account": "创建账号", + "step_create_project": "创建项目", + "step_connect_data": "连接数据", + "step_verify": "验证", + "action_login": "登录", + "action_skip_onboarding": "跳过引导", + "action_skip_for_now": "暂时跳过", + "action_next": "下一步", + "action_back": "返回", + "action_copy": "复制", + "action_save": "保存", + "action_your_dashboard": "进入仪表盘", + "skip_confirm_title": "跳过引导?", + "skip_confirm_description": "确定要跳过引导吗?由于你还没有任何项目,系统会将你登出。", + "project_create_new_workspace": "创建新工作区", + "project_use_existing_workspace": "使用现有工作区", + "project_workspace_name_help": "这是你的工作区名称,可以填写任何你喜欢的名字。", + "project_workspace_name_placeholder": "例如:The Music Company", + "project_select_timezone": "选择时区", + "project_select_workspace": "选择工作区", + "project_name_placeholder": "例如:The Music App", + "project_tracking_label": "你要跟踪什么?", + "project_type_website": "网站", + "project_type_app": "应用", + "project_type_backend": "后端 / API", + "project_tracking_required": "至少需要选择一种类型", + "project_domain_allowed_prefix": "来自", + "project_domain_allowed_suffix": "的所有事件都将被允许。还要允许其他来源吗?", + "field_workspace_name": "工作区名称", + "field_timezone": "时区", + "field_workspace": "工作区", + "field_first_project_name": "你的第一个项目名称", + "field_domain": "域名", + "field_allowed_domains": "允许的域名", + "field_client_id": "Client ID", + "field_client_secret": "Client secret", + "allowed_domains_placeholder": "接收来自这些域名的事件", + "allowed_domains_any_tag": "接收来自任意域名的事件", + "connect_project_missing_title": "未找到项目", + "connect_project_missing_description": "你要查找的项目不存在。请刷新页面。", + "connect_client_credentials_title": "客户端凭据", + "connect_quick_start_title": "快速开始", + "connect_pick_framework": "或者在下方选择一个框架开始。", + "connect_missing_framework": "缺少某个框架?", + "connect_let_us_know": "告诉我们!", + "verify_project_not_found": "未找到项目", + "verify_client_not_found": "未找到客户端", + "verify_connected_title": "已成功连接", + "verify_waiting_title": "正在等待事件", + "verify_waiting_description": "验证你的实现是否正常工作。", + "verify_more_events_one": "还有 {{count}} 个事件", + "verify_more_events_other": "还有 {{count}} 个事件", + "verify_allowed_domains_updated": "允许的域名已更新", + "verify_faq_no_events_title": "没有收到事件?", + "verify_faq_intro": "别担心,这种情况很常见。你可以检查以下几点:", + "verify_faq_client_id_title": "确认 client ID 正确", + "verify_faq_client_id_prefix": "对于网页跟踪,代码片段中的", + "verify_faq_client_id_suffix": "必须与此项目匹配。如有需要,可在这里复制:", + "verify_faq_domain_title": "确认域名配置正确", + "verify_faq_domain_description": "对于网站,正确配置域名很重要。我们会根据域名验证请求。请在下方更新允许的域名:", + "verify_faq_client_secret_title": "client secret 不正确", + "verify_faq_client_secret_prefix": "对于应用和后端事件,你需要正确的", + "verify_faq_client_secret_suffix": "。如有需要,可在这里复制。不要在网页或客户端代码中使用 client secret,否则会暴露你的凭据。", + "verify_support_prefix": "仍然有问题?加入我们的", + "verify_support_discord": "Discord 频道", + "verify_support_email_prefix": "或发送邮件到", + "verify_support_suffix": ",我们会帮你处理。", + "verify_personal_curl_title": "个人 curl 示例", + "testimonial_thomas_quote": "OpenPanel 是我见过最好的开源分析工具。更好的用户体验/界面、更多功能,还有创始人非常出色的支持。", + "testimonial_julien_quote": "在测试了几款产品分析工具后,我们选择了 OpenPanel,并且非常满意。Profiles 和 Conversion Events 是我们最喜欢的功能。", + "testimonial_piotr_quote": "Overview 标签页很棒,里面有我需要的一切。界面漂亮、干净、现代,看起来非常舒服。", + "testimonial_selfhost_quote": "多年为 PostHog 支付高额费用后,OpenPanel 给了我们同样、很多方面甚至更好的分析能力,同时让我们完全拥有自己的数据。没有 OpenPanel,我们已经不想再经营任何业务了。", + "testimonial_selfhost_author": "自托管用户" + }, + "organization": { + "not_found": "未找到组织", + "details_title": "详细信息", + "name_label": "名称", + "timezone_label": "时区", + "timezone_placeholder": "选择时区", + "toast_updated": "组织已更新", + "toast_updated_description": "你的组织信息已更新。", + "settings_page_title": "工作区设置", + "settings_page_description": "在这里管理你的工作区设置", + "projects_empty_title": "未找到项目", + "projects_empty_admin_description": "创建你的第一个项目,开始使用分析功能。", + "projects_empty_member_description": "你目前无权访问此组织中的任何项目。请联系管理员授予你访问权限。", + "create_project": "创建项目", + "projects_page_title": "项目", + "projects_page_description": "此工作区中的所有项目", + "search_projects": "搜索项目", + "feedback_prompt_title": "分享你的反馈", + "feedback_prompt_subtitle": "用你的想法帮助我们改进 OpenPanel", + "feedback_prompt_description": "你的反馈能帮助我们构建你真正需要的功能。欢迎分享想法、报告问题或提出改进建议。", + "feedback_prompt_cta": "提供反馈", + "supporter_prompt_title": "支持 OpenPanel", + "supporter_prompt_subtitle": "帮助我们建设开放分析的未来", + "supporter_prompt_cta": "成为支持者", + "supporter_prompt_footer": "每月 $20 起 • 随时取消 •", + "supporter_prompt_learn_more": "了解更多", + "supporter_perk_docker_title": "最新 Docker 镜像", + "supporter_perk_docker_description": "每次提交都会提供前沿构建", + "supporter_perk_support_title": "优先支持", + "supporter_perk_support_description": "通过优先 Discord 支持更快获得帮助", + "supporter_perk_requests_title": "功能请求", + "supporter_perk_requests_description": "你的想法会在我们的路线图中获得优先考虑", + "supporter_perk_discord_role_title": "专属 Discord 身份", + "supporter_perk_discord_role_description": "在社区中获得特别徽章和认可", + "supporter_perk_early_access_title": "抢先体验", + "supporter_perk_early_access_description": "在公开发布前试用新功能", + "supporter_perk_impact_title": "直接影响", + "supporter_perk_impact_description": "你的支持会直接资助开发工作" + }, + "account": { + "page_title": "你的账号", + "tab_profile": "个人资料", + "tab_email_preferences": "邮件偏好", + "tab_two_factor": "双重验证", + "profile_title": "个人资料", + "email_label": "邮箱", + "first_name_label": "名", + "last_name_label": "姓", + "toast_profile_updated": "个人资料已更新", + "toast_profile_updated_description": "你的个人资料已更新。", + "email_preferences_title": "邮件偏好", + "email_preferences_description": "选择你想接收的邮件类型。取消勾选某个类别即可停止接收相关邮件。", + "toast_email_preferences_updated": "邮件偏好已更新", + "toast_email_preferences_updated_description": "你的邮件偏好已保存。", + "email_category_onboarding": "新手引导", + "email_category_onboarding_description": "入门提示和引导邮件", + "email_category_billing": "账单", + "email_category_billing_description": "订阅更新和付款提醒", + "two_factor_title": "双重验证", + "two_factor_description": "使用身份验证器应用保护你的账号(Google Authenticator、1Password、Authy 等)。每次使用邮箱和密码登录时,你都需要输入 6 位验证码。", + "two_factor_not_available": "双重验证不可用。", + "two_factor_not_available_description": "你的账号通过 Google 或 GitHub 登录,双重验证由这些服务的账号设置处理。请在对应服务的安全设置中启用。", + "two_factor_disabled": "双重验证已关闭。", + "two_factor_enable": "启用", + "two_factor_enabled": "双重验证已启用。", + "two_factor_enabled_meta": "启用时间 {{date}} · 剩余 {{count}} 个恢复代码", + "two_factor_regenerate_recovery_codes": "重新生成恢复代码", + "two_factor_disable": "关闭", + "two_factor_enabled_meta_one": "启用时间 {{date}} · 剩余 {{count}} 个恢复代码", + "two_factor_enabled_meta_other": "启用时间 {{date}} · 剩余 {{count}} 个恢复代码" + }, + "members": { + "page_title": "成员", + "page_description": "在这里管理你的成员", + "tab_members": "成员", + "tab_invitations": "邀请" + }, + "billing": { + "page_title": "账单", + "page_description": "在这里管理你的账单", + "interval_month": "月", + "interval_year": "年", + "customer_portal": "客户门户", + "free_trial_badge": "免费试用", + "no_active_plan_badge": "无有效套餐", + "days_left": "剩余 {{count}} 天", + "trial_ends_description": "你的试用将于 {{date}} 结束。结束后,仪表盘会暂停,直到你选择套餐;你的数据仍会继续流入。", + "choose_plan_title": "选择套餐", + "toast_subscription_updated": "订阅已更新", + "toast_subscription_updated_description": "可能需要几秒钟才会更新", + "toast_subscription_canceled": "订阅已取消", + "plan_cancel_subscription": "取消订阅", + "plan_reactivate_subscription": "重新激活订阅", + "plan_change_subscription": "更改订阅", + "plan_pay_with_polar": "使用 Polar 支付", + "plan_current_usage": "你当前已使用 {{count}} / {{limit}} 个事件。", + "plan_downgrade_limit_notice": "如果你的使用量超过新套餐限制,则无法降级。", + "plan_switch_to_monthly": "切换为月付", + "plan_switch_to_yearly_prefix": "切换为年付并获得", + "plan_switch_to_yearly_discount": "免费 2 个月", + "plan_monthly": "月付", + "plan_yearly": "年付", + "status_subscription_renews_on": "你的订阅将于 {{date}} 续订", + "status_trial_ends_on": "你的试用将于 {{date}} 结束", + "status_trial_ended": "你的免费试用已结束。", + "status_subscription_will_cancel_on": "你的订阅将于 {{date}} 取消", + "status_subscription_canceled_on": "你的订阅已于 {{date}} 取消", + "status_subscription_canceled": "你的订阅已取消", + "status_payment_failed": "你上次付款失败,请更新付款方式。", + "status_subscription_unpaid": "你的订阅尚未付款。", + "status_subscription_incomplete": "你的订阅设置尚未完成。", + "status_subscription_expired_on": "你的订阅已于 {{date}} 过期", + "status_subscription_expired": "你的订阅已过期", + "usage_title": "使用量", + "usage_loading_error": "加载使用量数据时出现问题", + "usage_empty": "暂无使用量数据", + "usage_period": "周期", + "usage_left_to_use": "剩余额度", + "usage_events_count": "事件数", + "usage_limit": "限制", + "usage_subscription": "订阅", + "usage_no_active_subscription": "无有效订阅", + "usage_events_last_30_days": "过去 30 天的事件", + "usage_weekly_events": "每周事件", + "usage_daily_events": "每日事件", + "usage_unknown_date": "未知日期", + "usage_events_this_week": "本周事件", + "usage_events_this_day": "当天事件", + "usage_total_events": "总事件数", + "usage_your_events_count": "你的事件数", + "usage_your_tier_limit": "你的套餐限制", + "faq_title": "常见问题", + "faq_free_tier_question": "OpenPanel 有免费套餐吗?", + "faq_free_tier_answer_trial": "Cloud 套餐提供 30 天免费试用,主要是让你在决定付费前先试用 OpenPanel。", + "faq_free_tier_answer_self_host": "OpenPanel 也是开源的,你可以免费自托管!", + "faq_free_tier_answer_why_title": "为什么 OpenPanel 没有免费套餐?", + "faq_free_tier_answer_why_body": "我们希望 OpenPanel 被真正重视并认真使用的人使用。同时,我们也需要投入时间和资源来维护平台并为用户提供支持。", + "faq_exceeds_limit_question": "如果我的站点超过限制会怎样?", + "faq_exceeds_limit_answer": "在下一个账单周期之前,你将无法在 OpenPanel 中看到新的事件。如果连续 2 个月发生这种情况,我们会建议你升级套餐。", + "faq_cancel_subscription_question": "如果我取消订阅会怎样?", + "faq_cancel_subscription_answer_access": "如果你取消订阅,在当前账单周期结束前仍可访问 OpenPanel。你可以随时重新激活订阅。", + "faq_cancel_subscription_answer_data": "当前账单周期结束后,你将无法访问新的数据。", + "faq_cancel_subscription_answer_note": "注意:如果你的账号连续 3 个月不活跃,我们会删除你的事件。", + "faq_billing_information_question": "如何更改我的账单信息?", + "faq_billing_information_answer": "你可以在账单区域点击“客户门户”按钮来更改账单信息。", + "faq_custom_plan_question": "我们需要自定义套餐,可以帮忙吗?", + "faq_custom_plan_answer": "可以。请通过 hello@openpanel.dev 联系我们获取报价。", + "prompt_trial_ended_badge": "试用已结束", + "prompt_trial_ended_title": "你的 30 天试用已结束", + "prompt_trial_ended_lead": "感谢你试用 OpenPanel。你设置的一切仍在这里:项目、报表以及追踪过的每个事件。选择一个套餐后,你的仪表盘大约一分钟内就会恢复可用。", + "prompt_trial_ended_date_label": "试用结束", + "prompt_trial_ended_cta": "使用 {{plan}},{{price}}/月继续", + "prompt_trial_ended_note": "目前我们仍会继续收集你传入的事件,所以你决定期间不会丢失任何内容。", + "prompt_expired_badge": "订阅已结束", + "prompt_expired_title": "你的数据仍在原处", + "prompt_expired_lead": "你的订阅已结束,但我们没有删除任何内容。重新激活后,你的仪表盘、报表和事件会立即恢复。", + "prompt_expired_date_label": "订阅结束", + "prompt_expired_cta": "使用 {{plan}},{{price}}/月重新激活", + "prompt_unpaid_badge": "付款问题", + "prompt_unpaid_title": "你上次付款未成功", + "prompt_unpaid_lead": "通常是银行卡过期或银行拦截,修复只需一分钟。更新付款方式后,你的仪表盘会立即恢复。你的数据没有丢失。", + "prompt_unpaid_date_label": "已支付至", + "prompt_unpaid_cta": "更新付款方式", + "prompt_free_plan_badge": "套餐变更", + "prompt_free_plan_title": "我们已停止免费套餐", + "prompt_free_plan_lead": "相比无法妥善支持的免费服务,我们更愿意运营一个小而可持续的服务。付费套餐从 $2.5/月起,你的数据会原样保留。", + "prompt_free_plan_date_label": "订阅结束", + "prompt_free_plan_cta": "使用 {{plan}},{{price}}/月继续", + "prompt_custom_plan_cta": "获取自定义套餐", + "prompt_events_tracked_label": "已追踪事件,全部安全保存", + "prompt_usage_recommendation_prefix": "根据你的使用量,", + "prompt_usage_recommendation_suffix": "套餐适合你:每月最多 {{events}} 个事件,价格 {{price}}。", + "prompt_custom_plan_description": "你的使用量高于我们的标准套餐,我们可以为你设置自定义套餐。", + "prompt_see_all_plans": "查看所有套餐", + "prompt_questions_email": "有问题?给我们发邮件", + "prompt_feature_plans_start": "套餐从 $2.5/月起", + "prompt_feature_unlimited": "不限报表、成员和项目", + "prompt_feature_funnels": "高级漏斗和转化", + "prompt_feature_realtime": "实时分析", + "prompt_feature_kpis": "追踪 KPI 和自定义事件", + "prompt_feature_privacy": "注重隐私并符合 GDPR", + "prompt_feature_revenue": "收入追踪", + "prompt_feature_gsc": "Google Search Console 集成", + "days_left_one": "剩余 {{count}} 天", + "days_left_other": "剩余 {{count}} 天" + }, + "overview": { + "filters": "筛选", + "cohort": "群组", + "in_cohort": "在群组中", + "not_in_cohort": "不在群组中", + "operator": "运算符", + "pick_cohort": "选择群组", + "pick_value": "选择值", + "remove_filter": "移除筛选", + "refreshed_data": "数据已刷新", + "unique_visitors_last_5_minutes": "过去 5 分钟 {{count}} 位唯一访客", + "public": "公开", + "private": "私有", + "make_public": "设为公开", + "make_private": "设为私有", + "view": "查看", + "switch_to_chart_view": "切换到图表视图", + "switch_to_table_view": "切换到表格视图", + "more": "更多", + "search": "搜索", + "search_ellipsis": "搜索...", + "search_column": "搜索{{column}}...", + "search_pages": "搜索页面...", + "column_name": "名称", + "no_results_found": "未找到结果", + "no_data_available": "暂无数据", + "not_set": "未设置", + "direct_not_set": "直接访问 / 未设置", + "and_more_items_one": "还有 {{count}} 项", + "and_more_items_other": "还有 {{count}} 项", + "total": "总计", + "loading_map": "正在加载地图...", + "error_loading_map": "地图加载失败", + "last_30_min": "最近 30 分钟", + "live_30_min": "实时 · 30 分钟", + "geo_data_provided_by": "地理数据由", + "map": "地图", + "top_column": "热门{{column}}", + "unique_visitors": "唯一访客", + "sessions": "会话", + "sessions_short": "会话", + "pageviews": "浏览量", + "views": "浏览量", + "pages_per_session": "每次会话页数", + "bounce_rate": "跳出率", + "session_duration": "会话时长", + "revenue": "收入", + "toggle_mock_revenue": "切换模拟收入(仅开发)", + "mock_revenue": "模拟收入", + "mock_revenue_on": "模拟收入已开启", + "user_journey": "用户旅程", + "steps_count": "{{count}} 步", + "no_journey_data_available": "暂无旅程数据", + "step_number": "第 {{step}} 步", + "share": "占比", + "percent_of_total": "占总量百分比", + "percent_of_source": "占来源百分比", + "user_journey_description": "展示用户在应用中最常见的访问路径", + "day_mon_short": "周一", + "day_tue_short": "周二", + "day_wed_short": "周三", + "day_thu_short": "周四", + "day_fri_short": "周五", + "day_sat_short": "周六", + "day_sun_short": "周日", + "day_monday": "星期一", + "day_tuesday": "星期二", + "day_wednesday": "星期三", + "day_thursday": "星期四", + "day_friday": "星期五", + "day_saturday": "星期六", + "day_sunday": "星期日", + "path": "路径", + "bot": "机器人", + "date": "日期", + "event": "事件", + "count": "数量", + "device": "设备", + "devices": "设备", + "browser": "浏览器", + "browser_version": "浏览器版本", + "version": "版本", + "os": "操作系统", + "os_version": "操作系统版本", + "brand": "品牌", + "brands": "品牌", + "model": "型号", + "models": "型号", + "top_devices": "热门设备", + "top_browser": "热门浏览器", + "top_browser_version": "热门浏览器版本", + "top_os": "热门操作系统", + "top_os_version": "热门操作系统版本", + "top_brands": "热门品牌", + "top_models": "热门型号", + "countries": "国家/地区", + "regions": "地区", + "cities": "城市", + "top_countries": "热门国家/地区", + "top_regions": "热门地区", + "top_cities": "热门城市", + "refs": "来源", + "urls": "URL", + "types": "类型", + "source": "来源", + "medium": "媒介", + "campaign": "广告活动", + "term": "关键词", + "content": "内容", + "top_sources": "热门来源", + "top_urls": "热门 URL", + "top_types": "热门类型", + "utm_source": "UTM 来源", + "utm_medium": "UTM 媒介", + "utm_campaign": "UTM 广告活动", + "utm_term": "UTM 关键词", + "utm_content": "UTM 内容", + "top_pages": "热门页面", + "pages": "页面", + "entry_pages": "入口页面", + "exit_pages": "退出页面", + "entries": "入口", + "exits": "退出", + "hide_domain": "隐藏域名", + "show_domain": "显示域名", + "events": "事件", + "conversions": "转化", + "link_out": "外链点击", + "column_country": "国家/地区", + "column_region": "地区", + "column_city": "城市", + "column_browser": "浏览器", + "column_brand": "品牌", + "column_os": "操作系统", + "column_device": "设备", + "column_browser_version": "浏览器版本", + "column_os_version": "操作系统版本", + "column_model": "型号", + "column_referrer": "引荐来源", + "column_referrer_name": "引荐来源名称", + "column_referrer_type": "引荐来源类型", + "column_utm_source": "UTM 来源", + "column_utm_medium": "UTM 媒介", + "column_utm_campaign": "UTM 广告活动", + "column_utm_term": "UTM 关键词", + "column_utm_content": "UTM 内容", + "column_countries": "国家/地区", + "column_regions": "地区", + "column_cities": "城市", + "column_browsers": "浏览器", + "column_brands": "品牌", + "column_oss": "操作系统", + "column_devices": "设备", + "column_browser_versions": "浏览器版本", + "column_os_versions": "操作系统版本", + "column_models": "型号", + "column_referrers": "引荐来源", + "column_referrer_names": "引荐来源名称", + "column_referrer_types": "引荐来源类型", + "column_utm_sources": "UTM 来源", + "column_utm_mediums": "UTM 媒介", + "column_utm_campaigns": "UTM 广告活动", + "column_utm_terms": "UTM 关键词", + "column_utm_contents": "UTM 内容", + "and_more_items": "还有 {{count}} 项" + }, + "reports": { + "page_title": "报表", + "report": "报表", + "success": "成功", + "report_updated": "报表已更新。", + "update": "更新", + "save": "保存", + "available_charts": "可用图表", + "available_metrics": "可用指标", + "custom_dates": "自定义日期", + "duplicate": "复制", + "delete": "删除", + "settings": "设置", + "compare_to_previous_period": "与上一周期对比", + "criteria": "条件", + "select_criteria": "选择条件", + "criteria_on_or_after": "当天或之后", + "criteria_on": "当天", + "unit": "单位", + "unit_count": "计数", + "funnel_group": "漏斗分组", + "default_session": "默认:会话", + "session": "会话", + "profile": "用户档案", + "funnel_window": "漏斗窗口", + "default_24h": "默认:24 小时", + "mode": "模式", + "select_mode": "选择模式", + "mode_after": "之后", + "mode_before": "之前", + "mode_between": "之间", + "steps": "步骤", + "default_5": "默认:5", + "exclude_events": "排除事件", + "select_events_to_exclude": "选择要排除的事件", + "include_events": "包含事件", + "leave_empty_to_include_all": "留空表示包含全部", + "stack_series": "堆叠序列", + "metrics": "指标", + "formula_placeholder": "例如:A+B", + "hide_series_from_chart": "从图表隐藏序列 {{series}}", + "select_event": "选择事件", + "display_name": "显示名称", + "add_formula": "添加公式", + "add_filter": "添加筛选器", + "property_value": "属性:{{property}}", + "select_property": "选择属性", + "breakdown": "细分", + "cohorts": "群组", + "select_breakdown": "选择细分", + "global_filters": "全局筛选器", + "global_filters_description": "应用到此报表中的每个序列。", + "done": "完成", + "invalid_number": "不是有效数字", + "invalid_date": "不是有效日期", + "invalid_boolean": "使用 \"true\" 或 \"false\"", + "yes": "是", + "no": "否", + "yes_no": "是 / 否", + "select": "选择...", + "in_cohort": "在群组中", + "not_in_cohort": "不在群组中", + "operator": "运算符", + "select_cohorts": "选择群组...", + "value_type": "值类型", + "share": "分享", + "pick_events": "选择事件", + "unnamed_report": "未命名报表", + "search": "搜索", + "session_bounced": "跳出", + "session_bounced_description": "单页浏览会话", + "session_screen_views": "屏幕浏览", + "session_screen_views_description": "会话中的屏幕浏览次数", + "session_events": "事件", + "session_events_description": "会话中的事件总数", + "session_duration": "时长", + "session_duration_description": "会话时长(毫秒)", + "session_revenue": "收入", + "session_revenue_description": "归因到会话的收入", + "session_performed_event": "执行过事件", + "session_performed_event_description": "会话包含名为 X 的事件", + "event_properties": "事件属性", + "profile_properties": "用户档案属性", + "group_properties": "群组属性", + "all_cohorts": "所有群组", + "session_metrics": "会话指标" + }, + "report_chart": { + "start_here": "从这里开始", + "ready_when_you_are": "准备好了就开始", + "pick_event_to_start": "至少选择一个事件以开始可视化", + "no_data": "暂无数据", + "chart_load_error": "加载此图表时出错。", + "loading_slow": "请稍候,正在加载", + "search_placeholder": "搜索...", + "grouped": "分组", + "flat": "平铺", + "unselect_all": "全部取消选择", + "filter_by_name": "按名称筛选", + "sort_count_high_low": "计数(从高到低)", + "sort_count_low_high": "计数(从低到高)", + "sort_name_a_z": "名称(A 到 Z)", + "sort_name_z_a": "名称(Z 到 A)", + "sort_percentage_high_low": "百分比(从高到低)", + "sort_percentage_low_high": "百分比(从低到高)", + "date": "日期", + "total_profiles": "用户档案总数", + "retention_rate": "留存率", + "retained_users": "留存用户", + "total_users": "用户总数", + "select_two_events": "选择 2 个事件", + "retention_requires_two_events": "需要两个事件才能计算留存率。", + "conversion": "转化", + "serie": "序列", + "avg_rate": "平均转化率", + "total": "总计", + "conversions": "转化数", + "view_users": "查看用户", + "add_reference": "添加参考线", + "summary_flow": "流程", + "summary_average_conversion_rate": "平均转化率", + "summary_total_conversions": "总转化数", + "summary_previous_average_conversion_rate": "上一周期平均转化率", + "summary_previous_total_conversions": "上一周期总转化数", + "summary_best_breakdown_average": "最佳细分(平均)", + "summary_worst_breakdown_average": "最差细分(平均)", + "summary_breakdown_with_rate": "{{breakdown}},{{rate}}", + "summary_best_conversion_rate": "最佳转化率", + "summary_worst_conversion_rate": "最差转化率", + "summary_rate_on_breakdown_at_date": "{{date}},{{breakdown}} 为 {{rate}}", + "summary_rate_at_date": "{{date}} 为 {{rate}}", + "completed": "已完成", + "dropoff_hint": "在此事件后流失。优化此步骤通常会提高转化率。", + "most_dropoffs_after": "最多流失发生在", + "event": "事件", + "dropped_after": "之后流失", + "view_users_completed_step": "查看完成此步骤的用户", + "current": "当前", + "previous": "上一周期", + "improvement": "提升", + "decline": "下降", + "no_change": "无变化" + } +} diff --git a/apps/start/src/i18n/resources/zh-TW.json b/apps/start/src/i18n/resources/zh-TW.json new file mode 100644 index 000000000..c9e434350 --- /dev/null +++ b/apps/start/src/i18n/resources/zh-TW.json @@ -0,0 +1,1822 @@ +{ + "common": { + "language": "語言", + "loading": "載入中", + "theme": "主題", + "profile": "個人資料", + "account": "帳號", + "logout": "登出", + "go_home": "回到首頁", + "go_back_home": "返回首頁", + "or": "或", + "cancel": "取消", + "continue": "繼續", + "save": "儲存", + "delete": "刪除" + }, + "sidebar": { + "docs": "文件", + "support_us": "支持我們", + "pay_what_you_want": "自由贊助", + "organization": "組織", + "analytics": "分析", + "manage": "管理", + "overview": "概覽", + "dashboards": "看板", + "insights": "洞察", + "pages": "頁面", + "seo": "SEO", + "realtime": "即時", + "events": "事件", + "sessions": "工作階段", + "profiles": "使用者檔案", + "groups": "群組", + "cohorts": "客群", + "settings": "設定", + "references": "參照", + "notifications": "通知", + "back_to_workspace": "返回工作區", + "projects": "專案", + "billing": "帳單", + "members": "成員", + "integrations": "整合", + "give_feedback": "回饋", + "open_ai_chat": "開啟 AI 對話", + "action_create_report": "建立報告", + "action_create_reference": "建立參照", + "action_ask_ai": "詢問 AI", + "action_create_dashboard": "建立看板", + "action_create_notification_rule": "建立通知規則", + "action_create_project": "建立專案", + "action_invite_user": "邀請使用者", + "action_add_integration": "新增整合" + }, + "errors": { + "no_access": "無存取權限", + "something_went_wrong": "發生錯誤", + "page_not_found": "頁面不存在", + "page_not_found_description": "你要瀏覽的頁面不存在或已經移動。" + }, + "auth": { + "sign_in": "登入", + "no_account": "還沒有帳號?", + "create_one_today": "立即建立", + "error": "錯誤", + "correlation_id": "關聯 ID:{{id}}", + "contact_support": "如果遇到問題,請聯絡我們。", + "self_hosted_analytics": "自託管分析", + "open_panel_cloud": "OpenPanel 雲端服務", + "mixpanel_alternative": "Mixpanel 替代方案", + "posthog_alternative": "PostHog 替代方案", + "open_source_analytics": "開源分析", + "email": "電子郵件", + "password": "密碼", + "first_name": "名字", + "last_name": "姓氏", + "confirm_password": "確認密碼", + "new_password": "新密碼", + "sign_in_with_google": "使用 Google 登入", + "sign_up_with_google": "使用 Google 註冊", + "sign_in_with_github": "使用 GitHub 登入", + "sign_up_with_github": "使用 GitHub 註冊", + "used_last_time": "上次使用", + "successfully_signed_in": "登入成功", + "successfully_signed_up": "註冊成功", + "forgot_password": "忘記密碼?", + "create_account": "建立帳號", + "reset_password": "重設密碼", + "reset_your_password": "重設你的密碼", + "password_reset_successfully": "密碼重設成功", + "already_have_account": "已有帳號?", + "missing_reset_password_token": "缺少重設密碼權杖", + "two_factor_authentication": "雙因素驗證", + "totp_description": "請輸入驗證器應用程式中的 6 位數驗證碼。", + "recovery_code_description": "請輸入一組復原代碼。每組代碼只能使用一次。", + "verify": "驗證", + "signed_in": "已登入", + "use_recovery_code": "改用復原代碼", + "use_authenticator_app": "改用驗證器應用程式", + "sign_in_with_different_account": "使用其他帳號登入", + "start_tracking": "幾分鐘內開始追蹤", + "accept_terms_prefix": "建立帳號即表示你接受", + "terms_of_service": "服務條款", + "terms_connector": "和", + "privacy_policy": "隱私權政策", + "invitation_to": "加入 {{organization}} 的邀請", + "invitation_description": "建立帳號後,你會被加入該組織。", + "invitation_expired": "加入 {{organization}} 的邀請已過期", + "invitation_expired_description": "該邀請已過期。請聯絡組織擁有者取得新的邀請。", + "trial_benefits": "無需信用卡 · 免費試用 30 天 · 可隨時取消", + "sign_up_with_email": "使用電子郵件註冊", + "incorrect_password": "密碼錯誤", + "share_locked_title": "{{type}} 已鎖定", + "share_password_description": "請輸入正確密碼以存取此{{type}}", + "share_type_overview": "概覽", + "share_type_dashboard": "看板", + "share_type_report": "報告", + "enter_password": "輸入你的密碼", + "get_access": "取得存取權限", + "request_password_reset": "要求重設密碼", + "your_email_address": "你的電子郵件地址", + "reset_email_sent": "你很快會收到一封電子郵件!", + "login_panel_alternative_title": "最佳開源替代方案", + "login_panel_alternative_description": "Mixpanel 太貴,Google Analytics 隱私不足,Amplitude 陳舊乏味。", + "login_panel_reliable_title": "快速且可靠", + "login_panel_reliable_description": "透過即時分析掌握每一次變化。", + "login_panel_simple_title": "簡單易用", + "login_panel_simple_description": "相比其他工具,我們把體驗保持得足夠簡單。", + "login_panel_privacy_title": "預設保護隱私", + "login_panel_privacy_description": "我們從一開始就把隱私作為平台核心。", + "login_panel_open_source_title": "開源", + "login_panel_open_source_description": "你可以檢查程式碼,也可以選擇自託管。" + }, + "chat": { + "new_chat": "新對話", + "conversations": "對話", + "no_conversations": "還沒有對話。開始輸入即可建立。", + "untitled_chat": "未命名對話", + "new_conversation": "新增對話", + "close_chat": "關閉對話", + "confirm_delete": "確認刪除", + "delete_conversation": "刪除對話", + "click_again_to_confirm": "再次點擊以確認", + "delete": "刪除", + "ask_anything_placeholder": "詢問任何關於資料的問題...", + "ask_ai_placeholder": "向 AI 提問...", + "send_to_ai": "傳送給 AI", + "keyboard_shortcut": "鍵盤快速鍵:Cmd+J", + "stop_generating": "停止生成", + "send_message": "傳送訊息", + "thinking": "正在思考...", + "generic_error": "發生問題。請再試一次。", + "scroll_to_bottom": "捲動到底部", + "latest": "最新", + "tool_failed": "工具執行失敗", + "thought": "思考過程", + "ai_not_configured": "尚未設定 AI 對話", + "ai_not_configured_setup_prefix": "請在 API 服務中設定", + "ai_not_configured_setup_between": "和/或", + "ai_not_configured_setup_suffix": "以啟用 AI 對話,然後重新啟動服務。", + "ai_not_configured_description": "模型選擇器只會顯示已設定金鑰的供應商。", + "view_setup_docs": "查看設定文件", + "empty_no_context_headline": "詢問你的資料", + "empty_no_context_description": "我可以回答分析資料相關問題、產生報告,並深入查看使用者、工作階段或頁面。", + "empty_no_context_prompt_what_happened_yesterday": "昨天發生了什麼?", + "empty_no_context_prompt_last_seven_days_traffic": "顯示最近 7 天的流量", + "empty_no_context_prompt_highest_bounce_rate": "哪些頁面跳出率最高?", + "empty_overview_headline": "詢問此概覽", + "empty_overview_description": "我可以解釋趨勢、比較期間或篩選頁面。直接提問,或選擇一個起始問題。", + "empty_overview_prompt_compare_previous_period": "與上一期間相比有什麼變化?", + "empty_overview_prompt_filter_mobile_only": "僅篩選行動裝置", + "empty_overview_prompt_last_seven_days_traffic": "顯示最近 7 天的流量", + "empty_overview_prompt_top_referrers": "哪些來源帶來最多工作階段?", + "empty_insights_headline": "探索你的洞察", + "empty_insights_description": "我可以解釋洞察觸發原因、尋找相關洞察,或帶你查看最重要的內容。", + "empty_insights_prompt_most_important": "目前最重要的洞察有哪些?", + "empty_insights_prompt_biggest_anomaly": "解釋本週最大的異常", + "empty_insights_prompt_device_trends": "有沒有與裝置趨勢相關的洞察?", + "empty_pages_headline": "詢問你的頁面", + "empty_pages_description": "我可以依表現排序頁面、找出下滑頁面,或辨識入口與離開模式。", + "empty_pages_prompt_declining_pages": "哪些頁面相比上月在下滑?", + "empty_pages_prompt_highest_bounce_rate": "顯示跳出率最高的頁面", + "empty_pages_prompt_top_entry_pages": "最近 7 天的主要入口頁", + "empty_pages_prompt_underperforming_seo": "找出 SEO 表現不佳的頁面", + "empty_seo_headline": "深入分析 SEO", + "empty_seo_description": "我可以找出高機會查詢、檢查關鍵字內耗,並關聯 SEO 與站內互動。", + "empty_seo_prompt_page_two_queries": "曝光高但位於第 2 頁的查詢(容易優化)", + "empty_seo_prompt_query_cannibalization": "有沒有需要修復的查詢內耗?", + "empty_seo_prompt_gsc_clicks_bounce_hard": "哪些頁面帶來 GSC 點擊但跳出很高?", + "empty_seo_prompt_top_seo_queries": "最近 30 天的熱門 SEO 查詢", + "empty_events_headline": "分析你的事件", + "empty_events_description": "我可以分析分布、關聯事件,並深入查看屬性。", + "empty_events_prompt_events_together": "哪些事件經常一起發生?", + "empty_events_prompt_distribution_by_country": "依國家分析事件分布", + "empty_events_prompt_signup_events_only": "只篩選註冊事件", + "empty_events_prompt_common_properties": "最常見的事件屬性有哪些?", + "empty_profile_detail_headline": "詢問此使用者", + "empty_profile_detail_description": "我可以總結此使用者檔案、建立使用者旅程,或將其與平均使用者比較。", + "empty_profile_detail_prompt_user_journey": "告訴我這個使用者的旅程", + "empty_profile_detail_prompt_compare_average": "此使用者與平均水準相比如何?", + "empty_profile_detail_prompt_last_session": "他的最後一次工作階段是什麼?", + "empty_profile_detail_prompt_unusual_behavior": "他有沒有異常行為?", + "empty_session_detail_headline": "詢問此工作階段", + "empty_session_detail_description": "我可以梳理瀏覽路徑、比較典型工作階段,或解釋來源上下文。", + "empty_session_detail_prompt_walk_through": "帶我瀏覽這個工作階段", + "empty_session_detail_prompt_compare_typical": "這與典型工作階段相比如何?", + "empty_session_detail_prompt_traffic_source": "這些流量來自哪裡?", + "empty_session_detail_prompt_similar_sessions": "今天還有類似工作階段嗎?", + "empty_group_detail_headline": "詢問此群組", + "empty_group_detail_description": "我可以顯示指標、列出成員,並與相似群組比較。", + "empty_group_detail_prompt_summarize_activity": "總結此群組的活動", + "empty_group_detail_prompt_compare_groups": "與其他群組比較", + "empty_group_detail_prompt_active_members": "最活躍的成員是誰?", + "empty_group_detail_prompt_engagement_trend": "此群組的互動趨勢如何?", + "empty_report_editor_headline": "和我一起編輯此報告", + "empty_report_editor_description": "我可以預覽變更、建議拆分維度,或與上一期間比較。", + "empty_report_editor_prompt_useful_breakdowns": "為此報告建議有用的拆分維度", + "empty_report_editor_prompt_compare_previous_period": "與上一期間比較", + "empty_report_editor_prompt_find_anomalies": "尋找目前資料中的異常", + "empty_report_editor_prompt_country_breakdown": "新增國家拆分", + "empty_dashboard_headline": "詢問此看板", + "empty_dashboard_description": "我可以一次總結看板上的所有報告、標記變化,或深入查看單一圖表。", + "empty_dashboard_prompt_summarize_dashboard": "總結此看板", + "empty_dashboard_prompt_underperforming": "這裡哪些表現不佳?", + "empty_dashboard_prompt_compare_previous_period": "將此看板與上一期間比較", + "empty_dashboard_prompt_biggest_change": "哪份報告變化最大?", + "empty_default_context_headline": "詢問你的資料", + "empty_default_context_description": "我可以回答你正在查看頁面的相關問題、產生報告,並深入查看特定使用者、工作階段或頁面。", + "empty_default_context_prompt_visitor_count": "本週訪客數是多少?", + "empty_default_context_prompt_top_traffic_sources": "目前主要流量來源", + "empty_default_context_prompt_top_pages_bounce_rate": "依跳出率顯示熱門頁面", + "tool_working": "正在處理", + "tool_result_empty": "無結果。", + "tool_result_view_raw_output": "查看原始輸出", + "tool_result_item_count_one": "{{count}} 項", + "tool_result_item_count_other": "{{count}} 項", + "table_showing_limited_rows": "顯示 {{shown}} / {{total}} 筆", + "table_truncated_suffix": "(已截斷)", + "ui_apply_date_range_summary": "日期範圍:{{value}}", + "ui_apply_interval_summary": "間隔:{{value}}", + "ui_apply_filters_summary": "篩選條件", + "ui_apply_applied_summary": "已套用 {{summary}}", + "ui_apply_cleared_property_filters": "已清除屬性篩選", + "ui_apply_applied_filters": "已套用篩選:{{summary}}", + "ui_apply_cleared_event_filter": "已清除事件名稱篩選", + "ui_apply_filtered_events_one": "已篩選到事件:{{names}}", + "ui_apply_filtered_events_other": "已篩選到事件:{{names}}", + "tool_fallback_verb_list": "正在查找", + "tool_fallback_verb_get": "正在載入", + "tool_fallback_verb_find": "正在查找", + "tool_fallback_verb_query": "正在查詢", + "tool_fallback_verb_analyze": "正在分析", + "tool_fallback_verb_compare": "正在比較", + "tool_fallback_verb_correlate": "正在關聯", + "tool_fallback_verb_explain": "正在解釋", + "tool_fallback_verb_suggest": "正在建議", + "tool_fallback_verb_preview": "正在預覽", + "tool_fallback_verb_generate": "正在產生", + "tool_fallback_verb_apply": "正在套用", + "tool_fallback_verb_set": "正在更新", + "tool_fallback_verb_gsc": "正在載入 SEO", + "tool_fallback_verb_running": "正在執行", + "tool_list_event_names_active": "正在查找事件名稱", + "tool_list_event_names_done": "事件名稱", + "tool_list_event_properties_active": "正在查找屬性", + "tool_list_event_properties_done": "事件屬性", + "tool_get_event_property_values_active": "正在載入屬性值", + "tool_get_event_property_values_done": "屬性值", + "tool_list_dashboards_active": "正在載入看板", + "tool_list_dashboards_done": "看板", + "tool_list_reports_active": "正在載入報告", + "tool_list_reports_done": "報告", + "tool_get_report_data_active": "正在執行報告", + "tool_get_report_data_done": "報告", + "tool_generate_report_active": "正在產生報告", + "tool_generate_report_done": "報告", + "tool_get_analytics_overview_active": "正在載入概覽", + "tool_get_analytics_overview_done": "概覽", + "tool_get_top_pages_active": "正在載入熱門頁面", + "tool_get_top_pages_done": "熱門頁面", + "tool_get_top_referrers_active": "正在載入熱門來源", + "tool_get_top_referrers_done": "熱門來源", + "tool_get_country_breakdown_active": "正在載入地理拆分", + "tool_get_country_breakdown_done": "地理拆分", + "tool_get_device_breakdown_active": "正在載入裝置拆分", + "tool_get_device_breakdown_done": "裝置拆分", + "tool_get_rolling_active_users_active": "正在載入活躍使用者", + "tool_get_rolling_active_users_done": "活躍使用者", + "tool_get_funnel_active": "正在建立漏斗", + "tool_get_funnel_done": "漏斗", + "tool_get_retention_cohort_active": "正在建立留存客群", + "tool_get_retention_cohort_done": "留存", + "tool_get_user_flow_active": "正在建立使用者流程", + "tool_get_user_flow_done": "使用者流程", + "tool_query_events_active": "正在查詢事件", + "tool_query_events_done": "事件", + "tool_query_sessions_active": "正在查詢工作階段", + "tool_query_sessions_done": "工作階段", + "tool_find_profiles_active": "正在查找使用者檔案", + "tool_find_profiles_done": "使用者檔案", + "tool_get_profile_full_active": "正在載入使用者檔案", + "tool_get_profile_full_done": "使用者檔案", + "tool_get_profile_events_active": "正在載入使用者事件", + "tool_get_profile_events_done": "使用者事件", + "tool_get_profile_sessions_active": "正在載入使用者工作階段", + "tool_get_profile_sessions_done": "使用者工作階段", + "tool_get_profile_metrics_active": "正在載入使用者指標", + "tool_get_profile_metrics_done": "使用者指標", + "tool_get_profile_journey_active": "正在載入使用者旅程", + "tool_get_profile_journey_done": "使用者旅程", + "tool_get_profile_groups_active": "正在載入使用者群組", + "tool_get_profile_groups_done": "使用者群組", + "tool_compare_profile_to_average_active": "正在與平均水準比較", + "tool_compare_profile_to_average_done": "使用者比較", + "tool_get_session_full_active": "正在載入工作階段", + "tool_get_session_full_done": "工作階段", + "tool_get_session_path_active": "正在載入工作階段路徑", + "tool_get_session_path_done": "工作階段路徑", + "tool_get_session_events_active": "正在載入工作階段事件", + "tool_get_session_events_done": "工作階段事件", + "tool_get_similar_sessions_active": "正在查找相似工作階段", + "tool_get_similar_sessions_done": "相似工作階段", + "tool_compare_session_to_typical_active": "正在與典型工作階段比較", + "tool_compare_session_to_typical_done": "工作階段比較", + "tool_get_session_referrer_context_active": "正在載入來源上下文", + "tool_get_session_referrer_context_done": "來源上下文", + "tool_get_session_replay_summary_active": "正在載入工作階段回放", + "tool_get_session_replay_summary_done": "工作階段回放", + "tool_get_page_performance_active": "正在載入頁面表現", + "tool_get_page_performance_done": "頁面表現", + "tool_get_page_conversions_active": "正在載入頁面轉換", + "tool_get_page_conversions_done": "頁面轉換", + "tool_get_entry_exit_pages_active": "正在載入入口/離開頁面", + "tool_get_entry_exit_pages_done": "入口/離開頁面", + "tool_find_declining_pages_active": "正在查找下滑頁面", + "tool_find_declining_pages_done": "下滑頁面", + "tool_gsc_get_overview_active": "正在載入 SEO 概覽", + "tool_gsc_get_overview_done": "SEO 概覽", + "tool_gsc_get_top_queries_active": "正在載入熱門查詢", + "tool_gsc_get_top_queries_done": "熱門查詢", + "tool_gsc_get_top_pages_active": "正在載入熱門 SEO 頁面", + "tool_gsc_get_top_pages_done": "熱門 SEO 頁面", + "tool_gsc_get_query_details_active": "正在載入查詢詳情", + "tool_gsc_get_query_details_done": "查詢詳情", + "tool_gsc_get_page_details_active": "正在載入頁面詳情", + "tool_gsc_get_page_details_done": "頁面詳情", + "tool_gsc_get_query_opportunities_active": "正在查找查詢機會", + "tool_gsc_get_query_opportunities_done": "查詢機會", + "tool_gsc_get_cannibalization_active": "正在檢查關鍵字內耗", + "tool_gsc_get_cannibalization_done": "關鍵字內耗", + "tool_correlate_seo_with_traffic_active": "正在關聯 SEO 與流量", + "tool_correlate_seo_with_traffic_done": "SEO/流量關聯", + "tool_analyze_event_distribution_active": "正在分析事件分布", + "tool_analyze_event_distribution_done": "事件分布", + "tool_correlate_events_active": "正在關聯事件", + "tool_correlate_events_done": "事件關聯", + "tool_get_event_property_distribution_active": "正在載入屬性分布", + "tool_get_event_property_distribution_done": "屬性分布", + "tool_list_properties_for_event_active": "正在載入屬性", + "tool_list_properties_for_event_done": "事件屬性", + "tool_list_insights_active": "正在載入洞察", + "tool_list_insights_done": "洞察", + "tool_explain_insight_active": "正在載入洞察", + "tool_explain_insight_done": "洞察", + "tool_find_related_insights_active": "正在查找相關洞察", + "tool_find_related_insights_done": "相關洞察", + "tool_get_group_full_active": "正在載入群組", + "tool_get_group_full_done": "群組", + "tool_get_group_members_active": "正在載入群組成員", + "tool_get_group_members_done": "群組成員", + "tool_get_group_events_active": "正在載入群組事件", + "tool_get_group_events_done": "群組事件", + "tool_get_group_metrics_active": "正在載入群組指標", + "tool_get_group_metrics_done": "群組指標", + "tool_compare_groups_active": "正在比較群組", + "tool_compare_groups_done": "群組比較", + "tool_preview_report_with_changes_active": "正在預覽變更", + "tool_preview_report_with_changes_done": "報告預覽", + "tool_suggest_breakdowns_active": "正在建議拆分維度", + "tool_suggest_breakdowns_done": "拆分建議", + "tool_compare_to_previous_period_active": "正在與上一期間比較", + "tool_compare_to_previous_period_done": "期間比較", + "tool_find_anomalies_in_current_report_active": "正在尋找異常", + "tool_find_anomalies_in_current_report_done": "異常", + "tool_explain_filter_impact_active": "正在分析篩選影響", + "tool_explain_filter_impact_done": "篩選影響", + "tool_apply_filters_active": "正在套用日期範圍", + "tool_apply_filters_done": "日期範圍已更新", + "tool_set_property_filters_active": "正在套用篩選", + "tool_set_property_filters_done": "篩選已更新", + "tool_set_event_names_filter_active": "正在套用事件篩選", + "tool_set_event_names_filter_done": "事件篩選已更新", + "tool_list_references_active": "正在載入參照", + "tool_list_references_done": "參照", + "tool_get_references_around_active": "正在檢查此日期附近的參照", + "tool_get_references_around_done": "附近參照", + "resize_drawer": "調整對話抽屜寬度", + "select_model": "選擇模型", + "result_no_profile": "無使用者檔案", + "result_profile": "使用者檔案", + "result_sessions": "工作階段", + "result_total_events": "事件總數", + "result_avg_session": "平均工作階段", + "result_minutes": "{{value}} 分鐘", + "result_bounce_rate": "跳出率", + "result_revenue": "收入", + "result_open_profile": "開啟使用者檔案 →", + "result_no_data": "無資料", + "result_report": "報告", + "result_no_renderable_report_config": "報告回傳了資料,但沒有可轉譯設定。", + "result_chart_report_title": "{{chart}}報告", + "result_open_in_dashboard": "在看板中開啟 →", + "result_funnel_title": "漏斗:{{steps}}", + "result_day_active_users": "{{count}} 天活躍使用者", + "result_active_users_title": "{{label}} — 最近 {{count}} 天", + "result_chart_type_linear": "折線圖", + "result_chart_type_bar": "長條圖", + "result_chart_type_area": "面積圖", + "result_chart_type_pie": "圓餅圖", + "result_chart_type_funnel": "漏斗", + "result_chart_type_metric": "指標", + "result_chart_type_retention": "留存", + "result_chart_type_histogram": "直方圖", + "result_chart_type_sankey": "桑基圖", + "result_chart_type_map": "地圖", + "result_chart_type_conversion": "轉換" + }, + "ui": { + "click_to_copy": "點擊複製", + "copied_to_clipboard": "已複製到剪貼簿", + "error_title": "錯誤...", + "error_description": "發生問題...", + "fetching": "正在取得...", + "fetching_description": "請稍候,正在取得你的資料...", + "toggle_fullscreen": "切換全螢幕", + "exit_full_screen": "退出全螢幕", + "json_editor_invalid_json_syntax": "JSON 語法無效", + "json_editor_invalid_syntax": "{{language}} 無效。請檢查語法。", + "powered_by": "由", + "try_it_for_free_today": "今天免費試用!", + "time_window": "時間視窗", + "time_window_30min": "最近 30 分鐘", + "time_window_last_hour": "最近 1 小時", + "time_window_last_24h": "最近 24 小時", + "time_window_today": "今天", + "time_window_yesterday": "昨天", + "time_window_7d": "最近 7 天", + "time_window_30d": "最近 30 天", + "time_window_3m": "最近 3 個月", + "time_window_6m": "最近 6 個月", + "time_window_12m": "最近 12 個月", + "time_window_month_to_date": "本月至今", + "time_window_last_month": "上個月", + "time_window_year_to_date": "今年至今", + "time_window_last_year": "去年", + "time_window_custom": "自訂", + "last_days": "最近天數", + "custom_date_filter_days_aria_label": "自訂日期篩選的天數", + "x_days": "X 天", + "no_match": "無符合項目", + "search_item": "搜尋項目...", + "search": "搜尋", + "create_value": "建立「{{value}}」", + "pick_value": "選擇「{{value}}」", + "nothing_selected": "未選擇任何項目", + "search_event": "搜尋事件...", + "any_events": "任意事件", + "command_palette": "命令面板", + "command_palette_description": "搜尋要執行的命令..." + }, + "clients": { + "field_client_id": "用戶端 ID", + "field_secret": "密鑰", + "field_mcp_token": "MCP 權杖", + "secret_help": "只有在傳送伺服器端事件時才需要使用密鑰。", + "mcp_token_help": "使用此權杖向 MCP 伺服器進行身分驗證(用戶端 ID 和密鑰的 base64 編碼)。", + "action_save_credentials": "儲存憑證", + "get_started_title": "開始使用!", + "get_started_read_our": "閱讀我們的", + "get_started_suffix": "開始接入。很簡單!", + "column_name": "名稱", + "column_created_at": "建立時間", + "revoke_success_title": "成功", + "revoke_success_description": "用戶端已撤銷,傳入請求將被拒絕。", + "action_copy_client_id": "複製用戶端 ID", + "action_edit": "編輯", + "action_revoke": "撤銷", + "revoke_confirm_title": "撤銷用戶端", + "revoke_confirm_description": "確定要撤銷此用戶端嗎?此操作無法復原。" + }, + "integrations": { + "slack_name": "Slack", + "slack_description": "當 OpenPanel 中發生重要事件時,在 Slack 中接收通知。", + "slack_logo_alt": "Slack 標誌", + "discord_name": "Discord", + "discord_description": "將 OpenPanel 通知傳送到 Discord 頻道。", + "discord_logo_alt": "Discord 標誌", + "webhook_name": "Webhook", + "webhook_description": "將 OpenPanel 事件傳送到任意 HTTP 端點。", + "action_connect": "連線", + "action_create": "建立", + "action_update": "更新", + "action_delete": "刪除", + "action_edit": "編輯", + "action_test_connection": "測試連線", + "action_add_header": "新增請求標頭", + "status_connected": "已連線", + "empty_installed_title": "尚無集成", + "empty_installed_description": "集成可將你的系統連接到 OpenPanel。你可以在可用集成區域中新增。", + "delete_confirm_title": "刪除 {{name}}?", + "delete_confirm_description": "此操作無法復原。", + "modal_title": "建立集成", + "success_integration_saved": "集成已儲存", + "success_test_notification_sent": "測試通知已傳送", + "error_create_failed": "建立集成失敗", + "error_validation": "驗證錯誤", + "error_webhook_url_required": "Webhook URL 為必填項", + "error_test_notification_failed": "傳送測試通知失敗", + "error_invalid_javascript_template": "無效的 JavaScript 範本", + "field_name": "名稱", + "field_url": "URL", + "field_discord_webhook_url": "Discord Webhook URL", + "field_headers": "請求標頭", + "field_payload_format": "載荷格式", + "field_javascript_transform": "JavaScript 轉換", + "slack_name_placeholder": "例如:我的個人 Slack", + "discord_name_placeholder": "例如:我的個人 Discord", + "webhook_name_placeholder": "例如:Zapier webhook", + "headers_help": "新增自訂 HTTP 請求標頭,並隨 webhook 請求一起傳送", + "header_name_placeholder": "請求標頭名稱", + "header_value_placeholder": "請求標頭值", + "payload_format_help": "選擇 webhook 載荷的格式化方式", + "payload_format_placeholder": "選擇格式", + "payload_format_message": "訊息", + "payload_format_javascript": "JavaScript", + "javascript_transform_help": "撰寫一個用於轉換事件載荷的 JavaScript 函式。該函式接收 payload 作為參數,並應回傳一個物件。", + "available_payload_title": "payload 中可用:", + "payload_name_description": "事件名稱", + "payload_profile_id_description": "使用者檔案 ID", + "payload_properties_description": "完整屬性物件", + "payload_nested_property_description": "巢狀屬性值", + "payload_profile_property_description": "使用者檔案屬性", + "payload_more_fields": "以及更多...", + "available_helpers_title": "可用輔助物件:", + "example_title": "範例:", + "security_title": "安全:", + "security_description": "網路呼叫、檔案系統存取和其他危險操作已被阻止。", + "page_title": "集成", + "page_description": "在這裡管理你的集成", + "tab_installed": "已安裝", + "tab_available": "可用" + }, + "cohorts": { + "add_event_criteria": "新增事件條件", + "add_property_filter": "新增屬性篩選", + "all": "全部", + "all_of_these_events": "符合所有這些事件", + "all_of_these_properties": "符合所有這些屬性", + "any": "任一", + "any_of_these_events": "符合任一這些事件", + "any_of_these_properties": "符合任一這些屬性", + "at_least": "至少", + "at_most": "至多", + "between": "介於", + "capped_notice": "成員數上限為 10,000,請考慮縮小條件範圍。", + "cohort": "群組", + "cohort_deleted": "群組已刪除。", + "cohort_refresh_queued": "群組重新整理已排入佇列。", + "create_cohort": "建立群組", + "created": "建立時間", + "delete": "刪除", + "delete_cohort": "刪除群組", + "delete_confirm_description": "確定要刪除此群組嗎?此操作無法復原。", + "delete_named_confirm_description": "確定要刪除「{{name}}」嗎?此操作無法復原。", + "description": "根據事件和屬性建立並管理使用者分群", + "download": "下載", + "download_members_failed": "下載群組成員失敗", + "edit": "編輯", + "empty_description": "你尚未為此專案建立任何群組", + "empty_title": "尚無群組", + "event": "事件", + "event_based": "基於事件", + "event_filters": "事件篩選", + "events": "事件", + "events_last_30_days": "過去 30 天事件({{count}})", + "exactly": "剛好", + "frequency": "頻次", + "last": "最近", + "last_computed": "上次計算", + "match": "符合", + "member_count_one": "{{count}} 位成員", + "member_count_other": "{{count}} 位成員", + "members": "成員", + "no_events_yet": "尚無事件", + "not_computed_notice": "此群組尚未完成計算。成員將在一分鐘內顯示。", + "not_found": "找不到群組", + "operator": "運算子", + "overview": "概覽", + "period": "週期", + "period_180_days": "180 天", + "period_30_days": "30 天", + "period_365_days": "365 天", + "period_7_days": "7 天", + "period_90_days": "90 天", + "property_based": "基於屬性", + "refresh": "重新整理", + "select_event_placeholder": "選擇事件...", + "since": "自", + "static": "靜態", + "success": "成功", + "timeframe": "時間範圍", + "times": "次", + "title": "群組", + "to": "至", + "type": "類型", + "updated_at": "更新於 {{date}}" + }, + "filters": { + "add_filter": "新增篩選", + "cohort": "群組", + "filters": "篩選", + "group_property": "使用者群組 · {{property}}", + "no": "否", + "pick_cohort": "選擇群組", + "profile_property": "使用者 · {{property}}", + "remove_filter": "移除篩選", + "session_bounced": "跳出", + "session_duration": "時長", + "session_events": "事件", + "session_performed_event": "執行過事件", + "session_revenue": "收入", + "session_screen_views": "畫面瀏覽", + "yes": "是" + }, + "events": { + "page_title": "事件", + "page_description": "分頁查看你的事件、轉換和整體統計", + "tab_events": "事件", + "tab_conversions": "轉換", + "tab_stats": "統計", + "column_created_at": "建立時間", + "column_name": "名稱", + "column_profile": "使用者檔案", + "column_session_id": "工作階段 ID", + "column_device_id": "裝置 ID", + "column_country": "國家", + "column_os": "作業系統", + "column_browser": "瀏覽器", + "column_groups": "群組", + "column_properties": "屬性", + "screen_label": "畫面:", + "visit_label": "瀏覽:", + "route_name": "路由:{{path}}", + "unknown_profile": "未知", + "anonymous_profile": "匿名", + "more_properties_count_one": "還有 {{count}} 項", + "more_properties_count_other": "還有 {{count}} 項", + "empty_title": "暫無事件", + "empty_description": "開始傳送事件後,它們會顯示在這裡", + "date_range": "日期範圍", + "listening": "監聽中", + "new_events_suffix": "個新事件", + "listening_to_new_events": "正在監聽新事件", + "click_to_refresh": "點擊重新整理", + "all_events": "所有事件", + "events_per_day": "每日事件數", + "event_distribution": "事件分布" + }, + "groups": { + "page_title": "群組", + "page_description": "群組代表事件所屬的公司、團隊或其他實體。", + "group_page_title": "群組", + "group_events_title": "群組事件", + "group_members_title": "群組成員", + "add_group": "新增群組", + "all_types": "所有類型", + "empty_title": "找不到群組", + "empty_description": "群組代表事件所屬的公司、團隊或其他實體。", + "search_placeholder": "搜尋群組...", + "column_name": "名稱", + "column_id": "ID", + "column_type": "類型", + "column_members": "成員", + "column_last_active": "最後活躍", + "column_created": "建立時間", + "total_members": "總成員數", + "new_members_count": "+{{count}} 新增", + "new_members_last_30_days": "最近 30 天新增成員", + "no_data_yet": "暫無資料", + "tab_overview": "概覽", + "tab_members": "成員", + "tab_events": "事件", + "group_not_found": "找不到群組", + "edit": "編輯", + "delete": "刪除", + "delete_group": "刪除群組", + "delete_group_confirm": "確定要刪除「{{name}}」嗎?此操作無法復原。", + "total_events": "事件總數", + "unique_members": "唯一成員", + "first_seen": "首次出現", + "last_seen": "最後出現", + "group_information": "群組資訊", + "field_id": "id", + "field_name": "name", + "field_type": "type", + "field_created_at": "createdAt" + }, + "settings": { + "project_not_found": "找不到專案", + "project_settings_title": "專案設定", + "project_settings_description": "在這裡管理專案設定", + "tab_details": "詳細資料", + "tab_events": "事件", + "tab_clients_api_keys": "客戶端 / API 金鑰", + "tab_tracking_script": "追蹤程式碼", + "tab_mcp": "MCP", + "tab_widgets": "小工具", + "tab_imports": "匯入", + "tab_google_search": "Google 搜尋", + "details_title": "詳細資料", + "details_name_label": "名稱", + "details_domain_label": "網域", + "details_allowed_domains_label": "允許的網域", + "details_add_domain_placeholder": "新增網域", + "details_allow_all_domains": "允許所有網域", + "details_cross_domain_label": "跨網域支援", + "details_cross_domain_enable": "啟用跨網域支援", + "details_cross_domain_description": "這會讓你可以跨多個網域追蹤使用者", + "details_revenue_tracking_label": "收入追蹤", + "details_unsafe_revenue_enable": "允許「非安全」收入追蹤", + "details_unsafe_revenue_description": "啟用後,你可以從客戶端程式碼追蹤收入。", + "details_updated_toast": "專案已更新", + "details_domain_required": "請新增網域", + "details_cors_required": "請至少新增一個 CORS 網域", + "filters_title": "排除事件", + "filters_description": "透過新增篩選條件,排除不需要追蹤的事件。", + "filters_select_event_placeholder": "選擇事件名稱...", + "filters_add_property_filter": "新增屬性篩選", + "filters_ip_addresses_label": "IP 位址", + "filters_ip_addresses_placeholder": "排除 IP 位址", + "filters_profile_ids_label": "使用者檔案 ID", + "filters_profile_ids_placeholder": "排除使用者檔案 ID", + "filters_event_rules_label": "事件規則", + "filters_add_event_rule": "新增事件規則", + "filters_updated_toast": "專案篩選條件已更新", + "delete_account_title": "刪除帳號", + "delete_account_description": "刪除帳號會永久移除你的個人資料。你建立且沒有其他管理員的組織也會被刪除,包括其中的專案和事件。", + "delete_account_subscription_block_title": "請先取消訂閱", + "delete_account_subscription_block_description": "你建立的這些組織有有效訂閱。刪除帳號前,請逐一取消:", + "delete_project_title": "刪除專案", + "delete_project_description": "刪除專案會將它從組織中移除,並刪除所有相關資料。它會在 24 小時後被永久刪除。", + "delete_project_scheduled_toast": "專案已排程刪除", + "delete_project_cancelled_toast": "專案刪除已取消", + "delete_project_scheduled_title": "專案已排程刪除", + "delete_project_scheduled_prefix": "此專案將刪除於", + "delete_project_scheduled_suffix": "與此專案相關的所有事件都會被刪除。", + "delete_project_org_scheduled_notice": "整個組織已排程刪除。若要保留此專案,請在組織設定中取消刪除。", + "delete_project_cancel_button": "取消刪除", + "delete_project_confirm_text": "確定要刪除此專案嗎?", + "delete_organization_title": "刪除組織", + "delete_organization_description": "刪除此組織會移除它以及所有專案和相關資料。它會在 24 小時後被永久刪除。", + "delete_organization_cancelled_toast": "組織刪除已取消", + "delete_organization_scheduled_title": "組織已排程刪除", + "delete_organization_scheduled_prefix": "此組織將刪除於", + "delete_organization_scheduled_suffix": "其中所有專案及其事件都會被刪除。", + "delete_organization_subscription_block_title": "請先取消訂閱", + "delete_organization_subscription_block_description": "此組織有有效訂閱。刪除組織前,請先在帳單設定中取消訂閱。", + "invite_mail_column": "電子郵件", + "invite_email_label": "電子郵件", + "invite_search_email_placeholder": "搜尋電子郵件", + "invite_role_column": "角色", + "invite_created_column": "建立時間", + "invite_access_column": "存取權限", + "invite_revoked_toast": "{{email}} 的邀請已撤銷", + "invite_revoke_failed_toast": "撤銷 {{email}} 的邀請失敗", + "invite_copy_link": "複製邀請連結", + "invite_revoke": "撤銷邀請", + "invite_unknown_project": "未知", + "invite_all_projects": "所有專案", + "invite_user_button": "邀請使用者", + "members_name_column": "姓名", + "members_email_column": "電子郵件", + "members_search_email_placeholder": "搜尋電子郵件", + "members_role_column": "角色", + "members_created_column": "建立時間", + "members_access_column": "存取權限", + "members_all_projects": "所有專案", + "members_removed_toast": "{{name}} 已從組織中移除", + "members_remove_failed_toast": "從組織中移除 {{name}} 失敗", + "members_edit_access": "編輯存取權限", + "members_remove_member": "移除成員", + "tracking_select_client_placeholder": "選擇客戶端", + "tracking_copy_button": "複製", + "tracking_framework_prompt": "或者選擇下面的框架開始。", + "tracking_missing_framework": "缺少某個框架?", + "tracking_let_us_know": "告訴我們!", + "gsc_title": "Google Search Console", + "gsc_connect_description": "連接你的 Google Search Console 資源,以匯入搜尋成效資料。", + "gsc_authorize_description": "你將被重新導向到 Google 進行授權。我們只會要求 Search Console 資料的唯讀存取權限。", + "gsc_connect_button": "連接 Google Search Console", + "gsc_initiate_failed_toast": "無法發起 Google Search Console 連接", + "gsc_site_connected_toast": "網站已連接", + "gsc_backfill_started_toast": "已開始回填 6 個月的資料。", + "gsc_select_failed_toast": "選擇網站失敗", + "gsc_disconnected_toast": "已中斷 Google Search Console 連接", + "gsc_disconnect_failed_toast": "中斷連接失敗", + "gsc_select_property_title": "選擇資源", + "gsc_select_property_description": "選擇要連接到此專案的 Google Search Console 資源。", + "gsc_no_properties": "此 Google 帳號下找不到 Search Console 資源。", + "gsc_select_property_placeholder": "選擇資源...", + "gsc_connect_property_button": "連接資源", + "gsc_cancel_button": "取消", + "gsc_connected_description": "已連接到 Google Search Console。", + "gsc_authorization_expired": "授權已過期", + "gsc_authorization_expired_description": "你的 Google Search Console 授權已過期或被撤銷。請重新連接以繼續同步資料。", + "gsc_reconnect_button": "重新連接 Google Search Console", + "gsc_disconnect_button": "中斷連接", + "gsc_property_label": "資源", + "gsc_backfill_label": "回填", + "gsc_last_synced_label": "上次同步", + "gsc_last_error_label": "上次錯誤", + "imports_deleted_toast": "匯入已刪除", + "imports_deleted_description": "匯入已成功刪除。", + "imports_retried_toast": "已重試匯入", + "imports_retried_description": "匯入已重新加入處理佇列。", + "imports_import_data_button": "匯入資料", + "imports_history_title": "匯入歷史", + "imports_provider_column": "提供者", + "imports_created_column": "建立時間", + "imports_status_column": "狀態", + "imports_progress_column": "進度", + "imports_config_column": "設定", + "imports_actions_column": "操作", + "imports_empty_title": "還沒有匯入", + "imports_empty_description": "你的匯入歷史會顯示在這裡。", + "imports_estimated_events_tooltip": "事件數量為估算值,可能因提供者而不準確。", + "imports_config_badge": "設定", + "imports_retry_button": "重試", + "imports_delete_button": "刪除", + "mcp_title": "MCP 伺服器", + "mcp_description": "將任何相容 MCP 的 AI 客戶端(Claude、Cursor、Windsurf 等)連接到你的 OpenPanel 資料。伺服器為唯讀,並提供 38 個工具用於查詢事件、工作階段、使用者檔案、漏斗、留存等資料。", + "mcp_endpoint_label": "端點", + "mcp_token_help_prefix": "將", + "mcp_token_help_middle": "替換為", + "mcp_token_help_suffix": "你也可以把它作為", + "mcp_token_help_suffix_2": "標頭傳入,而不是使用查詢參數。", + "mcp_need_token_title": "需要權杖?", + "mcp_need_token_description_prefix": "只有", + "mcp_need_token_description_middle": "和", + "mcp_need_token_description_suffix": "客戶端可以透過 MCP 驗證。建立一個客戶端,並從成功畫面複製 MCP 權杖。它只會顯示一次。", + "mcp_create_client_button": "建立 MCP 客戶端", + "mcp_configure_client_title": "設定你的 AI 客戶端", + "mcp_config_file_label": "設定檔:", + "mcp_read_docs_button": "閱讀完整 MCP 文件", + "mcp_claude_desktop_description_prefix": "將以下設定區塊新增到", + "mcp_claude_desktop_description_suffix": "你可以從這裡開啟它:", + "mcp_claude_desktop_settings_path": "設定 → 開發人員 → 編輯設定", + "mcp_claude_code_description_prefix": "在終端機中執行一次。權杖也可以透過此標頭傳入:", + "mcp_cursor_description_prefix": "將伺服器新增到你的全域設定", + "mcp_cursor_description_suffix": "或專案設定", + "mcp_windsurf_description_prefix": "將伺服器新增到", + "mcp_windsurf_description_suffix": "Windsurf 同時接受", + "mcp_vscode_description_prefix": "將伺服器新增到工作區中的", + "mcp_vscode_description_suffix": ",或新增到你的使用者級 MCP 設定。", + "mcp_raycast_description_prefix": "複製下面的 JSON,然後在 Raycast 中執行", + "mcp_raycast_install_server": "Install Server", + "mcp_raycast_description_suffix": "命令,它會從剪貼簿自動填入表單。", + "widgets_enabled_toast": "小工具已啟用", + "widgets_disabled_toast": "小工具已停用", + "widgets_update_failed_toast": "更新小工具失敗", + "widgets_options_updated_toast": "小工具選項已更新", + "widgets_options_update_failed_toast": "更新選項失敗", + "widgets_realtime_title": "即時小工具", + "widgets_realtime_description": "在你的網站上嵌入即時訪客計數小工具。它會顯示即時訪客數、活動直方圖、熱門國家、來源和路徑。", + "widgets_options_title": "小工具選項", + "widgets_show_referrers": "顯示來源", + "widgets_show_countries": "顯示國家", + "widgets_show_paths": "顯示路徑", + "widgets_url_title": "小工具 URL", + "widgets_realtime_url_description": "小工具的直接連結。你可以在新分頁開啟,或將其嵌入。", + "widgets_embed_code_title": "嵌入程式碼", + "widgets_embed_code_description": "複製此程式碼,並貼到你希望顯示小工具的網站 HTML 中。", + "widgets_preview_title": "預覽", + "widgets_open_new_tab": "在新分頁開啟", + "widgets_counter_title": "計數器小工具", + "widgets_counter_description": "一個可嵌入任意位置的精簡即時訪客計數徽章。顯示目前唯一訪客數,並帶有即時指示器。", + "widgets_counter_url_description": "計數器小工具的直接連結。", + "widgets_badge_title": "Analytics 徽章", + "widgets_badge_description": "類似 Product Hunt 的徽章,顯示你的 30 天唯一訪客數。適合展示由 OpenPanel 提供支援的分析資料。", + "widgets_badge_url_description": "Analytics 徽章小工具的直接連結。", + "mcp_windsurf_url_connector": "和", + "widgets_realtime_preview_title": "即時小工具預覽", + "widgets_counter_preview_title": "計數器小工具預覽", + "widgets_badge_preview_title": "Analytics 徽章預覽", + "imports_provider_umami_description": "從 Umami 匯入你的分析資料", + "imports_provider_mixpanel_description": "從 Mixpanel API 匯入你的分析資料", + "imports_provider_amplitude_description": "從 Amplitude 匯出檔匯入你的分析資料" + }, + "projects": { + "metric_three_month_diff": "3 個月差異", + "metric_revenue": "收入", + "metric_three_months": "3 個月", + "metric_thirty_days": "30 天", + "metric_twenty_four_hours": "24 小時", + "chart_sessions": "工作階段", + "chart_revenue": "收入", + "chart_no_activity_title": "還沒有活動", + "chart_no_activity_description": "追蹤開始後,工作階段會顯示在這裡。", + "projects": "專案", + "select_project": "選擇專案", + "all_projects": "所有專案", + "create_new_project": "建立新專案", + "organizations": "組織", + "new_organization": "新增組織", + "project_mapper_optional": "專案映射(選填)", + "add_mapping": "新增映射", + "project_mapper_description": "將來源專案 ID 映射到你的 OpenPanel 專案。如果略過映射,所有資料都會匯入目前專案。", + "project_mapper_from_label": "來源(來源專案 ID)", + "project_mapper_from_placeholder": "例如:abc123", + "project_mapper_to_label": "目標(OpenPanel 專案)" + }, + "pages": { + "page_title": "頁面", + "page_description": "在這裡查看你的所有頁面", + "search_placeholder": "搜尋頁面", + "empty_title": "暫無頁面", + "empty_description": "將我們的 Web SDK 整合到你的網站後,頁面資料會顯示在這裡。", + "empty_search_description": "找不到符合「{{search}}」的頁面", + "column_page": "頁面", + "column_trend": "趨勢", + "column_views": "瀏覽量", + "column_sessions": "工作階段", + "column_bounce": "跳出", + "column_duration": "時長", + "column_impressions": "曝光", + "column_ctr": "CTR", + "column_clicks": "點擊", + "new_label": "新增", + "views_sessions": "瀏覽量與工作階段", + "trend_upward": "上升趨勢", + "trend_downward": "下降趨勢", + "trend_stable": "穩定趨勢" + }, + "profiles": { + "page_title": "使用者檔案", + "page_description": "如果尚未呼叫 identify,你的使用者檔案會維持匿名", + "tab_identified": "已識別", + "tab_anonymous": "匿名", + "tab_power_users": "高活躍使用者", + "search_placeholder": "搜尋使用者檔案", + "filters_title": "使用者檔案篩選", + "empty_title": "暫無使用者檔案", + "empty_description": "看起來你尚未識別任何使用者檔案。", + "column_name": "名稱", + "column_referrer": "來源", + "column_country": "國家/地區", + "column_os": "作業系統", + "column_browser": "瀏覽器", + "column_model": "型號", + "column_first_seen": "首次出現", + "column_last_seen": "最後出現", + "column_groups": "群組", + "column_events": "事件", + "most_visited_pages": "造訪最多的頁面", + "no_pages_visited_yet": "尚未造訪任何頁面", + "popular_events": "熱門事件", + "no_events_yet": "還沒有事件", + "latest_events": "最新事件", + "all": "全部", + "activity": "活躍度", + "activity_events_count_one": "{{count}} 個事件", + "activity_events_count_other": "{{count}} 個事件", + "no_activity": "沒有活動", + "groups": "群組", + "events": "事件", + "page_views": "頁面瀏覽", + "events_per_day": "每日事件", + "metric_total_events": "總事件數", + "metric_sessions": "工作階段", + "metric_page_views": "頁面瀏覽", + "metric_avg_events_per_session": "平均事件/工作階段", + "metric_bounce_rate": "跳出率", + "metric_session_duration_avg": "平均工作階段時長", + "metric_session_duration_p90": "P90 工作階段時長", + "metric_first_seen": "首次出現", + "metric_last_seen": "最後出現", + "metric_days_active": "活躍天數", + "metric_conversion_events": "轉換事件", + "metric_avg_time_between_sessions": "平均工作階段間隔(小時)", + "metric_revenue": "收入", + "profile_information": "使用者檔案資訊", + "tab_profile": "使用者檔案", + "tab_properties": "屬性", + "yes": "是", + "no": "否", + "no_properties_found": "找不到屬性" + }, + "sessions": { + "page_title": "工作階段", + "page_description": "在這裡查看你的所有工作階段", + "search_placeholder": "依路徑、來源搜尋工作階段...", + "filters_title": "工作階段篩選", + "empty_title": "找不到工作階段", + "empty_description": "看起來你尚未寫入任何事件。", + "column_started": "開始時間", + "column_session_id": "工作階段 ID", + "column_profile": "使用者檔案", + "column_entry_page": "進入頁面", + "column_exit_page": "離開頁面", + "column_duration": "時長", + "column_bounce": "跳出", + "column_referrer": "來源", + "column_location": "位置", + "column_os": "作業系統", + "column_browser": "瀏覽器", + "column_device": "裝置", + "column_page_views": "頁面瀏覽", + "column_events": "事件", + "column_revenue": "收入", + "column_device_id": "裝置 ID", + "column_groups": "群組", + "view_replay": "查看重播", + "yes": "是", + "no": "否", + "detail_title": "工作階段:{{id}}", + "detail_visited_pages": "造訪過的頁面", + "detail_event_distribution": "事件分布", + "detail_session_info": "工作階段資訊", + "detail_profile": "使用者檔案", + "detail_groups": "群組", + "detail_events": "事件", + "detail_no_events": "找不到事件", + "replay_pause": "暫停", + "replay_play": "播放", + "replay_timeline": "時間軸", + "replay_events_empty": "事件會隨著重播播放顯示在這裡。", + "replay_player_load_failed": "無法載入工作階段重播播放器。", + "replay_events_at_time_one": "{{time}} 有 {{count}} 個事件", + "replay_events_at_time_other": "{{time}} 有 {{count}} 個事件", + "replay_event_at_time": "{{event}} 於 {{time}}", + "exit_fullscreen": "退出全螢幕", + "enter_fullscreen": "進入全螢幕", + "loading_session_replay": "正在載入工作階段重播", + "no_replay_data": "此工作階段沒有可用的重播資料。" + }, + "dashboards": { + "page_title": "儀表板", + "page_description": "在這裡查看你的所有儀表板", + "dashboard": "儀表板", + "empty_title": "暫無儀表板", + "empty_description": "你尚未為這個專案建立任何儀表板", + "create_dashboard": "建立儀表板", + "force_delete": "強制刪除", + "success": "成功", + "delete_success": "儀表板已刪除。", + "more": "更多", + "detail_description": "查看並管理你的報表", + "search_reports_placeholder": "搜尋報表...", + "create_report": "建立報表", + "report": "報表", + "share_dashboard": "分享儀表板", + "reset_layout": "重設版面", + "reset_layout_confirm": "確定要將版面重設為預設嗎?這會清除所有自訂位置與尺寸。", + "delete_dashboard": "刪除儀表板", + "delete_dashboard_confirm": "確定要刪除這個儀表板嗎?其中所有報表都會被刪除!", + "no_reports_title": "暫無報表", + "no_reports_description": "你可以用報表將資料視覺化", + "no_matching_reports_title": "沒有符合的報表", + "no_matching_reports_description": "沒有報表符合「{{search}}」。請嘗試其他搜尋。", + "report_delete_success": "報表已刪除", + "report_duplicate_success": "報表已複製", + "layout_reset_success": "版面已重設為預設", + "edit": "編輯", + "delete": "刪除" + }, + "insights": { + "page_title": "洞察", + "page_description": "發現分析資料中的趨勢與變化", + "search_placeholder": "搜尋洞察...", + "time_window_placeholder": "時間視窗", + "all_windows": "所有視窗", + "yesterday": "昨天", + "seven_days": "7 天", + "thirty_days": "30 天", + "severity_placeholder": "嚴重程度", + "all_severity": "所有嚴重程度", + "severe": "嚴重", + "moderate": "中等", + "low": "低", + "no_severity": "無嚴重程度", + "direction_placeholder": "方向", + "all_directions": "所有方向", + "increasing": "上升", + "decreasing": "下降", + "flat": "持平", + "sort_placeholder": "排序方式", + "sort_impact_high_low": "影響(高 → 低)", + "sort_impact_low_high": "影響(低 → 高)", + "sort_severity_high_low": "嚴重程度(高 → 低)", + "sort_severity_low_high": "嚴重程度(低 → 高)", + "sort_most_recent": "最新", + "empty_title": "找不到洞察", + "empty_filtered_description": "嘗試調整篩選條件查看更多洞察。", + "empty_description": "偵測到分析趨勢後,洞察會顯示在這裡。", + "module_geo": "地理位置", + "module_devices": "裝置", + "module_referrers": "來源", + "module_entry_pages": "進入頁面", + "module_page_trends": "頁面趨勢", + "module_exit_pages": "離開頁面", + "module_traffic_anomalies": "異常", + "metric_share": "占比", + "metric_pageviews": "頁面瀏覽量", + "metric_sessions": "工作階段", + "count_one": "則洞察", + "count_other": "則洞察", + "showing_count": "顯示 {{count}} / {{total}} 則洞察" + }, + "share": { + "not_found_title": "找不到分享", + "report_not_found_description": "你要尋找的報表不存在。", + "dashboard_not_found_description": "你要尋找的儀表板不存在。", + "overview_not_found_description": "你要尋找的概覽不存在。", + "report": "報表", + "no_reports": "暫無報表" + }, + "seo": { + "page_title": "SEO", + "page_description": "Google Search Console 資料", + "empty_title": "暫無 SEO 資料", + "empty_description": "連接 Google Search Console 以追蹤搜尋曝光、點擊與關鍵字排名。", + "connect_gsc": "連接 Google Search Console", + "performance_description": "{{siteUrl}} 的搜尋表現", + "metric_clicks": "點擊", + "metric_impressions": "曝光", + "metric_avg_ctr": "平均 CTR", + "metric_avg_position": "平均排名", + "key_page": "頁面", + "key_query": "查詢", + "search_pages": "搜尋頁面", + "search_queries": "搜尋查詢", + "top_pages": "熱門頁面", + "top_queries": "熱門查詢", + "search_engines": "搜尋引擎", + "ai_referrals": "AI 來源", + "no_search_traffic": "此期間沒有搜尋流量", + "no_ai_traffic": "此期間沒有 AI 流量", + "chart_clicks_impressions": "點擊與曝光", + "other_source": "其他", + "metric_ctr": "CTR", + "metric_impressions_short": "曝光", + "metric_position_short": "排名", + "search": "搜尋", + "zero_results": "0 筆結果", + "results_range": "{{start}}-{{end}} / {{total}}", + "search_keywords": "搜尋關鍵字", + "keyword_cannibalization": "關鍵字蠶食", + "pages_count": "{{count}} 個頁面", + "impressions_avg_ctr_summary": "{{impressions}} 曝光 · {{ctr}}% 平均 CTR", + "cannibalization_advice_prefix": "這些頁面都在競爭", + "cannibalization_advice_suffix": "。建議將較弱頁面合併到排名最高的頁面,集中連結權重並避免分散點擊。", + "page_metrics_summary": "排名 {{position}} · {{ctr}}% CTR · {{impressions}} 曝光", + "ctr_vs_position": "CTR 與排名", + "your_ctr": "你的 CTR", + "your_avg_ctr": "你的平均 CTR", + "benchmark": "基準", + "position_number": "排名 #{{position}}", + "lower_is_better": "數值越低越好", + "insight_low_ctr": "低 CTR", + "insight_near_page_one": "接近第一頁", + "insight_low_visibility": "低可見度", + "insight_high_bounce": "高跳出", + "insight_low_ctr_headline": "排名 #{{position}},但 CTR 只有 {{ctr}}%", + "insight_low_ctr_suggestion": "你已經在第一頁,但使用者很少點擊。重寫標題標籤和 meta 描述,讓它們更有吸引力並符合搜尋意圖。", + "insight_near_page_one_headline": "排名 {{position}},再推一步就到第一頁", + "insight_near_page_one_suggestion": "更新內容、增加內部連結,或取得少量反向連結,可能把它推進前 10 並大幅提升點擊。", + "insight_invisible_clicks_headline": "{{impressions}} 次曝光,但只有 {{clicks}} 次點擊", + "insight_invisible_clicks_suggestion": "Google 經常展示這個頁面,但它幾乎沒有獲得點擊。檢查頁面是否瞄準了正確查詢,或是否需要改成更合適的內容形式(例如列表、教學)。", + "insight_high_bounce_headline": "有 {{sessions}} 個工作階段的頁面跳出率為 {{bounceRate}}%", + "insight_high_bounce_suggestion": "訪客沒有互動就離開了。檢查頁面是否兌現標題/meta 的承諾,最佳化頁面速度,並確保關鍵內容出現在首屏。", + "insight_high_bounce_no_gsc_headline": "{{sessions}} 個工作階段,跳出率 {{bounceRate}}%", + "insight_high_bounce_no_gsc_suggestion": "跳出率高且沒有搜尋可見度。檢查內容品質,並確認頁面已被索引且瞄準了正確關鍵字。", + "metrics_position_impressions_ctr": "排名 {{position}} · {{impressions}} 曝光 · {{ctr}}% CTR", + "metrics_position_impressions_clicks": "排名 {{position}} · {{impressions}} 曝光 · {{clicks}} 點擊", + "metrics_impressions_clicks_position": "{{impressions}} 曝光 · {{clicks}} 點擊 · 排名 {{position}}", + "metrics_bounce_sessions_impressions": "{{bounceRate}}% 跳出 · {{sessions}} 工作階段 · {{impressions}} 曝光", + "metrics_bounce_sessions": "{{bounceRate}}% 跳出 · {{sessions}} 工作階段", + "opportunities": "機會點" + }, + "realtime": { + "geo_title": "地理", + "paths_title": "路徑", + "referrals_title": "來源", + "column_country_city": "國家/城市", + "column_duration": "時長", + "column_events": "事件", + "column_sessions": "工作階段", + "column_path": "路徑", + "column_referrer": "來源", + "not_set": "(未設定)", + "active_users": "活躍使用者", + "referrers_label": "來源:", + "unique_visitors_last_30_min": "最近 30 分鐘不重複訪客", + "more": "更多", + "no_active_sessions": "暫無活躍工作階段", + "map_cluster_title": "即時聚合", + "map_sessions_count_one": "{{count}} 個工作階段", + "map_sessions_count_other": "{{count}} 個工作階段", + "map_profiles_count_one": "{{count}} 個使用者檔案", + "map_profiles_count_other": "{{count}} 個使用者檔案", + "map_locations": "位置", + "map_countries": "國家/地區", + "map_cities": "城市", + "map_top_referrers": "熱門來源", + "map_top_events": "熱門事件", + "map_top_paths": "熱門路徑", + "map_recent_sessions": "最近工作階段", + "no_data": "暫無資料", + "unknown_location": "未知", + "no_recent_sessions": "暫無最近工作階段", + "map_details_load_failed": "無法載入標記詳情。" + }, + "notifications": { + "page_title": "通知", + "page_description": "查看通知,並管理決定何時提醒你的規則。", + "tab_notifications": "通知", + "tab_rules": "規則", + "rules_empty_title": "還沒有規則", + "rules_empty_description": "你還沒有建立任何規則。建立一條規則即可開始接收通知。", + "action_add_rule": "新增規則", + "action_delete": "刪除", + "action_edit": "編輯", + "rule_any_event": "任意事件", + "rule_deleted_success": "規則已刪除", + "rule_events_prefix": "當以下事件", + "rule_events_suffix": "發生時通知我", + "rule_funnel_description": "當某個工作階段完成此漏斗時通知我", + "delete_rule_confirm_title": "刪除 {{name}}?", + "delete_rule_confirm_description": "此操作無法復原。", + "column_title": "標題", + "column_message": "訊息", + "column_integration": "整合", + "column_rule": "規則", + "column_country": "國家/地區", + "column_os": "作業系統", + "column_browser": "瀏覽器", + "column_profile": "使用者檔案", + "column_created_at": "建立時間", + "search_placeholder": "搜尋" + }, + "onboarding": { + "page_title": "引導流程", + "project_title": "專案", + "step_create_account": "建立帳號", + "step_create_project": "建立專案", + "step_connect_data": "連接資料", + "step_verify": "驗證", + "action_login": "登入", + "action_skip_onboarding": "略過引導", + "action_skip_for_now": "暫時略過", + "action_next": "下一步", + "action_back": "返回", + "action_copy": "複製", + "action_save": "儲存", + "action_your_dashboard": "進入儀表板", + "skip_confirm_title": "略過引導?", + "skip_confirm_description": "確定要略過引導嗎?由於你還沒有任何專案,系統會將你登出。", + "project_create_new_workspace": "建立新工作區", + "project_use_existing_workspace": "使用現有工作區", + "project_workspace_name_help": "這是你的工作區名稱,可以填寫任何你喜歡的名字。", + "project_workspace_name_placeholder": "例如:The Music Company", + "project_select_timezone": "選擇時區", + "project_select_workspace": "選擇工作區", + "project_name_placeholder": "例如:The Music App", + "project_tracking_label": "你要追蹤什麼?", + "project_type_website": "網站", + "project_type_app": "應用程式", + "project_type_backend": "後端 / API", + "project_tracking_required": "至少需要選擇一種類型", + "project_domain_allowed_prefix": "來自", + "project_domain_allowed_suffix": "的所有事件都會被允許。還要允許其他來源嗎?", + "field_workspace_name": "工作區名稱", + "field_timezone": "時區", + "field_workspace": "工作區", + "field_first_project_name": "你的第一個專案名稱", + "field_domain": "網域", + "field_allowed_domains": "允許的網域", + "field_client_id": "Client ID", + "field_client_secret": "Client secret", + "allowed_domains_placeholder": "接收來自這些網域的事件", + "allowed_domains_any_tag": "接收來自任意網域的事件", + "connect_project_missing_title": "找不到專案", + "connect_project_missing_description": "你要查找的專案不存在。請重新整理頁面。", + "connect_client_credentials_title": "用戶端憑證", + "connect_quick_start_title": "快速開始", + "connect_pick_framework": "或者在下方選擇一個框架開始。", + "connect_missing_framework": "缺少某個框架?", + "connect_let_us_know": "告訴我們!", + "verify_project_not_found": "找不到專案", + "verify_client_not_found": "找不到用戶端", + "verify_connected_title": "已成功連接", + "verify_waiting_title": "正在等待事件", + "verify_waiting_description": "驗證你的實作是否正常運作。", + "verify_more_events_one": "還有 {{count}} 個事件", + "verify_more_events_other": "還有 {{count}} 個事件", + "verify_allowed_domains_updated": "允許的網域已更新", + "verify_faq_no_events_title": "沒有收到事件?", + "verify_faq_intro": "別擔心,這種情況很常見。你可以檢查以下幾點:", + "verify_faq_client_id_title": "確認 client ID 正確", + "verify_faq_client_id_prefix": "對於網頁追蹤,程式碼片段中的", + "verify_faq_client_id_suffix": "必須與此專案相符。如有需要,可在這裡複製:", + "verify_faq_domain_title": "確認網域設定正確", + "verify_faq_domain_description": "對於網站,正確設定網域很重要。我們會根據網域驗證請求。請在下方更新允許的網域:", + "verify_faq_client_secret_title": "client secret 不正確", + "verify_faq_client_secret_prefix": "對於應用程式和後端事件,你需要正確的", + "verify_faq_client_secret_suffix": "。如有需要,可在這裡複製。不要在網頁或用戶端程式碼中使用 client secret,否則會暴露你的憑證。", + "verify_support_prefix": "仍然有問題?加入我們的", + "verify_support_discord": "Discord 頻道", + "verify_support_email_prefix": "或寄信到", + "verify_support_suffix": ",我們會協助你處理。", + "verify_personal_curl_title": "個人 curl 範例", + "testimonial_thomas_quote": "OpenPanel 是我見過最好的開源分析工具。更好的使用者體驗/介面、更多功能,還有創辦人非常出色的支援。", + "testimonial_julien_quote": "在測試了幾款產品分析工具後,我們選擇了 OpenPanel,而且非常滿意。Profiles 和 Conversion Events 是我們最喜歡的功能。", + "testimonial_piotr_quote": "Overview 分頁很棒,裡面有我需要的一切。介面漂亮、乾淨、現代,看起來非常舒服。", + "testimonial_selfhost_quote": "多年為 PostHog 支付高額費用後,OpenPanel 給了我們同樣、很多方面甚至更好的分析能力,同時讓我們完全擁有自己的資料。沒有 OpenPanel,我們已經不想再經營任何業務了。", + "testimonial_selfhost_author": "自託管使用者" + }, + "organization": { + "not_found": "找不到組織", + "details_title": "詳細資訊", + "name_label": "名稱", + "timezone_label": "時區", + "timezone_placeholder": "選擇時區", + "toast_updated": "組織已更新", + "toast_updated_description": "你的組織資訊已更新。", + "settings_page_title": "工作區設定", + "settings_page_description": "在這裡管理你的工作區設定", + "projects_empty_title": "找不到專案", + "projects_empty_admin_description": "建立你的第一個專案,開始使用分析功能。", + "projects_empty_member_description": "你目前無權存取此組織中的任何專案。請聯絡管理員授予你存取權限。", + "create_project": "建立專案", + "projects_page_title": "專案", + "projects_page_description": "此工作區中的所有專案", + "search_projects": "搜尋專案", + "feedback_prompt_title": "分享你的回饋", + "feedback_prompt_subtitle": "用你的想法幫助我們改進 OpenPanel", + "feedback_prompt_description": "你的回饋能幫助我們打造你真正需要的功能。歡迎分享想法、回報問題或提出改進建議。", + "feedback_prompt_cta": "提供回饋", + "supporter_prompt_title": "支持 OpenPanel", + "supporter_prompt_subtitle": "幫助我們打造開放分析的未來", + "supporter_prompt_cta": "成為支持者", + "supporter_prompt_footer": "每月 $20 起 • 隨時取消 •", + "supporter_prompt_learn_more": "瞭解更多", + "supporter_perk_docker_title": "最新 Docker 映像", + "supporter_perk_docker_description": "每次提交都會提供前沿建置", + "supporter_perk_support_title": "優先支援", + "supporter_perk_support_description": "透過優先 Discord 支援更快取得協助", + "supporter_perk_requests_title": "功能請求", + "supporter_perk_requests_description": "你的想法會在我們的路線圖中獲得優先考量", + "supporter_perk_discord_role_title": "專屬 Discord 身分", + "supporter_perk_discord_role_description": "在社群中獲得特別徽章與認可", + "supporter_perk_early_access_title": "搶先體驗", + "supporter_perk_early_access_description": "在公開發布前試用新功能", + "supporter_perk_impact_title": "直接影響", + "supporter_perk_impact_description": "你的支持會直接資助開發工作" + }, + "account": { + "page_title": "你的帳號", + "tab_profile": "個人資料", + "tab_email_preferences": "電子郵件偏好", + "tab_two_factor": "雙重驗證", + "profile_title": "個人資料", + "email_label": "電子郵件", + "first_name_label": "名字", + "last_name_label": "姓氏", + "toast_profile_updated": "個人資料已更新", + "toast_profile_updated_description": "你的個人資料已更新。", + "email_preferences_title": "電子郵件偏好", + "email_preferences_description": "選擇你想接收的電子郵件類型。取消勾選某個類別即可停止接收相關郵件。", + "toast_email_preferences_updated": "電子郵件偏好已更新", + "toast_email_preferences_updated_description": "你的電子郵件偏好已儲存。", + "email_category_onboarding": "新手引導", + "email_category_onboarding_description": "入門提示與引導郵件", + "email_category_billing": "帳單", + "email_category_billing_description": "訂閱更新與付款提醒", + "two_factor_title": "雙重驗證", + "two_factor_description": "使用驗證器應用程式保護你的帳號(Google Authenticator、1Password、Authy 等)。每次使用電子郵件和密碼登入時,你都需要輸入 6 位數驗證碼。", + "two_factor_not_available": "雙重驗證不可用。", + "two_factor_not_available_description": "你的帳號透過 Google 或 GitHub 登入,雙重驗證由這些服務的帳號設定處理。請在對應服務的安全性設定中啟用。", + "two_factor_disabled": "雙重驗證已關閉。", + "two_factor_enable": "啟用", + "two_factor_enabled": "雙重驗證已啟用。", + "two_factor_enabled_meta": "啟用時間 {{date}} · 剩餘 {{count}} 個恢復代碼", + "two_factor_regenerate_recovery_codes": "重新產生恢復代碼", + "two_factor_disable": "關閉", + "two_factor_enabled_meta_one": "啟用時間 {{date}} · 剩餘 {{count}} 個恢復代碼", + "two_factor_enabled_meta_other": "啟用時間 {{date}} · 剩餘 {{count}} 個恢復代碼" + }, + "members": { + "page_title": "成員", + "page_description": "在這裡管理你的成員", + "tab_members": "成員", + "tab_invitations": "邀請" + }, + "billing": { + "page_title": "帳單", + "page_description": "在這裡管理你的帳單", + "interval_month": "月", + "interval_year": "年", + "customer_portal": "客戶入口", + "free_trial_badge": "免費試用", + "no_active_plan_badge": "無有效方案", + "days_left": "剩餘 {{count}} 天", + "trial_ends_description": "你的試用將於 {{date}} 結束。結束後,儀表板會暫停,直到你選擇方案;你的資料仍會繼續流入。", + "choose_plan_title": "選擇方案", + "toast_subscription_updated": "訂閱已更新", + "toast_subscription_updated_description": "可能需要幾秒鐘才會更新", + "toast_subscription_canceled": "訂閱已取消", + "plan_cancel_subscription": "取消訂閱", + "plan_reactivate_subscription": "重新啟用訂閱", + "plan_change_subscription": "變更訂閱", + "plan_pay_with_polar": "使用 Polar 付款", + "plan_current_usage": "你目前已使用 {{count}} / {{limit}} 個事件。", + "plan_downgrade_limit_notice": "如果你的使用量超過新方案限制,則無法降級。", + "plan_switch_to_monthly": "切換為月付", + "plan_switch_to_yearly_prefix": "切換為年付並獲得", + "plan_switch_to_yearly_discount": "免費 2 個月", + "plan_monthly": "月付", + "plan_yearly": "年付", + "status_subscription_renews_on": "你的訂閱將於 {{date}} 續訂", + "status_trial_ends_on": "你的試用將於 {{date}} 結束", + "status_trial_ended": "你的免費試用已結束。", + "status_subscription_will_cancel_on": "你的訂閱將於 {{date}} 取消", + "status_subscription_canceled_on": "你的訂閱已於 {{date}} 取消", + "status_subscription_canceled": "你的訂閱已取消", + "status_payment_failed": "你上次付款失敗,請更新付款方式。", + "status_subscription_unpaid": "你的訂閱尚未付款。", + "status_subscription_incomplete": "你的訂閱設定尚未完成。", + "status_subscription_expired_on": "你的訂閱已於 {{date}} 過期", + "status_subscription_expired": "你的訂閱已過期", + "usage_title": "使用量", + "usage_loading_error": "載入使用量資料時發生問題", + "usage_empty": "尚無使用量資料", + "usage_period": "週期", + "usage_left_to_use": "剩餘額度", + "usage_events_count": "事件數", + "usage_limit": "限制", + "usage_subscription": "訂閱", + "usage_no_active_subscription": "無有效訂閱", + "usage_events_last_30_days": "過去 30 天的事件", + "usage_weekly_events": "每週事件", + "usage_daily_events": "每日事件", + "usage_unknown_date": "未知日期", + "usage_events_this_week": "本週事件", + "usage_events_this_day": "當天事件", + "usage_total_events": "總事件數", + "usage_your_events_count": "你的事件數", + "usage_your_tier_limit": "你的方案限制", + "faq_title": "常見問題", + "faq_free_tier_question": "OpenPanel 有免費方案嗎?", + "faq_free_tier_answer_trial": "Cloud 方案提供 30 天免費試用,主要是讓你在決定付費前先試用 OpenPanel。", + "faq_free_tier_answer_self_host": "OpenPanel 也是開源的,你可以免費自行託管!", + "faq_free_tier_answer_why_title": "為什麼 OpenPanel 沒有免費方案?", + "faq_free_tier_answer_why_body": "我們希望 OpenPanel 被真正重視並認真使用的人使用。同時,我們也需要投入時間與資源來維護平台並為使用者提供支援。", + "faq_exceeds_limit_question": "如果我的網站超過限制會怎樣?", + "faq_exceeds_limit_answer": "在下一個帳單週期之前,你將無法在 OpenPanel 中看到新的事件。如果連續 2 個月發生這種情況,我們會建議你升級方案。", + "faq_cancel_subscription_question": "如果我取消訂閱會怎樣?", + "faq_cancel_subscription_answer_access": "如果你取消訂閱,在目前帳單週期結束前仍可存取 OpenPanel。你可以隨時重新啟用訂閱。", + "faq_cancel_subscription_answer_data": "目前帳單週期結束後,你將無法存取新的資料。", + "faq_cancel_subscription_answer_note": "注意:如果你的帳號連續 3 個月不活躍,我們會刪除你的事件。", + "faq_billing_information_question": "如何變更我的帳單資訊?", + "faq_billing_information_answer": "你可以在帳單區域點擊「客戶入口」按鈕來變更帳單資訊。", + "faq_custom_plan_question": "我們需要自訂方案,可以協助嗎?", + "faq_custom_plan_answer": "可以。請透過 hello@openpanel.dev 聯絡我們取得報價。", + "prompt_trial_ended_badge": "試用已結束", + "prompt_trial_ended_title": "你的 30 天試用已結束", + "prompt_trial_ended_lead": "感謝你試用 OpenPanel。你設定的一切仍在這裡:專案、報表以及追蹤過的每個事件。選擇一個方案後,你的儀表板大約一分鐘內就會恢復可用。", + "prompt_trial_ended_date_label": "試用結束", + "prompt_trial_ended_cta": "使用 {{plan}},{{price}}/月繼續", + "prompt_trial_ended_note": "目前我們仍會繼續收集你傳入的事件,所以你決定期間不會遺失任何內容。", + "prompt_expired_badge": "訂閱已結束", + "prompt_expired_title": "你的資料仍在原處", + "prompt_expired_lead": "你的訂閱已結束,但我們沒有刪除任何內容。重新啟用後,你的儀表板、報表和事件會立即恢復。", + "prompt_expired_date_label": "訂閱結束", + "prompt_expired_cta": "使用 {{plan}},{{price}}/月重新啟用", + "prompt_unpaid_badge": "付款問題", + "prompt_unpaid_title": "你上次付款未成功", + "prompt_unpaid_lead": "通常是卡片過期或銀行攔截,修復只需一分鐘。更新付款方式後,你的儀表板會立即恢復。你的資料沒有遺失。", + "prompt_unpaid_date_label": "已付款至", + "prompt_unpaid_cta": "更新付款方式", + "prompt_free_plan_badge": "方案變更", + "prompt_free_plan_title": "我們已停止免費方案", + "prompt_free_plan_lead": "相比無法妥善支援的免費服務,我們更願意營運一個小而可持續的服務。付費方案從 $2.5/月起,你的資料會原樣保留。", + "prompt_free_plan_date_label": "訂閱結束", + "prompt_free_plan_cta": "使用 {{plan}},{{price}}/月繼續", + "prompt_custom_plan_cta": "取得自訂方案", + "prompt_events_tracked_label": "已追蹤事件,全部安全儲存", + "prompt_usage_recommendation_prefix": "根據你的使用量,", + "prompt_usage_recommendation_suffix": "方案適合你:每月最多 {{events}} 個事件,價格 {{price}}。", + "prompt_custom_plan_description": "你的使用量高於我們的標準方案,我們可以為你設定自訂方案。", + "prompt_see_all_plans": "查看所有方案", + "prompt_questions_email": "有問題?寄信給我們", + "prompt_feature_plans_start": "方案從 $2.5/月起", + "prompt_feature_unlimited": "不限報表、成員和專案", + "prompt_feature_funnels": "進階漏斗與轉換", + "prompt_feature_realtime": "即時分析", + "prompt_feature_kpis": "追蹤 KPI 和自訂事件", + "prompt_feature_privacy": "重視隱私並符合 GDPR", + "prompt_feature_revenue": "收入追蹤", + "prompt_feature_gsc": "Google Search Console 整合", + "days_left_one": "剩餘 {{count}} 天", + "days_left_other": "剩餘 {{count}} 天" + }, + "overview": { + "filters": "篩選", + "cohort": "群組", + "in_cohort": "在群組中", + "not_in_cohort": "不在群組中", + "operator": "運算子", + "pick_cohort": "選擇群組", + "pick_value": "選擇值", + "remove_filter": "移除篩選", + "refreshed_data": "資料已重新整理", + "unique_visitors_last_5_minutes": "過去 5 分鐘 {{count}} 位不重複訪客", + "public": "公開", + "private": "私人", + "make_public": "設為公開", + "make_private": "設為私人", + "view": "檢視", + "switch_to_chart_view": "切換到圖表檢視", + "switch_to_table_view": "切換到表格檢視", + "more": "更多", + "search": "搜尋", + "search_ellipsis": "搜尋...", + "search_column": "搜尋{{column}}...", + "search_pages": "搜尋頁面...", + "column_name": "名稱", + "no_results_found": "找不到結果", + "no_data_available": "暫無資料", + "not_set": "未設定", + "direct_not_set": "直接造訪 / 未設定", + "and_more_items_one": "還有 {{count}} 項", + "and_more_items_other": "還有 {{count}} 項", + "total": "總計", + "loading_map": "正在載入地圖...", + "error_loading_map": "地圖載入失敗", + "last_30_min": "最近 30 分鐘", + "live_30_min": "即時 · 30 分鐘", + "geo_data_provided_by": "地理資料由", + "map": "地圖", + "top_column": "熱門{{column}}", + "unique_visitors": "不重複訪客", + "sessions": "工作階段", + "sessions_short": "工作階段", + "pageviews": "瀏覽量", + "views": "瀏覽量", + "pages_per_session": "每次工作階段頁數", + "bounce_rate": "跳出率", + "session_duration": "工作階段時間", + "revenue": "收入", + "toggle_mock_revenue": "切換模擬收入(僅開發)", + "mock_revenue": "模擬收入", + "mock_revenue_on": "模擬收入已開啟", + "user_journey": "使用者旅程", + "steps_count": "{{count}} 步", + "no_journey_data_available": "暫無旅程資料", + "step_number": "第 {{step}} 步", + "share": "占比", + "percent_of_total": "占總量百分比", + "percent_of_source": "占來源百分比", + "user_journey_description": "顯示使用者在應用程式中最常見的瀏覽路徑", + "day_mon_short": "週一", + "day_tue_short": "週二", + "day_wed_short": "週三", + "day_thu_short": "週四", + "day_fri_short": "週五", + "day_sat_short": "週六", + "day_sun_short": "週日", + "day_monday": "星期一", + "day_tuesday": "星期二", + "day_wednesday": "星期三", + "day_thursday": "星期四", + "day_friday": "星期五", + "day_saturday": "星期六", + "day_sunday": "星期日", + "path": "路徑", + "bot": "機器人", + "date": "日期", + "event": "事件", + "count": "數量", + "device": "裝置", + "devices": "裝置", + "browser": "瀏覽器", + "browser_version": "瀏覽器版本", + "version": "版本", + "os": "作業系統", + "os_version": "作業系統版本", + "brand": "品牌", + "brands": "品牌", + "model": "型號", + "models": "型號", + "top_devices": "熱門裝置", + "top_browser": "熱門瀏覽器", + "top_browser_version": "熱門瀏覽器版本", + "top_os": "熱門作業系統", + "top_os_version": "熱門作業系統版本", + "top_brands": "熱門品牌", + "top_models": "熱門型號", + "countries": "國家/地區", + "regions": "地區", + "cities": "城市", + "top_countries": "熱門國家/地區", + "top_regions": "熱門地區", + "top_cities": "熱門城市", + "refs": "來源", + "urls": "URL", + "types": "類型", + "source": "來源", + "medium": "媒介", + "campaign": "行銷活動", + "term": "關鍵字", + "content": "內容", + "top_sources": "熱門來源", + "top_urls": "熱門 URL", + "top_types": "熱門類型", + "utm_source": "UTM 來源", + "utm_medium": "UTM 媒介", + "utm_campaign": "UTM 行銷活動", + "utm_term": "UTM 關鍵字", + "utm_content": "UTM 內容", + "top_pages": "熱門頁面", + "pages": "頁面", + "entry_pages": "進入頁面", + "exit_pages": "離開頁面", + "entries": "進入", + "exits": "離開", + "hide_domain": "隱藏網域", + "show_domain": "顯示網域", + "events": "事件", + "conversions": "轉換", + "link_out": "外連點擊", + "column_country": "國家/地區", + "column_region": "地區", + "column_city": "城市", + "column_browser": "瀏覽器", + "column_brand": "品牌", + "column_os": "作業系統", + "column_device": "裝置", + "column_browser_version": "瀏覽器版本", + "column_os_version": "作業系統版本", + "column_model": "型號", + "column_referrer": "推薦來源", + "column_referrer_name": "推薦來源名稱", + "column_referrer_type": "推薦來源類型", + "column_utm_source": "UTM 來源", + "column_utm_medium": "UTM 媒介", + "column_utm_campaign": "UTM 行銷活動", + "column_utm_term": "UTM 關鍵字", + "column_utm_content": "UTM 內容", + "column_countries": "國家/地區", + "column_regions": "地區", + "column_cities": "城市", + "column_browsers": "瀏覽器", + "column_brands": "品牌", + "column_oss": "作業系統", + "column_devices": "裝置", + "column_browser_versions": "瀏覽器版本", + "column_os_versions": "作業系統版本", + "column_models": "型號", + "column_referrers": "推薦來源", + "column_referrer_names": "推薦來源名稱", + "column_referrer_types": "推薦來源類型", + "column_utm_sources": "UTM 來源", + "column_utm_mediums": "UTM 媒介", + "column_utm_campaigns": "UTM 行銷活動", + "column_utm_terms": "UTM 關鍵字", + "column_utm_contents": "UTM 內容", + "and_more_items": "還有 {{count}} 項" + }, + "reports": { + "page_title": "報表", + "report": "報表", + "success": "成功", + "report_updated": "報表已更新。", + "update": "更新", + "save": "儲存", + "available_charts": "可用圖表", + "available_metrics": "可用指標", + "custom_dates": "自訂日期", + "duplicate": "複製", + "delete": "刪除", + "settings": "設定", + "compare_to_previous_period": "與上一週期比較", + "criteria": "條件", + "select_criteria": "選擇條件", + "criteria_on_or_after": "當天或之後", + "criteria_on": "當天", + "unit": "單位", + "unit_count": "計數", + "funnel_group": "漏斗分組", + "default_session": "預設:工作階段", + "session": "工作階段", + "profile": "使用者檔案", + "funnel_window": "漏斗視窗", + "default_24h": "預設:24 小時", + "mode": "模式", + "select_mode": "選擇模式", + "mode_after": "之後", + "mode_before": "之前", + "mode_between": "之間", + "steps": "步驟", + "default_5": "預設:5", + "exclude_events": "排除事件", + "select_events_to_exclude": "選擇要排除的事件", + "include_events": "包含事件", + "leave_empty_to_include_all": "留空表示包含全部", + "stack_series": "堆疊序列", + "metrics": "指標", + "formula_placeholder": "例如:A+B", + "hide_series_from_chart": "從圖表隱藏序列 {{series}}", + "select_event": "選擇事件", + "display_name": "顯示名稱", + "add_formula": "新增公式", + "add_filter": "新增篩選器", + "property_value": "屬性:{{property}}", + "select_property": "選擇屬性", + "breakdown": "細分", + "cohorts": "群組", + "select_breakdown": "選擇細分", + "global_filters": "全域篩選器", + "global_filters_description": "套用到此報表中的每個序列。", + "done": "完成", + "invalid_number": "不是有效數字", + "invalid_date": "不是有效日期", + "invalid_boolean": "使用 \"true\" 或 \"false\"", + "yes": "是", + "no": "否", + "yes_no": "是 / 否", + "select": "選擇...", + "in_cohort": "在群組中", + "not_in_cohort": "不在群組中", + "operator": "運算子", + "select_cohorts": "選擇群組...", + "value_type": "值類型", + "share": "分享", + "pick_events": "選擇事件", + "unnamed_report": "未命名報表", + "search": "搜尋", + "session_bounced": "跳出", + "session_bounced_description": "單頁瀏覽工作階段", + "session_screen_views": "畫面瀏覽", + "session_screen_views_description": "工作階段中的畫面瀏覽次數", + "session_events": "事件", + "session_events_description": "工作階段中的事件總數", + "session_duration": "時長", + "session_duration_description": "工作階段時長(毫秒)", + "session_revenue": "收入", + "session_revenue_description": "歸因到工作階段的收入", + "session_performed_event": "執行過事件", + "session_performed_event_description": "工作階段包含名為 X 的事件", + "event_properties": "事件屬性", + "profile_properties": "使用者檔案屬性", + "group_properties": "群組屬性", + "all_cohorts": "所有群組", + "session_metrics": "工作階段指標" + }, + "report_chart": { + "start_here": "從這裡開始", + "ready_when_you_are": "準備好了就開始", + "pick_event_to_start": "至少選擇一個事件以開始視覺化", + "no_data": "暫無資料", + "chart_load_error": "載入此圖表時發生錯誤。", + "loading_slow": "請稍候,正在載入", + "search_placeholder": "搜尋...", + "grouped": "分組", + "flat": "平鋪", + "unselect_all": "全部取消選擇", + "filter_by_name": "依名稱篩選", + "sort_count_high_low": "計數(從高到低)", + "sort_count_low_high": "計數(從低到高)", + "sort_name_a_z": "名稱(A 到 Z)", + "sort_name_z_a": "名稱(Z 到 A)", + "sort_percentage_high_low": "百分比(從高到低)", + "sort_percentage_low_high": "百分比(從低到高)", + "date": "日期", + "total_profiles": "使用者檔案總數", + "retention_rate": "留存率", + "retained_users": "留存使用者", + "total_users": "使用者總數", + "select_two_events": "選擇 2 個事件", + "retention_requires_two_events": "需要兩個事件才能計算留存率。", + "conversion": "轉換", + "serie": "序列", + "avg_rate": "平均轉換率", + "total": "總計", + "conversions": "轉換數", + "view_users": "查看使用者", + "add_reference": "新增參考線", + "summary_flow": "流程", + "summary_average_conversion_rate": "平均轉換率", + "summary_total_conversions": "總轉換數", + "summary_previous_average_conversion_rate": "上一週期平均轉換率", + "summary_previous_total_conversions": "上一週期總轉換數", + "summary_best_breakdown_average": "最佳細分(平均)", + "summary_worst_breakdown_average": "最差細分(平均)", + "summary_breakdown_with_rate": "{{breakdown}},{{rate}}", + "summary_best_conversion_rate": "最佳轉換率", + "summary_worst_conversion_rate": "最差轉換率", + "summary_rate_on_breakdown_at_date": "{{date}},{{breakdown}} 為 {{rate}}", + "summary_rate_at_date": "{{date}} 為 {{rate}}", + "completed": "已完成", + "dropoff_hint": "在此事件後流失。優化此步驟通常會提高轉換率。", + "most_dropoffs_after": "最多流失發生在", + "event": "事件", + "dropped_after": "之後流失", + "view_users_completed_step": "查看完成此步驟的使用者", + "current": "目前", + "previous": "上一週期", + "improvement": "提升", + "decline": "下降", + "no_change": "無變化" + } +} diff --git a/apps/start/src/router.tsx b/apps/start/src/router.tsx index 86ac130ac..647746228 100644 --- a/apps/start/src/router.tsx +++ b/apps/start/src/router.tsx @@ -1,5 +1,6 @@ import { createRouter as createTanstackRouter } from '@tanstack/react-router'; import { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query'; +import { useTranslation } from 'react-i18next'; import { FullPageEmptyState } from '@/components/full-page-empty-state'; import { LinkButton } from '@/components/ui/button'; import * as TanstackQuery from './integrations/tanstack-query/root-provider'; @@ -23,15 +24,19 @@ export const getRouter = async () => { }, }, defaultPreload: 'intent', - defaultNotFoundComponent: () => ( - - Go to home - - ), + defaultNotFoundComponent: () => { + const { t } = useTranslation(); + + return ( + + {t('common.go_home')} + + ); + }, Wrap: (props: { children: React.ReactNode }) => { return ( diff --git a/apps/start/src/routes/__root.tsx b/apps/start/src/routes/__root.tsx index 716025f5b..0914488bd 100644 --- a/apps/start/src/routes/__root.tsx +++ b/apps/start/src/routes/__root.tsx @@ -13,6 +13,8 @@ import type { QueryClient } from '@tanstack/react-query'; import { TRPCClientError } from '@trpc/client'; import type { TRPCOptionsProxy } from '@trpc/tanstack-react-query'; import { LockIcon } from 'lucide-react'; +import { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import appCss from '../styles.css?url'; import type { ConfigResonse } from './api/config'; import { FullPageEmptyState } from '@/components/full-page-empty-state'; @@ -23,6 +25,7 @@ import { ThemeScriptOnce } from '@/components/theme-provider'; import { LinkButton } from '@/components/ui/button'; import { getCookiesFn } from '@/hooks/use-cookie-store'; import { useSessionExtension } from '@/hooks/use-session-extension'; +import { normalizeLanguage } from '@/i18n/locales'; import type { RouterOutputs } from '@/trpc/client'; import { op } from '@/utils/op'; @@ -67,6 +70,8 @@ export const Route = createRootRouteWithContext()({ }), shellComponent: RootDocument, errorComponent: ({ error }) => { + const { t } = useTranslation(); + // Authorization failures (403) surface as a friendly "no access" page // instead of a scary error. 401s never reach here — handleUnauthorized // hard-redirects them to /login. @@ -75,18 +80,18 @@ export const Route = createRootRouteWithContext()({ - Go back to home + {t('common.go_back_home')} ); } return ( - Go back to home + {t('common.go_back_home')} ); }, @@ -95,9 +100,15 @@ export const Route = createRootRouteWithContext()({ function RootDocument({ children }: { children: React.ReactNode }) { useSessionExtension(); + const { i18n } = useTranslation(); + const language = normalizeLanguage(i18n.resolvedLanguage ?? i18n.language); + + useEffect(() => { + document.documentElement.lang = language; + }, [language]); return ( - + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d0048263b..034032f47 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -717,6 +717,12 @@ importers: hamburger-react: specifier: ^2.5.0 version: 2.5.0(react@19.2.3) + i18next: + specifier: ^26.3.1 + version: 26.3.1(typescript@5.9.3) + i18next-browser-languagedetector: + specifier: ^8.2.1 + version: 8.2.1 input-otp: specifier: ^1.2.4 version: 1.2.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -786,6 +792,9 @@ importers: react-hook-form: specifier: ^7.50.1 version: 7.50.1(react@19.2.3) + react-i18next: + specifier: ^17.0.8 + version: 17.0.8(i18next@26.3.1(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react-native@0.73.6(@babel/core@7.28.3)(@babel/preset-env@7.23.9(@babel/core@7.28.3))(react@19.2.3))(react@19.2.3)(typescript@5.9.3) react-in-viewport: specifier: 1.0.0-beta.8 version: 1.0.0-beta.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -2039,24 +2048,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@ast-grep/napi-linux-arm64-musl@0.40.5': resolution: {integrity: sha512-/qKsmds5FMoaEj6FdNzepbmLMtlFuBLdrAn9GIWCqOIcVcYvM1Nka8+mncfeXB/MFZKOrzQsQdPTWqrrQzXLrA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@ast-grep/napi-linux-x64-gnu@0.40.5': resolution: {integrity: sha512-DP4oDbq7f/1A2hRTFLhJfDFR6aI5mRWdEfKfHzRItmlKsR9WlcEl1qDJs/zX9R2EEtIDsSKRzuJNfJllY3/W8Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@ast-grep/napi-linux-x64-musl@0.40.5': resolution: {integrity: sha512-BRZUvVBPUNpWPo6Ns8chXVzxHPY+k9gpsubGTHy92Q26ecZULd/dTkWWdnvfhRqttsSQ9Pe/XQdi5+hDQ6RYcg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@ast-grep/napi-win32-arm64-msvc@0.40.5': resolution: {integrity: sha512-y95zSEwc7vhxmcrcH0GnK4ZHEBQrmrszRBNQovzaciF9GUqEcCACNLoBesn4V47IaOp4fYgD2/EhGRTIBFb2Ug==} @@ -3436,48 +3449,56 @@ packages: engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] + libc: [musl] '@biomejs/cli-linux-arm64-musl@2.3.15': resolution: {integrity: sha512-SSSIj2yMkFdSkXqASzIBdjySBXOe65RJlhKEDlri7MN19RC4cpez+C0kEwPrhXOTgJbwQR9QH1F4+VnHkC35pg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] + libc: [musl] '@biomejs/cli-linux-arm64@1.9.4': resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] + libc: [glibc] '@biomejs/cli-linux-arm64@2.3.15': resolution: {integrity: sha512-FN83KxrdVWANOn5tDmW6UBC0grojchbGmcEz6JkRs2YY6DY63sTZhwkQ56x6YtKhDVV1Unz7FJexy8o7KwuIhg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] + libc: [glibc] '@biomejs/cli-linux-x64-musl@1.9.4': resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] + libc: [musl] '@biomejs/cli-linux-x64-musl@2.3.15': resolution: {integrity: sha512-dbjPzTh+ijmmNwojFYbQNMFp332019ZDioBYAMMJj5Ux9d8MkM+u+J68SBJGVwVeSHMYj+T9504CoxEzQxrdNw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] + libc: [musl] '@biomejs/cli-linux-x64@1.9.4': resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] + libc: [glibc] '@biomejs/cli-linux-x64@2.3.15': resolution: {integrity: sha512-T8n9p8aiIKOrAD7SwC7opiBM1LYGrE5G3OQRXWgbeo/merBk8m+uxJ1nOXMPzfYyFLfPlKF92QS06KN1UW+Zbg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] + libc: [glibc] '@biomejs/cli-win32-arm64@1.9.4': resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==} @@ -4964,155 +4985,183 @@ packages: resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm64@1.2.4': resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.0.5': resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.0.4': resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.0.4': resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.0.4': resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.0.4': resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.33.5': resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.33.5': resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.33.5': resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.33.5': resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.33.5': resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.33.5': resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.33.5': resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} @@ -5392,72 +5441,84 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@next/swc-linux-arm64-gnu@15.0.4': resolution: {integrity: sha512-12oSaBFjGpB227VHzoXF3gJoK2SlVGmFJMaBJSu5rbpaoT5OjP5OuCLuR9/jnyBF1BAWMs/boa6mLMoJPRriMA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@next/swc-linux-arm64-gnu@16.0.7': resolution: {integrity: sha512-mloD5WcPIeIeeZqAIP5c2kdaTa6StwP4/2EGy1mUw8HiexSHGK/jcM7lFuS3u3i2zn+xH9+wXJs6njO7VrAqww==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@next/swc-linux-arm64-musl@15.0.3': resolution: {integrity: sha512-WkAk6R60mwDjH4lG/JBpb2xHl2/0Vj0ZRu1TIzWuOYfQ9tt9NFsIinI1Epma77JVgy81F32X/AeD+B2cBu/YQA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@next/swc-linux-arm64-musl@15.0.4': resolution: {integrity: sha512-QARO88fR/a+wg+OFC3dGytJVVviiYFEyjc/Zzkjn/HevUuJ7qGUUAUYy5PGVWY1YgTzeRYz78akQrVQ8r+sMjw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@next/swc-linux-arm64-musl@16.0.7': resolution: {integrity: sha512-+ksWNrZrthisXuo9gd1XnjHRowCbMtl/YgMpbRvFeDEqEBd523YHPWpBuDjomod88U8Xliw5DHhekBC3EOOd9g==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@next/swc-linux-x64-gnu@15.0.3': resolution: {integrity: sha512-gWL/Cta1aPVqIGgDb6nxkqy06DkwJ9gAnKORdHWX1QBbSZZB+biFYPFti8aKIQL7otCE1pjyPaXpFzGeG2OS2w==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@next/swc-linux-x64-gnu@15.0.4': resolution: {integrity: sha512-Z50b0gvYiUU1vLzfAMiChV8Y+6u/T2mdfpXPHraqpypP7yIT2UV9YBBhcwYkxujmCvGEcRTVWOj3EP7XW/wUnw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@next/swc-linux-x64-gnu@16.0.7': resolution: {integrity: sha512-4WtJU5cRDxpEE44Ana2Xro1284hnyVpBb62lIpU5k85D8xXxatT+rXxBgPkc7C1XwkZMWpK5rXLXTh9PFipWsA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@next/swc-linux-x64-musl@15.0.3': resolution: {integrity: sha512-QQEMwFd8r7C0GxQS62Zcdy6GKx999I/rTO2ubdXEe+MlZk9ZiinsrjwoiBL5/57tfyjikgh6GOU2WRQVUej3UA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@next/swc-linux-x64-musl@15.0.4': resolution: {integrity: sha512-7H9C4FAsrTAbA/ENzvFWsVytqRYhaJYKa2B3fyQcv96TkOGVMcvyS6s+sj4jZlacxxTcn7ygaMXUPkEk7b78zw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@next/swc-linux-x64-musl@16.0.7': resolution: {integrity: sha512-HYlhqIP6kBPXalW2dbMTSuB4+8fe+j9juyxwfMwCe9kQPPeiyFn7NMjNfoFOfJ2eXkeQsoUGXg+O2SE3m4Qg2w==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@next/swc-win32-arm64-msvc@15.0.3': resolution: {integrity: sha512-9TEp47AAd/ms9fPNgtgnT7F3M1Hf7koIYYWCMQ9neOwjbVWJsHZxrFbI3iEDJ8rf1TDGpmHbKxXf2IFpAvheIQ==} @@ -5605,24 +5666,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@node-rs/argon2-linux-arm64-musl@2.0.2': resolution: {integrity: sha512-p3YqVMNT/4DNR67tIHTYGbedYmXxW9QlFmF39SkXyEbGQwpgSf6pH457/fyXBIYznTU/smnG9EH+C1uzT5j4hA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@node-rs/argon2-linux-x64-gnu@2.0.2': resolution: {integrity: sha512-ZM3jrHuJ0dKOhvA80gKJqBpBRmTJTFSo2+xVZR+phQcbAKRlDMSZMFDiKbSTnctkfwNFtjgDdh5g1vaEV04AvA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@node-rs/argon2-linux-x64-musl@2.0.2': resolution: {integrity: sha512-of5uPqk7oCRF/44a89YlWTEfjsftPywyTULwuFDKyD8QtVZoonrJR6ZWvfFE/6jBT68S0okAkAzzMEdBVWdxWw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@node-rs/argon2-wasm32-wasi@2.0.2': resolution: {integrity: sha512-U3PzLYKSQYzTERstgtHLd4ZTkOF9co57zTXT77r0cVUsleGZOrd6ut7rHzeWwoJSiHOVxxa0OhG1JVQeB7lLoQ==} @@ -6344,36 +6409,42 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-arm64-musl@0.102.0': resolution: {integrity: sha512-DyH/t/zSZHuX4Nn239oBteeMC4OP7B13EyXWX18Qg8aJoZ+lZo90WPGOvhP04zII33jJ7di+vrtAUhsX64lp+A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-minify/binding-linux-riscv64-gnu@0.102.0': resolution: {integrity: sha512-CMvzrmOg+Gs44E7TRK/IgrHYp+wwVJxVV8niUrDR2b3SsrCO3NQz5LI+7bM1qDbWnuu5Cl1aiitoMfjRY61dSg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-s390x-gnu@0.102.0': resolution: {integrity: sha512-tZWr6j2s0ddm9MTfWTI3myaAArg9GDy4UgvpF00kMQAjLcGUNhEEQbB9Bd9KtCvDQzaan8HQs0GVWUp+DWrymw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-x64-gnu@0.102.0': resolution: {integrity: sha512-0YEKmAIun1bS+Iy5Shx6WOTSj3GuilVuctJjc5/vP8/EMTZ/RI8j0eq0Mu3UFPoT/bMULL3MBXuHuEIXmq7Ddg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-x64-musl@0.102.0': resolution: {integrity: sha512-Ew4QDpEsXoV+pG5+bJpheEy3GH436GBe6ASPB0X27Hh9cQ2gb1NVZ7cY7xJj68+fizwS/PtT8GHoG3uxyH17Pg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxc-minify/binding-openharmony-arm64@0.102.0': resolution: {integrity: sha512-wYPXS8IOu/sXiP3CGHJNPzZo4hfPAwJKevcFH2syvU2zyqUxym7hx6smfcK/mgJBiX7VchwArdGRwrEQKcBSaQ==} @@ -6475,84 +6546,98 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-arm64-gnu@0.124.0': resolution: {integrity: sha512-gNeyEcXTtfrRCbj2EfxWU85Fs0wIX3p44Y3twnvuMfkWlLrb9M1Z25AYNSKjJM+fdAjeeQCjw0on47zFuBYwQw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-arm64-musl@0.102.0': resolution: {integrity: sha512-/XWcmglH/VJ4yKAGTLRgPKSSikh3xciNxkwGiURt8dS30b+3pwc4ZZmudMu0tQ3mjSu0o7V9APZLMpbHK8Bp5w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-parser/binding-linux-arm64-musl@0.124.0': resolution: {integrity: sha512-uvG7v4Tz9S8/PVqY0SP0DLHxo4hZGe+Pv2tGVnwcsjKCCUPjplbrFVvDzXq+kOaEoUkiCY0Kt1hlZ6FDJ1LKNQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-parser/binding-linux-ppc64-gnu@0.124.0': resolution: {integrity: sha512-t7KZaaUhfp2au0MRpoENEFqwLKYDdptEry6V7pTAVdPEcFG4P6ii8yeGU9m6p5vb+b8WEKmdpGMNXBEYy7iJdw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-riscv64-gnu@0.102.0': resolution: {integrity: sha512-2jtIq4nswvy6xdqv1ndWyvVlaRpS0yqomLCvvHdCFx3pFXo5Aoq4RZ39kgvFWrbAtpeYSYeAGFnwgnqjx9ftdw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-riscv64-gnu@0.124.0': resolution: {integrity: sha512-eurGGaxHZiIQ+fBSageS8TAkRqZgdOiBeqNrWAqAPup9hXBTmQ0WcBjwsLElf+3jvDL9NhnX0dOgOqPfsjSjdg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-riscv64-musl@0.124.0': resolution: {integrity: sha512-d1V7/ll1i/LhqE/gZy6Wbz6evlk0egh2XKkwMI3epiojtbtUwQSLIER0Y3yDBBocPuWOjJdvmjtEmPTTLXje/w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [musl] '@oxc-parser/binding-linux-s390x-gnu@0.102.0': resolution: {integrity: sha512-Yp6HX/574mvYryiqj0jNvNTJqo4pdAsNP2LPBTxlDQ1cU3lPd7DUA4MQZadaeLI8+AGB2Pn50mPuPyEwFIxeFg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-s390x-gnu@0.124.0': resolution: {integrity: sha512-w1+cBvriUteOpox6ATqCFVkpGL47PFdcfCPGmgUZbd78Fw44U0gQkc+kVGvAOTvGrptMYgwomD1c6OTVvkrpGg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-x64-gnu@0.102.0': resolution: {integrity: sha512-R4b0xZpDRhoNB2XZy0kLTSYm0ZmWeKjTii9fcv1Mk3/SIGPrrglwt4U6zEtwK54Dfi4Bve5JnQYduigR/gyDzw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-x64-gnu@0.124.0': resolution: {integrity: sha512-RRB1evQiXRtMCsQQiAh9U0H3HzguLpE0ytfStuhRgmOj7tqUCOVxkHsvM9geZjAax6NqVRj7VXx32qjjkZPsBw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-x64-musl@0.102.0': resolution: {integrity: sha512-xM5A+03Ti3jvWYZoqaBRS3lusvnvIQjA46Fc9aBE/MHgvKgHSkrGEluLWg/33QEwBwxupkH25Pxc1yu97oZCtg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxc-parser/binding-linux-x64-musl@0.124.0': resolution: {integrity: sha512-asVYN0qmSHlCU8H9Q47SmeJ/Z5EG4IWCC+QGxkfFboI5qh15aLlJnHmnrV61MwQRPXGnVC/sC3qKhrUyqGxUqw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxc-parser/binding-openharmony-arm64@0.102.0': resolution: {integrity: sha512-AieLlsliblyaTFq7Iw9Nc618tgwV02JT4fQ6VIUd/3ZzbluHIHfPjIXa6Sds+04krw5TvCS8lsegtDYAyzcyhg==} @@ -6654,41 +6739,49 @@ packages: resolution: {integrity: sha512-heV2+jmXyYnUrpUXSPugqWDRpnsQcDm2AX4wzTuvgdlZfoNYO0O3W2AVpJYaDn9AG4JdM6Kxom8+foE7/BcSig==} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-arm64-musl@11.19.1': resolution: {integrity: sha512-jvo2Pjs1c9KPxMuMPIeQsgu0mOJF9rEb3y3TdpsrqwxRM+AN6/nDDwv45n5ZrUnQMsdBy5gIabioMKnQfWo9ew==} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-resolver/binding-linux-ppc64-gnu@11.19.1': resolution: {integrity: sha512-vLmdNxWCdN7Uo5suays6A/+ywBby2PWBBPXctWPg5V0+eVuzsJxgAn6MMB4mPlshskYbppjpN2Zg83ArHze9gQ==} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-riscv64-gnu@11.19.1': resolution: {integrity: sha512-/b+WgR+VTSBxzgOhDO7TlMXC1ufPIMR6Vj1zN+/x+MnyXGW7prTLzU9eW85Aj7Th7CCEG9ArCbTeqxCzFWdg2w==} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-riscv64-musl@11.19.1': resolution: {integrity: sha512-YlRdeWb9j42p29ROh+h4eg/OQ3dTJlpHSa+84pUM9+p6i3djtPz1q55yLJhgW9XfDch7FN1pQ/Vd6YP+xfRIuw==} cpu: [riscv64] os: [linux] + libc: [musl] '@oxc-resolver/binding-linux-s390x-gnu@11.19.1': resolution: {integrity: sha512-EDpafVOQWF8/MJynsjOGFThcqhRHy417sRyLfQmeiamJ8qVhSKAn2Dn2VVKUGCjVB9C46VGjhNo7nOPUi1x6uA==} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-x64-gnu@11.19.1': resolution: {integrity: sha512-NxjZe+rqWhr+RT8/Ik+5ptA3oz7tUw361Wa5RWQXKnfqwSSHdHyrw6IdcTfYuml9dM856AlKWZIUXDmA9kkiBQ==} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-x64-musl@11.19.1': resolution: {integrity: sha512-cM/hQwsO3ReJg5kR+SpI69DMfvNCp+A/eVR4b4YClE5bVZwz8rh2Nh05InhwI5HR/9cArbEkzMjcKgTHS6UaNw==} cpu: [x64] os: [linux] + libc: [musl] '@oxc-resolver/binding-openharmony-arm64@11.19.1': resolution: {integrity: sha512-QF080IowFB0+9Rh6RcD19bdgh49BpQHUW5TajG1qvWHvmrQznTZZjYlgE2ltLXyKY+qs4F/v5xuX1XS7Is+3qA==} @@ -6750,36 +6843,42 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-arm64-musl@0.102.0': resolution: {integrity: sha512-I08iWABrN7zakn3wuNIBWY3hALQGsDLPQbZT1mXws7tyiQqJNGe49uS0/O50QhX3KXj+mbRGsmjVXLXGJE1CVQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-transform/binding-linux-riscv64-gnu@0.102.0': resolution: {integrity: sha512-9+SYW1ARAF6Oj/82ayoqKRe8SI7O1qvzs3Y0kijvhIqAaaZWcFRjI5DToyWRAbnzTtHlMcSllZLXNYdmxBjFxA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-s390x-gnu@0.102.0': resolution: {integrity: sha512-HV9nTyQw0TTKYPu+gBhaJBioomiM9O4LcGXi+s5IylCGG6imP0/U13q/9xJnP267QFmiWWqnnSFcv0QAWCyh8A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-x64-gnu@0.102.0': resolution: {integrity: sha512-4wcZ08mmdFk8OjsnglyeYGu5PW3TDh87AmcMOi7tZJ3cpJjfzwDfY27KTEUx6G880OpjAiF36OFSPwdKTKgp2g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-x64-musl@0.102.0': resolution: {integrity: sha512-rUHZSZBw0FUnUgOhL/Rs7xJz9KjH2eFur/0df6Lwq/isgJc/ggtBtFoZ+y4Fb8ON87a3Y2gS2LT7SEctX0XdPQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxc-transform/binding-openharmony-arm64@0.102.0': resolution: {integrity: sha512-98y4tccTQ/pA+r2KA/MEJIZ7J8TNTJ4aCT4rX8kWK4pGOko2YsfY3Ru9DVHlLDwmVj7wP8Z4JNxdBrAXRvK+0g==} @@ -6833,36 +6932,42 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.1': resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.1': resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.1': resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.1': resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.1': resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@parcel/watcher-wasm@2.5.1': resolution: {integrity: sha512-RJxlQQLkaMMIuWRozy+z2vEqbaQlCuaCgVZIUCzQLYggY22LZbP5Y1+ia+FD724Ids9e+XIyOLXLrLgQSHIthw==} @@ -8173,24 +8278,28 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-arm64-musl@1.0.0-beta.43': resolution: {integrity: sha512-Pa8QMwlkrztTo/1mVjZmPIQ44tCSci10TBqxzVBvXVA5CFh5EpiEi99fPSll2dHG2uT4dCOMeC6fIhyDdb0zXA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@rolldown/binding-linux-x64-gnu@1.0.0-beta.43': resolution: {integrity: sha512-BgynXKMjeaX4AfWLARhOKDetBOOghnSiVRjAHVvhiAaDXgdQN8e65mSmXRiVoVtD3cHXx/cfU8Gw0p0K+qYKVQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@rolldown/binding-linux-x64-musl@1.0.0-beta.43': resolution: {integrity: sha512-VIsoPlOB/tDSAw9CySckBYysoIBqLeps1/umNSYUD8pMtalJyzMTneAVI1HrUdf4ceFmQ5vARoLIXSsPwVFxNg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@rolldown/binding-openharmony-arm64@1.0.0-beta.43': resolution: {integrity: sha512-YDXTxVJG67PqTQMKyjVJSddoPbSWJ4yRz/E3xzTLHqNrTDGY0UuhG8EMr8zsYnfH/0cPFJ3wjQd/hJWHuR6nkA==} @@ -8385,81 +8494,97 @@ packages: resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.52.5': resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.12.0': resolution: {integrity: sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-gnu@4.52.5': resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.12.0': resolution: {integrity: sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-musl@4.52.5': resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.52.5': resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.52.5': resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.12.0': resolution: {integrity: sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.52.5': resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.52.5': resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.52.5': resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.12.0': resolution: {integrity: sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.52.5': resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.12.0': resolution: {integrity: sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-linux-x64-musl@4.52.5': resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openharmony-arm64@4.52.5': resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==} @@ -9050,48 +9175,56 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': resolution: {integrity: sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.12': resolution: {integrity: sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-arm64-musl@4.1.17': resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.12': resolution: {integrity: sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-gnu@4.1.17': resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.12': resolution: {integrity: sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-musl@4.1.17': resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.12': resolution: {integrity: sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg==} @@ -10257,7 +10390,7 @@ packages: '@xmldom/xmldom@0.7.13': resolution: {integrity: sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==} engines: {node: '>=10.0.0'} - deprecated: this version has critical issues, please update to the latest version + deprecated: this version is no longer supported, please update to at least 0.8.* '@xmldom/xmldom@0.8.10': resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} @@ -13162,11 +13295,11 @@ packages: glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + deprecated: Glob versions prior to v9 are no longer supported glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + deprecated: Glob versions prior to v9 are no longer supported glob@9.3.5: resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} @@ -13411,6 +13544,9 @@ packages: html-escaper@3.0.3: resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} + html-parse-stringify@3.0.1: + resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} + html-to-text@9.0.5: resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==} engines: {node: '>=14'} @@ -13471,6 +13607,17 @@ packages: hyphenate-style-name@1.0.4: resolution: {integrity: sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==} + i18next-browser-languagedetector@8.2.1: + resolution: {integrity: sha512-bZg8+4bdmaOiApD7N7BPT9W8MLZG+nPTOFlLiJiT8uzKXFjhxw4v2ierCXOwB5sFDMtuA5G4kgYZ0AznZxQ/cw==} + + i18next@26.3.1: + resolution: {integrity: sha512-txQqd5EULsqEh9OJqRH15aCaOuy/nLJyhw5EHCSKLKJE1aBbb3Zve2+uQIxgWhPm1QqUQoWyQBm2kfmmIrzkcQ==} + peerDependencies: + typescript: ^5 || ^6 + peerDependenciesMeta: + typescript: + optional: true + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -14344,72 +14491,84 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-gnu@1.30.1: resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-gnu@1.30.2: resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.19.0: resolution: {integrity: sha512-vSCKO7SDnZaFN9zEloKSZM5/kC5gbzUjoJQ43BvUpyTFUX7ACs/mDfl2Eq6fdz2+uWhUh7vf92c4EaaP4udEtA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-arm64-musl@1.30.1: resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.19.0: resolution: {integrity: sha512-0AFQKvVzXf9byrXUq9z0anMGLdZJS+XSDqidyijI5njIwj6MdbvX2UZK/c4FfNmeRa2N/8ngTffoIuOUit5eIQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-gnu@1.30.1: resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.19.0: resolution: {integrity: sha512-SJoM8CLPt6ECCgSuWe+g0qo8dqQYVcPiW2s19dxkmSI5+Uu1GIRzyKA0b7QqmEXolA+oSJhQqCmJpzjY4CuZAg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-linux-x64-musl@1.30.1: resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.30.1: resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} @@ -16608,6 +16767,22 @@ packages: peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 + react-i18next@17.0.8: + resolution: {integrity: sha512-0ooKbGLU8JXhe1zwpQUWIeXSgLPOfwJmgheWRIUpcoA0CpyabpGhayjdG+/eA5esC1AQ8h2jWpXjJfzQzeDOCw==} + peerDependencies: + i18next: '>= 26.2.0' + react: '>= 16.8.0' + react-dom: '*' + react-native: '*' + typescript: ^5 || ^6 + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + typescript: + optional: true + react-in-viewport@1.0.0-beta.8: resolution: {integrity: sha512-vcQLHOBNHdbB9sIdtDW6LnbGPlY+WDDYbv/uWL3x/Fk61vMK1ugw1cwDwo9hpD4oNF6SAaToXLbMJ8l8KOntXQ==} peerDependencies: @@ -18019,7 +18194,6 @@ packages: tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} - deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me tar@7.4.3: resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} @@ -18960,7 +19134,6 @@ packages: uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true uuid@9.0.1: @@ -19336,6 +19509,10 @@ packages: vlq@1.0.1: resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} + void-elements@3.1.0: + resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} + engines: {node: '>=0.10.0'} + vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} @@ -27174,7 +27351,7 @@ snapshots: '@radix-ui/react-dialog@1.0.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@babel/runtime': 7.23.9 + '@babel/runtime': 7.29.2 '@radix-ui/primitive': 1.0.0 '@radix-ui/react-compose-refs': 1.0.0(react@19.2.3) '@radix-ui/react-context': 1.0.0(react@19.2.3) @@ -35227,6 +35404,10 @@ snapshots: html-escaper@3.0.3: {} + html-parse-stringify@3.0.1: + dependencies: + void-elements: 3.1.0 + html-to-text@9.0.5: dependencies: '@selderee/plugin-htmlparser2': 0.11.0 @@ -35306,6 +35487,14 @@ snapshots: hyphenate-style-name@1.0.4: {} + i18next-browser-languagedetector@8.2.1: + dependencies: + '@babel/runtime': 7.29.2 + + i18next@26.3.1(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -36842,7 +37031,7 @@ snapshots: metro-runtime@0.80.6: dependencies: - '@babel/runtime': 7.23.9 + '@babel/runtime': 7.29.2 metro-source-map@0.80.6: dependencies: @@ -39105,7 +39294,7 @@ snapshots: rc-resize-observer@1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@babel/runtime': 7.23.9 + '@babel/runtime': 7.29.2 classnames: 2.5.1 rc-util: 5.43.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 @@ -39114,7 +39303,7 @@ snapshots: rc-util@5.43.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@babel/runtime': 7.23.9 + '@babel/runtime': 7.29.2 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) react-is: 18.2.0 @@ -39232,6 +39421,18 @@ snapshots: dependencies: react: 19.2.3 + react-i18next@17.0.8(i18next@26.3.1(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react-native@0.73.6(@babel/core@7.28.3)(@babel/preset-env@7.23.9(@babel/core@7.28.3))(react@19.2.3))(react@19.2.3)(typescript@5.9.3): + dependencies: + '@babel/runtime': 7.29.2 + html-parse-stringify: 3.0.1 + i18next: 26.3.1(typescript@5.9.3) + react: 19.2.3 + use-sync-external-store: 1.6.0(react@19.2.3) + optionalDependencies: + react-dom: 19.2.3(react@19.2.3) + react-native: 0.73.6(@babel/core@7.28.3)(@babel/preset-env@7.23.9(@babel/core@7.28.3))(react@19.2.3) + typescript: 5.9.3 + react-in-viewport@1.0.0-beta.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: hoist-non-react-statics: 3.3.2 @@ -42434,6 +42635,8 @@ snapshots: vlq@1.0.1: {} + void-elements@3.1.0: {} + vscode-uri@3.1.0: {} vue-bundle-renderer@2.2.0: From 17ccd0c8b217ce6dc915540e8768d52120d6fe15 Mon Sep 17 00:00:00 2001 From: ischanx Date: Mon, 22 Jun 2026 00:50:42 +0800 Subject: [PATCH 2/8] feat(start): localize auth and onboarding flows --- apps/start/src/components/auth/or.tsx | 6 +- .../components/auth/reset-password-form.tsx | 16 ++- .../components/auth/share-enter-password.tsx | 20 +-- .../components/auth/sign-in-email-form.tsx | 16 ++- .../src/components/auth/sign-in-github.tsx | 10 +- .../src/components/auth/sign-in-google.tsx | 10 +- .../components/auth/sign-up-email-form.tsx | 16 ++- .../start/src/components/login-left-panel.tsx | 59 +++----- apps/start/src/components/login-navbar.tsx | 130 +++++++++--------- .../src/components/onboarding-left-panel.tsx | 51 ++++--- .../src/components/onboarding/connect-web.tsx | 12 +- .../onboarding/onboarding-verify-listener.tsx | 14 +- .../components/onboarding/skip-onboarding.tsx | 10 +- .../start/src/components/onboarding/steps.tsx | 15 +- .../src/components/onboarding/verify-faq.tsx | 65 +++++---- apps/start/src/routes/_login.login.tsx | 16 ++- .../src/routes/_login.reset-password.tsx | 10 +- apps/start/src/routes/_login.verify.tsx | 20 +-- apps/start/src/routes/_public.onboarding.tsx | 42 +++--- .../_steps.onboarding.$projectId.connect.tsx | 22 ++- .../_steps.onboarding.$projectId.verify.tsx | 30 +++- .../src/routes/_steps.onboarding.project.tsx | 62 +++++---- apps/start/src/routes/_steps.tsx | 22 ++- 23 files changed, 391 insertions(+), 283 deletions(-) diff --git a/apps/start/src/components/auth/or.tsx b/apps/start/src/components/auth/or.tsx index 7463afdc9..51415dee4 100644 --- a/apps/start/src/components/auth/or.tsx +++ b/apps/start/src/components/auth/or.tsx @@ -1,10 +1,14 @@ import { cn } from '@/utils/cn'; +import { useTranslation } from 'react-i18next'; export function Or({ className }: { className?: string }) { + const { t } = useTranslation(); return (
- OR + + {t('common.or')} +
); diff --git a/apps/start/src/components/auth/reset-password-form.tsx b/apps/start/src/components/auth/reset-password-form.tsx index a4d6dd4ca..533d23956 100644 --- a/apps/start/src/components/auth/reset-password-form.tsx +++ b/apps/start/src/components/auth/reset-password-form.tsx @@ -4,6 +4,7 @@ import { zResetPassword } from '@openpanel/validation'; import { useMutation } from '@tanstack/react-query'; import { useNavigate } from '@tanstack/react-router'; import { useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; import { toast } from 'sonner'; import type { z } from 'zod'; import { InputWithLabel } from '../forms/input-with-label'; @@ -13,12 +14,13 @@ const validator = zResetPassword; type IForm = z.infer; export function ResetPasswordForm({ token }: { token: string }) { + const { t } = useTranslation(); const navigate = useNavigate(); const trpc = useTRPC(); const mutation = useMutation( trpc.auth.resetPassword.mutationOptions({ onSuccess() { - toast.success('Password reset successfully'); + toast.success(t('auth.password_reset_successfully')); navigate({ to: '/login', }); @@ -45,23 +47,23 @@ export function ResetPasswordForm({ token }: { token: string }) {

- Reset your password + {t('auth.reset_your_password')}

- Already have an account?{' '} + {t('auth.already_have_account')}{' '} - Sign in + {t('auth.sign_in')}

- +
); diff --git a/apps/start/src/components/auth/share-enter-password.tsx b/apps/start/src/components/auth/share-enter-password.tsx index 9f1e7ce7a..63a5aa209 100644 --- a/apps/start/src/components/auth/share-enter-password.tsx +++ b/apps/start/src/components/auth/share-enter-password.tsx @@ -3,6 +3,7 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { type ISignInShare, zSignInShare } from '@openpanel/validation'; import { useMutation } from '@tanstack/react-query'; import { useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; import { toast } from 'sonner'; import { PublicPageCard } from '../public-page-card'; import { Button } from '../ui/button'; @@ -15,14 +16,15 @@ export function ShareEnterPassword({ shareId: string; shareType?: 'overview' | 'dashboard' | 'report'; }) { + const { t } = useTranslation(); const trpc = useTRPC(); const mutation = useMutation( - trpc.auth.signInShare.mutationOptions({ + trpc.auth.sign_inShare.mutationOptions({ onSuccess() { window.location.reload(); }, onError() { - toast.error('Incorrect password'); + toast.error(t('auth.incorrect_password')); }, }), ); @@ -45,24 +47,24 @@ export function ShareEnterPassword({ const typeLabel = shareType === 'dashboard' - ? 'Dashboard' + ? t('auth.share_type_dashboard') : shareType === 'report' - ? 'Report' - : 'Overview'; + ? t('auth.share_type_report') + : t('auth.share_type_overview'); return (
- +
); diff --git a/apps/start/src/components/auth/sign-in-email-form.tsx b/apps/start/src/components/auth/sign-in-email-form.tsx index aec9a789a..a13a66da8 100644 --- a/apps/start/src/components/auth/sign-in-email-form.tsx +++ b/apps/start/src/components/auth/sign-in-email-form.tsx @@ -5,6 +5,7 @@ import { zSignInEmail } from '@openpanel/validation'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useNavigate, useRouter } from '@tanstack/react-router'; import { type SubmitHandler, useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; import { toast } from 'sonner'; import type { z } from 'zod'; import { InputWithLabel } from '../forms/input-with-label'; @@ -17,15 +18,16 @@ export function SignInEmailForm({ isLastUsed, inviteId, }: { isLastUsed?: boolean; inviteId?: string }) { + const { t } = useTranslation(); const trpc = useTRPC(); const mutation = useMutation( - trpc.auth.signInEmail.mutationOptions({ + trpc.auth.sign_inEmail.mutationOptions({ async onSuccess(data) { if (data.type === 'totp_required') { window.location.href = '/verify'; return; } - toast.success('Successfully signed in'); + toast.success(t('auth.successfully_signed_in')); window.location.href = '/'; }, onError(error) { @@ -52,23 +54,23 @@ export function SignInEmailForm({
{isLastUsed && ( - Used last time + {t('auth.used_last_time')} )}
@@ -81,7 +83,7 @@ export function SignInEmailForm({ } className="text-sm text-muted-foreground hover:text-highlight hover:underline transition-colors duration-200 text-center mt-2" > - Forgot password? + {t('auth.forgot_password')} ); diff --git a/apps/start/src/components/auth/sign-in-github.tsx b/apps/start/src/components/auth/sign-in-github.tsx index f4e7e99d9..c7969e6d8 100644 --- a/apps/start/src/components/auth/sign-in-github.tsx +++ b/apps/start/src/components/auth/sign-in-github.tsx @@ -1,5 +1,6 @@ import { useTRPC } from '@/integrations/trpc/react'; import { useMutation } from '@tanstack/react-query'; +import { useTranslation } from 'react-i18next'; import { Button } from '../ui/button'; export function SignInGithub({ @@ -7,9 +8,10 @@ export function SignInGithub({ inviteId, isLastUsed, }: { type: 'sign-in' | 'sign-up'; inviteId?: string; isLastUsed?: boolean }) { + const { t } = useTranslation(); const trpc = useTRPC(); const mutation = useMutation( - trpc.auth.signInOAuth.mutationOptions({ + trpc.auth.sign_inOAuth.mutationOptions({ onSuccess(res) { if (res.url) { window.location.href = res.url; @@ -18,8 +20,8 @@ export function SignInGithub({ }), ); const title = () => { - if (type === 'sign-in') return 'Sign in with Github'; - if (type === 'sign-up') return 'Sign up with Github'; + if (type === 'sign-in') return t('auth.sign_in_with_github'); + if (type === 'sign-up') return t('auth.sign_up_with_github'); }; return (
@@ -47,7 +49,7 @@ export function SignInGithub({ {isLastUsed && ( - Used last time + {t('auth.used_last_time')} )}
diff --git a/apps/start/src/components/auth/sign-in-google.tsx b/apps/start/src/components/auth/sign-in-google.tsx index 35125873f..96985e0cb 100644 --- a/apps/start/src/components/auth/sign-in-google.tsx +++ b/apps/start/src/components/auth/sign-in-google.tsx @@ -1,4 +1,5 @@ import { useMutation } from '@tanstack/react-query'; +import { useTranslation } from 'react-i18next'; import { Button } from '../ui/button'; import { useTRPC } from '@/integrations/trpc/react'; @@ -11,9 +12,10 @@ export function SignInGoogle({ inviteId?: string; isLastUsed?: boolean; }) { + const { t } = useTranslation(); const trpc = useTRPC(); const mutation = useMutation( - trpc.auth.signInOAuth.mutationOptions({ + trpc.auth.sign_inOAuth.mutationOptions({ onSuccess(res) { if (res.url) { window.location.href = res.url; @@ -23,10 +25,10 @@ export function SignInGoogle({ ); const title = () => { if (type === 'sign-in') { - return 'Sign in with Google'; + return t('auth.sign_in_with_google'); } if (type === 'sign-up') { - return 'Sign up with Google'; + return t('auth.sign_up_with_google'); } }; return ( @@ -67,7 +69,7 @@ export function SignInGoogle({ {isLastUsed && ( - Used last time + {t('auth.used_last_time')} )}
diff --git a/apps/start/src/components/auth/sign-up-email-form.tsx b/apps/start/src/components/auth/sign-up-email-form.tsx index f85df49ff..d186c9ce0 100644 --- a/apps/start/src/components/auth/sign-up-email-form.tsx +++ b/apps/start/src/components/auth/sign-up-email-form.tsx @@ -5,6 +5,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useRouter } from '@tanstack/react-router'; import { type SubmitHandler, useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; import { toast } from 'sonner'; import type { z } from 'zod'; import { InputWithLabel } from '../forms/input-with-label'; @@ -16,11 +17,12 @@ type IForm = z.infer; export function SignUpEmailForm({ inviteId, }: { inviteId: string | undefined }) { + const { t } = useTranslation(); const trpc = useTRPC(); const mutation = useMutation( trpc.auth.signUpEmail.mutationOptions({ async onSuccess() { - toast.success('Successfully signed up'); + toast.success(t('auth.successfully_signed_up')); window.location.href = '/'; }, onError(error) { @@ -41,14 +43,14 @@ export function SignUpEmailForm({
); diff --git a/apps/start/src/components/login-left-panel.tsx b/apps/start/src/components/login-left-panel.tsx index ccc4288d7..48fa034e0 100644 --- a/apps/start/src/components/login-left-panel.tsx +++ b/apps/start/src/components/login-left-panel.tsx @@ -5,62 +5,35 @@ import { CarouselNext, CarouselPrevious, } from '@/components/ui/carousel'; +import { useTranslation } from 'react-i18next'; import { SellingPoint } from './selling-points'; const sellingPoints = [ { - key: 'welcome', - render: () => ( - - ), + key: 'alternative', + bgImage: '/img-1.webp', }, { - key: 'selling-point-2', - render: () => ( - - ), + key: 'reliable', + bgImage: '/img-2.webp', }, { - key: 'selling-point-3', - render: () => ( - - ), + key: 'simple', + bgImage: '/img-3.webp', }, { - key: 'selling-point-4', - render: () => ( - - ), + key: 'privacy', + bgImage: '/img-4.webp', }, { - key: 'selling-point-5', - render: () => ( - - ), + key: 'open_source', + bgImage: '/img-5.webp', }, ]; export function LoginLeftPanel() { + const { t } = useTranslation(); + return (
{/* Carousel */} @@ -79,7 +52,11 @@ export function LoginLeftPanel() { className="p-8 pb-32 pt-0" >
- {point.render()} +
))} diff --git a/apps/start/src/components/login-navbar.tsx b/apps/start/src/components/login-navbar.tsx index 67d70418c..bfaa9dd7a 100644 --- a/apps/start/src/components/login-navbar.tsx +++ b/apps/start/src/components/login-navbar.tsx @@ -1,11 +1,14 @@ import { MenuIcon, XIcon } from 'lucide-react'; import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { LanguageToggle } from './language-toggle'; import { LogoSquare } from './logo'; import { Button } from './ui/button'; import { useAppContext } from '@/hooks/use-app-context'; import { cn } from '@/utils/cn'; export function LoginNavbar({ className }: { className?: string }) { + const { t } = useTranslation(); const { isSelfHosted } = useAppContext(); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); @@ -19,90 +22,93 @@ export function LoginNavbar({ className }: { className?: string }) { - {isSelfHosted ? 'Self-hosted analytics' : 'OpenPanel.dev'} + {isSelfHosted ? t('auth.self_hosted_analytics') : 'OpenPanel.dev'} {isSelfHosted && ( )} -
- - {mobileMenuOpen && ( - <> - + {mobileMenuOpen && ( + <> +
); diff --git a/apps/start/src/components/onboarding-left-panel.tsx b/apps/start/src/components/onboarding-left-panel.tsx index 99d668cfa..e90e8edc4 100644 --- a/apps/start/src/components/onboarding-left-panel.tsx +++ b/apps/start/src/components/onboarding-left-panel.tsx @@ -3,40 +3,47 @@ import { CarouselContent, CarouselItem, } from '@/components/ui/carousel'; +import type { TFunction } from 'i18next'; import Autoplay from 'embla-carousel-autoplay'; import { QuoteIcon } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; -const testimonials = [ +type Testimonial = { + key: string; + bgImage: string; + quoteKey: string; + author?: string; + authorKey?: string; + site?: string; +}; + +const testimonials: Testimonial[] = [ { key: 'thomas', bgImage: '/img-1.webp', - quote: - "OpenPanel is BY FAR the best open-source analytics I've ever seen. Better UX/UI, many more features, and incredible support from the founder.", + quoteKey: 'onboarding.testimonial_thomas_quote', author: 'Thomas Sanlis', site: 'uneed.best', }, { key: 'julien', bgImage: '/img-2.webp', - quote: - 'After testing several product analytics tools, we chose OpenPanel and we are very satisfied. Profiles and Conversion Events are our favorite features.', + quoteKey: 'onboarding.testimonial_julien_quote', author: 'Julien Hany', site: 'strackr.com', }, { key: 'piotr', bgImage: '/img-3.webp', - quote: - 'The Overview tab is great — it has everything I need. The UI is beautiful, clean, modern, very pleasing to the eye.', + quoteKey: 'onboarding.testimonial_piotr_quote', author: 'Piotr Kulpinski', site: 'producthunt.com', }, { key: 'selfhost', bgImage: '/img-4.webp', - quote: - "After paying a lot to PostHog for years, OpenPanel gives us the same — in many ways better — analytics while keeping full ownership of our data. We don't want to run any business without OpenPanel anymore.", - author: 'Self-hosting user', + quoteKey: 'onboarding.testimonial_selfhost_quote', + authorKey: 'onboarding.testimonial_selfhost_author', site: undefined, }, ]; @@ -45,12 +52,16 @@ function TestimonialSlide({ bgImage, quote, author, + authorKey, site, + t, }: { bgImage: string; quote: string; - author: string; + author?: string; + authorKey?: string; site?: string; + t: TFunction; }) { return (
@@ -66,7 +77,7 @@ function TestimonialSlide({ {quote}
- — {author} + — {authorKey ? t(authorKey) : author} {site && · {site}}
@@ -75,6 +86,8 @@ function TestimonialSlide({ } export function OnboardingLeftPanel() { + const { t } = useTranslation(); + return (
@@ -84,14 +97,16 @@ export function OnboardingLeftPanel() { plugins={[Autoplay({ delay: 6000, stopOnInteraction: false })]} > - {testimonials.map((t) => ( - + {testimonials.map((testimonial) => ( +
diff --git a/apps/start/src/components/onboarding/connect-web.tsx b/apps/start/src/components/onboarding/connect-web.tsx index a1b4a9dee..500a5c4b9 100644 --- a/apps/start/src/components/onboarding/connect-web.tsx +++ b/apps/start/src/components/onboarding/connect-web.tsx @@ -6,12 +6,14 @@ import Syntax from '@/components/syntax'; import { useAppContext } from '@/hooks/use-app-context'; import { pushModal } from '@/modals'; import { clipboard } from '@/utils/clipboard'; +import { useTranslation } from 'react-i18next'; interface Props { client: IServiceClient | null; } const ConnectWeb = ({ client }: Props) => { + const { t } = useTranslation(); const context = useAppContext(); const code = `