diff --git a/global.d.ts b/global.d.ts new file mode 100644 index 0000000..1cbcc65 --- /dev/null +++ b/global.d.ts @@ -0,0 +1,4 @@ +// Use type safe message keys with `next-intl` +// eslint-disable-next-line @typescript-eslint/consistent-type-imports +type Messages = typeof import("./messages/en.json"); +type IntlMessages = Messages; diff --git a/messages/en.json b/messages/en.json new file mode 100644 index 0000000..c85959b --- /dev/null +++ b/messages/en.json @@ -0,0 +1,719 @@ +{ + "admin-config": {}, + "admin-config-[classify]": {}, + "admin-config-code-input-dialog": { + "edit": "Edit", + "preview": "Preview" + }, + "admin-config-config-field": { + "save": "Save" + }, + "admin-config-config-list": {}, + "admin-config-cron-input": { + "after": "After", + "any_value": "Any Value", + "day": "Day", + "hide": "Hide", + "hour": "Hour", + "minute": "Minute", + "month": "Month", + "more": "More", + "next": "Next", + "possible_values": "Possible Values", + "step": "Step", + "value_in_range": "Value in Range", + "value_separator": "Value Separator", + "week": "Week" + }, + "admin-config-layout": { + "general": "General", + "general_config_etc": "general config, etc.", + "including_log_config": "Including log config", + "log_config": "Log Config", + "node_related_config": "Node Related Config", + "payment_records": "Payment Records", + "recharge_code": "Recharge Code", + "system_config": "System Config", + "website_system_config": "Website System Config", + "withdrawal_records": "Withdrawal Records" + }, + "admin-config-payment": {}, + "admin-config-payment-info": {}, + "admin-config-payment-table": { + "info": "Info", + "received_amount": "Received Amount", + "recharge_amount": "Recharge Amount", + "reset": "Reset", + "status": "Status", + "user": "User" + }, + "admin-config-recharge-code": { + "balance": "Balance", + "batch_generate_export_recharge_code": "Batch generate and export recharge code", + "manage_recharge_code": "Manage Recharge Code", + "personal_center": "Personal Center", + "recharge_code": "Recharge Code", + "recharge_code_in": "Recharge code in", + "recharge_use": "Recharge Use" + }, + "admin-config-recharge-code-table": { + "add": "Add", + "amount": "Amount", + "cancel": "Cancel", + "confirm_delete_recharge_code": "Are you sure you want to delete this recharge code?", + "continue": "Continue", + "create_recharge_code": "Create Recharge Code", + "export_after_creation": "Export after creation", + "pieces": "pieces", + "quantity": "Quantity", + "recharge_code": "Recharge Code", + "reset": "Reset", + "save": "Save", + "total": "Total", + "usage_status": "Usage Status", + "used": "Used", + "used_by": "Used By", + "user": "User", + "yuan": "yuan" + }, + "admin-config-traffic-price-config": { + "price": "Price", + "unit": "Unit" + }, + "admin-config-withdraw": {}, + "admin-config-withdrawal-table": { + "address": "Address", + "operation_successful": "Operation Successful", + "reset": "Reset", + "status": "Status", + "user": "User", + "user_wallet_balance_updated": "User wallet earnings balance has been automatically updated", + "withdrawal_amount": "Withdrawal Amount", + "withdrawal_status_updated": "Withdrawal status has been updated" + }, + "admin-log": { + "logs": "Logs" + }, + "admin-log-log": { + "copied_to_clipboard": "Copied to clipboard" + }, + "admin-log-log-delete": { + "cancel": "Cancel", + "confirm_delete_all_logs": "Are you sure you want to delete all logs?", + "continue": "Continue" + }, + "admin-log-log-glance": {}, + "admin-log-log-search-keyword": { + "advanced_search": "Advanced Search", + "array_index_is": "Array index is", + "array_index_with": "Array index with", + "default_fuzzy_search": "Default fuzzy search", + "field": "Field", + "for_example": "For example", + "format": "Format", + "of": "of", + "query": "Query", + "search": "Search", + "separated": "separated", + "support": "Support", + "syntax": "Syntax", + "with": "with", + "wrapped": "wrapped" + }, + "admin-log-log-toolbar": { + "add_log_display_field_config": "Add log display field configuration", + "new_logs_available": "New logs available", + "reset": "Reset" + }, + "admin-log-logs": {}, + "admin-users": { + "users": "Users" + }, + "admin-users-user-role-setting": { + "modify_role": "Modify Role", + "relogin_required_after_modification": "Relogin required after modification" + }, + "admin-users-user-status": { + "activate_user": "Activate this user", + "ban_user": "Ban this user" + }, + "admin-users-user-table": { + "email": "Email", + "filter_name": "Filter Name", + "info": "Info", + "operation": "Operation", + "reset": "Reset", + "role": "Role", + "status": "Status" + }, + "agent": {}, + "agent-[agentId]-config-base": { + "basic_info": "Basic Info", + "server": "Server" + }, + "agent-[agentId]-config-other": { + "other_settings": "Other Settings", + "server": "Server" + }, + "agent-[agentId]-forward": { + "forward": "Forward", + "server": "Server" + }, + "agent-[agentId]-install": { + "install": "Install", + "server": "Server" + }, + "agent-[agentId]-layout": { + "server": "Server" + }, + "agent-[agentId]-loading": {}, + "agent-[agentId]-log": { + "logs": "Logs", + "server": "Server" + }, + "agent-[agentId]-status": { + "address": "Address", + "bandwidth": "Bandwidth", + "info": "Info", + "last_response": "Last Response", + "memory": "Memory", + "node_version": "Node Version", + "price": "Price", + "server": "Server", + "status": "Status", + "system": "System", + "traffic": "Traffic", + "unknown": "Unknown" + }, + "agent-agent-command": { + "enter_command": "Enter command", + "execute": "Execute", + "execute_command": "Execute Command", + "execution_result": "Execution Result", + "failed": "Failed", + "success": "Success", + "type": "Type" + }, + "agent-agent-config": { + "server_basic_info_settings": "Server Basic Info Settings" + }, + "agent-agent-delete": { + "all_forwarding_stopped": "All forwarding will be stopped.", + "all_related_data_deleted": "And all related data will be deleted.", + "cancel": "Cancel", + "confirm_delete_server": "Are you sure you want to delete this server?", + "continue": "Continue", + "operation_irreversible": "This action cannot be undone.", + "server_deleted_from_system": "This server will be deleted from the system." + }, + "agent-agent-form": { + "description": "Description", + "name": "Name", + "save": "Save", + "server_description": "Server Description", + "server_name": "Server Name", + "share": "Share", + "share_with_other_users": "Share with other users", + "used_to_distinguish_servers": "Used to distinguish different servers" + }, + "agent-agent-install": { + "after_installation": "After installation", + "click": "click", + "copy_command_below_to_install": "Copy the command below to install", + "copy_command_below_to_uninstall": "Copy the command below to uninstall", + "execute_in_installation_directory": "Please execute in the installation directory", + "if_installation_command_leaked": "If the installation command is leaked", + "install": "Install", + "server_status_will_change": "the server status will change", + "successful_log_message": "You will see a successful log message", + "uninstall": "Uninstall", + "uninstall_deletes_all_configs_and_files": "Uninstalling will delete all configurations and files under the installation directory", + "update": "Update", + "version": "Version", + "view_installation_progress_on_logs_page": "You can view the installation progress on the logs page" + }, + "agent-agent-list": {}, + "agent-agent-list-aside": { + "add_server": "Add Server", + "offline_servers": "Offline Servers", + "online_servers": "Online Servers", + "search_server": "Search Server", + "unknown_servers": "Unknown Servers", + "add_tips": "Click save to view the sidebar server list.Add Relay Server, Save to receive an installation command, Copy and execute it on the server" + }, + "agent-agent-menu": { + "basic_info": "Basic Info", + "config": "Config", + "forward": "Forward", + "install": "Install", + "log_config_etc": "Log config, etc.", + "logs": "Logs", + "other_settings": "Other Settings", + "port": "Port", + "price": "Price", + "remarks_etc": "Remarks, etc.", + "server_name": "Server Name", + "status": "Status" + }, + "agent-agent-price": {}, + "agent-agent-resizable-layout": {}, + "agent-bandwidth-usage": { + "download": "Download", + "upload": "Upload" + }, + "agent-cpu-usage": {}, + "agent-mem-usage": {}, + "agent-traffic-usage": { + "download": "Download", + "upload": "Upload" + }, + "auth-error": { + "access_denied": "Access Denied", + "an_error_occurred": "Whoops! Something went wrong.", + "back_to_signin": "Back to Sign In", + "check_details_provided_are_correct": "Check that the details you provided are correct.", + "check_information_provided_is_correct": "Please check that the information you provided is correct.", + "check_server_logs_for_more_info": "Check the server logs for more information.", + "email_could_not_be_sent": "The email could not be sent.", + "it_may_have_been_used_or_expired": "It may have been used already or it may have expired.", + "not_authorized_to_signin": "You are not authorized to sign in.", + "please_signin_to_access_this_page": "Please sign in to access this page.", + "server_error": "Server Error", + "server_misconfigured": "There's a problem with the server configuration.", + "signin_link_no_longer_valid": "The sign-in link is no longer valid.", + "oauth_account_not_linked": "To confirm your identity, please sign in with the same account you originally used.", + "try_signing_in_with_different_account": "Try signing in with a different account.", + "unable_to_signin": "Unable to Sign In", + "user_disabled": "User Disabled", + "your_account_has_been_disabled": "Your account has been disabled." + }, + "auth-layout": {}, + "auth-new": { + "create_password": "Create Password", + "create_password_for_account": "Create a password for your account", + "skip_password_tips": "Skip password setup and sign in directly", + "create_password_tips": "Create a password for your account, so you can sign in with your email address and password." + }, + "auth-signin": { + "and": "and", + "by_continuing_you_agree_to_our": "By continuing, you agree to our", + "continue": "Continue", + "create_an_account": "Create an Account", + "enter_email_signin_or_register": "Enter your email to sign in or create an account.", + "or_use": "Or use", + "password_signin": "Sign in with Password", + "privacy_policy": "Privacy Policy", + "registration_closed": "Registration is currently closed.", + "signin": "Sign In", + "terms_of_service": "Terms of Service", + "your_email_address": "Your Email Address" + }, + "auth-signin-credential": { + "and": "and", + "back_to_signup": "Back to Sign Up", + "by_continuing_you_agree_to_our": "By continuing, you agree to our", + "enter_valid_email_address": "Please enter a valid email address.", + "enter_your_password": "Please enter your password.", + "password_signin": "Sign in with Password", + "privacy_policy": "Privacy Policy", + "signin": "Sign In", + "terms_of_service": "Terms of Service", + "your_email_address": "Your Email Address", + "your_password": "Your Password" + }, + "auth-signout": { + "confirm": "Confirm", + "confirm_sign_out": "Sure you wanna sign out?" + }, + "auth-verify": {}, + "dashboard": { + "announcement": "Announcement", + "balance": "Balance", + "earnings": "Earnings", + "no_announcement": "No announcement", + "recent_days_traffic_usage": "Recent 7 days of traffic usage", + "system_running_normally": "System is running normally", + "system_status": "System Status", + "traffic_usage": "Traffic Usage", + "yesterday_consumption": "Yesterday's Consumption", + "yesterday_earnings": "Yesterday's Earnings" + }, + "dashboard-system-status": { + "download": "Download", + "memory": "Memory", + "network": "Network", + "upload": "Upload" + }, + "dashboard-traffic-usage": { + "used_traffic": "Used Traffic" + }, + "forward": { + "forward": "Forward" + }, + "forward-forward-delete": { + "all_related_data_deleted": "and all related data will be deleted.", + "cancel": "Cancel", + "confirm_delete_forward_config": "Are you sure you want to delete this forwarding configuration?", + "continue": "Continue", + "delete_entire_network_on_networking_page": "you should go to the networking page to delete the entire network", + "forwarding_stopped": "Forwarding will be stopped", + "if_forward_created_through_networking": "If this forwarding was created through networking", + "operation_irreversible": "This action cannot be undone." + }, + "forward-forward-modify-remark": { + "cancel": "Cancel", + "enter_remark_here": "Enter your remark here", + "save": "Save", + "update_forward_remark": "Update Forward Remark" + }, + "forward-forward-new": { + "can_be": "Can be", + "enter_forwarding_info": "Please fill in the forwarding information", + "forwarding_method": "Forwarding Method", + "forwarding_target": "Forwarding Target", + "limit_range": "Limit Range", + "more_config": "More Config", + "new_forward": "New Forward", + "no_available_servers": "No available servers", + "or_domain_name": "or domain name", + "relay_server": "Relay Server", + "remark": "Remark", + "reset": "Reset", + "save": "Save", + "select_forwarding_method": "Please select a forwarding method", + "select_relay_server": "Please select a relay server", + "server": "Server", + "server_port": "Server Port", + "target_port": "Target Port" + }, + "forward-forward-new-gost": { + "channel": "Channel", + "enable_after_selection": "Enable after selection", + "multiplexing": "Multiplexing", + "protocol": "Protocol", + "relay_data_channel": "Relay Data Channel", + "relay_data_protocol": "Relay Data Protocol" + }, + "forward-forward-reset-traffic": { + "cancel": "Cancel", + "confirm_reset_forward_traffic": "Are you sure you want to reset the traffic for this forwarding configuration?", + "continue": "Continue", + "operation_irreversible": "This action cannot be undone.", + "used_traffic_reset": "Used traffic will be reset" + }, + "forward-forward-table": { + "add": "Add", + "delete": "Delete", + "modify_remark": "Modify Remark", + "remark": "Remark", + "reset": "Reset", + "reset_traffic": "Reset Traffic", + "server": "Server", + "status": "Status", + "target": "Target", + "used_traffic": "Used Traffic", + "user": "User" + }, + "global_theme-provider": {}, + "global_monthly-traffic-usage": { + "january": "January", + "february": "February", + "march": "March", + "april": "April", + "may": "May", + "june": "June", + "july": "July", + "august": "August", + "september": "September", + "october": "October", + "november": "November", + "december": "December", + "upload": "Upload", + "download": "Download" + }, + "global_user-column": {}, + "global_channel-selector": { + "select-a-channel": "Select a channel", + "search": "Search", + "no-data": "No data" + }, + "global_search-empty-state": {}, + "global_update-password-dialog": { + "change-password": "Change Password", + "set-password": "Set Password", + "update-password": "Update Password" + }, + "global_resizable-layout": {}, + "global_traffic": {}, + "global_code-input": { + "format": "Format" + }, + "global_update-password-form": { + "password-must-be-at-least": "Password must be at least", + "characters-long": "characters long", + "and-contain-at-least": "and contain at least", + "letters-and": "letters and", + "numbers": "numbers", + "passwords-do-not-match": "Passwords do not match", + "please-enter-your-old-password": "Please enter your old password", + "old-password": "Old Password", + "password": "Password", + "confirm-password": "Confirm Password", + "save": "Save" + }, + "global_locale-switcher": { + "label": "Change language", + "locale": "{locale, select, zh {🇨🇳 简体中文} en {🇺🇸 English} other {Unknown}}" + }, + "global_faceted-filter": {}, + "global_logo": {}, + "global_id": { + "created-at": "Created at" + }, + "global_menu": { + "personal-center": "Personal Center", + "balance": "Balance", + "logout": "Logout", + "dashboard": "Dashboard", + "forward": "Forward", + "agent": "Agent", + "network": "Network", + "ticket": "Ticket", + "manage": "Manage", + "users": "Users", + "statistics": "Statistics", + "system": "System", + "log": "Log", + "config": "Config" + }, + "global_table-faceted-filter": {}, + "global_loading": {}, + "global_table": { + "no-data": "No data" + }, + "global_sidebar-nav": {}, + "global_welcome": {}, + "global_table-view-options": {}, + "index": { + "Dashboard": "Dashboard", + "Sign In": "Sign In", + "Welcome": "Welcome" + }, + "network": { + "networking": "Nope" + }, + "network-[networkId]": { + "networking": "Nope" + }, + "network-agent-edge": { + "random": "Random" + }, + "network-agent-edge-forward-settings": { + "channel": "Channel", + "default_random": "Default Random", + "enter_port_to_forward": "Enter the port you need to forward", + "forwarding_method": "Forwarding Method", + "forwarding_method_required": "Forwarding method is required", + "forwarding_port": "Forwarding Port", + "forwarding_port_required": "Forwarding port is required", + "listening_port": "Listening Port", + "listening_port_greater_than": "Listening port must be greater than", + "listening_port_less_than": "Listening port must be less than", + "port_range": "Port Range", + "relay_settings": "Relay Settings", + "target_port_greater_than": "Target port must be greater than", + "target_port_less_than": "Target port must be less than" + }, + "network-agent-edge-test": { + "avg_delay": "Avg Delay", + "diagnose_relayed_network_connection": "Diagnose relayed network connection", + "execution_result": "Execution Result", + "failed": "Failed", + "max_delay": "Max Delay", + "min_delay": "Min Delay", + "network_diagnostics": "Network Diagnostics", + "packet_loss_rate": "Packet Loss Rate", + "start": "Start", + "test": "Test", + "test_method": "Test Method" + }, + "network-agent-edge-toolbar": {}, + "network-agent-node": {}, + "network-external-node": {}, + "network-external-node-new": { + "address": "Address", + "address_or_domain_name": "address or domain name", + "create": "Create", + "create_external_node": "Create External Node", + "enter_external_node": "Enter external node", + "enter_external_node_name": "Enter external node name", + "enter_node_address": "Enter node address", + "enter_node_name": "Enter node name", + "enter_valid_address": "Please enter a valid address.", + "name": "Name", + "support": "Support", + "used_to_identify_node": "Used to identify this node" + }, + "network-network-command": { + "add_external_node": "Add External Node", + "added": "Added", + "operation": "Operation", + "search_add_server": "Search and add server" + }, + "network-network-delete": { + "all_forwarding_stopped": "All forwarding will be stopped.", + "all_related_data_deleted": "And all related data will be deleted.", + "cancel": "Cancel", + "confirm_delete_network_config": "Are you sure you want to delete this network configuration?", + "continue": "Continue", + "network_config_deleted_from_system": "This network configuration will be deleted from the system.", + "operation_irreversible": "This action cannot be undone." + }, + "network-network-edit": { + "apply_to_network": "Apply to Network", + "cancel": "Cancel", + "network_name": "Network Name", + "please_operate_with_caution": "Please proceed with caution.", + "save": "Save", + "save_as_new_network_config": "Save as New Network Config", + "this_will_overwrite_current_network_config": "This will overwrite the current network configuration.", + "update_network_config": "Update Network Config" + }, + "network-network-flow": { + "new_network": "New Network" + }, + "network-network-selector": {}, + "network-network-table": { + "copy_entrance_address": "Copy Entrance Address", + "create_new_network": "Create New Network", + "creator": "Creator", + "filter_name": "Filter Name", + "name": "Name", + "node_info": "Node Info", + "nodes": "Nodes", + "reset": "Reset", + "traffic": "Traffic" + }, + "ticket": { + "tickets": "Tickets" + }, + "ticket-[ticketId]": { + "created_at": "Created At", + "ticket": "Ticket" + }, + "ticket-markdown-input": { + "edit": "Edit", + "preview": "Preview" + }, + "ticket-new": { + "create_ticket": "Create Ticket", + "ticket": "Ticket" + }, + "ticket-new-ticket-form": { + "briefly_describe_problem": "Please briefly describe your problem", + "characters": "characters", + "content": "Content", + "format": "format", + "max_length": "Max length", + "save": "Save", + "support": "Support", + "title": "Title" + }, + "ticket-ticket-close": { + "cancel": "Cancel", + "close": "Close", + "confirm_close_ticket": "Are you sure you want to close this ticket?", + "continue": "Continue" + }, + "ticket-ticket-reply": { + "reply": "Reply" + }, + "ticket-ticket-status-badge": {}, + "ticket-ticket-table": { + "create_new_ticket": "Create New Ticket", + "creator": "Creator", + "reset": "Reset", + "status": "Status", + "title": "Title" + }, + "user-[userId]": { + "profile": "Profile", + "relogin_required_to_take_effect": "Requires re-login to take effect", + "set_name_avatar": "Set your name and avatar" + }, + "user-[userId]-account": { + "account": "Account", + "email": "Email", + "password": "Password", + "password_not_set": "Password not set", + "view_update_account_info": "View and update your account information" + }, + "user-[userId]-balance": { + "available_balance": "Available Balance", + "earnings_amount": "Earnings Amount" + }, + "user-[userId]-balance-log": { + "balance": "Balance", + "balance_history": "Balance History", + "change_amount": "Change Amount", + "other_info": "Other Info", + "time": "Time" + }, + "user-[userId]-layout": { + "account": "Account", + "balance": "Balance", + "manage_account_settings_email_preferences": "Manage your account settings and set email preferences", + "personal_center": "Personal Center", + "profile": "Profile", + "user_center": "User Center" + }, + "user-[userId]-profile-form": { + "avatar": "Avatar", + "avatar_link": "Avatar Link", + "name": "Name", + "name_displayed_in_profile": "Name displayed in your profile", + "save": "Save" + }, + "user-[userId]-recharge-balance": { + "balance_recharge": "Balance Recharge", + "enter_recharge_code": "Enter recharge code", + "recharge": "Recharge", + "recharge_code": "Recharge Code" + }, + "user-[userId]-recharge-depay": { + "after_clicking_confirm": "After clicking confirm", + "and": "and", + "confirm": "Confirm", + "enter_crypto_wallet_select_payment_method": "you will enter the crypto wallet to select a payment method", + "invalid_amount": "Invalid amount", + "minimum_recharge_amount": "Minimum recharge amount", + "notes": "Notes", + "recharge": "Recharge", + "recharge_amount": "Recharge Amount", + "recharge_failed": "Recharge Failed", + "recharge_handling_fee": "Recharge requires a handling fee of", + "recharge_successful": "Recharge Successful", + "support": "Support", + "supported_networks": "Supported networks" + }, + "user-[userId]-update-balance": { + "add_or_subtract_balance": "Add or subtract balance for the user", + "amount": "Amount", + "reduce_balance": "Reduce Balance", + "remark": "Remark", + "save": "Save", + "update_balance": "Update Balance" + }, + "user-[userId]-withdrawal-balance": { + "amount": "Amount", + "current_earnings_balance": "Current Earnings Balance", + "deduct_handling_fee": "A handling fee will be deducted", + "minimum_withdrawal_amount": "Minimum withdrawal amount is", + "please_provide": "Please provide", + "receiving_address": "Receiving Address", + "request_withdrawal": "Request Withdrawal", + "request_withdrawal_to_specified_address": "Request withdrawal to the specified address", + "subject_to_actual_received_amount": "Subject to the actual received amount", + "withdrawal": "Withdrawal" + } +} diff --git a/messages/zh.json b/messages/zh.json new file mode 100644 index 0000000..9c65efb --- /dev/null +++ b/messages/zh.json @@ -0,0 +1,719 @@ +{ + "admin-config": {}, + "admin-config-[classify]": {}, + "admin-config-code-input-dialog": { + "edit": "编辑", + "preview": "预览" + }, + "admin-config-config-field": { + "save": "保存" + }, + "admin-config-config-list": {}, + "admin-config-cron-input": { + "after": "之后", + "any_value": "任何值", + "day": "日", + "hide": "隐藏", + "hour": "时", + "minute": "分", + "month": "月", + "more": "更多", + "next": "下次", + "possible_values": "可取的值", + "step": "步长", + "value_in_range": "范围内的值", + "value_separator": "取值分隔符", + "week": "周" + }, + "admin-config-layout": { + "general": "通用", + "general_config_etc": "通用配置等", + "including_log_config": "包括日志配置", + "log_config": "日志配置", + "node_related_config": "节点相关配置", + "payment_records": "支付记录", + "recharge_code": "充值码", + "system_config": "系统配置", + "website_system_config": "网站系统配置", + "withdrawal_records": "提现记录" + }, + "admin-config-payment-info": {}, + "admin-config-payment": {}, + "admin-config-payment-table": { + "info": "信息", + "received_amount": "到账金额", + "recharge_amount": "充值金额", + "reset": "重置", + "status": "状态", + "user": "用户" + }, + "admin-config-recharge-code": { + "balance": "余额", + "batch_generate_export_recharge_code": "可以批量生成导出充值码", + "manage_recharge_code": "管理充值码", + "personal_center": "个人中心", + "recharge_code": "充值码", + "recharge_code_in": "充值码在", + "recharge_use": "充值使用" + }, + "admin-config-recharge-code-table": { + "add": "添加", + "amount": "金额", + "cancel": "取消", + "confirm_delete_recharge_code": "你确认要删除这条充值码吗", + "continue": "继续", + "create_recharge_code": "创建充值码", + "export_after_creation": "创建后导出", + "pieces": "个", + "quantity": "数量", + "recharge_code": "充值码", + "reset": "重置", + "save": "保存", + "total": "共", + "usage_status": "使用状态", + "used": "已使用", + "used_by": "使用用户", + "user": "用户", + "yuan": "元" + }, + "admin-config-traffic-price-config": { + "price": "价格", + "unit": "单位" + }, + "admin-config-withdraw": {}, + "admin-config-withdrawal-table": { + "address": "地址", + "operation_successful": "操作成功", + "reset": "重置", + "status": "状态", + "user": "用户", + "user_wallet_balance_updated": "已自动更新用户钱包收益余额", + "withdrawal_amount": "提现金额", + "withdrawal_status_updated": "提现状态已更新" + }, + "admin-log": { + "logs": "日志" + }, + "admin-log-log": { + "copied_to_clipboard": "已复制到剪贴板" + }, + "admin-log-log-delete": { + "cancel": "取消", + "confirm_delete_all_logs": "你确认要删除所有日志吗", + "continue": "继续" + }, + "admin-log-log-glance": {}, + "admin-log-log-search-keyword": { + "advanced_search": "高级搜索", + "array_index_is": "数组下标为", + "array_index_with": "数组下标以", + "default_fuzzy_search": "默认模糊查询", + "field": "字段", + "for_example": "如", + "format": "格式", + "of": "的", + "query": "查询", + "search": "搜索", + "separated": "分割", + "support": "支持", + "syntax": "语法", + "with": "以", + "wrapped": "包裹" + }, + "admin-log-log-toolbar": { + "add_log_display_field_config": "增加日志展示字段的配置", + "new_logs_available": "有新日志", + "reset": "重置" + }, + "admin-log-logs": {}, + "admin-users": { + "users": "用户" + }, + "admin-users-user-role-setting": { + "modify_role": "修改角色", + "relogin_required_after_modification": "修改之后需重新登录" + }, + "admin-users-user-status": { + "activate_user": "激活此用户", + "ban_user": "封禁此用户" + }, + "admin-users-user-table": { + "email": "邮箱", + "filter_name": "过滤名称", + "info": "信息", + "operation": "操作", + "reset": "重置", + "role": "角色", + "status": "状态" + }, + "agent": {}, + "agent-[agentId]-config-base": { + "basic_info": "基础信息", + "server": "服务器" + }, + "agent-[agentId]-config-other": { + "other_settings": "其它设置", + "server": "服务器" + }, + "agent-[agentId]-forward": { + "forward": "转发", + "server": "服务器" + }, + "agent-[agentId]-install": { + "install": "安装", + "server": "服务器" + }, + "agent-[agentId]-layout": { + "server": "服务器" + }, + "agent-[agentId]-loading": {}, + "agent-[agentId]-log": { + "logs": "日志", + "server": "服务器" + }, + "agent-[agentId]-status": { + "address": "地址", + "bandwidth": "带宽", + "info": "信息", + "last_response": "上次响应", + "memory": "内存", + "node_version": "节点版本", + "price": "价格", + "server": "服务器", + "status": "状态", + "system": "系统", + "traffic": "流量", + "unknown": "未知" + }, + "agent-agent-command": { + "enter_command": "请输入命令", + "execute": "执行", + "execute_command": "执行命令", + "execution_result": "执行结果", + "failed": "失败", + "success": "成功", + "type": "类型" + }, + "agent-agent-config": { + "server_basic_info_settings": "服务器基本信息设置" + }, + "agent-agent-delete": { + "all_forwarding_stopped": "会停止所有的转发", + "all_related_data_deleted": "并且删除所有相关的数据", + "cancel": "取消", + "confirm_delete_server": "你确认要删除这台服务器吗", + "continue": "继续", + "operation_irreversible": "这个操作不可逆转", + "server_deleted_from_system": "将会从系统上将这台服务器删除" + }, + "agent-agent-form": { + "description": "描述", + "name": "名称", + "save": "保存", + "server_description": "服务器描述", + "server_name": "服务器名称", + "share": "共享", + "share_with_other_users": "是否共享给其他用户", + "used_to_distinguish_servers": "用于区分不同服务器" + }, + "agent-agent-install": { + "after_installation": "安装完成后", + "click": "可以点击", + "copy_command_below_to_install": "复制下方命令进行安装", + "copy_command_below_to_uninstall": "复制下方命令进行卸载", + "execute_in_installation_directory": "请在安装目录下执行", + "if_installation_command_leaked": "如果安装命令泄露", + "install": "安装", + "server_status_will_change": "服务器状态将会修改", + "successful_log_message": "成功将会看到一条", + "uninstall": "卸载", + "uninstall_deletes_all_configs_and_files": "卸载后会删除所有配置和安装目录下的文件", + "update": "更新", + "version": "版本", + "view_installation_progress_on_logs_page": "可以通过日志页面查看安装情况" + }, + "agent-agent-list": {}, + "agent-agent-list-aside": { + "add_server": "添加服务器", + "offline_servers": "掉线服务器", + "online_servers": "在线服务器", + "search_server": "搜索服务器", + "unknown_servers": "未知服务器", + "add_tips": "点击保存后查看侧边服务器栏。添加中转服务器,保存后会给你一个安装命令,复制到服务器上执行即可" + }, + "agent-agent-menu": { + "basic_info": "基础信息", + "config": "配置", + "forward": "转发", + "install": "安装", + "log_config_etc": "日志等配置", + "logs": "日志", + "other_settings": "其它设置", + "port": "端口", + "price": "价格", + "remarks_etc": "备注等", + "server_name": "服务器名称", + "status": "状态" + }, + "agent-agent-price": {}, + "agent-agent-resizable-layout": {}, + "agent-bandwidth-usage": { + "download": "下载", + "upload": "上传" + }, + "agent-cpu-usage": {}, + "agent-mem-usage": {}, + "agent-traffic-usage": { + "download": "下载", + "upload": "上传" + }, + "auth-error": { + "access_denied": "拒绝访问", + "an_error_occurred": "发生错误", + "back_to_signin": "返回登录", + "check_details_provided_are_correct": "检查您提供的详细信息是否正确", + "check_information_provided_is_correct": "请检查您提供的信息是否正确", + "check_server_logs_for_more_info": "检查服务器日志以获取更多信息", + "email_could_not_be_sent": "电子邮件无法发送", + "it_may_have_been_used_or_expired": "它可能已经被使用过或者可能已经过期", + "not_authorized_to_signin": "您没有登录权限", + "please_signin_to_access_this_page": "请登录才能访问此页面", + "server_error": "服务器错误", + "server_misconfigured": "服务器配置有问题", + "signin_link_no_longer_valid": "登录链接不再有效", + "oauth_account_not_linked": "要确认您的身份,请使用您最初使用的同一帐户登录", + "try_signing_in_with_different_account": "尝试使用其他帐户登录", + "unable_to_signin": "无法登录", + "user_disabled": "用户已禁用", + "your_account_has_been_disabled": "您的帐户已被禁用" + }, + "auth-layout": {}, + "auth-new": { + "create_password": "创建密码", + "signin_directly": "直接登录", + "skip_password_tips": "不设置密码,直接登录", + "create_password_tips": "为您的账户创建一个密码,以便您可以使用电子邮件地址和密码登录" + }, + "auth-signin": { + "and": "和", + "by_continuing_you_agree_to_our": "继续即表示您同意我们的", + "continue": "继续", + "create_an_account": "创建一个账号", + "enter_email_signin_or_register": "输入你的邮箱来登录或者注册一个账号", + "or_use": "或者使用", + "password_signin": "密码登录", + "privacy_policy": "隐私政策", + "registration_closed": "已关闭注册", + "signin": "登录", + "terms_of_service": "服务条款", + "your_email_address": "你的邮箱地址" + }, + "auth-signin-credential": { + "and": "和", + "back_to_signup": "返回注册", + "by_continuing_you_agree_to_our": "继续即表示您同意我们的", + "enter_valid_email_address": "请输入正确的邮箱地址", + "enter_your_password": "请输入你的密码", + "password_signin": "密码登录", + "privacy_policy": "隐私政策", + "signin": "登录", + "terms_of_service": "服务条款", + "your_email_address": "你的邮箱地址", + "your_password": "你的密码" + }, + "auth-signout": { + "confirm": "确认", + "confirm_sign_out": "确认退出登录" + }, + "auth-verify": {}, + "dashboard": { + "announcement": "公告", + "balance": "余额", + "earnings": "收益", + "no_announcement": "暂无公告", + "recent_days_traffic_usage": "最近7天的流量使用情况", + "system_running_normally": "系统运行正常", + "system_status": "系统状态", + "traffic_usage": "流量使用", + "yesterday_consumption": "昨日消费", + "yesterday_earnings": "昨日收益" + }, + "dashboard-system-status": { + "download": "下载", + "memory": "内存", + "network": "网络", + "upload": "上传" + }, + "dashboard-traffic-usage": { + "used_traffic": "使用流量" + }, + "forward": { + "forward": "Forward" + }, + "forward-forward-delete": { + "all_related_data_deleted": "并且删除所有相关的数据", + "cancel": "取消", + "confirm_delete_forward_config": "你确认要删除这个转发配置吗", + "continue": "继续", + "delete_entire_network_on_networking_page": "你应该去组网页面删除整个组网", + "forwarding_stopped": "将会停止转发", + "if_forward_created_through_networking": "如果这个转发是通过组网创建的", + "operation_irreversible": "这个操作不可逆转" + }, + "forward-forward-modify-remark": { + "cancel": "取消", + "enter_remark_here": "在这里输入你的备注", + "save": "保存", + "update_forward_remark": "更新转发备注" + }, + "forward-forward-new": { + "can_be": "可以是", + "enter_forwarding_info": "请填写转发信息", + "forwarding_method": "转发方式", + "forwarding_target": "转发目标", + "limit_range": "限制范围", + "more_config": "更多配置", + "new_forward": "新增转发", + "no_available_servers": "暂无可用服务器", + "or_domain_name": "或者域名", + "relay_server": "中转服务器", + "remark": "备注", + "reset": "重置", + "save": "保存", + "select_forwarding_method": "请选择一种转发方式进行转发", + "select_relay_server": "请选择中转服务器", + "server": "服务器", + "server_port": "服务器端口", + "target_port": "目标端口" + }, + "forward-forward-new-gost": { + "channel": "通道", + "enable_after_selection": "选择后开启", + "multiplexing": "多路复用", + "protocol": "协议", + "relay_data_channel": "中转数据通道", + "relay_data_protocol": "中转数据协议" + }, + "forward-forward-reset-traffic": { + "cancel": "取消", + "confirm_reset_forward_traffic": "你确认要重置这个转发配置的流量吗", + "continue": "继续", + "operation_irreversible": "这个操作不可逆转", + "used_traffic_reset": "将会重置已使用的流量" + }, + "forward-forward-table": { + "add": "添加", + "delete": "删除", + "modify_remark": "修改备注", + "remark": "备注", + "reset": "重置", + "reset_traffic": "重置流量", + "server": "服务器", + "status": "状态", + "target": "目标", + "used_traffic": "已用流量", + "user": "用户" + }, + "index": { + "Dashboard": "控制台", + "Sign In": "登录", + "Welcome": "欢迎" + }, + "global_theme-provider": {}, + "global_monthly-traffic-usage": { + "january": "一月", + "february": "二月", + "march": "三月", + "april": "四月", + "may": "五月", + "june": "六月", + "july": "七月", + "august": "八月", + "september": "九月", + "october": "十月", + "november": "十一月", + "december": "十二月", + "upload": "上传", + "download": "下载" + }, + "global_user-column": {}, + "global_channel-selector": { + "select-a-channel": "选择一个通道", + "search": "搜索", + "no-data": "无数据" + }, + "global_search-empty-state": {}, + "global_update-password-dialog": { + "change-password": "更改密码", + "set-password": "设置密码", + "update-password": "更新密码" + }, + "global_resizable-layout": {}, + "global_traffic": {}, + "global_code-input": { + "format": "格式化" + }, + "global_update-password-form": { + "password-must-be-at-least": "密码必须至少为", + "characters-long": "个字符", + "and-contain-at-least": "并且至少包含", + "letters-and": "个字母和", + "numbers": "个数字", + "passwords-do-not-match": "密码不匹配", + "please-enter-your-old-password": "请输入原密码", + "old-password": "原密码", + "password": "密码", + "confirm-password": "确认密码", + "save": "保存" + }, + "global_locale-switcher": { + "label": "选择语言", + "locale": "{locale, select, zh {🇨🇳 简体中文} en {🇺🇸 English} other {Unknown}}" + }, + "global_faceted-filter": {}, + "global_logo": {}, + "global_id": { + "created-at": "创建于" + }, + "global_menu": { + "personal-center": "个人中心", + "balance": "余额", + "logout": "退出", + "dashboard": "控制台", + "forward": "转发", + "agent": "服务器", + "network": "组网", + "ticket": "工单", + "manage": "管理", + "users": "用户", + "statistics": "统计", + "system": "系统", + "log": "日志", + "config": "配置" + }, + "global_table-faceted-filter": {}, + "global_loading": {}, + "global_table": { + "no-data": "无数据" + }, + "global_sidebar-nav": {}, + "global_welcome": {}, + "global_table-view-options": {}, + "network": { + "networking": "组网" + }, + "network-[networkId]": { + "networking": "组网" + }, + "network-agent-edge": { + "random": "随机" + }, + "network-agent-edge-forward-settings": { + "channel": "通道", + "default_random": "默认随机", + "enter_port_to_forward": "填写你需要转发的端口", + "forwarding_method": "转发方式", + "forwarding_method_required": "必须选择转发方式", + "forwarding_port": "转发端口", + "forwarding_port_required": "必须填写转发端口", + "listening_port": "监听端口", + "listening_port_greater_than": "监听端口必须大于", + "listening_port_less_than": "监听端口必须小于", + "port_range": "端口范围", + "relay_settings": "中转设置", + "target_port_greater_than": "目标端口必须大于", + "target_port_less_than": "目标端口必须小于" + }, + "network-agent-edge-test": { + "avg_delay": "平均延迟", + "diagnose_relayed_network_connection": "诊断中转的网络连接", + "execution_result": "执行结果", + "failed": "失败", + "max_delay": "最大延迟", + "min_delay": "最小延迟", + "network_diagnostics": "网络诊断", + "packet_loss_rate": "丢包率", + "start": "开始", + "test": "测试", + "test_method": "测试方式" + }, + "network-agent-edge-toolbar": {}, + "network-agent-node": {}, + "network-external-node": {}, + "network-external-node-new": { + "address": "地址", + "address_or_domain_name": "地址或域名", + "create": "创建", + "create_external_node": "创建外部节点", + "enter_external_node": "请输入外部节点的", + "enter_external_node_name": "请输入外部节点的名称", + "enter_node_address": "请输入节点地址", + "enter_node_name": "请输入节点名称", + "enter_valid_address": "请输入正确的地址", + "name": "名称", + "support": "支持", + "used_to_identify_node": "用于标识该节点" + }, + "network-network-command": { + "add_external_node": "添加外部节点", + "added": "已添加", + "operation": "操作", + "search_add_server": "搜索添加服务器" + }, + "network-network-delete": { + "all_forwarding_stopped": "会停止所有的转发", + "all_related_data_deleted": "并且删除所有相关的数据", + "cancel": "取消", + "confirm_delete_network_config": "你确认要删除这条网络配置吗", + "continue": "继续", + "network_config_deleted_from_system": "将会从系统上将这条网络配置删除", + "operation_irreversible": "这个操作不可逆转" + }, + "network-network-edit": { + "apply_to_network": "是否应用至网络", + "cancel": "取消", + "network_name": "组网名称", + "please_operate_with_caution": "请谨慎操作", + "save": "保存", + "save_as_new_network_config": "保存为新的组网配置", + "this_will_overwrite_current_network_config": "选择此选项将会覆盖当前网络配置", + "update_network_config": "更新组网配置" + }, + "network-network-flow": { + "new_network": "新的组网" + }, + "network-network-selector": {}, + "network-network-table": { + "copy_entrance_address": "复制入口地址", + "create_new_network": "创建新的组网", + "creator": "创建者", + "filter_name": "过滤名称", + "name": "名称", + "node_info": "节点信息", + "nodes": "个节点", + "reset": "重置", + "traffic": "流量" + }, + "ticket": { + "tickets": "工单" + }, + "ticket-[ticketId]": { + "created_at": "创建时间", + "ticket": "工单" + }, + "ticket-markdown-input": { + "edit": "编辑", + "preview": "预览" + }, + "ticket-new": { + "create_ticket": "创建工单", + "ticket": "工单" + }, + "ticket-new-ticket-form": { + "briefly_describe_problem": "请简要描述您的问题", + "characters": "字符", + "content": "内容", + "format": "格式", + "max_length": "最大长度", + "save": "保存", + "support": "支持", + "title": "标题" + }, + "ticket-ticket-close": { + "cancel": "取消", + "close": "关闭", + "confirm_close_ticket": "你确认要关闭这个工单吗", + "continue": "继续" + }, + "ticket-ticket-reply": { + "reply": "回复" + }, + "ticket-ticket-status-badge": {}, + "ticket-ticket-table": { + "create_new_ticket": "创建新的工单", + "creator": "创建者", + "reset": "重置", + "status": "状态", + "title": "标题" + }, + "user-[userId]": { + "profile": "个人资料", + "relogin_required_to_take_effect": "需要重新登录后生效", + "set_name_avatar": "设置你的名称和头像" + }, + "user-[userId]-account": { + "account": "账号", + "email": "邮箱", + "password": "密码", + "password_not_set": "未设置密码", + "view_update_account_info": "查看和更新你的账号信息" + }, + "user-[userId]-balance": { + "available_balance": "可消费余额", + "earnings_amount": "收益金额" + }, + "user-[userId]-balance-log": { + "balance": "余额", + "balance_history": "余额历史", + "change_amount": "变动金额", + "other_info": "其它信息", + "time": "时间" + }, + "user-[userId]-layout": { + "account": "账户", + "balance": "余额", + "manage_account_settings_email_preferences": "管理您的帐户设置并设置电子邮件首选项", + "personal_center": "个人中心", + "profile": "个人资料", + "user_center": "用户中心" + }, + "user-[userId]-profile-form": { + "avatar": "头像", + "avatar_link": "头像链接", + "name": "名称", + "name_displayed_in_profile": "显示在您的个人资料中的名称", + "save": "保存" + }, + "user-[userId]-recharge-balance": { + "balance_recharge": "余额充值", + "enter_recharge_code": "请输入充值码", + "recharge": "充值", + "recharge_code": "充值码" + }, + "user-[userId]-recharge-depay": { + "after_clicking_confirm": "点击确认后", + "and": "和", + "confirm": "确认", + "enter_crypto_wallet_select_payment_method": "将会进入加密钱包选择支付方式", + "invalid_amount": "无效的金额", + "minimum_recharge_amount": "充值金额最低", + "notes": "注意事项", + "recharge": "充值", + "recharge_amount": "充值金额", + "recharge_failed": "充值失败", + "recharge_handling_fee": "充值需要收取", + "recharge_successful": "充值成功", + "support": "支持", + "supported_networks": "支持的网络" + }, + "user-[userId]-update-balance": { + "add_or_subtract_balance": "为用户添加或减少余额", + "amount": "金额", + "reduce_balance": "减少余额", + "remark": "备注", + "save": "保存", + "update_balance": "更新余额" + }, + "user-[userId]-withdrawal-balance": { + "amount": "金额", + "current_earnings_balance": "当前收益余额", + "deduct_handling_fee": "需要扣除部分手续费", + "minimum_withdrawal_amount": "最低提现金额为", + "please_provide": "请提供", + "receiving_address": "收款地址", + "request_withdrawal": "申请提现", + "request_withdrawal_to_specified_address": "申请提现到指定的地址", + "subject_to_actual_received_amount": "以实际到账金额为准", + "withdrawal": "提现" + } +} diff --git a/next.config.js b/next.config.js index b273362..c519344 100644 --- a/next.config.js +++ b/next.config.js @@ -2,8 +2,12 @@ * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful * for Docker builds. */ +import createNextIntlPlugin from "next-intl/plugin"; + await import("./src/env.js"); +const withNextIntl = createNextIntlPlugin(); + /** @type {import("next").NextConfig} */ const config = { experimental: { @@ -30,4 +34,4 @@ const config = { }, }; -export default config; +export default withNextIntl(config); diff --git a/package-lock.json b/package-lock.json index c3225ba..58af33c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,6 +57,7 @@ "lucide-react": "^0.316.0", "next": "^14.1.0", "next-auth": "^4.24.5", + "next-intl": "^3.9.5", "next-themes": "^0.2.1", "nodemailer": "^6.9.9", "pino": "^8.17.2", @@ -3371,6 +3372,92 @@ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==" }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.18.2.tgz", + "integrity": "sha512-+QoPW4csYALsQIl8GbN14igZzDbuwzcpWrku9nyMXlaqAlwRBgl5V+p0vWMGFqHOw37czNXaP/lEk4wbLgcmtA==", + "dependencies": { + "@formatjs/intl-localematcher": "0.5.4", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/ecma402-abstract/node_modules/@formatjs/intl-localematcher": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz", + "integrity": "sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz", + "integrity": "sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.0.tgz", + "integrity": "sha512-Qxv/lmCN6hKpBSss2uQ8IROVnta2r9jd3ymUEIjm2UyIkUCHVcbUVRGL/KS/wv7876edvsPe+hjHVJ4z8YuVaw==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/icu-skeleton-parser": "1.3.6", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser/node_modules/@formatjs/ecma402-abstract": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz", + "integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==", + "dependencies": { + "@formatjs/intl-localematcher": "0.2.25", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser/node_modules/@formatjs/intl-localematcher": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz", + "integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.6.tgz", + "integrity": "sha512-I96mOxvml/YLrwU2Txnd4klA7V8fRhb6JG/4hm3VMNmeJo1F03IpV2L3wWt7EweqNLES59SZ4d6hVOPCSf80Bg==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser/node_modules/@formatjs/ecma402-abstract": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz", + "integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==", + "dependencies": { + "@formatjs/intl-localematcher": "0.2.25", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser/node_modules/@formatjs/intl-localematcher": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz", + "integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.2.32", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.32.tgz", + "integrity": "sha512-k/MEBstff4sttohyEpXxCmC3MqbUn9VvHGlZ8fauLzkbwXmVrEeyzS+4uhrvAk9DWU9/7otYWxyDox4nT/KVLQ==", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@hookform/resolvers": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.3.4.tgz", @@ -11251,6 +11338,34 @@ "node": ">=12" } }, + "node_modules/intl-messageformat": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.13.0.tgz", + "integrity": "sha512-7sGC7QnSQGa5LZP7bXLDhVDtQOeKGeBFGHF2Y8LVBwYZoQZCgWeKoPGTa5GMG8g/TzDgeXuYJQis7Ggiw2xTOw==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/fast-memoize": "1.2.1", + "@formatjs/icu-messageformat-parser": "2.1.0", + "tslib": "^2.1.0" + } + }, + "node_modules/intl-messageformat/node_modules/@formatjs/ecma402-abstract": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz", + "integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==", + "dependencies": { + "@formatjs/intl-localematcher": "0.2.25", + "tslib": "^2.1.0" + } + }, + "node_modules/intl-messageformat/node_modules/@formatjs/intl-localematcher": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz", + "integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -14127,6 +14242,14 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/next": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/next/-/next-14.1.0.tgz", @@ -14199,6 +14322,26 @@ } } }, + "node_modules/next-intl": { + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-3.9.5.tgz", + "integrity": "sha512-tsp4N433WgTAbbyZdMlcsLGHFM88wv2a7ZpF/od8X9+qAlO1TrajZrNrGBpIg6nA9EGZyMbQPzZD7XZrqYIv7g==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "dependencies": { + "@formatjs/intl-localematcher": "^0.2.32", + "negotiator": "^0.6.3", + "use-intl": "^3.9.5" + }, + "peerDependencies": { + "next": "^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/next-themes": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz", @@ -17643,6 +17786,18 @@ } } }, + "node_modules/use-intl": { + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-3.9.5.tgz", + "integrity": "sha512-1g+f/pKEeXqOXrd+QBvwnIN5kzM56PHsorbVWzNvlnGk2fo/eRwuuT/S0jTuzKLRW4uNybpHvRs6U06rP31iKw==", + "dependencies": { + "@formatjs/ecma402-abstract": "^1.11.4", + "intl-messageformat": "^9.3.18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/use-sidecar": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", diff --git a/package.json b/package.json index ad5a920..995257d 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "lucide-react": "^0.316.0", "next": "^14.1.0", "next-auth": "^4.24.5", + "next-intl": "^3.9.5", "next-themes": "^0.2.1", "nodemailer": "^6.9.9", "pino": "^8.17.2", diff --git a/src/app/(manage)/admin/config/payment/page.tsx b/src/app/(manage)/admin/config/payment/page.tsx deleted file mode 100644 index 1e05cfa..0000000 --- a/src/app/(manage)/admin/config/payment/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import PaymentTable from "~/app/(manage)/admin/config/_components/payment-table"; - -export default function PaymentPage() { - return ; -} diff --git a/src/app/(manage)/admin/config/withdraw/page.tsx b/src/app/(manage)/admin/config/withdraw/page.tsx deleted file mode 100644 index a02775d..0000000 --- a/src/app/(manage)/admin/config/withdraw/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import WithdrawalTable from "~/app/(manage)/admin/config/_components/withdrawal-table"; - -export default function WithdrawalPage() { - return ; -} diff --git a/src/app/(manage)/forward/page.tsx b/src/app/(manage)/forward/page.tsx deleted file mode 100644 index 0db7afd..0000000 --- a/src/app/(manage)/forward/page.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import ForwardTable from "~/app/(manage)/forward/_components/forward-table"; - -export const metadata = { - title: "转发 - vortex", -}; - -export default function Forward() { - return ( -
-

转发

- -
- ); -} diff --git a/src/app/(manage)/network/page.tsx b/src/app/(manage)/network/page.tsx deleted file mode 100644 index e4384ce..0000000 --- a/src/app/(manage)/network/page.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import "reactflow/dist/style.css"; -import NetworkTable from "~/app/(manage)/network/_components/network-table"; - -export const metadata = { - title: "组网 - vortex", -}; - -export default async function NetworksPage({ - searchParams: { keyword }, -}: { - searchParams: { keyword: string }; -}) { - return ( -
-
-

Network

-
- -
- ); -} diff --git a/src/app/(manage)/ticket/page.tsx b/src/app/(manage)/ticket/page.tsx deleted file mode 100644 index d0b689d..0000000 --- a/src/app/(manage)/ticket/page.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import TicketTable from "~/app/(manage)/ticket/_components/ticket-table"; - -export const metadata = { - title: "工单 - vortex", -}; - -export default function TicketsPage({ - searchParams: { keyword }, -}: { - searchParams: { keyword: string }; -}) { - return ( -
-
-

工单

-
- -
- ); -} diff --git a/src/app/(manage)/admin/config/[classify]/page.tsx b/src/app/[local]/(manage)/admin/config/[classify]/page.tsx similarity index 93% rename from src/app/(manage)/admin/config/[classify]/page.tsx rename to src/app/[local]/(manage)/admin/config/[classify]/page.tsx index 238ad29..fec046b 100644 --- a/src/app/(manage)/admin/config/[classify]/page.tsx +++ b/src/app/[local]/(manage)/admin/config/[classify]/page.tsx @@ -1,5 +1,5 @@ import { api } from "~/trpc/server"; -import ConfigList from "~/app/(manage)/admin/config/_components/config-list"; +import ConfigList from "~/app/[local]/(manage)/admin/config/_components/config-list"; import { GLOBAL_CONFIG_SCHEMA_MAP } from "~/lib/constants/config"; import { type CONFIG_KEY } from "~/lib/types"; diff --git a/src/app/(manage)/admin/config/_components/code-input-dialog.tsx b/src/app/[local]/(manage)/admin/config/_components/code-input-dialog.tsx similarity index 97% rename from src/app/(manage)/admin/config/_components/code-input-dialog.tsx rename to src/app/[local]/(manage)/admin/config/_components/code-input-dialog.tsx index 15b9e9c..45eedaa 100644 --- a/src/app/(manage)/admin/config/_components/code-input-dialog.tsx +++ b/src/app/[local]/(manage)/admin/config/_components/code-input-dialog.tsx @@ -5,7 +5,7 @@ import { DialogTitle, DialogTrigger, } from "~/lib/ui/dialog"; -import CodeInput from "~/app/_components/code-input"; +import CodeInput from "~/app/[local]/_components/code-input"; import { useState } from "react"; import { Tabs, TabsList, TabsTrigger } from "~/lib/ui/tabs"; import Markdown from "react-markdown"; diff --git a/src/app/(manage)/admin/config/_components/config-field.tsx b/src/app/[local]/(manage)/admin/config/_components/config-field.tsx similarity index 97% rename from src/app/(manage)/admin/config/_components/config-field.tsx rename to src/app/[local]/(manage)/admin/config/_components/config-field.tsx index 0094f87..d88db6c 100644 --- a/src/app/(manage)/admin/config/_components/config-field.tsx +++ b/src/app/[local]/(manage)/admin/config/_components/config-field.tsx @@ -18,7 +18,7 @@ import { } from "~/lib/ui/select"; import { Switch } from "~/lib/ui/switch"; import { CONFIG_DEFAULT_VALUE_MAP } from "~/lib/constants/config"; -import CodeInputDialog from "~/app/(manage)/admin/config/_components/code-input-dialog"; +import CodeInputDialog from "~/app/[local]/(manage)/admin/config/_components/code-input-dialog"; import { isTrue } from "~/lib/utils"; import { useTrack } from "~/lib/hooks/use-track"; diff --git a/src/app/(manage)/admin/config/_components/config-list.tsx b/src/app/[local]/(manage)/admin/config/_components/config-list.tsx similarity index 91% rename from src/app/(manage)/admin/config/_components/config-list.tsx rename to src/app/[local]/(manage)/admin/config/_components/config-list.tsx index 85b6a2e..5f294c6 100644 --- a/src/app/(manage)/admin/config/_components/config-list.tsx +++ b/src/app/[local]/(manage)/admin/config/_components/config-list.tsx @@ -1,5 +1,5 @@ import { type Config } from "@prisma/client"; -import ConfigField from "~/app/(manage)/admin/config/_components/config-field"; +import ConfigField from "~/app/[local]/(manage)/admin/config/_components/config-field"; import { type CONFIG_KEY, type ConfigSchema } from "~/lib/types"; export default function ConfigList({ diff --git a/src/app/(manage)/admin/config/_components/cron-input.tsx b/src/app/[local]/(manage)/admin/config/_components/cron-input.tsx similarity index 100% rename from src/app/(manage)/admin/config/_components/cron-input.tsx rename to src/app/[local]/(manage)/admin/config/_components/cron-input.tsx diff --git a/src/app/(manage)/admin/config/_components/payment-info.tsx b/src/app/[local]/(manage)/admin/config/_components/payment-info.tsx similarity index 98% rename from src/app/(manage)/admin/config/_components/payment-info.tsx rename to src/app/[local]/(manage)/admin/config/_components/payment-info.tsx index e108064..84c6970 100644 --- a/src/app/(manage)/admin/config/_components/payment-info.tsx +++ b/src/app/[local]/(manage)/admin/config/_components/payment-info.tsx @@ -2,7 +2,7 @@ import Blockchains from "@depay/web3-blockchains"; import * as React from "react"; import { Label } from "~/lib/ui/label"; import Link from "next/link"; -import ID from "~/app/_components/id"; +import ID from "~/app/[local]/_components/id"; import Image from "next/image"; import { Badge } from "~/lib/ui/badge"; import { formatDate } from "~/lib/utils"; diff --git a/src/app/(manage)/admin/config/_components/payment-table.tsx b/src/app/[local]/(manage)/admin/config/_components/payment-table.tsx similarity index 95% rename from src/app/(manage)/admin/config/_components/payment-table.tsx rename to src/app/[local]/(manage)/admin/config/_components/payment-table.tsx index c8222ed..4d6da1f 100644 --- a/src/app/(manage)/admin/config/_components/payment-table.tsx +++ b/src/app/[local]/(manage)/admin/config/_components/payment-table.tsx @@ -11,15 +11,15 @@ import { } from "@tanstack/react-table"; import { api } from "~/trpc/react"; import { Input } from "~/lib/ui/input"; -import Table from "~/app/_components/table"; +import Table from "~/app/[local]/_components/table"; import { type PaymentGetAllOutput } from "~/lib/types/trpc"; import { Button } from "~/lib/ui/button"; import { MoreHorizontalIcon, XIcon } from "lucide-react"; -import { DataTableViewOptions } from "~/app/_components/table-view-options"; -import ID from "~/app/_components/id"; -import UserColumn from "~/app/_components/user-column"; +import { DataTableViewOptions } from "~/app/[local]/_components/table-view-options"; +import ID from "~/app/[local]/_components/id"; +import UserColumn from "~/app/[local]/_components/user-column"; import { MoneyInput } from "~/lib/ui/money-input"; -import { TableFacetedFilter } from "~/app/_components/table-faceted-filter"; +import { TableFacetedFilter } from "~/app/[local]/_components/table-faceted-filter"; import { PaymentStatusOptions } from "~/lib/constants"; import { type $Enums } from ".prisma/client"; import { cn, formatDate } from "~/lib/utils"; @@ -37,7 +37,7 @@ import { AccordionItem, AccordionTrigger, } from "~/lib/ui/accordion"; -import PaymentInfo from "~/app/(manage)/admin/config/_components/payment-info"; +import PaymentInfo from "~/app/[local]/(manage)/admin/config/_components/payment-info"; type PaymentStatus = $Enums.PaymentStatus; diff --git a/src/app/(manage)/admin/config/_components/recharge-code-table.tsx b/src/app/[local]/(manage)/admin/config/_components/recharge-code-table.tsx similarity index 97% rename from src/app/(manage)/admin/config/_components/recharge-code-table.tsx rename to src/app/[local]/(manage)/admin/config/_components/recharge-code-table.tsx index b6d8e4c..c20aa66 100644 --- a/src/app/(manage)/admin/config/_components/recharge-code-table.tsx +++ b/src/app/[local]/(manage)/admin/config/_components/recharge-code-table.tsx @@ -9,13 +9,13 @@ import { } from "@tanstack/react-table"; import { api } from "~/trpc/react"; import { Input } from "~/lib/ui/input"; -import Table from "~/app/_components/table"; +import Table from "~/app/[local]/_components/table"; import { type RechargeCodeGetAllOutput } from "~/lib/types/trpc"; import { Button } from "~/lib/ui/button"; import { TicketCheckIcon, TicketIcon, Trash2Icon, XIcon } from "lucide-react"; -import { DataTableViewOptions } from "~/app/_components/table-view-options"; -import ID from "~/app/_components/id"; -import UserColumn from "~/app/_components/user-column"; +import { DataTableViewOptions } from "~/app/[local]/_components/table-view-options"; +import ID from "~/app/[local]/_components/id"; +import UserColumn from "~/app/[local]/_components/user-column"; import { AlertDialog, AlertDialogAction, diff --git a/src/app/(manage)/admin/config/_components/traffic-price-config.tsx b/src/app/[local]/(manage)/admin/config/_components/traffic-price-config.tsx similarity index 100% rename from src/app/(manage)/admin/config/_components/traffic-price-config.tsx rename to src/app/[local]/(manage)/admin/config/_components/traffic-price-config.tsx diff --git a/src/app/(manage)/admin/config/_components/withdrawal-table.tsx b/src/app/[local]/(manage)/admin/config/_components/withdrawal-table.tsx similarity index 94% rename from src/app/(manage)/admin/config/_components/withdrawal-table.tsx rename to src/app/[local]/(manage)/admin/config/_components/withdrawal-table.tsx index 809c70a..6cc6154 100644 --- a/src/app/(manage)/admin/config/_components/withdrawal-table.tsx +++ b/src/app/[local]/(manage)/admin/config/_components/withdrawal-table.tsx @@ -11,15 +11,15 @@ import { } from "@tanstack/react-table"; import { api } from "~/trpc/react"; import { Input } from "~/lib/ui/input"; -import Table from "~/app/_components/table"; +import Table from "~/app/[local]/_components/table"; import { type WithdrawalGetAllOutput } from "~/lib/types/trpc"; import { Button } from "~/lib/ui/button"; import { CheckSquareIcon, XIcon } from "lucide-react"; -import { DataTableViewOptions } from "~/app/_components/table-view-options"; -import ID from "~/app/_components/id"; -import UserColumn from "~/app/_components/user-column"; +import { DataTableViewOptions } from "~/app/[local]/_components/table-view-options"; +import ID from "~/app/[local]/_components/id"; +import UserColumn from "~/app/[local]/_components/user-column"; import { MoneyInput } from "~/lib/ui/money-input"; -import { TableFacetedFilter } from "~/app/_components/table-faceted-filter"; +import { TableFacetedFilter } from "~/app/[local]/_components/table-faceted-filter"; import { WithdrawalStatusOptions } from "~/lib/constants"; import { Badge } from "~/lib/ui/badge"; import { toast } from "~/lib/ui/use-toast"; diff --git a/src/app/(manage)/admin/config/layout.tsx b/src/app/[local]/(manage)/admin/config/layout.tsx similarity index 95% rename from src/app/(manage)/admin/config/layout.tsx rename to src/app/[local]/(manage)/admin/config/layout.tsx index 5e448a8..2491dba 100644 --- a/src/app/(manage)/admin/config/layout.tsx +++ b/src/app/[local]/(manage)/admin/config/layout.tsx @@ -1,6 +1,6 @@ import { Separator } from "~/lib/ui/separator"; import { type ReactNode } from "react"; -import { SidebarNav } from "~/app/_components/sidebar-nav"; +import { SidebarNav } from "~/app/[local]/_components/sidebar-nav"; import type { Metadata } from "next"; export const metadata: Metadata = { diff --git a/src/app/(manage)/admin/config/page.tsx b/src/app/[local]/(manage)/admin/config/page.tsx similarity index 76% rename from src/app/(manage)/admin/config/page.tsx rename to src/app/[local]/(manage)/admin/config/page.tsx index 8359e28..6b36275 100644 --- a/src/app/(manage)/admin/config/page.tsx +++ b/src/app/[local]/(manage)/admin/config/page.tsx @@ -1,5 +1,5 @@ import { api } from "~/trpc/server"; -import ConfigList from "~/app/(manage)/admin/config/_components/config-list"; +import ConfigList from "~/app/[local]/(manage)/admin/config/_components/config-list"; import { GLOBAL_CONFIG_SCHEMA_MAP } from "~/lib/constants/config"; export default async function Config() { diff --git a/src/app/[local]/(manage)/admin/config/payment/page.tsx b/src/app/[local]/(manage)/admin/config/payment/page.tsx new file mode 100644 index 0000000..5319477 --- /dev/null +++ b/src/app/[local]/(manage)/admin/config/payment/page.tsx @@ -0,0 +1,5 @@ +import PaymentTable from "~/app/[local]/(manage)/admin/config/_components/payment-table"; + +export default function PaymentPage() { + return ; +} diff --git a/src/app/(manage)/admin/config/recharge-code/page.tsx b/src/app/[local]/(manage)/admin/config/recharge-code/page.tsx similarity index 90% rename from src/app/(manage)/admin/config/recharge-code/page.tsx rename to src/app/[local]/(manage)/admin/config/recharge-code/page.tsx index e3e33dc..fe7efc2 100644 --- a/src/app/(manage)/admin/config/recharge-code/page.tsx +++ b/src/app/[local]/(manage)/admin/config/recharge-code/page.tsx @@ -1,4 +1,4 @@ -import RechargeCodeTable from "~/app/(manage)/admin/config/_components/recharge-code-table"; +import RechargeCodeTable from "~/app/[local]/(manage)/admin/config/_components/recharge-code-table"; import { Separator } from "~/lib/ui/separator"; import Link from "next/link"; import { MoveRightIcon } from "lucide-react"; diff --git a/src/app/[local]/(manage)/admin/config/withdraw/page.tsx b/src/app/[local]/(manage)/admin/config/withdraw/page.tsx new file mode 100644 index 0000000..0e3d5c6 --- /dev/null +++ b/src/app/[local]/(manage)/admin/config/withdraw/page.tsx @@ -0,0 +1,5 @@ +import WithdrawalTable from "~/app/[local]/(manage)/admin/config/_components/withdrawal-table"; + +export default function WithdrawalPage() { + return ; +} diff --git a/src/app/(manage)/admin/log/_components/log-delete.tsx b/src/app/[local]/(manage)/admin/log/_components/log-delete.tsx similarity index 95% rename from src/app/(manage)/admin/log/_components/log-delete.tsx rename to src/app/[local]/(manage)/admin/log/_components/log-delete.tsx index 59283c9..0f59852 100644 --- a/src/app/(manage)/admin/log/_components/log-delete.tsx +++ b/src/app/[local]/(manage)/admin/log/_components/log-delete.tsx @@ -14,7 +14,7 @@ import { Button } from "~/lib/ui/button"; import { Trash2Icon } from "lucide-react"; import React from "react"; import { toast } from "~/lib/ui/use-toast"; -import { useLogStore } from "~/app/(manage)/admin/log/store/log-store"; +import { useLogStore } from "~/app/[local]/(manage)/admin/log/store/log-store"; import { useTrack } from "~/lib/hooks/use-track"; export default function LogDelete() { diff --git a/src/app/(manage)/admin/log/_components/log-glance.tsx b/src/app/[local]/(manage)/admin/log/_components/log-glance.tsx similarity index 98% rename from src/app/(manage)/admin/log/_components/log-glance.tsx rename to src/app/[local]/(manage)/admin/log/_components/log-glance.tsx index 639d0f3..2e7d2a5 100644 --- a/src/app/(manage)/admin/log/_components/log-glance.tsx +++ b/src/app/[local]/(manage)/admin/log/_components/log-glance.tsx @@ -7,7 +7,7 @@ import { import { BarChartHorizontalIcon } from "lucide-react"; import React from "react"; import { cn } from "~/lib/utils"; -import { useLogStore } from "~/app/(manage)/admin/log/store/log-store"; +import { useLogStore } from "~/app/[local]/(manage)/admin/log/store/log-store"; import { api } from "~/trpc/react"; export default function LogGlance() { diff --git a/src/app/(manage)/admin/log/_components/log-search-keyword.tsx b/src/app/[local]/(manage)/admin/log/_components/log-search-keyword.tsx similarity index 96% rename from src/app/(manage)/admin/log/_components/log-search-keyword.tsx rename to src/app/[local]/(manage)/admin/log/_components/log-search-keyword.tsx index a776d32..f6792ac 100644 --- a/src/app/(manage)/admin/log/_components/log-search-keyword.tsx +++ b/src/app/[local]/(manage)/admin/log/_components/log-search-keyword.tsx @@ -1,4 +1,4 @@ -import { useLogStore } from "~/app/(manage)/admin/log/store/log-store"; +import { useLogStore } from "~/app/[local]/(manage)/admin/log/store/log-store"; import { Popover, PopoverContent, PopoverTrigger } from "~/lib/ui/popover"; import { Input } from "~/lib/ui/input"; import React, { useEffect } from "react"; diff --git a/src/app/(manage)/admin/log/_components/log-toolbar.tsx b/src/app/[local]/(manage)/admin/log/_components/log-toolbar.tsx similarity index 90% rename from src/app/(manage)/admin/log/_components/log-toolbar.tsx rename to src/app/[local]/(manage)/admin/log/_components/log-toolbar.tsx index 308b036..9762763 100644 --- a/src/app/(manage)/admin/log/_components/log-toolbar.tsx +++ b/src/app/[local]/(manage)/admin/log/_components/log-toolbar.tsx @@ -6,10 +6,10 @@ import { Popover, PopoverContent, PopoverTrigger } from "~/lib/ui/popover"; import { Label } from "~/lib/ui/label"; import React from "react"; import { LEVELS } from "~/lib/constants/log-level"; -import { useLogStore } from "~/app/(manage)/admin/log/store/log-store"; -import LogDelete from "~/app/(manage)/admin/log/_components/log-delete"; -import { FacetedFilter } from "~/app/_components/faceted-filter"; -import LogSearchKeyword from "~/app/(manage)/admin/log/_components/log-search-keyword"; +import { useLogStore } from "~/app/[local]/(manage)/admin/log/store/log-store"; +import LogDelete from "~/app/[local]/(manage)/admin/log/_components/log-delete"; +import { FacetedFilter } from "~/app/[local]/_components/faceted-filter"; +import LogSearchKeyword from "~/app/[local]/(manage)/admin/log/_components/log-search-keyword"; export default function LogToolbar() { const { params, setParams, resetParams, isFiltering } = useLogStore(); diff --git a/src/app/(manage)/admin/log/_components/log.tsx b/src/app/[local]/(manage)/admin/log/_components/log.tsx similarity index 100% rename from src/app/(manage)/admin/log/_components/log.tsx rename to src/app/[local]/(manage)/admin/log/_components/log.tsx diff --git a/src/app/(manage)/admin/log/_components/logs.tsx b/src/app/[local]/(manage)/admin/log/_components/logs.tsx similarity index 88% rename from src/app/(manage)/admin/log/_components/logs.tsx rename to src/app/[local]/(manage)/admin/log/_components/logs.tsx index b133e07..54413e3 100644 --- a/src/app/(manage)/admin/log/_components/logs.tsx +++ b/src/app/[local]/(manage)/admin/log/_components/logs.tsx @@ -3,12 +3,12 @@ import React, { useEffect } from "react"; import { ScrollArea } from "~/lib/ui/scroll-area"; import { Accordion } from "~/lib/ui/accordion"; import { api } from "~/trpc/react"; -import { useLogStore } from "~/app/(manage)/admin/log/store/log-store"; -import LogGlance from "~/app/(manage)/admin/log/_components/log-glance"; -import Log from "~/app/(manage)/admin/log/_components/log"; -import LogToolbar from "~/app/(manage)/admin/log/_components/log-toolbar"; +import { useLogStore } from "~/app/[local]/(manage)/admin/log/store/log-store"; +import LogGlance from "~/app/[local]/(manage)/admin/log/_components/log-glance"; +import Log from "~/app/[local]/(manage)/admin/log/_components/log"; +import LogToolbar from "~/app/[local]/(manage)/admin/log/_components/log-toolbar"; import type { LogsOutput } from "~/lib/types/trpc"; -import SearchEmptyState from "~/app/_components/search-empty-state"; +import SearchEmptyState from "~/app/[local]/_components/search-empty-state"; export function Logs({ agentId }: { agentId?: string }) { const { convertParams, setParams, params } = useLogStore(); diff --git a/src/app/(manage)/admin/log/page.tsx b/src/app/[local]/(manage)/admin/log/page.tsx similarity index 74% rename from src/app/(manage)/admin/log/page.tsx rename to src/app/[local]/(manage)/admin/log/page.tsx index 6fe30b9..a02a00c 100644 --- a/src/app/(manage)/admin/log/page.tsx +++ b/src/app/[local]/(manage)/admin/log/page.tsx @@ -1,4 +1,4 @@ -import { Logs } from "~/app/(manage)/admin/log/_components/logs"; +import { Logs } from "~/app/[local]/(manage)/admin/log/_components/logs"; export const metadata = { title: "日志 - vortex", diff --git a/src/app/(manage)/admin/log/store/log-store.ts b/src/app/[local]/(manage)/admin/log/store/log-store.ts similarity index 100% rename from src/app/(manage)/admin/log/store/log-store.ts rename to src/app/[local]/(manage)/admin/log/store/log-store.ts diff --git a/src/app/(manage)/admin/users/_components/user-role-setting.tsx b/src/app/[local]/(manage)/admin/users/_components/user-role-setting.tsx similarity index 100% rename from src/app/(manage)/admin/users/_components/user-role-setting.tsx rename to src/app/[local]/(manage)/admin/users/_components/user-role-setting.tsx diff --git a/src/app/(manage)/admin/users/_components/user-status.tsx b/src/app/[local]/(manage)/admin/users/_components/user-status.tsx similarity index 100% rename from src/app/(manage)/admin/users/_components/user-status.tsx rename to src/app/[local]/(manage)/admin/users/_components/user-status.tsx diff --git a/src/app/(manage)/admin/users/_components/user-table.tsx b/src/app/[local]/(manage)/admin/users/_components/user-table.tsx similarity index 90% rename from src/app/(manage)/admin/users/_components/user-table.tsx rename to src/app/[local]/(manage)/admin/users/_components/user-table.tsx index fab8c87..8328ddf 100644 --- a/src/app/(manage)/admin/users/_components/user-table.tsx +++ b/src/app/[local]/(manage)/admin/users/_components/user-table.tsx @@ -7,12 +7,12 @@ import { } from "@tanstack/react-table"; import { Input } from "~/lib/ui/input"; import { type ChangeEvent, useMemo, useState } from "react"; -import Table from "~/app/_components/table"; +import Table from "~/app/[local]/_components/table"; import { api } from "~/trpc/react"; import { type UserGetAllOutput } from "~/lib/types/trpc"; -import ID from "~/app/_components/id"; -import UserColumn from "~/app/_components/user-column"; -import UserStatusSwitch from "~/app/(manage)/admin/users/_components/user-status"; +import ID from "~/app/[local]/_components/id"; +import UserColumn from "~/app/[local]/_components/user-column"; +import UserStatusSwitch from "~/app/[local]/(manage)/admin/users/_components/user-status"; import { TooltipProvider } from "~/lib/ui/tooltip"; import { Badge } from "~/lib/ui/badge"; import { @@ -22,8 +22,8 @@ import { } from "~/lib/ui/dropdown-menu"; import { Button } from "~/lib/ui/button"; import { MoreHorizontalIcon, XIcon } from "lucide-react"; -import UserRoleSettings from "~/app/(manage)/admin/users/_components/user-role-setting"; -import { DataTableViewOptions } from "~/app/_components/table-view-options"; +import UserRoleSettings from "~/app/[local]/(manage)/admin/users/_components/user-role-setting"; +import { DataTableViewOptions } from "~/app/[local]/_components/table-view-options"; export default function UserTable() { const [keyword, setKeyword] = useState(""); diff --git a/src/app/(manage)/admin/users/page.tsx b/src/app/[local]/(manage)/admin/users/page.tsx similarity index 73% rename from src/app/(manage)/admin/users/page.tsx rename to src/app/[local]/(manage)/admin/users/page.tsx index 2a667ca..5fda043 100644 --- a/src/app/(manage)/admin/users/page.tsx +++ b/src/app/[local]/(manage)/admin/users/page.tsx @@ -1,4 +1,4 @@ -import UserTable from "~/app/(manage)/admin/users/_components/user-table"; +import UserTable from "~/app/[local]/(manage)/admin/users/_components/user-table"; export const metadata = { title: "用户 - vortex", diff --git a/src/app/(manage)/agent/[agentId]/config/base/page.tsx b/src/app/[local]/(manage)/agent/[agentId]/config/base/page.tsx similarity index 82% rename from src/app/(manage)/agent/[agentId]/config/base/page.tsx rename to src/app/[local]/(manage)/agent/[agentId]/config/base/page.tsx index f1196b9..9ba019a 100644 --- a/src/app/(manage)/agent/[agentId]/config/base/page.tsx +++ b/src/app/[local]/(manage)/agent/[agentId]/config/base/page.tsx @@ -1,4 +1,4 @@ -import { AgentForm } from "~/app/(manage)/agent/_components/agent-form"; +import { AgentForm } from "~/app/[local]/(manage)/agent/_components/agent-form"; import { api } from "~/trpc/server"; export const metadata = { diff --git a/src/app/(manage)/agent/[agentId]/config/other/page.tsx b/src/app/[local]/(manage)/agent/[agentId]/config/other/page.tsx similarity index 86% rename from src/app/(manage)/agent/[agentId]/config/other/page.tsx rename to src/app/[local]/(manage)/agent/[agentId]/config/other/page.tsx index 7e98a0e..1fa77d4 100644 --- a/src/app/(manage)/agent/[agentId]/config/other/page.tsx +++ b/src/app/[local]/(manage)/agent/[agentId]/config/other/page.tsx @@ -1,4 +1,4 @@ -import ConfigList from "~/app/(manage)/admin/config/_components/config-list"; +import ConfigList from "~/app/[local]/(manage)/admin/config/_components/config-list"; import { AGENT_CONFIG_SCHEMA_MAP } from "~/lib/constants/config"; import { api } from "~/trpc/server"; diff --git a/src/app/(manage)/agent/[agentId]/forward/page.tsx b/src/app/[local]/(manage)/agent/[agentId]/forward/page.tsx similarity index 76% rename from src/app/(manage)/agent/[agentId]/forward/page.tsx rename to src/app/[local]/(manage)/agent/[agentId]/forward/page.tsx index cb21c66..5327010 100644 --- a/src/app/(manage)/agent/[agentId]/forward/page.tsx +++ b/src/app/[local]/(manage)/agent/[agentId]/forward/page.tsx @@ -1,4 +1,4 @@ -import ForwardTable from "~/app/(manage)/forward/_components/forward-table"; +import ForwardTable from "~/app/[local]/(manage)/forward/_components/forward-table"; export const metadata = { title: "服务器 - 转发 - vortex", diff --git a/src/app/(manage)/agent/[agentId]/install/page.tsx b/src/app/[local]/(manage)/agent/[agentId]/install/page.tsx similarity index 73% rename from src/app/(manage)/agent/[agentId]/install/page.tsx rename to src/app/[local]/(manage)/agent/[agentId]/install/page.tsx index 3400a66..72aabda 100644 --- a/src/app/(manage)/agent/[agentId]/install/page.tsx +++ b/src/app/[local]/(manage)/agent/[agentId]/install/page.tsx @@ -1,4 +1,4 @@ -import AgentInstall from "~/app/(manage)/agent/_components/agent-install"; +import AgentInstall from "~/app/[local]/(manage)/agent/_components/agent-install"; export const metadata = { title: "服务器 - 安装 - vortex", diff --git a/src/app/(manage)/agent/[agentId]/layout.tsx b/src/app/[local]/(manage)/agent/[agentId]/layout.tsx similarity index 85% rename from src/app/(manage)/agent/[agentId]/layout.tsx rename to src/app/[local]/(manage)/agent/[agentId]/layout.tsx index 0d69e04..ca9d8bd 100644 --- a/src/app/(manage)/agent/[agentId]/layout.tsx +++ b/src/app/[local]/(manage)/agent/[agentId]/layout.tsx @@ -1,7 +1,7 @@ import { api } from "~/trpc/server"; -import AgentResizableLayout from "~/app/(manage)/agent/_components/agent-resizable-layout"; +import AgentResizableLayout from "~/app/[local]/(manage)/agent/_components/agent-resizable-layout"; import { type ReactNode } from "react"; -import AgentMenu from "~/app/(manage)/agent/_components/agent-menu"; +import AgentMenu from "~/app/[local]/(manage)/agent/_components/agent-menu"; export const metadata = { title: "服务器 - vortex", diff --git a/src/app/(manage)/agent/[agentId]/loading.tsx b/src/app/[local]/(manage)/agent/[agentId]/loading.tsx similarity index 100% rename from src/app/(manage)/agent/[agentId]/loading.tsx rename to src/app/[local]/(manage)/agent/[agentId]/loading.tsx diff --git a/src/app/(manage)/agent/[agentId]/log/page.tsx b/src/app/[local]/(manage)/agent/[agentId]/log/page.tsx similarity index 77% rename from src/app/(manage)/agent/[agentId]/log/page.tsx rename to src/app/[local]/(manage)/agent/[agentId]/log/page.tsx index 5942ddf..4714d35 100644 --- a/src/app/(manage)/agent/[agentId]/log/page.tsx +++ b/src/app/[local]/(manage)/agent/[agentId]/log/page.tsx @@ -1,4 +1,4 @@ -import { Logs } from "~/app/(manage)/admin/log/_components/logs"; +import { Logs } from "~/app/[local]/(manage)/admin/log/_components/logs"; export const metadata = { title: "服务器 - 日志 - vortex", diff --git a/src/app/(manage)/agent/[agentId]/status/page.tsx b/src/app/[local]/(manage)/agent/[agentId]/status/page.tsx similarity index 94% rename from src/app/(manage)/agent/[agentId]/status/page.tsx rename to src/app/[local]/(manage)/agent/[agentId]/status/page.tsx index 14f001b..08e9208 100644 --- a/src/app/(manage)/agent/[agentId]/status/page.tsx +++ b/src/app/[local]/(manage)/agent/[agentId]/status/page.tsx @@ -1,22 +1,22 @@ import { getPlatformIcon } from "~/lib/icons"; import CpuUsage, { type CpuStat, -} from "~/app/(manage)/agent/_components/cpu-usage"; +} from "~/app/[local]/(manage)/agent/_components/cpu-usage"; import MemUsage, { type MemStat, -} from "~/app/(manage)/agent/_components/mem-usage"; +} from "~/app/[local]/(manage)/agent/_components/mem-usage"; import BandwidthUsage, { type BandwidthStat, -} from "~/app/(manage)/agent/_components/bandwidth-usage"; +} from "~/app/[local]/(manage)/agent/_components/bandwidth-usage"; import TrafficUsage, { type TrafficStat, -} from "~/app/(manage)/agent/_components/traffic-usage"; +} from "~/app/[local]/(manage)/agent/_components/traffic-usage"; import { convertBytes, convertBytesToBestUnit, formatDate } from "~/lib/utils"; import "/node_modules/flag-icons/css/flag-icons.min.css"; -import ID from "~/app/_components/id"; +import ID from "~/app/[local]/_components/id"; import { MoveDownIcon, MoveUpIcon } from "lucide-react"; import { api } from "~/trpc/server"; -import AgentPrice from "~/app/(manage)/agent/_components/agent-price"; +import AgentPrice from "~/app/[local]/(manage)/agent/_components/agent-price"; export const metadata = { title: "服务器 - 状态 - vortex", diff --git a/src/app/(manage)/agent/_components/agent-command.tsx b/src/app/[local]/(manage)/agent/_components/agent-command.tsx similarity index 100% rename from src/app/(manage)/agent/_components/agent-command.tsx rename to src/app/[local]/(manage)/agent/_components/agent-command.tsx diff --git a/src/app/(manage)/agent/_components/agent-config.tsx b/src/app/[local]/(manage)/agent/_components/agent-config.tsx similarity index 84% rename from src/app/(manage)/agent/_components/agent-config.tsx rename to src/app/[local]/(manage)/agent/_components/agent-config.tsx index 7cb456b..8f8f9ab 100644 --- a/src/app/(manage)/agent/_components/agent-config.tsx +++ b/src/app/[local]/(manage)/agent/_components/agent-config.tsx @@ -1,4 +1,4 @@ -import ConfigList from "~/app/(manage)/admin/config/_components/config-list"; +import ConfigList from "~/app/[local]/(manage)/admin/config/_components/config-list"; import { AGENT_CONFIG_SCHEMA_MAP } from "~/lib/constants/config"; import { api } from "~/trpc/server"; diff --git a/src/app/(manage)/agent/_components/agent-delete.tsx b/src/app/[local]/(manage)/agent/_components/agent-delete.tsx similarity index 100% rename from src/app/(manage)/agent/_components/agent-delete.tsx rename to src/app/[local]/(manage)/agent/_components/agent-delete.tsx diff --git a/src/app/(manage)/agent/_components/agent-form.tsx b/src/app/[local]/(manage)/agent/_components/agent-form.tsx similarity index 100% rename from src/app/(manage)/agent/_components/agent-form.tsx rename to src/app/[local]/(manage)/agent/_components/agent-form.tsx diff --git a/src/app/(manage)/agent/_components/agent-install.tsx b/src/app/[local]/(manage)/agent/_components/agent-install.tsx similarity index 100% rename from src/app/(manage)/agent/_components/agent-install.tsx rename to src/app/[local]/(manage)/agent/_components/agent-install.tsx diff --git a/src/app/(manage)/agent/_components/agent-list-aside.tsx b/src/app/[local]/(manage)/agent/_components/agent-list-aside.tsx similarity index 78% rename from src/app/(manage)/agent/_components/agent-list-aside.tsx rename to src/app/[local]/(manage)/agent/_components/agent-list-aside.tsx index 0d2f21c..bff04b7 100644 --- a/src/app/(manage)/agent/_components/agent-list-aside.tsx +++ b/src/app/[local]/(manage)/agent/_components/agent-list-aside.tsx @@ -1,7 +1,7 @@ "use client"; import { ScrollArea } from "~/lib/ui/scroll-area"; -import AgentList from "~/app/(manage)/agent/_components/agent-list"; -import { AgentForm } from "~/app/(manage)/agent/_components/agent-form"; +import AgentList from "~/app/[local]/(manage)/agent/_components/agent-list"; +import { AgentForm } from "~/app/[local]/(manage)/agent/_components/agent-form"; import { Button } from "~/lib/ui/button"; import { PlusIcon } from "lucide-react"; import { type AgentGetAllOutput } from "~/lib/types/trpc"; @@ -9,7 +9,7 @@ import { api } from "~/trpc/react"; import { cn } from "~/lib/utils"; import { hasPermission } from "~/lib/constants/permission"; import { useSession } from "next-auth/react"; -import { CSSProperties, useMemo, useState } from "react"; +import { type CSSProperties, useMemo, useState } from "react"; import { Dialog, DialogContent, @@ -19,6 +19,7 @@ import { DialogTrigger, } from "~/lib/ui/dialog"; import { Input } from "~/lib/ui/input"; +import { useTranslations } from "use-intl"; export default function AgentListAside({ agentId, @@ -31,6 +32,7 @@ export default function AgentListAside({ className?: string; style?: CSSProperties; }) { + const t = useTranslations("agent-agent-list-aside"); const [keyword, setKeyword] = useState(""); agents = api.agent.getAll.useQuery(undefined, { @@ -52,23 +54,23 @@ export default function AgentListAside({
setKeyword(e.target.value)} /> @@ -79,15 +81,13 @@ export default function AgentListAside({ - 添加服务器 - - 点击保存后查看侧边服务器栏。添加中转服务器,保存后会给你一个安装命令,复制到服务器上执行即可。 - + {t("add_server")} + {t("add_tips")} diff --git a/src/app/(manage)/agent/_components/agent-list.tsx b/src/app/[local]/(manage)/agent/_components/agent-list.tsx similarity index 100% rename from src/app/(manage)/agent/_components/agent-list.tsx rename to src/app/[local]/(manage)/agent/_components/agent-list.tsx diff --git a/src/app/(manage)/agent/_components/agent-menu.tsx b/src/app/[local]/(manage)/agent/_components/agent-menu.tsx similarity index 96% rename from src/app/(manage)/agent/_components/agent-menu.tsx rename to src/app/[local]/(manage)/agent/_components/agent-menu.tsx index ec4d207..b513585 100644 --- a/src/app/(manage)/agent/_components/agent-menu.tsx +++ b/src/app/[local]/(manage)/agent/_components/agent-menu.tsx @@ -12,8 +12,8 @@ import { usePathname } from "next/navigation"; import * as React from "react"; import { cn } from "~/lib/utils"; import { useSession } from "next-auth/react"; -import AgentCommand from "~/app/(manage)/agent/_components/agent-command"; -import AgentDelete from "~/app/(manage)/agent/_components/agent-delete"; +import AgentCommand from "~/app/[local]/(manage)/agent/_components/agent-command"; +import AgentDelete from "~/app/[local]/(manage)/agent/_components/agent-delete"; import { type Agent } from ".prisma/client"; import { Role } from "@prisma/client"; diff --git a/src/app/(manage)/agent/_components/agent-price.tsx b/src/app/[local]/(manage)/agent/_components/agent-price.tsx similarity index 100% rename from src/app/(manage)/agent/_components/agent-price.tsx rename to src/app/[local]/(manage)/agent/_components/agent-price.tsx diff --git a/src/app/(manage)/agent/_components/agent-resizable-layout.tsx b/src/app/[local]/(manage)/agent/_components/agent-resizable-layout.tsx similarity index 93% rename from src/app/(manage)/agent/_components/agent-resizable-layout.tsx rename to src/app/[local]/(manage)/agent/_components/agent-resizable-layout.tsx index 4f70122..e76d751 100644 --- a/src/app/(manage)/agent/_components/agent-resizable-layout.tsx +++ b/src/app/[local]/(manage)/agent/_components/agent-resizable-layout.tsx @@ -4,7 +4,7 @@ import { ResizablePanel, ResizablePanelGroup, } from "~/lib/ui/resizable"; -import AgentListAside from "~/app/(manage)/agent/_components/agent-list-aside"; +import AgentListAside from "~/app/[local]/(manage)/agent/_components/agent-list-aside"; import { type AgentGetAllOutput } from "~/lib/types/trpc"; import { type ReactNode, useRef } from "react"; import { useResizeObserver } from "~/lib/hooks/use-resize-observer"; diff --git a/src/app/(manage)/agent/_components/bandwidth-usage.tsx b/src/app/[local]/(manage)/agent/_components/bandwidth-usage.tsx similarity index 100% rename from src/app/(manage)/agent/_components/bandwidth-usage.tsx rename to src/app/[local]/(manage)/agent/_components/bandwidth-usage.tsx diff --git a/src/app/(manage)/agent/_components/cpu-usage.tsx b/src/app/[local]/(manage)/agent/_components/cpu-usage.tsx similarity index 100% rename from src/app/(manage)/agent/_components/cpu-usage.tsx rename to src/app/[local]/(manage)/agent/_components/cpu-usage.tsx diff --git a/src/app/(manage)/agent/_components/mem-usage.tsx b/src/app/[local]/(manage)/agent/_components/mem-usage.tsx similarity index 100% rename from src/app/(manage)/agent/_components/mem-usage.tsx rename to src/app/[local]/(manage)/agent/_components/mem-usage.tsx diff --git a/src/app/(manage)/agent/_components/traffic-usage.tsx b/src/app/[local]/(manage)/agent/_components/traffic-usage.tsx similarity index 100% rename from src/app/(manage)/agent/_components/traffic-usage.tsx rename to src/app/[local]/(manage)/agent/_components/traffic-usage.tsx diff --git a/src/app/(manage)/agent/page.tsx b/src/app/[local]/(manage)/agent/page.tsx similarity index 77% rename from src/app/(manage)/agent/page.tsx rename to src/app/[local]/(manage)/agent/page.tsx index bd3df06..ab8fc21 100644 --- a/src/app/(manage)/agent/page.tsx +++ b/src/app/[local]/(manage)/agent/page.tsx @@ -1,7 +1,20 @@ -import AgentResizableLayout from "~/app/(manage)/agent/_components/agent-resizable-layout"; +import AgentResizableLayout from "~/app/[local]/(manage)/agent/_components/agent-resizable-layout"; import { api } from "~/trpc/server"; import { redirect, RedirectType } from "next/navigation"; import { AgentStatus } from "@prisma/client"; +import { getTranslations } from "next-intl/server"; + +export async function generateMetadata({ + params: { locale }, +}: { + params: { locale: string }; +}) { + const t = await getTranslations({ locale, namespace: "global_menu" }); + + return { + title: `${t("agent")} - vortex`, + }; +} export default async function AgentPage() { const agents = await api.agent.getAll.query(undefined); diff --git a/src/app/(manage)/dashboard/_components/system-status.tsx b/src/app/[local]/(manage)/dashboard/_components/system-status.tsx similarity index 92% rename from src/app/(manage)/dashboard/_components/system-status.tsx rename to src/app/[local]/(manage)/dashboard/_components/system-status.tsx index 7604ed1..1146e29 100644 --- a/src/app/(manage)/dashboard/_components/system-status.tsx +++ b/src/app/[local]/(manage)/dashboard/_components/system-status.tsx @@ -7,8 +7,10 @@ import { Line, LineChart, ResponsiveContainer, Tooltip } from "recharts"; import { useEffect, useState } from "react"; import { MoveDownIcon, MoveUpIcon } from "lucide-react"; import type { TooltipProps } from "recharts/types/component/Tooltip"; +import { useTranslations } from "use-intl"; export default function SystemStatus() { + const t = useTranslations("dashboard-system-status"); const [networks, setNetworks] = useState< { upload: number; @@ -57,8 +59,8 @@ export default function SystemStatus() {
- 下载 - 上传 + {t("download")} + {t("upload")}
{`${download} ${downloadUnit}`} @@ -84,7 +86,7 @@ export default function SystemStatus() {
- +
{data?.mem.toFixed(2)}% @@ -93,7 +95,7 @@ export default function SystemStatus() {
- +
diff --git a/src/app/(manage)/dashboard/_components/traffic-usage.tsx b/src/app/[local]/(manage)/dashboard/_components/traffic-usage.tsx similarity index 91% rename from src/app/(manage)/dashboard/_components/traffic-usage.tsx rename to src/app/[local]/(manage)/dashboard/_components/traffic-usage.tsx index e698522..f1c9b10 100644 --- a/src/app/(manage)/dashboard/_components/traffic-usage.tsx +++ b/src/app/[local]/(manage)/dashboard/_components/traffic-usage.tsx @@ -5,8 +5,10 @@ import { convertBytesToBestUnit } from "~/lib/utils"; import { api } from "~/trpc/react"; import dayjs from "dayjs"; import { useMemo } from "react"; +import { useTranslations } from "use-intl"; export default function UserTrafficUsage() { + const t = useTranslations("dashboard-traffic-usage"); const startDate = dayjs().subtract(7, "day").startOf("day").toDate(); const endDate = dayjs().endOf("day").toDate(); @@ -36,7 +38,7 @@ export default function UserTrafficUsage() {

{`${payload[0]?.payload.date}`}

- 使用流量 + {t("used_traffic")}
{`${traffic} ${trafficUnit}`} diff --git a/src/app/(manage)/dashboard/page.tsx b/src/app/[local]/(manage)/dashboard/page.tsx similarity index 83% rename from src/app/(manage)/dashboard/page.tsx rename to src/app/[local]/(manage)/dashboard/page.tsx index 4a49550..1c32af8 100644 --- a/src/app/(manage)/dashboard/page.tsx +++ b/src/app/[local]/(manage)/dashboard/page.tsx @@ -9,14 +9,16 @@ import { CardTitle, } from "~/lib/ui/card"; import Link from "next/link"; -import UserTrafficUsage from "~/app/(manage)/dashboard/_components/traffic-usage"; -import SystemStatus from "~/app/(manage)/dashboard/_components/system-status"; +import UserTrafficUsage from "~/app/[local]/(manage)/dashboard/_components/traffic-usage"; +import SystemStatus from "~/app/[local]/(manage)/dashboard/_components/system-status"; import { api } from "~/trpc/server"; import { MoneyInput } from "~/lib/ui/money-input"; import { MoreHorizontalIcon } from "lucide-react"; import Markdown from "react-markdown"; import { Dialog, DialogContent, DialogTrigger } from "~/lib/ui/dialog"; import { type RouterOutputs } from "~/trpc/shared"; +import { getTranslations } from "next-intl/server"; +import { type NamespaceKeys } from "use-intl/core"; export const metadata = { title: "Dashboard - vortex", @@ -27,6 +29,7 @@ export default async function Dashboard() { if (!session) { return null; } + const t = await getTranslations("dashboard"); const wallet = await api.user.getWallet.query({ id: session.user.id }); const yesterdayBalanceChange = await api.user.getYesterdayBalanceChange.query( { id: session.user.id }, @@ -55,8 +58,10 @@ export default async function Dashboard() {
- 流量使用 - 最近7天的流量使用情况 + {t("traffic_usage")} + + {t("recent_days_traffic_usage")} + @@ -71,8 +76,8 @@ export default async function Dashboard() { - 系统状态 - 系统运行正常 + {t("system_status")} + {t("system_running_normally")} - 公告 + {t("announcement")} {announcement && ( )} @@ -107,7 +113,7 @@ export default async function Dashboard() { {announcement} ) : ( -

暂无公告

+

{t("no_announcement")}

)}
@@ -121,17 +127,21 @@ function UserBalance({ userId, wallet, yesterdayBalanceChange, + t, }: { userId: string; wallet: RouterOutputs["user"]["getWallet"]; yesterdayBalanceChange: RouterOutputs["user"]["getYesterdayBalanceChange"]; + t: Awaited< + ReturnType>> + >; }) { return ( <>

- 余额 + {t("balance")}

@@ -144,7 +154,9 @@ function UserBalance({ className="bg-gradient-to-r from-blue-500 to-green-500 bg-clip-text text-5xl text-transparent" />
- 昨日消费 + + {t("yesterday_consumption")} + {yesterdayBalanceChange?.CONSUMPTION?.toNumber() ?? 0} @@ -153,7 +165,7 @@ function UserBalance({

- 收益 + {t("earnings")}

- 昨日收益 + + {t("yesterday_earnings")} + {yesterdayBalanceChange?.INCOME?.toNumber() ?? 0} diff --git a/src/app/(manage)/forward/_components/forward-delete.tsx b/src/app/[local]/(manage)/forward/_components/forward-delete.tsx similarity index 100% rename from src/app/(manage)/forward/_components/forward-delete.tsx rename to src/app/[local]/(manage)/forward/_components/forward-delete.tsx diff --git a/src/app/(manage)/forward/_components/forward-modify-remark.tsx b/src/app/[local]/(manage)/forward/_components/forward-modify-remark.tsx similarity index 100% rename from src/app/(manage)/forward/_components/forward-modify-remark.tsx rename to src/app/[local]/(manage)/forward/_components/forward-modify-remark.tsx diff --git a/src/app/(manage)/forward/_components/forward-new-form-schema.ts b/src/app/[local]/(manage)/forward/_components/forward-new-form-schema.ts similarity index 100% rename from src/app/(manage)/forward/_components/forward-new-form-schema.ts rename to src/app/[local]/(manage)/forward/_components/forward-new-form-schema.ts diff --git a/src/app/(manage)/forward/_components/forward-new-gost.tsx b/src/app/[local]/(manage)/forward/_components/forward-new-gost.tsx similarity index 93% rename from src/app/(manage)/forward/_components/forward-new-gost.tsx rename to src/app/[local]/(manage)/forward/_components/forward-new-gost.tsx index f069921..1c6e1ba 100644 --- a/src/app/(manage)/forward/_components/forward-new-gost.tsx +++ b/src/app/[local]/(manage)/forward/_components/forward-new-gost.tsx @@ -13,9 +13,9 @@ import { SelectTrigger, SelectValue, } from "~/lib/ui/select"; -import { type ForwardForm } from "~/app/(manage)/forward/_components/forward-new-form-schema"; +import { type ForwardForm } from "~/app/[local]/(manage)/forward/_components/forward-new-form-schema"; import { GostChannelOptions, GostProtocolOptions } from "~/lib/constants"; -import { WithDescSelector } from "~/app/_components/with-desc-selector"; +import { WithDescSelector } from "~/app/[local]/_components/with-desc-selector"; export default function ForwardNewGost({ form }: { form: ForwardForm }) { return ( diff --git a/src/app/(manage)/forward/_components/forward-new.tsx b/src/app/[local]/(manage)/forward/_components/forward-new.tsx similarity index 99% rename from src/app/(manage)/forward/_components/forward-new.tsx rename to src/app/[local]/(manage)/forward/_components/forward-new.tsx index 6f085d3..c7ba6a1 100644 --- a/src/app/(manage)/forward/_components/forward-new.tsx +++ b/src/app/[local]/(manage)/forward/_components/forward-new.tsx @@ -29,7 +29,7 @@ import { cn } from "~/lib/utils"; import { forwardFormSchema, type ForwardFormValues, -} from "~/app/(manage)/forward/_components/forward-new-form-schema"; +} from "~/app/[local]/(manage)/forward/_components/forward-new-form-schema"; import { Dialog, DialogContent, diff --git a/src/app/(manage)/forward/_components/forward-reset-traffic.tsx b/src/app/[local]/(manage)/forward/_components/forward-reset-traffic.tsx similarity index 100% rename from src/app/(manage)/forward/_components/forward-reset-traffic.tsx rename to src/app/[local]/(manage)/forward/_components/forward-reset-traffic.tsx diff --git a/src/app/(manage)/forward/_components/forward-table.tsx b/src/app/[local]/(manage)/forward/_components/forward-table.tsx similarity index 92% rename from src/app/(manage)/forward/_components/forward-table.tsx rename to src/app/[local]/(manage)/forward/_components/forward-table.tsx index dc7cf0d..6b06e38 100644 --- a/src/app/(manage)/forward/_components/forward-table.tsx +++ b/src/app/[local]/(manage)/forward/_components/forward-table.tsx @@ -10,8 +10,8 @@ import { } from "@tanstack/react-table"; import { api } from "~/trpc/react"; import { Input } from "~/lib/ui/input"; -import Table from "~/app/_components/table"; -import { TableFacetedFilter } from "~/app/_components/table-faceted-filter"; +import Table from "~/app/[local]/_components/table"; +import { TableFacetedFilter } from "~/app/[local]/_components/table-faceted-filter"; import { ForwardStatusOptions } from "~/lib/constants"; import { type ForwardGetAllOutput } from "~/lib/types/trpc"; import { type AgentInfo } from "~/lib/types/agent"; @@ -21,7 +21,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "~/lib/ui/tooltip"; import { $Enums, type Agent, ForwardTargetType } from ".prisma/client"; import { Button } from "~/lib/ui/button"; import { MoreHorizontalIcon, XIcon } from "lucide-react"; -import { DataTableViewOptions } from "~/app/_components/table-view-options"; +import { DataTableViewOptions } from "~/app/[local]/_components/table-view-options"; import { DropdownMenu, DropdownMenuContent, @@ -29,13 +29,13 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "~/lib/ui/dropdown-menu"; -import ForwardDelete from "~/app/(manage)/forward/_components/forward-delete"; -import ForwardModifyRemark from "~/app/(manage)/forward/_components/forward-modify-remark"; -import ForwardResetTraffic from "~/app/(manage)/forward/_components/forward-reset-traffic"; -import ForwardNew from "~/app/(manage)/forward/_components/forward-new"; -import ID from "~/app/_components/id"; -import UserColumn from "~/app/_components/user-column"; -import Traffic from "~/app/_components/traffic"; +import ForwardDelete from "~/app/[local]/(manage)/forward/_components/forward-delete"; +import ForwardModifyRemark from "~/app/[local]/(manage)/forward/_components/forward-modify-remark"; +import ForwardResetTraffic from "~/app/[local]/(manage)/forward/_components/forward-reset-traffic"; +import ForwardNew from "~/app/[local]/(manage)/forward/_components/forward-new"; +import ID from "~/app/[local]/_components/id"; +import UserColumn from "~/app/[local]/_components/user-column"; +import Traffic from "~/app/[local]/_components/traffic"; import { useSession } from "next-auth/react"; import { Role } from "@prisma/client"; import ForwardStatus = $Enums.ForwardStatus; diff --git a/src/app/[local]/(manage)/forward/page.tsx b/src/app/[local]/(manage)/forward/page.tsx new file mode 100644 index 0000000..9f4cb96 --- /dev/null +++ b/src/app/[local]/(manage)/forward/page.tsx @@ -0,0 +1,24 @@ +import ForwardTable from "~/app/[local]/(manage)/forward/_components/forward-table"; +import { getTranslations } from "next-intl/server"; + +export async function generateMetadata({ + params: { locale }, +}: { + params: { locale: string }; +}) { + const t = await getTranslations({ locale, namespace: "global_menu" }); + + return { + title: `${t("forward")} - vortex`, + }; +} + +export default async function Forward() { + const t = await getTranslations("global_menu"); + return ( +
+

{t("forward")}

+ +
+ ); +} diff --git a/src/app/(manage)/layout.tsx b/src/app/[local]/(manage)/layout.tsx similarity index 92% rename from src/app/(manage)/layout.tsx rename to src/app/[local]/(manage)/layout.tsx index 3e48e62..88a4a10 100644 --- a/src/app/(manage)/layout.tsx +++ b/src/app/[local]/(manage)/layout.tsx @@ -1,5 +1,5 @@ import { type ReactNode } from "react"; -import ResizableLayout from "~/app/_components/resizable-layout"; +import ResizableLayout from "~/app/[local]/_components/resizable-layout"; import { cookies } from "next/headers"; import { getServerAuthSession } from "~/server/auth"; import { redirect } from "next/navigation"; diff --git a/src/app/(manage)/loading.tsx b/src/app/[local]/(manage)/loading.tsx similarity index 100% rename from src/app/(manage)/loading.tsx rename to src/app/[local]/(manage)/loading.tsx diff --git a/src/app/(manage)/network/[networkId]/page.tsx b/src/app/[local]/(manage)/network/[networkId]/page.tsx similarity index 84% rename from src/app/(manage)/network/[networkId]/page.tsx rename to src/app/[local]/(manage)/network/[networkId]/page.tsx index 6b56085..3c21597 100644 --- a/src/app/(manage)/network/[networkId]/page.tsx +++ b/src/app/[local]/(manage)/network/[networkId]/page.tsx @@ -1,5 +1,5 @@ import { api } from "~/trpc/server"; -import NetworkFlow from "~/app/(manage)/network/_components/network-flow"; +import NetworkFlow from "~/app/[local]/(manage)/network/_components/network-flow"; export const metadata = { title: "组网 - vortex", diff --git a/src/app/(manage)/network/_components/agent-edge-forward-settings.tsx b/src/app/[local]/(manage)/network/_components/agent-edge-forward-settings.tsx similarity index 97% rename from src/app/(manage)/network/_components/agent-edge-forward-settings.tsx rename to src/app/[local]/(manage)/network/_components/agent-edge-forward-settings.tsx index 465d029..a719796 100644 --- a/src/app/(manage)/network/_components/agent-edge-forward-settings.tsx +++ b/src/app/[local]/(manage)/network/_components/agent-edge-forward-settings.tsx @@ -11,7 +11,7 @@ import { import { ForwardMethod } from ".prisma/client"; import { useStore } from "zustand"; import { useContext, useMemo, useState } from "react"; -import { NetworkContext } from "~/app/(manage)/network/store/network-store"; +import { NetworkContext } from "~/app/[local]/(manage)/network/store/network-store"; import { type NetworkAgentEdge } from "~/lib/types/agent"; import { Input } from "~/lib/ui/input"; import { z } from "zod"; @@ -27,7 +27,7 @@ import { import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { cn } from "~/lib/utils"; -import { WithDescSelector } from "~/app/_components/with-desc-selector"; +import { WithDescSelector } from "~/app/[local]/_components/with-desc-selector"; import { ForwardMethodOptions, GostChannelOptions } from "~/lib/constants"; import { api } from "~/trpc/react"; diff --git a/src/app/(manage)/network/_components/agent-edge-test.tsx b/src/app/[local]/(manage)/network/_components/agent-edge-test.tsx similarity index 98% rename from src/app/(manage)/network/_components/agent-edge-test.tsx rename to src/app/[local]/(manage)/network/_components/agent-edge-test.tsx index 64fdaff..6eb6794 100644 --- a/src/app/(manage)/network/_components/agent-edge-test.tsx +++ b/src/app/[local]/(manage)/network/_components/agent-edge-test.tsx @@ -12,7 +12,7 @@ import { import { useContext, useMemo, useState } from "react"; import { api } from "~/trpc/react"; import { useStore } from "zustand"; -import { NetworkContext } from "~/app/(manage)/network/store/network-store"; +import { NetworkContext } from "~/app/[local]/(manage)/network/store/network-store"; import { cn, isBase64, isJson } from "~/lib/utils"; import { type NetworkExternalNode } from "~/lib/types/agent"; import { useTrack } from "~/lib/hooks/use-track"; diff --git a/src/app/(manage)/network/_components/agent-edge-toolbar.tsx b/src/app/[local]/(manage)/network/_components/agent-edge-toolbar.tsx similarity index 63% rename from src/app/(manage)/network/_components/agent-edge-toolbar.tsx rename to src/app/[local]/(manage)/network/_components/agent-edge-toolbar.tsx index affd9d2..03c814a 100644 --- a/src/app/(manage)/network/_components/agent-edge-toolbar.tsx +++ b/src/app/[local]/(manage)/network/_components/agent-edge-toolbar.tsx @@ -1,7 +1,7 @@ "use client"; import { type NetworkAgentEdge } from "~/lib/types/agent"; -import AgentEdgeTest from "~/app/(manage)/network/_components/agent-edge-test"; -import AgentEdgeForwardSettings from "~/app/(manage)/network/_components/agent-edge-forward-settings"; +import AgentEdgeTest from "~/app/[local]/(manage)/network/_components/agent-edge-test"; +import AgentEdgeForwardSettings from "~/app/[local]/(manage)/network/_components/agent-edge-forward-settings"; export default function AgentEdgeToolbar({ id, diff --git a/src/app/(manage)/network/_components/agent-edge.tsx b/src/app/[local]/(manage)/network/_components/agent-edge.tsx similarity index 94% rename from src/app/(manage)/network/_components/agent-edge.tsx rename to src/app/[local]/(manage)/network/_components/agent-edge.tsx index ccc4d1b..6f3b070 100644 --- a/src/app/(manage)/network/_components/agent-edge.tsx +++ b/src/app/[local]/(manage)/network/_components/agent-edge.tsx @@ -4,12 +4,12 @@ import { type EdgeProps, getBezierPath, } from "reactflow"; -import AgentEdgeToolbar from "~/app/(manage)/network/_components/agent-edge-toolbar"; +import AgentEdgeToolbar from "~/app/[local]/(manage)/network/_components/agent-edge-toolbar"; import { type NetworkAgentEdge } from "~/lib/types/agent"; import { MoveRightIcon, XIcon } from "lucide-react"; import { useStore } from "zustand"; import { useContext, useMemo } from "react"; -import { NetworkContext } from "~/app/(manage)/network/store/network-store"; +import { NetworkContext } from "~/app/[local]/(manage)/network/store/network-store"; export default function AgentEdge({ id, diff --git a/src/app/(manage)/network/_components/agent-node.tsx b/src/app/[local]/(manage)/network/_components/agent-node.tsx similarity index 96% rename from src/app/(manage)/network/_components/agent-node.tsx rename to src/app/[local]/(manage)/network/_components/agent-node.tsx index fad1199..abcb3a2 100644 --- a/src/app/(manage)/network/_components/agent-node.tsx +++ b/src/app/[local]/(manage)/network/_components/agent-node.tsx @@ -12,7 +12,7 @@ import { ServerIcon } from "~/lib/icons"; import { type NetworkAgentNode } from "~/lib/types/agent"; import { useStore } from "zustand"; import { useContext } from "react"; -import { NetworkContext } from "~/app/(manage)/network/store/network-store"; +import { NetworkContext } from "~/app/[local]/(manage)/network/store/network-store"; export default function AgentNode(props: NodeProps) { const { data } = props; diff --git a/src/app/(manage)/network/_components/external-node-new.tsx b/src/app/[local]/(manage)/network/_components/external-node-new.tsx similarity index 97% rename from src/app/(manage)/network/_components/external-node-new.tsx rename to src/app/[local]/(manage)/network/_components/external-node-new.tsx index 65b2e40..c8b684d 100644 --- a/src/app/(manage)/network/_components/external-node-new.tsx +++ b/src/app/[local]/(manage)/network/_components/external-node-new.tsx @@ -22,7 +22,7 @@ import { import { Input } from "~/lib/ui/input"; import React, { useContext } from "react"; import { useStore } from "zustand"; -import { NetworkContext } from "~/app/(manage)/network/store/network-store"; +import { NetworkContext } from "~/app/[local]/(manage)/network/store/network-store"; import { getNewNodePosition, isValidHost, uuid } from "~/lib/utils"; import { useStoreApi } from "reactflow"; diff --git a/src/app/(manage)/network/_components/external-node.tsx b/src/app/[local]/(manage)/network/_components/external-node.tsx similarity index 100% rename from src/app/(manage)/network/_components/external-node.tsx rename to src/app/[local]/(manage)/network/_components/external-node.tsx diff --git a/src/app/(manage)/network/_components/network-command.tsx b/src/app/[local]/(manage)/network/_components/network-command.tsx similarity index 98% rename from src/app/(manage)/network/_components/network-command.tsx rename to src/app/[local]/(manage)/network/_components/network-command.tsx index 4e1eaf7..9a9ae69 100644 --- a/src/app/(manage)/network/_components/network-command.tsx +++ b/src/app/[local]/(manage)/network/_components/network-command.tsx @@ -16,7 +16,7 @@ import { useStore } from "zustand"; import { type AgentProps, NetworkContext, -} from "~/app/(manage)/network/store/network-store"; +} from "~/app/[local]/(manage)/network/store/network-store"; import { AgentStatus } from "@prisma/client"; import { getNewNodePosition } from "~/lib/utils"; import { useStoreApi } from "reactflow"; diff --git a/src/app/(manage)/network/_components/network-delete.tsx b/src/app/[local]/(manage)/network/_components/network-delete.tsx similarity index 100% rename from src/app/(manage)/network/_components/network-delete.tsx rename to src/app/[local]/(manage)/network/_components/network-delete.tsx diff --git a/src/app/(manage)/network/_components/network-edit.tsx b/src/app/[local]/(manage)/network/_components/network-edit.tsx similarity index 97% rename from src/app/(manage)/network/_components/network-edit.tsx rename to src/app/[local]/(manage)/network/_components/network-edit.tsx index cabb3ec..ca73819 100644 --- a/src/app/(manage)/network/_components/network-edit.tsx +++ b/src/app/[local]/(manage)/network/_components/network-edit.tsx @@ -12,7 +12,7 @@ import { useContext, useEffect, useState } from "react"; import { api } from "~/trpc/react"; import { Button } from "~/lib/ui/button"; import { Input } from "~/lib/ui/input"; -import { NetworkContext } from "~/app/(manage)/network/store/network-store"; +import { NetworkContext } from "~/app/[local]/(manage)/network/store/network-store"; import { useStore } from "zustand"; import { useRouter } from "next/navigation"; import { Switch } from "~/lib/ui/switch"; diff --git a/src/app/(manage)/network/_components/network-flow.tsx b/src/app/[local]/(manage)/network/_components/network-flow.tsx similarity index 81% rename from src/app/(manage)/network/_components/network-flow.tsx rename to src/app/[local]/(manage)/network/_components/network-flow.tsx index 5c01dbf..beb41b3 100644 --- a/src/app/(manage)/network/_components/network-flow.tsx +++ b/src/app/[local]/(manage)/network/_components/network-flow.tsx @@ -1,7 +1,7 @@ "use client"; import ReactFlow, { Background, Controls, Panel } from "reactflow"; import { useEffect, useRef } from "react"; -import AgentNode from "~/app/(manage)/network/_components/agent-node"; +import AgentNode from "~/app/[local]/(manage)/network/_components/agent-node"; import { type AgentGetAllOutput, type NetworkGetOneOutput, @@ -9,13 +9,13 @@ import { import { createNetworkStore, NetworkContext, -} from "~/app/(manage)/network/store/network-store"; -import AgentEdge from "~/app/(manage)/network/_components/agent-edge"; -import ExternalNode from "~/app/(manage)/network/_components/external-node"; -import { NetworkCommand } from "~/app/(manage)/network/_components/network-command"; -import NetworkEdit from "~/app/(manage)/network/_components/network-edit"; +} from "~/app/[local]/(manage)/network/store/network-store"; +import AgentEdge from "~/app/[local]/(manage)/network/_components/agent-edge"; +import ExternalNode from "~/app/[local]/(manage)/network/_components/external-node"; +import { NetworkCommand } from "~/app/[local]/(manage)/network/_components/network-command"; +import NetworkEdit from "~/app/[local]/(manage)/network/_components/network-edit"; import "reactflow/dist/style.css"; -import ExternalNodeNew from "~/app/(manage)/network/_components/external-node-new"; +import ExternalNodeNew from "~/app/[local]/(manage)/network/_components/external-node-new"; interface NetworkFlowProps { agents: AgentGetAllOutput; diff --git a/src/app/(manage)/network/_components/network-selector.tsx b/src/app/[local]/(manage)/network/_components/network-selector.tsx similarity index 96% rename from src/app/(manage)/network/_components/network-selector.tsx rename to src/app/[local]/(manage)/network/_components/network-selector.tsx index 780b4d9..bd4727f 100644 --- a/src/app/(manage)/network/_components/network-selector.tsx +++ b/src/app/[local]/(manage)/network/_components/network-selector.tsx @@ -16,7 +16,7 @@ import { import { Popover, PopoverContent, PopoverTrigger } from "~/lib/ui/popover"; import { CheckIcon, ChevronsUpDownIcon } from "lucide-react"; import { useStore } from "zustand"; -import { NetworkContext } from "~/app/(manage)/network/store/network-store"; +import { NetworkContext } from "~/app/[local]/(manage)/network/store/network-store"; import Link from "next/link"; import { type NetworkGetOneOutput } from "~/lib/types/trpc"; diff --git a/src/app/(manage)/network/_components/network-table.tsx b/src/app/[local]/(manage)/network/_components/network-table.tsx similarity index 95% rename from src/app/(manage)/network/_components/network-table.tsx rename to src/app/[local]/(manage)/network/_components/network-table.tsx index 2d8eb50..1c51f4c 100644 --- a/src/app/(manage)/network/_components/network-table.tsx +++ b/src/app/[local]/(manage)/network/_components/network-table.tsx @@ -7,19 +7,19 @@ import { } from "@tanstack/react-table"; import { Input } from "~/lib/ui/input"; import { type ChangeEvent, useMemo, useState } from "react"; -import Table from "~/app/_components/table"; +import Table from "~/app/[local]/_components/table"; import { api } from "~/trpc/react"; import { type NetworkGetAllOutput } from "~/lib/types/trpc"; -import ID from "~/app/_components/id"; -import UserColumn from "~/app/_components/user-column"; -import NetworkDelete from "~/app/(manage)/network/_components/network-delete"; +import ID from "~/app/[local]/_components/id"; +import UserColumn from "~/app/[local]/_components/user-column"; +import NetworkDelete from "~/app/[local]/(manage)/network/_components/network-delete"; import { Button } from "~/lib/ui/button"; import { ArrowRightIcon, CopyIcon, XIcon } from "lucide-react"; import Link from "next/link"; import { copyToClipboard } from "~/lib/utils"; import { type AgentInfo, type NetworkFlow } from "~/lib/types/agent"; import { Tooltip, TooltipContent, TooltipTrigger } from "~/lib/ui/tooltip"; -import Traffic from "~/app/_components/traffic"; +import Traffic from "~/app/[local]/_components/traffic"; import { ForwardTrafficDimensions } from "~/lib/constants"; export default function NetworkTable({ keyword: k }: { keyword: string }) { diff --git a/src/app/[local]/(manage)/network/page.tsx b/src/app/[local]/(manage)/network/page.tsx new file mode 100644 index 0000000..d67dbc3 --- /dev/null +++ b/src/app/[local]/(manage)/network/page.tsx @@ -0,0 +1,30 @@ +import "reactflow/dist/style.css"; +import NetworkTable from "~/app/[local]/(manage)/network/_components/network-table"; +import { getTranslations } from "next-intl/server"; + +export async function generateMetadata({ + params: { locale }, +}: { + params: { locale: string }; +}) { + const t = await getTranslations({ locale, namespace: "global_menu" }); + + return { + title: `${t("network")} - vortex`, + }; +} + +export default async function NetworksPage({ + searchParams: { keyword }, +}: { + searchParams: { keyword: string }; +}) { + return ( +
+
+

Network

+
+ +
+ ); +} diff --git a/src/app/(manage)/network/store/network-store.ts b/src/app/[local]/(manage)/network/store/network-store.ts similarity index 100% rename from src/app/(manage)/network/store/network-store.ts rename to src/app/[local]/(manage)/network/store/network-store.ts diff --git a/src/app/(manage)/ticket/[ticketId]/page.tsx b/src/app/[local]/(manage)/ticket/[ticketId]/page.tsx similarity index 88% rename from src/app/(manage)/ticket/[ticketId]/page.tsx rename to src/app/[local]/(manage)/ticket/[ticketId]/page.tsx index 78e1b7c..b14b3bd 100644 --- a/src/app/(manage)/ticket/[ticketId]/page.tsx +++ b/src/app/[local]/(manage)/ticket/[ticketId]/page.tsx @@ -1,8 +1,8 @@ import { api } from "~/trpc/server"; import Markdown from "react-markdown"; -import UserColumn from "~/app/_components/user-column"; -import TicketReply from "~/app/(manage)/ticket/_components/ticket-reply"; -import TicketStatusBadge from "~/app/(manage)/ticket/_components/ticket-status-badge"; +import UserColumn from "~/app/[local]/_components/user-column"; +import TicketReply from "~/app/[local]/(manage)/ticket/_components/ticket-reply"; +import TicketStatusBadge from "~/app/[local]/(manage)/ticket/_components/ticket-status-badge"; import dayjs from "dayjs"; export const metadata = { diff --git a/src/app/(manage)/ticket/_components/markdown-input.tsx b/src/app/[local]/(manage)/ticket/_components/markdown-input.tsx similarity index 94% rename from src/app/(manage)/ticket/_components/markdown-input.tsx rename to src/app/[local]/(manage)/ticket/_components/markdown-input.tsx index 238e968..d35ffc5 100644 --- a/src/app/(manage)/ticket/_components/markdown-input.tsx +++ b/src/app/[local]/(manage)/ticket/_components/markdown-input.tsx @@ -1,6 +1,6 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/lib/ui/tabs"; import Markdown from "react-markdown"; -import CodeInput from "~/app/_components/code-input"; +import CodeInput from "~/app/[local]/_components/code-input"; interface MarkdownInputProps { value: string; diff --git a/src/app/(manage)/ticket/_components/new-ticket-form.tsx b/src/app/[local]/(manage)/ticket/_components/new-ticket-form.tsx similarity index 96% rename from src/app/(manage)/ticket/_components/new-ticket-form.tsx rename to src/app/[local]/(manage)/ticket/_components/new-ticket-form.tsx index 3f3ddae..b885c5d 100644 --- a/src/app/(manage)/ticket/_components/new-ticket-form.tsx +++ b/src/app/[local]/(manage)/ticket/_components/new-ticket-form.tsx @@ -9,7 +9,7 @@ import { FormMessage, } from "~/lib/ui/form"; import { Input } from "~/lib/ui/input"; -import MarkdownInput from "~/app/(manage)/ticket/_components/markdown-input"; +import MarkdownInput from "~/app/[local]/(manage)/ticket/_components/markdown-input"; import { Button } from "~/lib/ui/button"; import { useTrack } from "~/lib/hooks/use-track"; import { api } from "~/trpc/react"; diff --git a/src/app/(manage)/ticket/_components/ticket-close.tsx b/src/app/[local]/(manage)/ticket/_components/ticket-close.tsx similarity index 100% rename from src/app/(manage)/ticket/_components/ticket-close.tsx rename to src/app/[local]/(manage)/ticket/_components/ticket-close.tsx diff --git a/src/app/(manage)/ticket/_components/ticket-reply.tsx b/src/app/[local]/(manage)/ticket/_components/ticket-reply.tsx similarity index 93% rename from src/app/(manage)/ticket/_components/ticket-reply.tsx rename to src/app/[local]/(manage)/ticket/_components/ticket-reply.tsx index 9e6b48f..7fad6a9 100644 --- a/src/app/(manage)/ticket/_components/ticket-reply.tsx +++ b/src/app/[local]/(manage)/ticket/_components/ticket-reply.tsx @@ -1,5 +1,5 @@ "use client"; -import MarkdownInput from "~/app/(manage)/ticket/_components/markdown-input"; +import MarkdownInput from "~/app/[local]/(manage)/ticket/_components/markdown-input"; import { Button } from "~/lib/ui/button"; import { useState } from "react"; import { api } from "~/trpc/react"; diff --git a/src/app/(manage)/ticket/_components/ticket-status-badge.tsx b/src/app/[local]/(manage)/ticket/_components/ticket-status-badge.tsx similarity index 100% rename from src/app/(manage)/ticket/_components/ticket-status-badge.tsx rename to src/app/[local]/(manage)/ticket/_components/ticket-status-badge.tsx diff --git a/src/app/(manage)/ticket/_components/ticket-table.tsx b/src/app/[local]/(manage)/ticket/_components/ticket-table.tsx similarity index 91% rename from src/app/(manage)/ticket/_components/ticket-table.tsx rename to src/app/[local]/(manage)/ticket/_components/ticket-table.tsx index 4c48f4f..0bbb715 100644 --- a/src/app/(manage)/ticket/_components/ticket-table.tsx +++ b/src/app/[local]/(manage)/ticket/_components/ticket-table.tsx @@ -8,16 +8,16 @@ import { import { Input } from "~/lib/ui/input"; import * as React from "react"; import { type ChangeEvent, useMemo, useState } from "react"; -import Table from "~/app/_components/table"; +import Table from "~/app/[local]/_components/table"; import { api } from "~/trpc/react"; import { type TicketGetAllOutput } from "~/lib/types/trpc"; -import ID from "~/app/_components/id"; -import UserColumn from "~/app/_components/user-column"; +import ID from "~/app/[local]/_components/id"; +import UserColumn from "~/app/[local]/_components/user-column"; import { Button } from "~/lib/ui/button"; import { XIcon } from "lucide-react"; import Link from "next/link"; -import TicketStatusBadge from "~/app/(manage)/ticket/_components/ticket-status-badge"; -import TicketClose from "~/app/(manage)/ticket/_components/ticket-close"; +import TicketStatusBadge from "~/app/[local]/(manage)/ticket/_components/ticket-status-badge"; +import TicketClose from "~/app/[local]/(manage)/ticket/_components/ticket-close"; export default function TicketTable({ keyword: k }: { keyword: string }) { const [keyword, setKeyword] = useState(k); diff --git a/src/app/(manage)/ticket/new/page.tsx b/src/app/[local]/(manage)/ticket/new/page.tsx similarity index 72% rename from src/app/(manage)/ticket/new/page.tsx rename to src/app/[local]/(manage)/ticket/new/page.tsx index d6da472..3557b8a 100644 --- a/src/app/(manage)/ticket/new/page.tsx +++ b/src/app/[local]/(manage)/ticket/new/page.tsx @@ -1,4 +1,4 @@ -import NewTicketForm from "~/app/(manage)/ticket/_components/new-ticket-form"; +import NewTicketForm from "~/app/[local]/(manage)/ticket/_components/new-ticket-form"; export const metadata = { title: "工单 - vortex", diff --git a/src/app/[local]/(manage)/ticket/page.tsx b/src/app/[local]/(manage)/ticket/page.tsx new file mode 100644 index 0000000..217faef --- /dev/null +++ b/src/app/[local]/(manage)/ticket/page.tsx @@ -0,0 +1,30 @@ +import TicketTable from "~/app/[local]/(manage)/ticket/_components/ticket-table"; +import { getTranslations } from "next-intl/server"; + +export async function generateMetadata({ + params: { locale }, +}: { + params: { locale: string }; +}) { + const t = await getTranslations({ locale, namespace: "global_menu" }); + + return { + title: `${t("ticket")} - vortex`, + }; +} + +export default async function TicketsPage({ + searchParams: { keyword }, +}: { + searchParams: { keyword: string }; +}) { + const t = await getTranslations("global_menu"); + return ( +
+
+

{t("ticket")}

+
+ +
+ ); +} diff --git a/src/app/(manage)/user/[userId]/_components/balance-log.tsx b/src/app/[local]/(manage)/user/[userId]/_components/balance-log.tsx similarity index 98% rename from src/app/(manage)/user/[userId]/_components/balance-log.tsx rename to src/app/[local]/(manage)/user/[userId]/_components/balance-log.tsx index 01a09f6..badce1c 100644 --- a/src/app/(manage)/user/[userId]/_components/balance-log.tsx +++ b/src/app/[local]/(manage)/user/[userId]/_components/balance-log.tsx @@ -4,7 +4,7 @@ import { ScrollArea } from "~/lib/ui/scroll-area"; import { api } from "~/trpc/react"; import React from "react"; import { formatDate } from "~/lib/utils"; -import SearchEmptyState from "~/app/_components/search-empty-state"; +import SearchEmptyState from "~/app/[local]/_components/search-empty-state"; import { Tooltip, TooltipContent, TooltipTrigger } from "~/lib/ui/tooltip"; import type { RouterOutputs } from "~/trpc/shared"; import { MoneyInput } from "~/lib/ui/money-input"; diff --git a/src/app/(manage)/user/[userId]/_components/balance.tsx b/src/app/[local]/(manage)/user/[userId]/_components/balance.tsx similarity index 81% rename from src/app/(manage)/user/[userId]/_components/balance.tsx rename to src/app/[local]/(manage)/user/[userId]/_components/balance.tsx index 46a5a14..215e6ae 100644 --- a/src/app/(manage)/user/[userId]/_components/balance.tsx +++ b/src/app/[local]/(manage)/user/[userId]/_components/balance.tsx @@ -1,12 +1,12 @@ "use client"; import { Card, CardContent, CardFooter, CardHeader } from "~/lib/ui/card"; -import UpdateBalance from "~/app/(manage)/user/[userId]/_components/update-balance"; +import UpdateBalance from "~/app/[local]/(manage)/user/[userId]/_components/update-balance"; import { useSession } from "next-auth/react"; import { hasPermission } from "~/lib/constants/permission"; -import RechargeBalance from "~/app/(manage)/user/[userId]/_components/recharge-balance"; +import RechargeBalance from "~/app/[local]/(manage)/user/[userId]/_components/recharge-balance"; import { MoneyInput } from "~/lib/ui/money-input"; import { BalanceType } from "@prisma/client"; -import WithdrawalBalance from "~/app/(manage)/user/[userId]/_components/withdrawal-balance"; +import WithdrawalBalance from "~/app/[local]/(manage)/user/[userId]/_components/withdrawal-balance"; interface BalanceProps { wallet: { diff --git a/src/app/(manage)/user/[userId]/_components/profile-form.tsx b/src/app/[local]/(manage)/user/[userId]/_components/profile-form.tsx similarity index 100% rename from src/app/(manage)/user/[userId]/_components/profile-form.tsx rename to src/app/[local]/(manage)/user/[userId]/_components/profile-form.tsx diff --git a/src/app/(manage)/user/[userId]/_components/recharge-balance.tsx b/src/app/[local]/(manage)/user/[userId]/_components/recharge-balance.tsx similarity index 100% rename from src/app/(manage)/user/[userId]/_components/recharge-balance.tsx rename to src/app/[local]/(manage)/user/[userId]/_components/recharge-balance.tsx diff --git a/src/app/(manage)/user/[userId]/_components/recharge-depay.tsx b/src/app/[local]/(manage)/user/[userId]/_components/recharge-depay.tsx similarity index 100% rename from src/app/(manage)/user/[userId]/_components/recharge-depay.tsx rename to src/app/[local]/(manage)/user/[userId]/_components/recharge-depay.tsx diff --git a/src/app/(manage)/user/[userId]/_components/update-balance.tsx b/src/app/[local]/(manage)/user/[userId]/_components/update-balance.tsx similarity index 100% rename from src/app/(manage)/user/[userId]/_components/update-balance.tsx rename to src/app/[local]/(manage)/user/[userId]/_components/update-balance.tsx diff --git a/src/app/(manage)/user/[userId]/_components/withdrawal-balance.tsx b/src/app/[local]/(manage)/user/[userId]/_components/withdrawal-balance.tsx similarity index 100% rename from src/app/(manage)/user/[userId]/_components/withdrawal-balance.tsx rename to src/app/[local]/(manage)/user/[userId]/_components/withdrawal-balance.tsx diff --git a/src/app/(manage)/user/[userId]/account/page.tsx b/src/app/[local]/(manage)/user/[userId]/account/page.tsx similarity index 88% rename from src/app/(manage)/user/[userId]/account/page.tsx rename to src/app/[local]/(manage)/user/[userId]/account/page.tsx index b69d957..3bf0369 100644 --- a/src/app/(manage)/user/[userId]/account/page.tsx +++ b/src/app/[local]/(manage)/user/[userId]/account/page.tsx @@ -1,7 +1,7 @@ -import { Separator } from "~/lib/ui/separator"; +import { Separator } from "../../../../../../lib/ui/separator"; import { api } from "~/trpc/server"; import { Label } from "~/lib/ui/label"; -import UpdatePasswordDialog from "~/app/_components/update-password-dialog"; +import UpdatePasswordDialog from "~/app/[local]/_components/update-password-dialog"; export default async function UserAccountPage({ params: { userId }, diff --git a/src/app/(manage)/user/[userId]/balance/page.tsx b/src/app/[local]/(manage)/user/[userId]/balance/page.tsx similarity index 91% rename from src/app/(manage)/user/[userId]/balance/page.tsx rename to src/app/[local]/(manage)/user/[userId]/balance/page.tsx index 1e07e05..a3e05a0 100644 --- a/src/app/(manage)/user/[userId]/balance/page.tsx +++ b/src/app/[local]/(manage)/user/[userId]/balance/page.tsx @@ -1,7 +1,7 @@ import { Separator } from "~/lib/ui/separator"; import { api } from "~/trpc/server"; -import Balance from "~/app/(manage)/user/[userId]/_components/balance"; -import BalanceLog from "~/app/(manage)/user/[userId]/_components/balance-log"; +import Balance from "~/app/[local]/(manage)/user/[userId]/_components/balance"; +import BalanceLog from "~/app/[local]/(manage)/user/[userId]/_components/balance-log"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/lib/ui/tabs"; import { getServerAuthSession } from "~/server/auth"; import { BalanceType, Role } from "@prisma/client"; diff --git a/src/app/(manage)/user/[userId]/layout.tsx b/src/app/[local]/(manage)/user/[userId]/layout.tsx similarity index 94% rename from src/app/(manage)/user/[userId]/layout.tsx rename to src/app/[local]/(manage)/user/[userId]/layout.tsx index 3e3abeb..2c90c63 100644 --- a/src/app/(manage)/user/[userId]/layout.tsx +++ b/src/app/[local]/(manage)/user/[userId]/layout.tsx @@ -1,6 +1,6 @@ import { Separator } from "~/lib/ui/separator"; import { type ReactNode } from "react"; -import { SidebarNav } from "~/app/_components/sidebar-nav"; +import { SidebarNav } from "~/app/[local]/_components/sidebar-nav"; import type { Metadata } from "next"; export const metadata: Metadata = { diff --git a/src/app/(manage)/user/[userId]/page.tsx b/src/app/[local]/(manage)/user/[userId]/page.tsx similarity index 87% rename from src/app/(manage)/user/[userId]/page.tsx rename to src/app/[local]/(manage)/user/[userId]/page.tsx index 33b9b3d..ccded3b 100644 --- a/src/app/(manage)/user/[userId]/page.tsx +++ b/src/app/[local]/(manage)/user/[userId]/page.tsx @@ -1,5 +1,5 @@ import { Separator } from "~/lib/ui/separator"; -import ProfileForm from "~/app/(manage)/user/[userId]/_components/profile-form"; +import ProfileForm from "~/app/[local]/(manage)/user/[userId]/_components/profile-form"; import { api } from "~/trpc/server"; export default async function SettingProfilePage({ diff --git a/src/app/_components/code-input.tsx b/src/app/[local]/_components/code-input.tsx similarity index 97% rename from src/app/_components/code-input.tsx rename to src/app/[local]/_components/code-input.tsx index e584e28..d6e680f 100644 --- a/src/app/_components/code-input.tsx +++ b/src/app/[local]/_components/code-input.tsx @@ -12,6 +12,7 @@ import { linter, lintGutter } from "@codemirror/lint"; import { ClipboardTypeIcon } from "lucide-react"; import { cn } from "~/lib/utils"; import { Tooltip, TooltipContent, TooltipTrigger } from "~/lib/ui/tooltip"; +import { useTranslations } from "use-intl"; interface CodeInputProps { className?: string; @@ -36,7 +37,7 @@ const CodeInput: React.FC = ({ }) => { const [code, setCode] = useState(""); const [extensions, setExtensions] = useState([]); - + const t = useTranslations("global_code-input"); useEffect(() => { if (language === "json") { try { @@ -156,7 +157,7 @@ const CodeInput: React.FC = ({ /> - 格式化 + {t("format")}
diff --git a/src/app/_components/faceted-filter.tsx b/src/app/[local]/_components/faceted-filter.tsx similarity index 100% rename from src/app/_components/faceted-filter.tsx rename to src/app/[local]/_components/faceted-filter.tsx diff --git a/src/app/_components/id.tsx b/src/app/[local]/_components/id.tsx similarity index 89% rename from src/app/_components/id.tsx rename to src/app/[local]/_components/id.tsx index 246ee27..c6af473 100644 --- a/src/app/_components/id.tsx +++ b/src/app/[local]/_components/id.tsx @@ -4,6 +4,7 @@ import { CopyIcon } from "lucide-react"; import { cn, copyToClipboard } from "~/lib/utils"; import { Tooltip, TooltipContent, TooltipTrigger } from "~/lib/ui/tooltip"; import dayjs from "dayjs"; +import { useTranslations } from "use-intl"; interface IDProps { id: string; @@ -13,6 +14,7 @@ interface IDProps { export default function ID({ id, createdAt, copy = true }: IDProps) { if (!id) return null; + const t = useTranslations("global_id"); const shortId = id.length > 10 ? id.slice(0, 4) + " ... " + id.slice(-6) : id; return ( @@ -35,7 +37,7 @@ export default function ID({ id, createdAt, copy = true }: IDProps) {

{createdAt && (

- 创建于 {dayjs(createdAt).locale("zh-cn").fromNow()} + {t("created-at")} {dayjs(createdAt).locale("zh-cn").fromNow()}

)}
diff --git a/src/app/_components/loading.tsx b/src/app/[local]/_components/loading.tsx similarity index 100% rename from src/app/_components/loading.tsx rename to src/app/[local]/_components/loading.tsx diff --git a/src/app/[local]/_components/locale-switcher.tsx b/src/app/[local]/_components/locale-switcher.tsx new file mode 100644 index 0000000..0328179 --- /dev/null +++ b/src/app/[local]/_components/locale-switcher.tsx @@ -0,0 +1,52 @@ +"use client"; +import { useLocale, useTranslations } from "use-intl"; +import { locales } from "~/lib/constants"; +import { usePathname, useRouter } from "~/navigation"; +import { useTransition } from "react"; +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuTrigger, +} from "~/lib/ui/dropdown-menu"; +import { Button } from "~/lib/ui/button"; +import { LanguagesIcon } from "lucide-react"; + +export default function LocaleSwitcher() { + const t = useTranslations("global_locale-switcher"); + const locale = useLocale(); + + const router = useRouter(); + const [isPending, startTransition] = useTransition(); + const pathname = usePathname(); + + function handleLocaleChange(nextLocale: string) { + startTransition(() => { + router.replace(pathname, { locale: nextLocale }); + }); + } + + return ( + + + + + + {locales.map((option) => ( + handleLocaleChange(option)} + disabled={isPending} + className="cursor-pointer" + > + {t("locale", { locale: option })} + + ))} + + + ); +} diff --git a/src/app/_components/logo.tsx b/src/app/[local]/_components/logo.tsx similarity index 100% rename from src/app/_components/logo.tsx rename to src/app/[local]/_components/logo.tsx diff --git a/src/app/_components/menu.tsx b/src/app/[local]/_components/menu.tsx similarity index 69% rename from src/app/_components/menu.tsx rename to src/app/[local]/_components/menu.tsx index f68a7fc..2c46e23 100644 --- a/src/app/_components/menu.tsx +++ b/src/app/[local]/_components/menu.tsx @@ -4,11 +4,11 @@ import Link from "next/link"; import { Button, buttonVariants } from "~/lib/ui/button"; import { cn, comparePath } from "~/lib/utils"; import { usePathname } from "next/navigation"; -import { ThemeChange } from "~/app/_components/theme-provider"; -import Logo from "~/app/_components/logo"; +import { ThemeChange } from "~/app/[local]/_components/theme-provider"; +import Logo from "~/app/[local]/_components/logo"; import { type Menu } from "~/lib/types"; import { Tooltip, TooltipContent, TooltipTrigger } from "~/lib/ui/tooltip"; -import { type CSSProperties, Fragment, type ReactNode } from "react"; +import { type CSSProperties, Fragment, type ReactNode, useMemo } from "react"; import { Separator } from "~/lib/ui/separator"; import { DropdownMenu, @@ -20,6 +20,8 @@ import { import { Avatar, AvatarFallback, AvatarImage } from "~/lib/ui/avatar"; import { useSession } from "next-auth/react"; import { env } from "~/env"; +import LocaleSwitcher from "~/app/[local]/_components/locale-switcher"; +import { type MessageKeys, useLocale, useTranslations } from "use-intl"; interface MenuProps { menus: Menu[]; @@ -28,24 +30,44 @@ interface MenuProps { style?: CSSProperties; } +type MenuMessagesType = MessageKeys; + export default function Menu({ menus, isCollapsed = false, className, style, }: MenuProps) { + const t = useTranslations("global_menu"); + const local = useLocale(); const pathName = usePathname(); - const menusWithActive = menus.map((menu) => { - return { - ...menu, - active: menu.href ? false : comparePath(pathName, menu.href!), - }; - }); + const menusWithActive = useMemo(() => { + const removedLocalPathName = pathName.replace(`/${local}`, ""); + return menus.map((menu) => { + return { + ...menu, + active: menu.href + ? comparePath(removedLocalPathName, menu.href) + : false, + children: menu.children?.map((child) => { + return { + ...child, + active: child.href + ? comparePath(removedLocalPathName, child.href) + : false, + }; + }), + }; + }); + }, [local, menus, pathName]); - const renderCollapsedMenu = (menu: Menu, index: number): ReactNode => { + const renderCollapsedMenu = ( + menu: Menu & { active: boolean }, + index: number, + ): ReactNode => { if (menu.href) { - const active = comparePath(pathName, menu.href); + const active = menu.active; return ( @@ -63,11 +85,13 @@ export default function Menu({ )} > {menu.icon && } - {menu.title} + + {t(menu.title as MenuMessagesType)} + - {menu.title} + {t(menu.title as MenuMessagesType)} ); @@ -76,15 +100,21 @@ export default function Menu({ {menu.children?.map((child, index) => { - return renderCollapsedMenu(child, index); + return renderCollapsedMenu( + child as Menu & { active: boolean }, + index, + ); })} ); }; - const renderMenu = (menu: Menu, index: number): ReactNode => { + const renderMenu = ( + menu: Menu & { active: boolean }, + index: number, + ): ReactNode => { if (menu.href) { - const active = comparePath(pathName, menu.href); + const active = menu.active; return ( {menu.icon && } - {menu.title} + {t(menu.title as MenuMessagesType)} ); } return ( - + {menu.children?.map((child, index) => { - return renderMenu(child, index); + return renderMenu(child as Menu & { active: boolean }, index); })} ); @@ -139,15 +171,26 @@ export default function Menu({
- - + +
+ + +
{!isCollapsed && }
); } -function UserProfile({ isCollapsed = false }: { isCollapsed?: boolean }) { +function UserProfile({ + isCollapsed = false, + t, +}: { + isCollapsed?: boolean; + t: ReturnType; +}) { const { data: session } = useSession(); return ( @@ -183,7 +226,7 @@ function UserProfile({ isCollapsed = false }: { isCollapsed?: boolean }) { className="flex w-full items-center" > - 个人中心 + {t("personal-center")} @@ -192,14 +235,14 @@ function UserProfile({ isCollapsed = false }: { isCollapsed?: boolean }) { className="flex w-full items-center" > - 余额 + {t("balance")} - 退出 + {t("logout")} @@ -209,7 +252,7 @@ function UserProfile({ isCollapsed = false }: { isCollapsed?: boolean }) { function Version() { return ( -
+
{ column?: Column; diff --git a/src/app/_components/table-view-options.tsx b/src/app/[local]/_components/table-view-options.tsx similarity index 100% rename from src/app/_components/table-view-options.tsx rename to src/app/[local]/_components/table-view-options.tsx diff --git a/src/app/_components/table.tsx b/src/app/[local]/_components/table.tsx similarity index 95% rename from src/app/_components/table.tsx rename to src/app/[local]/_components/table.tsx index 4e6ea3d..9afec94 100644 --- a/src/app/_components/table.tsx +++ b/src/app/[local]/_components/table.tsx @@ -10,6 +10,7 @@ import { import { flexRender, type Table as ReactTable } from "@tanstack/react-table"; import { DataTablePagination } from "~/lib/ui/pagination"; import { LoaderIcon } from "lucide-react"; +import { useTranslations } from "use-intl"; export default function Table({ table, @@ -18,6 +19,7 @@ export default function Table({ table: ReactTable; isLoading: boolean; }) { + const t = useTranslations("global_table"); return ( <>
@@ -74,7 +76,7 @@ export default function Table({ colSpan={table.getAllColumns().length} className="h-24 text-center" > - 无数据 + {t("no-data")} )} diff --git a/src/app/_components/theme-provider.tsx b/src/app/[local]/_components/theme-provider.tsx similarity index 100% rename from src/app/_components/theme-provider.tsx rename to src/app/[local]/_components/theme-provider.tsx diff --git a/src/app/_components/traffic-usage-month.tsx b/src/app/[local]/_components/traffic-usage-month.tsx similarity index 100% rename from src/app/_components/traffic-usage-month.tsx rename to src/app/[local]/_components/traffic-usage-month.tsx diff --git a/src/app/_components/traffic.tsx b/src/app/[local]/_components/traffic.tsx similarity index 95% rename from src/app/_components/traffic.tsx rename to src/app/[local]/_components/traffic.tsx index c7c1086..8720f9a 100644 --- a/src/app/_components/traffic.tsx +++ b/src/app/[local]/_components/traffic.tsx @@ -5,7 +5,7 @@ import { HoverCardTrigger, } from "~/lib/ui/hover-card"; import { MoveDownIcon, MoveUpIcon } from "lucide-react"; -import TrafficUsageMonth from "~/app/_components/traffic-usage-month"; +import TrafficUsageMonth from "~/app/[local]/_components/traffic-usage-month"; import { type ForwardTrafficDimensions } from "~/lib/types"; interface TrafficProps { diff --git a/src/app/_components/update-password-dialog.tsx b/src/app/[local]/_components/update-password-dialog.tsx similarity index 88% rename from src/app/_components/update-password-dialog.tsx rename to src/app/[local]/_components/update-password-dialog.tsx index ee8454b..2c188d1 100644 --- a/src/app/_components/update-password-dialog.tsx +++ b/src/app/[local]/_components/update-password-dialog.tsx @@ -5,7 +5,7 @@ import { DialogTitle, DialogTrigger, } from "~/lib/ui/dialog"; -import UpdatePasswordForm from "~/app/_components/update-password-form"; +import UpdatePasswordForm from "~/app/[local]/_components/update-password-form"; import { Button } from "~/lib/ui/button"; export default function UpdatePasswordDialog({ diff --git a/src/app/_components/update-password-form.tsx b/src/app/[local]/_components/update-password-form.tsx similarity index 100% rename from src/app/_components/update-password-form.tsx rename to src/app/[local]/_components/update-password-form.tsx diff --git a/src/app/_components/user-column.tsx b/src/app/[local]/_components/user-column.tsx similarity index 100% rename from src/app/_components/user-column.tsx rename to src/app/[local]/_components/user-column.tsx diff --git a/src/app/_components/welcome.tsx b/src/app/[local]/_components/welcome.tsx similarity index 97% rename from src/app/_components/welcome.tsx rename to src/app/[local]/_components/welcome.tsx index 8ceb83f..52a718e 100644 --- a/src/app/_components/welcome.tsx +++ b/src/app/[local]/_components/welcome.tsx @@ -1,10 +1,16 @@ import { cn } from "~/lib/utils"; import Image from "next/image"; -export default function Welcome({ className }: { className?: string }) { +export default function Welcome({ + className, + welcome, +}: { + className?: string; + welcome: string; +}) { return (
-

Welcome

+

{welcome}

= { default: { - heading: "发生错误", + heading: t("an_error_occurred"), }, configuration: { - heading: "服务器错误", + heading: t("server_error"), message: (
-

服务器配置有问题。

-

检查服务器日志以获取更多信息。

+

{t("server_misconfigured")}

+

{t("check_server_logs_for_more_info")}

), }, accessdenied: { - heading: "拒绝访问", + heading: t("access_denied"), message: (
-

您没有登录权限。

+

{t("not_authorized_to_signin")}

), }, verification: { - heading: "无法登录", + heading: t("unable_to_signin"), message: (
-

登录链接不再有效。

-

它可能已经被使用过或者可能已经过期。

+

{t("signin_link_no_longer_valid")}

+

{t("it_may_have_been_used_or_expired")}

), }, signin: { - heading: "无法登录", + heading: t("unable_to_signin"), message: (
-

检查您提供的详细信息是否正确。

+

{t("check_details_provided_are_correct")}

), }, oauthsignin: { - heading: "无法登录", + heading: t("unable_to_signin"), message: (
-

尝试使用其他帐户登录。

+

{t("try_signing_in_with_different_account")}

), }, oauthcallback: { - heading: "无法登录", + heading: t("unable_to_signin"), message: (
-

尝试使用其他帐户登录。

+

{t("try_signing_in_with_different_account")}

), }, oauthcreateaccount: { - heading: "无法登录", + heading: t("unable_to_signin"), message: (
-

尝试使用其他帐户登录。

+

{t("try_signing_in_with_different_account")}

), }, emailcreateaccount: { - heading: "无法登录", + heading: t("unable_to_signin"), message: (
-

尝试使用其他帐户登录。

+

{t("try_signing_in_with_different_account")}

), }, callback: { - heading: "无法登录", + heading: t("unable_to_signin"), message: (
-

尝试使用其他帐户登录。

+

{t("try_signing_in_with_different_account")}

), }, oauthaccountnotlinked: { - heading: "无法登录", + heading: t("unable_to_signin"), message: (
-

要确认您的身份,请使用您最初使用的同一帐户登录。

+

{t("oauth_account_not_linked")}

), }, emailsignin: { - heading: "无法登录", + heading: t("unable_to_signin"), message: (
-

电子邮件无法发送。

+

{t("email_could_not_be_sent")}

), }, credentialssignin: { - heading: "无法登录", + heading: t("unable_to_signin"), message: (
-

请检查您提供的信息是否正确。

+

{t("check_information_provided_is_correct")}

), }, sessionrequired: { - heading: "拒绝访问", + heading: t("access_denied"), message: (
-

请登录才能访问此页面。

+

{t("please_signin_to_access_this_page")}

), }, userbanned: { - heading: "用户已禁用", + heading: t("user_disabled"), message: (
-

您的帐户已被禁用。

+

{t("your_account_has_been_disabled")}

), }, @@ -157,7 +159,7 @@ export default function AuthErrorPage({

{heading}

{message}
- 返回登录 + {t("back_to_signin")}
diff --git a/src/app/auth/layout.tsx b/src/app/[local]/auth/layout.tsx similarity index 72% rename from src/app/auth/layout.tsx rename to src/app/[local]/auth/layout.tsx index b199e60..5fb8e6a 100644 --- a/src/app/auth/layout.tsx +++ b/src/app/[local]/auth/layout.tsx @@ -1,5 +1,7 @@ import React, { type ReactNode } from "react"; -import Logo from "~/app/_components/logo"; +import Logo from "~/app/[local]/_components/logo"; +import LocaleSwitcher from "~/app/[local]/_components/locale-switcher"; +import { ThemeChange } from "~/app/[local]/_components/theme-provider"; export default function SigninLayout({ children }: { children: ReactNode }) { return ( @@ -21,7 +23,13 @@ export default function SigninLayout({ children }: { children: ReactNode }) {
-
{children}
+
+ {children} +
+ + +
+
); diff --git a/src/app/auth/new/page.tsx b/src/app/[local]/auth/new/page.tsx similarity index 68% rename from src/app/auth/new/page.tsx rename to src/app/[local]/auth/new/page.tsx index febb588..e9c2505 100644 --- a/src/app/auth/new/page.tsx +++ b/src/app/[local]/auth/new/page.tsx @@ -1,8 +1,9 @@ import { redirect, RedirectType } from "next/navigation"; import React from "react"; -import UpdatePasswordForm from "~/app/_components/update-password-form"; +import UpdatePasswordForm from "~/app/[local]/_components/update-password-form"; import { getServerAuthSession } from "~/server/auth"; import Link from "next/link"; +import { getTranslations } from "next-intl/server"; export default async function NewUserPage() { const session = await getServerAuthSession(); @@ -15,20 +16,24 @@ export default async function NewUserPage() { redirect("/", RedirectType.replace); } + const t = await getTranslations("auth-new"); + return (
-

创建密码

+

+ {t("create_password")} +

- 为您的账户创建一个密码,以便您可以使用电子邮件地址和密码登录。 + {t("create_password_tips")}

- 不设置密码,直接登录 + {t("skip_password_tips")}
); diff --git a/src/app/auth/signin/credential/page.tsx b/src/app/[local]/auth/signin/credential/page.tsx similarity index 88% rename from src/app/auth/signin/credential/page.tsx rename to src/app/[local]/auth/signin/credential/page.tsx index 1c864be..183d65e 100644 --- a/src/app/auth/signin/credential/page.tsx +++ b/src/app/[local]/auth/signin/credential/page.tsx @@ -15,6 +15,7 @@ import { FormMessage, } from "~/lib/ui/form"; import { signIn } from "next-auth/react"; +import { useTranslations } from "use-intl"; const credentialSignInFormSchema = z.object({ username: z.string().email("请输入正确的邮箱地址"), @@ -26,6 +27,7 @@ export default function SigninCredentialPage({ }: { searchParams: { callbackUrl: string }; }) { + const t = useTranslations("auth-signin-credential"); const form = useForm>({ resolver: zodResolver(credentialSignInFormSchema), }); @@ -48,11 +50,13 @@ export default function SigninCredentialPage({ } className="absolute right-4 top-4 md:right-8 md:top-8" > - 返回注册 + {t("back_to_signup")}
-

密码登录

+

+ {t("password_signin")} +

@@ -68,7 +72,7 @@ export default function SigninCredentialPage({ @@ -102,25 +106,25 @@ export default function SigninCredentialPage({ data-umami-event="signin-credential-button" data-umami-username={form.getValues("username")} > - 登录 + {t("signin")}

- 继续即表示您同意我们的{" "} + {t("by_continuing_you_agree_to_our")}{" "} - 服务条款 + {t("terms_of_service")} {" "} - 和{" "} + {t("and")}{" "} - 隐私政策 + {t("privacy_policy")}

diff --git a/src/app/auth/signin/page.tsx b/src/app/[local]/auth/signin/page.tsx similarity index 89% rename from src/app/auth/signin/page.tsx rename to src/app/[local]/auth/signin/page.tsx index 421244d..0f2aded 100644 --- a/src/app/auth/signin/page.tsx +++ b/src/app/[local]/auth/signin/page.tsx @@ -12,6 +12,7 @@ import { redirect } from "next/navigation"; import { RedirectType } from "next/dist/client/components/redirect"; import { api } from "~/trpc/server"; import Image from "next/image"; +import { getTranslations } from "next-intl/server"; export default async function SigninPage({ searchParams: { error, callbackUrl }, @@ -21,6 +22,7 @@ export default async function SigninPage({ if (error) { redirect(`/auth/error?error=${error}`, RedirectType.replace); } + const t = await getTranslations("auth-signin"); const { ENABLE_REGISTER } = await api.publicSystem.getConfig.query({ key: "ENABLE_REGISTER", }); @@ -36,7 +38,7 @@ export default async function SigninPage({ } className="absolute right-4 top-4 md:right-8 md:top-8" > - 密码登录 + {t("password_signin")} ); @@ -53,7 +55,7 @@ export default async function SigninPage({ height={200} />

- 已关闭注册! + {t("registration_closed")}!

@@ -86,7 +88,7 @@ export default async function SigninPage({
@@ -124,7 +126,7 @@ export default async function SigninPage({ {provider.id === "google" && ( )} - {provider.name} 登录 + {provider.name} {t("signin")} ); @@ -137,10 +139,10 @@ export default async function SigninPage({

- 创建一个账号 + {t("create_an_account")}

- 输入你的邮箱来登录或者注册一个账号 + {t("enter_email_signin_or_register")}

@@ -151,26 +153,26 @@ export default async function SigninPage({
- 或者使用 + {t("or_use")}

- 继续即表示您同意我们的{" "} + {t("by_continuing_you_agree_to_our")}{" "} - 服务条款 + {t("terms_of_service")} {" "} - 和{" "} + {t("and")}{" "} - 隐私政策 + {t("privacy_policy")}

diff --git a/src/app/auth/signout/page.tsx b/src/app/[local]/auth/signout/page.tsx similarity index 79% rename from src/app/auth/signout/page.tsx rename to src/app/[local]/auth/signout/page.tsx index 052c6f4..22c36f1 100644 --- a/src/app/auth/signout/page.tsx +++ b/src/app/[local]/auth/signout/page.tsx @@ -1,19 +1,21 @@ "use client"; import { Button } from "~/lib/ui/button"; import { signOut } from "next-auth/react"; +import { useTranslations } from "use-intl"; export default function SignOutPage() { + const t = useTranslations("auth-signout"); return (

- 确认退出登录? + {t("confirm_sign_out")}

diff --git a/src/app/auth/verify/page.tsx b/src/app/[local]/auth/verify/page.tsx similarity index 100% rename from src/app/auth/verify/page.tsx rename to src/app/[local]/auth/verify/page.tsx diff --git a/src/app/layout.tsx b/src/app/[local]/layout.tsx similarity index 59% rename from src/app/layout.tsx rename to src/app/[local]/layout.tsx index 23a2b64..1c5f638 100644 --- a/src/app/layout.tsx +++ b/src/app/[local]/layout.tsx @@ -4,10 +4,13 @@ import { Inter } from "next/font/google"; import { cookies } from "next/headers"; import { TRPCReactProvider } from "~/trpc/react"; -import { ThemeProvider } from "~/app/_components/theme-provider"; +import { ThemeProvider } from "~/app/[local]/_components/theme-provider"; import { Toaster } from "~/lib/ui/toaster"; import Script from "next/script"; import { env } from "~/env"; +import { type ReactNode } from "react"; +import { NextIntlClientProvider } from "next-intl"; +import { getMessages, unstable_setRequestLocale } from "next-intl/server"; const inter = Inter({ subsets: ["latin"], @@ -20,13 +23,18 @@ export const metadata = { icons: [{ rel: "icon", url: "/favicon.ico" }], }; -export default function RootLayout({ +export default async function RootLayout({ children, + params: { locale }, }: { - children: React.ReactNode; + children: ReactNode; + params: { locale: string }; }) { + unstable_setRequestLocale(locale); + const messages = await getMessages({ locale }); + return ( - + - - {children} - - + + + {children} + + + {env.NEXT_PUBLIC_UMAMI && env.NEXT_PUBLIC_UMAMI_ID && ( diff --git a/src/app/[local]/page.tsx b/src/app/[local]/page.tsx new file mode 100644 index 0000000..f5c7bc2 --- /dev/null +++ b/src/app/[local]/page.tsx @@ -0,0 +1,32 @@ +import { getServerAuthSession } from "~/server/auth"; +import Logo from "~/app/[local]/_components/logo"; +import Welcome from "~/app/[local]/_components/welcome"; +import Link from "next/link"; +import LocaleSwitcher from "~/app/[local]/_components/locale-switcher"; +import { getTranslations } from "next-intl/server"; +import { ThemeChange } from "~/app/[local]/_components/theme-provider"; + +export default async function Home() { + const session = await getServerAuthSession(); + const t = await getTranslations("index"); + + return ( +
+ + +
+ + + {session ? ( + + {t("Dashboard")} + + ) : ( + + {t("Sign In")} + + )} +
+
+ ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx index 3c279f9..77d15e3 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,26 +1,5 @@ -import { getServerAuthSession } from "~/server/auth"; -import Logo from "~/app/_components/logo"; -import Welcome from "~/app/_components/welcome"; -import Link from "next/link"; +import { redirect } from "next/navigation"; -export default async function Home() { - const session = await getServerAuthSession(); - - return ( -
- - -
- {session ? ( - - Dashboard - - ) : ( - - Sign In - - )} -
-
- ); +export default function RootPage() { + redirect("/en"); } diff --git a/src/i18n.ts b/src/i18n.ts new file mode 100644 index 0000000..b7f89e5 --- /dev/null +++ b/src/i18n.ts @@ -0,0 +1,14 @@ +import { notFound } from "next/navigation"; +import { getRequestConfig } from "next-intl/server"; + +// Can be imported from a shared config +const locales = ["en", "zh"]; + +export default getRequestConfig(async ({ locale }) => { + // Validate that the incoming `locale` parameter is valid + if (!locales.includes(locale)) notFound(); + + return { + messages: (await import(`../messages/${locale}.json`)).default, + }; +}); diff --git a/src/lib/constants/custom-component-config.ts b/src/lib/constants/custom-component-config.ts index 3e7520f..4ed5920 100644 --- a/src/lib/constants/custom-component-config.ts +++ b/src/lib/constants/custom-component-config.ts @@ -1,10 +1,13 @@ "use client"; import type { ConfigSchema } from "~/lib/types"; import dynamic from "next/dynamic"; -import { TrafficPriceSkeleton } from "~/app/(manage)/admin/config/_components/traffic-price-config"; +import { TrafficPriceSkeleton } from "~/app/[local]/(manage)/admin/config/_components/traffic-price-config"; const TrafficPriceConfig = dynamic( - () => import("~/app/(manage)/admin/config/_components/traffic-price-config"), + () => + import( + "~/app/[local]/(manage)/admin/config/_components/traffic-price-config" + ), { ssr: false, loading: TrafficPriceSkeleton, diff --git a/src/lib/constants/index.ts b/src/lib/constants/index.ts index 51b9a6e..12743f5 100644 --- a/src/lib/constants/index.ts +++ b/src/lib/constants/index.ts @@ -5,6 +5,8 @@ import { XSquareIcon, } from "lucide-react"; +export const locales = ["en", "zh"] as const; + export const Regexps = { ipv4: /^([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/, ipv6: /(^(?:(?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$)|(^\[(?:(?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))]$)/i, diff --git a/src/lib/constants/menu.ts b/src/lib/constants/menu.ts index 9efb983..b373acd 100644 --- a/src/lib/constants/menu.ts +++ b/src/lib/constants/menu.ts @@ -17,55 +17,55 @@ import { env } from "~/env"; const menus: Menu[] = [ { - title: "控制台", + title: "dashboard", href: "/dashboard", icon: LayoutDashboardIcon, }, { - title: "转发", + title: "forward", href: "/forward", icon: OrbitIcon, }, { - title: "服务器", + title: "agent", href: "/agent", icon: ServerIcon, }, { - title: "组网", + title: "network", href: "/network", icon: NetworkIcon, }, { - title: "工单", + title: "ticket", href: "/ticket", icon: TicketIcon, }, { - title: "管理", + title: "manage", children: [ { - title: "用户", + title: "users", href: "/admin/users", icon: UserIcon, }, { - title: "统计", + title: "statistics", href: env.NEXT_PUBLIC_UMAMI_URL ?? "/not-found", icon: LineChartIcon, }, ], }, { - title: "系统", + title: "system", children: [ { - title: "日志", + title: "log", href: "/admin/log", icon: LibraryBigIcon, }, { - title: "配置", + title: "config", href: "/admin/config", icon: Settings2Icon, }, diff --git a/src/lib/messages/en.json b/src/lib/messages/en.json new file mode 100644 index 0000000..04a23fd --- /dev/null +++ b/src/lib/messages/en.json @@ -0,0 +1,9 @@ +{ + "locale-switcher": { + "label": "Change language", + "locale": "{locale, select, zh {🇨🇳 Chinese} en {🇺🇸 English} other {Unknown}}" + }, + "index": { + "Welcome": "Welcome" + } +} diff --git a/src/lib/messages/zh.json b/src/lib/messages/zh.json new file mode 100644 index 0000000..dff5f37 --- /dev/null +++ b/src/lib/messages/zh.json @@ -0,0 +1,9 @@ +{ + "locale-switcher": { + "label": "选择语言", + "locale": "{locale, select, zh {🇨🇳 中文} en {🇺🇸 English} other {Unknown}}" + }, + "index": { + "Welcome": "欢迎" + } +} diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..85850b2 --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,14 @@ +import createMiddleware from "next-intl/middleware"; + +export default createMiddleware({ + // A list of all locales that are supported + locales: ["en", "zh"], + + // Used when no locale matches + defaultLocale: "en", +}); + +export const config = { + // Match only internationalized pathnames + matcher: ["/", "/((?!api|_next|_vercel|.*\\..*).*)", "/(zh|en)/:path*"], +}; diff --git a/src/navigation.ts b/src/navigation.ts new file mode 100644 index 0000000..94cbebb --- /dev/null +++ b/src/navigation.ts @@ -0,0 +1,7 @@ +import { createSharedPathnamesNavigation } from "next-intl/navigation"; +import { locales } from "~/lib/constants"; + +export const localePrefix = "as-needed"; + +export const { Link, redirect, usePathname, useRouter } = + createSharedPathnamesNavigation({ locales, localePrefix }); diff --git a/src/server/logger.ts b/src/server/logger.ts index 1c0531d..b7bece0 100644 --- a/src/server/logger.ts +++ b/src/server/logger.ts @@ -3,19 +3,13 @@ import pino, { type Logger } from "pino"; import "pino-abstract-transport"; const targets = []; -targets.push({ - target: path.join(process.cwd(), "./src/lib/pino-prisma.mjs"), - options: {}, - level: "trace", -}); + if (process.env.NODE_ENV === "production") { - // targets.push({ - // target: 'pino/file', - // options: { - // destination: path.join(process.cwd(), './app.log'), - // }, - // level: 'trace', - // }) + targets.push({ + target: path.join(process.cwd(), "./src/lib/pino-prisma.mjs"), + options: {}, + level: "trace", + }); } else { targets.push({ target: "pino-pretty",