Browse Source

Improving the translatability of project texts

BrettonYe 1 year ago
parent
commit
7087faf0d6
100 changed files with 3213 additions and 3392 deletions
  1. 1 1
      .env.example
  2. 1 1
      app/Channels/BarkChannel.php
  3. 4 4
      app/Channels/DingTalkChannel.php
  4. 32 32
      app/Channels/Library/WeChat.php
  5. 2 2
      app/Channels/PushDeerChannel.php
  6. 2 2
      app/Channels/PushPlusChannel.php
  7. 4 4
      app/Channels/ServerChanChannel.php
  8. 2 2
      app/Channels/TgChatChannel.php
  9. 6 6
      app/Channels/WeChatChannel.php
  10. 3 14
      app/Channels/iYuuChannel.php
  11. 1 1
      app/Console/Commands/AutoClearLogs.php
  12. 3 3
      app/Console/Commands/NodeStatusDetection.php
  13. 6 7
      app/Console/Commands/PanelUpdate.php
  14. 2 2
      app/Console/Commands/TaskDaily.php
  15. 1 1
      app/Console/Commands/TaskMonthly.php
  16. 4 4
      app/Http/Controllers/Admin/AffiliateController.php
  17. 10 10
      app/Http/Controllers/Admin/ArticleController.php
  18. 8 8
      app/Http/Controllers/Admin/CertController.php
  19. 9 9
      app/Http/Controllers/Admin/Config/CategoryController.php
  20. 11 11
      app/Http/Controllers/Admin/Config/CountryController.php
  21. 8 8
      app/Http/Controllers/Admin/Config/EmailFilterController.php
  22. 7 7
      app/Http/Controllers/Admin/Config/LabelController.php
  23. 9 9
      app/Http/Controllers/Admin/Config/LevelController.php
  24. 10 8
      app/Http/Controllers/Admin/Config/SsConfigController.php
  25. 34 35
      app/Http/Controllers/Admin/CouponController.php
  26. 3 4
      app/Http/Controllers/Admin/LogsController.php
  27. 1 2
      app/Http/Controllers/Admin/MarketingController.php
  28. 12 7
      app/Http/Controllers/Admin/NodeAuthController.php
  29. 18 19
      app/Http/Controllers/Admin/NodeController.php
  30. 12 7
      app/Http/Controllers/Admin/PermissionController.php
  31. 11 8
      app/Http/Controllers/Admin/RoleController.php
  32. 17 10
      app/Http/Controllers/Admin/RuleController.php
  33. 12 7
      app/Http/Controllers/Admin/RuleGroupController.php
  34. 13 13
      app/Http/Controllers/Admin/ShopController.php
  35. 1 1
      app/Http/Controllers/Admin/SubscribeController.php
  36. 10 8
      app/Http/Controllers/Admin/TicketController.php
  37. 17 16
      app/Http/Controllers/Admin/ToolsController.php
  38. 32 29
      app/Http/Controllers/Admin/UserController.php
  39. 13 8
      app/Http/Controllers/Admin/UserGroupController.php
  40. 16 17
      app/Http/Controllers/AdminController.php
  41. 2 2
      app/Http/Controllers/Api/Client/ClientController.php
  42. 23 41
      app/Http/Controllers/AuthController.php
  43. 3 1
      app/Http/Controllers/MessageController.php
  44. 6 6
      app/Http/Controllers/OAuthController.php
  45. 40 42
      app/Http/Controllers/PaymentController.php
  46. 78 90
      app/Http/Controllers/TelegramController.php
  47. 6 6
      app/Http/Controllers/User/AffiliateController.php
  48. 22 26
      app/Http/Controllers/UserController.php
  49. 4 4
      app/Models/Marketing.php
  50. 1 1
      app/Models/Order.php
  51. 1 1
      app/Models/ReferralLog.php
  52. 1 1
      app/Notifications/Custom.php
  53. 2 2
      app/Notifications/NodeOffline.php
  54. 8 7
      app/Notifications/PaymentConfirm.php
  55. 1 1
      app/Notifications/TicketClosed.php
  56. 2 2
      app/Notifications/TicketCreated.php
  57. 2 2
      app/Notifications/TicketReplied.php
  58. 2 2
      app/Observers/OrderObserver.php
  59. 1 2
      app/Services/ArticleService.php
  60. 4 4
      app/Services/CouponService.php
  61. 3 3
      app/Services/OrderService.php
  62. 1 1
      app/Utils/Clients/Surge.php
  63. 1 1
      app/Utils/Payments/CodePay.php
  64. 1 1
      app/Utils/Payments/EPay.php
  65. 1 1
      app/Utils/Payments/F2Fpay.php
  66. 2 2
      app/Utils/Payments/Local.php
  67. 2 2
      app/Utils/Payments/Manual.php
  68. 3 3
      app/Utils/Payments/PayBeaver.php
  69. 1 1
      app/Utils/Payments/PayJs.php
  70. 2 2
      app/Utils/Payments/PayPal.php
  71. 5 5
      app/Utils/Payments/Stripe.php
  72. 2 2
      app/Utils/Payments/THeadPay.php
  73. 12 1
      resources/lang/de.json
  74. 363 494
      resources/lang/de/admin.php
  75. 1 12
      resources/lang/de/auth.php
  76. 97 89
      resources/lang/de/common.php
  77. 13 13
      resources/lang/de/errors.php
  78. 151 150
      resources/lang/de/model.php
  79. 33 19
      resources/lang/de/notification.php
  80. 10 0
      resources/lang/de/setup.php
  81. 185 146
      resources/lang/de/user.php
  82. 12 1
      resources/lang/en.json
  83. 363 494
      resources/lang/en/admin.php
  84. 1 12
      resources/lang/en/auth.php
  85. 97 89
      resources/lang/en/common.php
  86. 13 13
      resources/lang/en/errors.php
  87. 151 150
      resources/lang/en/model.php
  88. 33 19
      resources/lang/en/notification.php
  89. 10 0
      resources/lang/en/setup.php
  90. 189 150
      resources/lang/en/user.php
  91. 12 1
      resources/lang/fa.json
  92. 363 494
      resources/lang/fa/admin.php
  93. 1 12
      resources/lang/fa/auth.php
  94. 97 89
      resources/lang/fa/common.php
  95. 13 13
      resources/lang/fa/errors.php
  96. 152 151
      resources/lang/fa/model.php
  97. 33 19
      resources/lang/fa/notification.php
  98. 10 0
      resources/lang/fa/setup.php
  99. 185 146
      resources/lang/fa/user.php
  100. 12 1
      resources/lang/ja.json

+ 1 - 1
.env.example

@@ -1,5 +1,5 @@
 APP_NAME=ProxyPanel
-APP_ENV=production
+APP_ENV=local
 APP_KEY=
 APP_DEBUG=
 APP_DEMO=

+ 1 - 1
app/Channels/BarkChannel.php

@@ -42,7 +42,7 @@ class BarkChannel
             return false;
         }
         // 发送错误
-        Log::critical('[Bark] 消息推送异常:'.var_export($response, true));
+        Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.bark'), 'reason' => var_export($response, true)]));
 
         return false;
     }

+ 4 - 4
app/Channels/DingTalkChannel.php

@@ -22,7 +22,7 @@ class DingTalkChannel
         }
 
         if (Cache::get($cacheKey) > 20) { // 每个机器人每分钟最多发送20条消息到群里,如果超过20条,会限流10分钟。
-            Log::critical('[钉钉] 消息推送异常:每个机器人每分钟最多发送20条消息到群里,如果超过20条,会限流10分钟。');
+            Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.dingtalk'), 'reason' => trans('notification.ding_bot_limit')]));
 
             return false;
         }
@@ -65,7 +65,7 @@ class DingTalkChannel
                 'msgtype' => 'link',
                 'link' => [
                     'title' => $message['title'],
-                    'text' => '请点击下方按钮【查看详情】',
+                    'text' => trans('notification.details_btn'),
                     'messageUrl' => route('message.show', ['type' => $message['url_type'], $msgId]),
                 ],
             ];
@@ -89,12 +89,12 @@ class DingTalkChannel
                 return $ret;
             }
             // 发送失败
-            Helpers::addNotificationLog($message['title'], $message['content'] ?? var_export($message['body'], true), 10, -1, $ret ? $ret['errmsg'] : '未知');
+            Helpers::addNotificationLog($message['title'], $message['content'] ?? var_export($message['body'], true), 10, -1, $ret ? $ret['errmsg'] : trans('common.status.unknown'));
 
             return false;
         }
         // 发送错误
-        Log::critical('[钉钉] 消息推送异常:'.var_export($response, true));
+        Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.dingtalk'), 'reason' => var_export($response, true)]));
 
         return false;
     }

+ 32 - 32
app/Channels/Library/WeChat.php

@@ -41,6 +41,34 @@ class WeChat
         return 0;
     }
 
+    public function prpcrypt_encrypt(string $data): array
+    {
+        try {
+            //拼接
+            $data = Str::random().pack('N', strlen($data)).$data.sysConfig('wechat_cid');
+            //添加PKCS#7填充
+            $data = $this->pkcs7_encode($data);
+            //加密
+            $encrypted = openssl_encrypt($data, 'AES-256-CBC', $this->key, OPENSSL_ZERO_PADDING, $this->iv);
+
+            return [0, $encrypted];
+        } catch (Exception $e) {
+            Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.wechat'), 'reason' => var_export($e->getMessage(), true)]));
+
+            return [-40006, null]; // EncryptAESError
+        }
+    }
+
+    public function pkcs7_encode(string $data): string
+    {// 对需要加密的明文进行填充补位
+        //计算需要填充的位数
+        $padding = 32 - (strlen($data) % 32);
+        $padding = ($padding === 0) ? 32 : $padding;
+        $pattern = chr($padding);
+
+        return $data.str_repeat($pattern, $padding); // 获得补位所用的字符
+    }
+
     public function getSHA1(string $timestamp, string $nonce, string $encryptMsg): array
     {
         $data = [$encryptMsg, sysConfig('wechat_token'), $timestamp, $nonce];
@@ -102,7 +130,7 @@ XML;
 
             return [0, $encrypt];
         } catch (Exception $e) {
-            Log::critical('企业微信消息推送异常:'.var_export($e->getMessage(), true));
+            Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.wechat'), 'reason' => var_export($e->getMessage(), true)]));
 
             return [-40002, null]; // ParseXmlError
         }
@@ -128,7 +156,7 @@ XML;
         $signature = $array[1];
 
         if ($sMsgSignature !== $signature) {
-            Log::critical('企业微信消息推送异常:安全签名验证失败');
+            Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.wechat'), 'reason' => trans('notification.sign_failed')]));
 
             return -40004; // ValidateSignatureError
         }
@@ -136,41 +164,13 @@ XML;
         $sMsg = $encrypt;
     }
 
-    public function prpcrypt_encrypt(string $data): array
-    {
-        try {
-            //拼接
-            $data = Str::random().pack('N', strlen($data)).$data.sysConfig('wechat_cid');
-            //添加PKCS#7填充
-            $data = $this->pkcs7_encode($data);
-            //加密
-            $encrypted = openssl_encrypt($data, 'AES-256-CBC', $this->key, OPENSSL_ZERO_PADDING, $this->iv);
-
-            return [0, $encrypted];
-        } catch (Exception $e) {
-            Log::critical('企业微信消息推送异常:'.var_export($e->getMessage(), true));
-
-            return [-40006, null]; // EncryptAESError
-        }
-    }
-
-    public function pkcs7_encode(string $data): string
-    {// 对需要加密的明文进行填充补位
-        //计算需要填充的位数
-        $padding = 32 - (strlen($data) % 32);
-        $padding = ($padding === 0) ? 32 : $padding;
-        $pattern = chr($padding);
-
-        return $data.str_repeat($pattern, $padding); // 获得补位所用的字符
-    }
-
     public function prpcrypt_decrypt(string $encrypted): array
     {
         try {
             //解密
             $decrypted = openssl_decrypt($encrypted, 'AES-256-CBC', $this->key, OPENSSL_ZERO_PADDING, $this->iv);
         } catch (Exception $e) {
-            Log::critical('企业微信消息推送异常:'.var_export($e->getMessage(), true));
+            Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.wechat'), 'reason' => var_export($e->getMessage(), true)]));
 
             return [-40007, null]; // DecryptAESError
         }
@@ -188,7 +188,7 @@ XML;
             $from_receiveId = substr($content, $xml_len + 4);
         } catch (Exception $e) {
             // 发送错误
-            Log::critical('企业微信消息推送异常:'.var_export($e->getMessage(), true));
+            Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.wechat'), 'reason' => var_export($e->getMessage(), true)]));
 
             return [-40008, null]; // IllegalBuffer
         }

+ 2 - 2
app/Channels/PushDeerChannel.php

@@ -26,12 +26,12 @@ class PushDeerChannel
                 return $ret;
             }
             // 发送失败
-            Helpers::addNotificationLog($message['title'], $message['content'], 9, -1, $ret ? $ret['error'] : '未知');
+            Helpers::addNotificationLog($message['title'], $message['content'], 9, -1, $ret ? $ret['error'] : trans('common.status.unknown'));
 
             return false;
         }
         // 发送错误
-        Log::critical('[PushDeer] 消息推送异常:'.var_export($response, true));
+        Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.pushdeer'), 'reason' => var_export($response, true)]));
 
         return false;
     }

+ 2 - 2
app/Channels/PushPlusChannel.php

@@ -30,12 +30,12 @@ class PushPlusChannel
                 return $ret;
             }
             // 发送失败
-            Helpers::addNotificationLog($message['title'], $message['content'], 7, -1, $ret ? $ret['msg'] : '未知');
+            Helpers::addNotificationLog($message['title'], $message['content'], 7, -1, $ret ? $ret['msg'] : trans('common.status.unknown'));
 
             return false;
         }
         // 发送错误
-        Log::critical('[PushPlus] 消息推送异常:'.var_export($response, true));
+        Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.pushplus'), 'reason' => var_export($response, true)]));
 
         return false;
     }

+ 4 - 4
app/Channels/ServerChanChannel.php

@@ -33,12 +33,12 @@ class ServerChanChannel
                 $response = Http::timeout(15)
                     ->post('https://sctapi.ftqq.com/'.sysConfig('server_chan_key').'.send?title='.urlencode($message['title']).'&desp='.urlencode($message['content']));
             } else {
-                Log::critical('[ServerChan] 消息推送异常:分钟频率过高,请优化通知场景!');
+                Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.serverchan'), 'reason' => trans('notification.serverChan_limit')]));
 
                 return false;
             }
         } else {
-            Log::critical('[ServerChan] 消息推送异常:今日限额已耗尽!');
+            Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.serverchan'), 'reason' => trans('notification.serverChan_exhausted')]));
 
             return false;
         }
@@ -52,12 +52,12 @@ class ServerChanChannel
                 return $ret;
             }
             // 发送失败
-            Helpers::addNotificationLog($message['title'], $message['content'], 2, -1, $ret ? $ret['errmsg'] : '未知');
+            Helpers::addNotificationLog($message['title'], $message['content'], 2, -1, $ret ? $ret['errmsg'] : trans('common.status.unknown'));
 
             return false;
         }
         // 发送错误
-        Log::critical('[ServerChan] 消息推送异常:'.var_export($response, true));
+        Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.serverchan'), 'reason' => var_export($response, true)]));
 
         return false;
     }

+ 2 - 2
app/Channels/TgChatChannel.php

@@ -24,12 +24,12 @@ class TgChatChannel
                 return $ret;
             }
             // 发送失败
-            Helpers::addNotificationLog($message['title'], $message['content'], 6, -1, $ret ? $ret['message'] : '未知');
+            Helpers::addNotificationLog($message['title'], $message['content'], 6, -1, $ret ? $ret['message'] : trans('common.status.unknown'));
 
             return false;
         }
         // 发送错误
-        Log::critical('[TG酱] 消息推送异常:'.var_export($response, true));
+        Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.tg_chat'), 'reason' => var_export($response, true)]));
 
         return false;
     }

+ 6 - 6
app/Channels/WeChatChannel.php

@@ -54,9 +54,9 @@ class WeChatChannel
                 'msgtype' => 'textcard',
                 'textcard' => [
                     'title' => $message['title'],
-                    'description' => '请点击下方按钮【查看详情】',
+                    'description' => trans('notification.details_btn'),
                     'url' => route('message.show', ['type' => $message['url_type'], $msgId]),
-                    'btntxt' => '查看详情',
+                    'btntxt' => trans('notification.details'),
                 ],
             ];
         } else { // 文本消息
@@ -82,9 +82,9 @@ class WeChatChannel
                 return $ret;
             }
             // 发送失败
-            Helpers::addNotificationLog($message['title'], $message['content'] ?? var_export($message['body'], true), 5, -1, $ret ? $ret['errmsg'] : '未知');
+            Helpers::addNotificationLog($message['title'], $message['content'] ?? var_export($message['body'], true), 5, -1, $ret ? $ret['errmsg'] : trans('common.status.unknown'));
         } else {
-            Log::critical('[企业微信] 消息推送异常:'.var_export($response, true)); // 发送错误
+            Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.wechat'), 'reason' => var_export($response, true)]));
         }
 
         return false;
@@ -101,7 +101,7 @@ class WeChatChannel
                 $access_token = $response->json()['access_token'];
                 Cache::put('wechat_access_token', $access_token, 7189); // 2小时
             } else {
-                Log::critical('[企业微信] 消息推送异常:获取access_token失败!'.PHP_EOL.'携带访问参数:'.$response->body());
+                Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.wechat'), 'reason' => trans('notification.get_access_token_failed', ['body' => $response->body()])]));
                 abort(400);
             }
         }
@@ -116,6 +116,6 @@ class WeChatChannel
             exit($sEchoStr);
         }
 
-        Log::critical('[企业微信] 互动消息推送异常:'.var_export($errCode, true));
+        Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.wechat'), 'reason' => trans('notification.sign_failed')]).var_export($errCode, true));
     }
 }

+ 3 - 14
app/Channels/iYuuChannel.php

@@ -9,22 +9,11 @@ use Log;
 
 class iYuuChannel
 {
-    private ?string $token;
-
-    public function __construct()
-    {
-        $this->token = sysConfig('iYuu_token');
-
-        if ($this->token) {
-            Log::critical('[爱语飞飞] TOKEN 为空');
-        }
-    }
-
     public function send($notifiable, Notification $notification)
     {
         $message = $notification->toCustom($notifiable);
 
-        $response = Http::timeout(15)->post('https://iyuu.cn/'.$this->token.'.send?title='.urlencode($message['title']).'&desp='.urlencode($message['content']));
+        $response = Http::timeout(15)->post('https://iyuu.cn/'.sysConfig('iYuu_token').'.send?title='.urlencode($message['title']).'&desp='.urlencode($message['content']));
 
         // 发送成功
         if ($response->ok()) {
@@ -35,12 +24,12 @@ class iYuuChannel
                 return $ret;
             }
             // 发送失败
-            Helpers::addNotificationLog($message['title'], $message['content'], 8, -1, $ret ? $ret['errmsg'] : '未知');
+            Helpers::addNotificationLog($message['title'], $message['content'], 8, -1, $ret ? $ret['errmsg'] : trans('common.status.unknown'));
 
             return false;
         }
         // 发送错误
-        Log::critical('[爱语飞飞] 消息推送异常:'.var_export($response, true));
+        Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.iyuu'), 'reason' => var_export($response, true)]));
 
         return false;
     }

+ 1 - 1
app/Console/Commands/AutoClearLogs.php

@@ -61,7 +61,7 @@ class AutoClearLogs extends Command
 
             UserDataFlowLog::where('log_time', '<=', strtotime(config('tasks.clean.traffic_logs')))->delete(); // 清除用户流量日志
         } catch (Exception $e) {
-            Log::emergency('【清理日志】错误: '.$e->getMessage());
+            Log::emergency(trans('common.error_item', ['attribute' => trans('admin.system.is_clear_log')]).': '.$e->getMessage());
         }
     }
 }

+ 3 - 3
app/Console/Commands/NodeStatusDetection.php

@@ -33,7 +33,7 @@ class NodeStatusDetection extends Command
             if (! $lastCheckTime || $lastCheckTime <= time()) {
                 $this->checkNodeNetwork();
             } else {
-                Log::info('下次节点阻断检测时间:'.date('Y-m-d H:i:s', $lastCheckTime));
+                Log::info(trans('notification.next_check_time', ['time' => date('Y-m-d H:i:s', $lastCheckTime)]));
             }
         }
 
@@ -110,7 +110,7 @@ class NodeStatusDetection extends Command
                 if ($times > $detectionCheckTimes) {
                     Cache::forget($cacheKey);
                     $node->update(['status' => 0]);
-                    $data[$node_id]['message'] = '自动进入维护状态';
+                    $data[$node_id]['message'] = trans('notification.into_maintenance');
                 }
             }
 
@@ -122,7 +122,7 @@ class NodeStatusDetection extends Command
         if (! empty($data)) { //只有在出现阻断线路时,才会发出警报
             Notification::send(User::find(1), new NodeBlocked($data));
 
-            Log::notice("节点状态日志: \r\n".var_export($data, true));
+            Log::notice(trans('notification.node_block').": \r\n".var_export($data, true));
         }
 
         Cache::put('LastCheckTime', time() + random_int(3000, Hour), 3700); // 随机生成下次检测时间

+ 6 - 7
app/Console/Commands/PanelUpdate.php

@@ -17,14 +17,13 @@ class PanelUpdate extends Command
         $bar->minSecondsBetweenRedraws(0);
         $this->displayBanner();
         $bar->start();
-
         $this->updateDatabase();
-        $bar->advance();
 
+        $bar->advance();
         $this->updateCache();
-        $bar->finish();
 
-        $this->info(' 更新完毕! ');
+        $bar->finish();
+        $this->info(trans('setup.update_complete'));
     }
 
     private function displayBanner(): void
@@ -44,17 +43,17 @@ BANNER;
 
     private function updateDatabase(): void
     {
-        $this->line('更新数据库...');
+        $this->line(trans('setup.update_db'));
         Artisan::call('migrate --force');
 
-        if (config('app.env') === 'demo' && $this->confirm('检测到您在DEMO模式, 是否重置数据库?')) {
+        if (config('app.env') === 'demo' && $this->confirm(trans('setup.demo_reset'))) {
             Artisan::call('migrate:fresh --seed --force');
         }
     }
 
     private function updateCache(): void
     {
-        $this->line('更新缓存...');
+        $this->line(trans('setup.update_cache'));
         Artisan::call('optimize');
     }
 }

+ 2 - 2
app/Console/Commands/TaskDaily.php

@@ -100,9 +100,9 @@ class TaskDaily extends Command
                 $oldData = $user->transfer_enable;
                 // 重置流量与重置日期
                 if ($user->update((new OrderService($order))->resetTimeAndData($user->expired_at))) {
-                    Helpers::addUserTrafficModifyLog($order->user_id, $oldData, $user->transfer_enable, __('[Daily Task] Reset Account Traffic, Next Reset Date: :date', ['date' => $user->reset_date]), $order->id);
+                    Helpers::addUserTrafficModifyLog($order->user_id, $oldData, $user->transfer_enable, trans('[Daily Task] Reset Account Traffic, Next Reset Date: :date', ['date' => $user->reset_date]), $order->id);
                 } else {
-                    Log::error("[每日任务]用户ID: $user->id | 邮箱: $user->username 流量重置失败");
+                    Log::error(trans('notification.reset_failed', ['uid' => $user->id, 'username' => $user->username]));
                 }
             });
         });

+ 1 - 1
app/Console/Commands/TaskMonthly.php

@@ -52,7 +52,7 @@ class TaskMonthly extends Command
 
             Order::whereStatus(-1)->where('created_at', '<=', date('Y-m-d H:i:s', strtotime(config('tasks.clean.unpaid_orders'))))->delete(); // 清理用户未支付订单
         } catch (Exception $e) {
-            Log::emergency('【清理日志】错误: '.$e->getMessage());
+            Log::emergency(trans('common.error_item', ['attribute' => trans('admin.system.is_clear_log')]).': '.$e->getMessage());
         }
     }
 }

+ 4 - 4
app/Http/Controllers/Admin/AffiliateController.php

@@ -42,17 +42,17 @@ class AffiliateController extends Controller
         $status = (int) $request->input('status');
 
         if ($aff->update(['status' => $status])) {
-            // 审核申请的时候将关联的
+            // 将关联的返现单更新状态
             if ($status === 1 || $status === 2) {
                 if ($aff->referral_logs()->update(['status' => $status])) {
-                    return response()->json(['status' => 'success', 'message' => '操作成功']);
+                    return response()->json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.action')])]);
                 }
             }
 
-            return response()->json(['status' => 'success', 'message' => '操作成功']);
+            return response()->json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.action')])]);
         }
 
-        return response()->json(['status' => 'fail', 'message' => '操作失败']);
+        return response()->json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.action')])]);
     }
 
     // 用户返利流水记录

+ 10 - 10
app/Http/Controllers/Admin/ArticleController.php

@@ -42,21 +42,21 @@ class ArticleController extends Controller
             if ($data['type'] !== '4' && $request->hasFile('logo')) {
                 $path = $this->fileUpload($request->file('logo'));
                 if ($path === false) {
-                    return redirect()->back()->withInput()->withErrors('Logo存储失败');
+                    return redirect()->back()->withInput()->withErrors(trans('common.failed_action_item', ['action' => trans('common.store'), 'attribute' => trans('model.article.logo')]));
                 }
                 $data['logo'] = $path;
             }
 
             if ($article = Article::create($data)) {
-                return redirect(route('admin.article.edit', $article))->with('successMsg', '添加成功');
+                return redirect(route('admin.article.edit', $article))->with('successMsg', trans('common.success_item', ['attribute' => trans('common.add')]));
             }
         } catch (Exception $e) {
-            Log::error('添加文章错误:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.add'), 'attribute' => trans('model.article.attribute')]).': '.$e->getMessage());
 
             return redirect()->back()->withInput()->withErrors($e->getMessage());
         }
 
-        return redirect()->back()->withInput()->withErrors('添加失败');
+        return redirect()->back()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.add')]));
     }
 
     public function fileUpload(UploadedFile $file): string|bool
@@ -98,7 +98,7 @@ class ArticleController extends Controller
         if ($data['type'] !== '4' && $request->hasFile('logo')) {
             $path = $this->fileUpload($request->file('logo'));
             if ($path === false) {
-                return redirect()->back()->withInput()->withErrors('Logo存储失败');
+                return redirect()->back()->withInput()->withErrors(trans('common.failed_action_item', ['action' => trans('common.store'), 'attribute' => trans('model.article.logo')]));
             }
             $data['logo'] = $path;
         } elseif (! $request->has('logo')) {
@@ -106,10 +106,10 @@ class ArticleController extends Controller
         }
 
         if ($article->update($data)) {
-            return redirect()->back()->with('successMsg', '编辑成功');
+            return redirect()->back()->with('successMsg', trans('common.success_item', ['attribute' => trans('common.edit')]));
         }
 
-        return redirect()->back()->withInput()->withErrors('编辑失败');
+        return redirect()->back()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.edit')]));
     }
 
     public function destroy(Article $article): JsonResponse
@@ -118,11 +118,11 @@ class ArticleController extends Controller
         try {
             $article->delete();
         } catch (Exception $e) {
-            Log::error('删除文章失败:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('model.article.attribute')]).', '.$e->getMessage());
 
-            return response()->json(['status' => 'fail', 'message' => '删除失败:'.$e->getMessage()]);
+            return response()->json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return response()->json(['status' => 'success', 'message' => '删除成功']);
+        return response()->json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
     }
 }

+ 8 - 8
app/Http/Controllers/Admin/CertController.php

@@ -32,10 +32,10 @@ class CertController extends Controller
     public function store(CertRequest $request)
     {
         if ($cert = NodeCertificate::create($request->validated())) {
-            return redirect(route('admin.node.cert.edit', $cert))->with('successMsg', trans('common.generate_item', ['attribute' => trans('common.success')]));
+            return redirect(route('admin.node.cert.edit', $cert))->with('successMsg', trans('common.success_item', ['attribute' => trans('common.add')]));
         }
 
-        return redirect()->back()->withInput()->withErrors('生成失败');
+        return redirect()->back()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.add')]));
     }
 
     public function create()
@@ -51,24 +51,24 @@ class CertController extends Controller
     public function update(CertRequest $request, NodeCertificate $cert): RedirectResponse
     {
         if ($cert->update($request->validated())) {
-            return redirect()->back()->with('successMsg', trans('common.update_action', ['action' => trans('common.success')]));
+            return redirect()->back()->with('successMsg', trans('common.success_item', ['attribute' => trans('common.edit')]));
         }
 
-        return redirect()->back()->withInput()->withErrors(trans('common.update_action', ['action' => trans('common.failed')]));
+        return redirect()->back()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.edit')]));
     }
 
     public function destroy(NodeCertificate $cert): JsonResponse
     {
         try {
             if ($cert->delete()) {
-                return response()->json(['status' => 'success', 'message' => '删除成功']);
+                return response()->json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
             }
         } catch (Exception $e) {
-            Log::error('删除域名证书失败:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('model.node_cert.attribute')]).': '.$e->getMessage());
 
-            return response()->json(['status' => 'fail', 'message' => '删除错误:'.$e->getMessage()]);
+            return response()->json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return response()->json(['status' => 'fail', 'message' => '删除失败']);
+        return response()->json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 }

+ 9 - 9
app/Http/Controllers/Admin/Config/CategoryController.php

@@ -23,10 +23,10 @@ class CategoryController extends Controller
         }
 
         if (GoodsCategory::create($validator->validated())) {
-            return Response::json(['status' => 'success', 'message' => '提交成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.add')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '操作失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.add')])]);
     }
 
     // 编辑等级
@@ -41,10 +41,10 @@ class CategoryController extends Controller
             return Response::json(['status' => 'fail', 'message' => $validator->errors()->all()]);
         }
         if ($category->update($validator->validated())) {
-            return Response::json(['status' => 'success', 'message' => '操作成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.edit')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '操作失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.edit')])]);
     }
 
     // 删除等级
@@ -52,19 +52,19 @@ class CategoryController extends Controller
     {
         // 校验该等级下是否存在关联账号
         if ($category->goods()->exists()) {
-            return Response::json(['status' => 'fail', 'message' => '该分类下存在关联账号,请先取消关联']);
+            return Response::json(['status' => 'fail', 'message' => trans('common.exists_error', ['attribute' => trans('model.goods.category')])]);
         }
 
         try {
             if ($category->delete()) {
-                return Response::json(['status' => 'success', 'message' => '删除成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
             }
         } catch (Exception $e) {
-            Log::error('删除时报错:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('model.common.level')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => '删除失败:'.$e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '删除失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 }

+ 11 - 11
app/Http/Controllers/Admin/Config/CountryController.php

@@ -26,10 +26,10 @@ class CountryController extends Controller
         }
 
         if (Country::create($validator->validated())) {
-            return Response::json(['status' => 'success', 'message' => trans('common.generate_item', ['attribute' => trans('common.success')])]);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.add')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '生成失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.add')])]);
     }
 
     // 编辑国家/地区
@@ -43,15 +43,15 @@ class CountryController extends Controller
 
         try {
             if ($country->update($validator->validated())) {
-                return Response::json(['status' => 'success', 'message' => '编辑成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.edit')])]);
             }
         } catch (Exception $e) {
-            Log::error('编辑国家/地区时失败:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.edit'), 'attribute' => trans('model.node.country')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => '编辑失败:'.$e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.edit')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '编辑失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.edit')])]);
     }
 
     // 删除国家/地区
@@ -59,19 +59,19 @@ class CountryController extends Controller
     {
         // 校验该国家/地区下是否存在关联节点
         if ($country->nodes()->exists()) {
-            return Response::json(['status' => 'fail', 'message' => '该国家/地区下存在关联节点,请先取消关联']);
+            return Response::json(['status' => 'fail', 'message' => trans('common.exists_error', ['attribute' => trans('model.node.country')])]);
         }
 
         try {
             if ($country->delete()) {
-                return Response::json(['status' => 'success', 'message' => '操作成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
             }
         } catch (Exception $e) {
-            Log::error('删除国家/地区失败:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('model.node.country')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => '删除失败:'.$e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '删除失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 }

+ 8 - 8
app/Http/Controllers/Admin/Config/EmailFilterController.php

@@ -33,15 +33,15 @@ class EmailFilterController extends Controller
 
         try {
             if (EmailFilter::create($validator->validated())) {
-                return Response::json(['status' => 'success', 'message' => '添加成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.add')])]);
             }
         } catch (Exception $e) {
-            Log::error('添加邮箱后缀时失败:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.add'), 'attribute' => trans('admin.setting.email.tail')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => '添加失败:'.$e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.add')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '添加失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.add')])]);
     }
 
     // 删除邮箱后缀
@@ -49,14 +49,14 @@ class EmailFilterController extends Controller
     {
         try {
             if ($filter->delete()) {
-                return Response::json(['status' => 'success', 'message' => '删除成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
             }
         } catch (Exception $e) {
-            Log::error('删除邮箱后缀失败:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('admin.setting.email.tail')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => '删除失败:'.$e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '删除失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 }

+ 7 - 7
app/Http/Controllers/Admin/Config/LabelController.php

@@ -26,10 +26,10 @@ class LabelController extends Controller
         }
 
         if (Label::create($validator->validated())) {
-            return Response::json(['status' => 'success', 'message' => '添加成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.add')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '添加失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.add')])]);
     }
 
     // 编辑标签
@@ -45,10 +45,10 @@ class LabelController extends Controller
         }
 
         if ($label->update($validator->validated())) {
-            return Response::json(['status' => 'success', 'message' => '编辑成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.edit')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '编辑失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.edit')])]);
     }
 
     // 删除标签
@@ -57,11 +57,11 @@ class LabelController extends Controller
         try {
             $label->delete();
 
-            return Response::json(['status' => 'success', 'message' => '删除成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
         } catch (Exception $e) {
-            Log::error('删除标签失败:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('model.node.label')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => '删除失败:'.$e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
     }
 }

+ 9 - 9
app/Http/Controllers/Admin/Config/LevelController.php

@@ -26,10 +26,10 @@ class LevelController extends Controller
         }
 
         if (Level::create($validator->validated())) {
-            return Response::json(['status' => 'success', 'message' => '提交成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.add')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '操作失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.add')])]);
     }
 
     // 编辑等级
@@ -45,10 +45,10 @@ class LevelController extends Controller
         }
 
         if ($level->update($validator->validated())) {
-            return Response::json(['status' => 'success', 'message' => '操作成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.edit')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '操作失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.edit')])]);
     }
 
     // 删除等级
@@ -56,19 +56,19 @@ class LevelController extends Controller
     {
         // 校验该等级下是否存在关联账号
         if ($level->users()->exists()) {
-            return Response::json(['status' => 'fail', 'message' => '该等级下存在关联账号,请先取消关联']);
+            return Response::json(['status' => 'fail', 'message' => trans('common.exists_error', ['attribute' => trans('model.common.level')])]);
         }
 
         try {
             if ($level->delete()) {
-                return Response::json(['status' => 'success', 'message' => '删除成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
             }
         } catch (Exception $e) {
-            Log::error('删除等级时报错:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('model.common.level')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => '删除失败:'.$e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '删除失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 }

+ 10 - 8
app/Http/Controllers/Admin/Config/SsConfigController.php

@@ -26,18 +26,20 @@ class SsConfigController extends Controller
         }
 
         if (SsConfig::create($validator->validated())) {
-            return Response::json(['status' => 'success', 'message' => '添加成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.add')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '添加失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.add')])]);
     }
 
     // 设置SS默认配置
     public function update(SsConfig $ss): JsonResponse
     {
-        $ss->setDefault();
+        if ($ss->setDefault()) {
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.edit')])]);
+        }
 
-        return Response::json(['status' => 'success', 'message' => '操作成功']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.edit')])]);
     }
 
     // 删除SS配置
@@ -45,14 +47,14 @@ class SsConfigController extends Controller
     {
         try {
             if ($ss->delete()) {
-                return Response::json(['status' => 'success', 'message' => '删除成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
             }
         } catch (Exception $e) {
-            Log::error('删除SS配置时失败:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('user.node.info')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => '删除失败:'.$e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '删除失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 }

+ 34 - 35
app/Http/Controllers/Admin/CouponController.php

@@ -58,7 +58,7 @@ class CouponController extends Controller
             $file = $request->file('logo');
             $fileName = Str::random(8).time().'.'.$file->getClientOriginalExtension();
             if (! $file->storeAs('public', $fileName)) {
-                return Redirect::back()->withInput()->withErrors('LOGO不合法');
+                return Redirect::back()->withInput()->withErrors(trans('common.failed_action_item', ['action' => trans('common.store'), 'attribute' => trans('model.coupon.logo')]));
             }
             $logo = 'upload/'.$fileName;
         }
@@ -95,11 +95,11 @@ class CouponController extends Controller
                 Coupon::create($data);
             }
 
-            return Redirect::route('admin.coupon.index')->with('successMsg', trans('common.generate_item', ['attribute' => trans('common.success')]));
+            return Redirect::route('admin.coupon.index')->with('successMsg', trans('common.success_item', ['attribute' => trans('common.generate')]));
         } catch (Exception $e) {
-            Log::error('生成优惠券失败:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.generate'), 'attribute' => trans('model.coupon.attribute')]).': '.$e->getMessage());
 
-            return Redirect::back()->withInput()->withInput()->withErrors('生成优惠券失败:'.$e->getMessage());
+            return Redirect::back()->withInput()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.generate')]).', '.$e->getMessage());
         }
     }
 
@@ -117,15 +117,15 @@ class CouponController extends Controller
     {
         try {
             if ($coupon->delete()) {
-                return Response::json(['status' => 'success', 'message' => '删除成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
             }
         } catch (Exception $e) {
-            Log::error('删除优惠券失败:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('model.coupon.attribute')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'success', 'message' => '删除优惠券失败:'.$e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '删除失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 
     // 导出卡券
@@ -133,37 +133,36 @@ class CouponController extends Controller
     {
         $couponList = Coupon::whereStatus(0)->get();
 
-        try {
-            $filename = '卡券_Coupon_'.date('Ymd').'.xlsx';
-            $spreadsheet = new Spreadsheet;
-            $spreadsheet->getProperties()
-                ->setCreator('ProxyPanel')
-                ->setLastModifiedBy('ProxyPanel')
-                ->setTitle('卡券')
-                ->setSubject('卡券');
-
-            $sheet = $spreadsheet->getActiveSheet();
-            $sheet->setTitle('卡券');
-            $sheet->fromArray([
-                trans('model.common.type'), trans('model.coupon.name'), trans('model.coupon.usable_times'), trans('common.available_date'), trans('common.expired_at'), trans('model.coupon.sn'), trans('admin.coupon.discount'),
-                trans('model.coupon.priority'), trans('model.rule.attribute'),
-            ]);
-
-            foreach ($couponList as $index => $coupon) {
-                $sheet->fromArray([
-                    [trans('common.status.unknown'), trans('admin.coupon.type.voucher'), trans('admin.coupon.type.discount'), trans('admin.coupon.type.charge')][$coupon->type], $coupon->name,
-                    $coupon->type === 3 ? trans('admin.coupon.single_use') : ($coupon->usable_times ?? trans('common.unlimited')), $coupon->start_time, $coupon->end_time, $coupon->sn,
-                    $coupon->type === 2 ? $coupon->value : Helpers::getPriceTag($coupon->value), $coupon->priority, json_encode($coupon->limit),
-                ], null, 'A'.($index + 2));
-            }
+        $filename = trans('model.coupon.attribute').'_'.date('Ymd').'.xlsx';
+        $spreadsheet = new Spreadsheet;
+        $spreadsheet->getProperties()
+            ->setCreator('ProxyPanel')
+            ->setLastModifiedBy('ProxyPanel')
+            ->setTitle(trans('model.coupon.attribute'))
+            ->setSubject(trans('model.coupon.attribute'));
+
+        $sheet = $spreadsheet->getActiveSheet();
+        $sheet->setTitle(trans('model.coupon.attribute'));
+        $sheet->fromArray([
+            trans('model.common.type'), trans('model.coupon.name'), trans('model.coupon.usable_times'), trans('common.available_date'), trans('common.expired_at'), trans('model.coupon.sn'), trans('admin.coupon.discount'),
+            trans('model.coupon.priority'), trans('model.rule.attribute'),
+        ]);
 
-            header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
-            header('Content-Disposition: attachment;filename="'.$filename.'"');
-            header('Cache-Control: max-age=0');
+        foreach ($couponList as $index => $coupon) {
+            $sheet->fromArray([
+                [trans('common.status.unknown'), trans('admin.coupon.type.voucher'), trans('admin.coupon.type.discount'), trans('admin.coupon.type.charge')][$coupon->type], $coupon->name,
+                $coupon->type === 3 ? trans('admin.coupon.single_use') : ($coupon->usable_times ?? trans('common.unlimited')), $coupon->start_time, $coupon->end_time, $coupon->sn,
+                $coupon->type === 2 ? $coupon->value : Helpers::getPriceTag($coupon->value), $coupon->priority, json_encode($coupon->limit),
+            ], null, 'A'.($index + 2));
+        }
+        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
+        header('Content-Disposition: attachment;filename="'.$filename.'"');
+        header('Cache-Control: max-age=0');
+        try {
             $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
             $writer->save('php://output');
         } catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
-            Log::error('导出优惠券时报错:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('admin.massive_export'), 'attribute' => trans('model.coupon.attribute')]).': '.$e->getMessage());
         }
     }
 }

+ 3 - 4
app/Http/Controllers/Admin/LogsController.php

@@ -72,14 +72,14 @@ class LogsController extends Controller
         $status = (int) $request->input('status');
 
         if ($order->status === 3 && $status === 2 && $order->goods->type === 2 && Order::userActivePlan($order->user_id)->exists()) {
-            return Response::json(['status' => 'fail', 'message' => '更新失败, 订单冲突']); // 防止预支付订单假激活
+            return Response::json(['status' => 'fail', 'message' => trans('admin.logs.order.update_conflict')]); // 防止预支付订单假激活
         }
 
         if ($order->update(['is_expire' => 0, 'expired_at' => null, 'status' => $status])) {
-            return Response::json(['status' => 'success', 'message' => '更新成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.update')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '更新失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.update')])]);
     }
 
     // 流量日志
@@ -254,7 +254,6 @@ class LogsController extends Controller
 
         $nodeOnlineIPs = NodeOnlineIp::with('node:id,name')->where('created_at', '>=', strtotime('-10 minutes'))->latest()->distinct()->get();
         foreach ($userList as $user) {
-            //Todo node_online_ip表 api可以用user_id
             // 最近5条在线IP记录,如果后端设置为60秒上报一次,则为10分钟内的在线IP
             $user->onlineIPList = $nodeOnlineIPs->where('port', $user->port)->take(5);
         }

+ 1 - 2
app/Http/Controllers/Admin/MarketingController.php

@@ -9,7 +9,6 @@ use App\Models\User;
 use App\Models\UserGroup;
 use App\Models\UserHourlyDataFlow;
 use App\Notifications\Custom;
-use Carbon;
 use Helpers;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
@@ -101,7 +100,7 @@ class MarketingController extends Controller
 
         // 最近N分钟活跃过
         $request->whenFilled('lastAlive', function ($value) use ($users) {
-            $users->where('t', '>=', Carbon::now()->subMinutes($value)->timestamp);
+            $users->where('t', '>=', now()->subMinutes($value)->timestamp);
         });
 
         $paidOrderCondition = function ($query) {

+ 12 - 7
app/Http/Controllers/Admin/NodeAuthController.php

@@ -7,6 +7,7 @@ use App\Models\Node;
 use App\Models\NodeAuth;
 use Exception;
 use Illuminate\Http\JsonResponse;
+use Log;
 use Response;
 use Str;
 
@@ -24,34 +25,38 @@ class NodeAuthController extends Controller
         $nodes = Node::whereStatus(1)->doesntHave('auth')->orderBy('id')->get();
 
         if ($nodes->isEmpty()) {
-            return Response::json(['status' => 'success', 'message' => '没有需要生成授权的节点']);
+            return Response::json(['status' => 'success', 'message' => trans('admin.node.auth.empty')]);
         }
         $nodes->each(function ($node) {
             $node->auth()->create(['key' => Str::random(), 'secret' => Str::random(8)]);
         });
 
-        return Response::json(['status' => 'success', 'message' => trans('common.generate_item', ['attribute' => trans('common.success')])]);
+        return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.generate')])]);
     }
 
     // 重置节点授权
     public function update(NodeAuth $auth): JsonResponse
     {
         if ($auth->update(['key' => Str::random(), 'secret' => Str::random(8)])) {
-            return Response::json(['status' => 'success', 'message' => '操作成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.reset')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '操作失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.reset')])]);
     }
 
     // 删除节点授权
     public function destroy(NodeAuth $auth): JsonResponse
     {
         try {
-            $auth->delete();
+            if ($auth->delete()) {
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
+            }
         } catch (Exception $e) {
-            return Response::json(['status' => 'fail', 'message' => '错误:'.var_export($e, true)]);
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('admin.menu.node.auth')]).': '.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('admin.menu.node.auth')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'success', 'message' => '操作成功']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 }

+ 18 - 19
app/Http/Controllers/Admin/NodeController.php

@@ -51,20 +51,19 @@ class NodeController extends Controller
     { // 添加节点
         try {
             if ($node = Node::create($this->nodeStore($request->validated()))) {
-                // 生成节点标签
-                if ($request->has('labels')) {
+                if ($request->has('labels')) { // 生成节点标签
                     $node->labels()->attach($request->input('labels'));
                 }
 
-                return Response::json(['status' => 'success', 'message' => '添加成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.add')])]);
             }
         } catch (Exception $e) {
-            Log::error('添加节点信息异常:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.add'), 'attribute' => trans('model.node.attribute')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => '添加线路失败:'.$e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.add')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '添加线路失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.add')])]);
     }
 
     public function create()
@@ -188,30 +187,30 @@ class NodeController extends Controller
                 // 更新节点标签
                 $node->labels()->sync($request->input('labels'));
 
-                return Response::json(['status' => 'success', 'message' => '编辑成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.edit')])]);
             }
         } catch (Exception $e) {
-            Log::error('编辑节点信息异常:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.edit'), 'attribute' => trans('model.node.attribute')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => '编辑失败:'.$e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.edit')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '编辑失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.edit')])]);
     }
 
     public function destroy(Node $node): JsonResponse
     { // 删除节点
         try {
             if ($node->delete()) {
-                return Response::json(['status' => 'success', 'message' => '删除成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
             }
         } catch (Exception $e) {
-            Log::error('删除线路失败:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('model.node.attribute')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => '删除线路失败:'.$e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '删除线路失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 
     public function checkNode(Node $node): JsonResponse
@@ -221,7 +220,7 @@ class NodeController extends Controller
             $data[$ip] = [config('common.network_status')[$status['icmp']], config('common.network_status')[$status['tcp']]];
         }
 
-        return Response::json(['status' => 'success', 'title' => '['.$node->name.']阻断信息', 'message' => $data ?? []]);
+        return Response::json(['status' => 'success', 'title' => '['.$node->name.'] '.trans('admin.node.connection_test'), 'message' => $data ?? []]);
     }
 
     public function refreshGeo($id): JsonResponse
@@ -239,10 +238,10 @@ class NodeController extends Controller
         }
 
         if ($ret) {
-            return Response::json(['status' => 'success', 'message' => '获取地理位置更新成功!']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.update')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '【存在】获取地理位置更新失败!']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.update')])]);
     }
 
     public function reload($id): JsonResponse
@@ -261,10 +260,10 @@ class NodeController extends Controller
         }
 
         if ($ret) {
-            return Response::json(['status' => 'success', 'message' => '重载成功!']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('admin.node.reload')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '【存在】重载失败!']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('admin.node.reload')])]);
     }
 
     public function nodeMonitor(Node $node)

+ 12 - 7
app/Http/Controllers/Admin/PermissionController.php

@@ -8,6 +8,7 @@ use Exception;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\RedirectResponse;
 use Illuminate\Http\Request;
+use Log;
 use Spatie\Permission\Models\Permission;
 
 class PermissionController extends Controller
@@ -28,10 +29,10 @@ class PermissionController extends Controller
     public function store(PermissionRequest $request): RedirectResponse
     {
         if ($permission = Permission::create($request->validated())) {
-            return redirect()->route('admin.permission.edit', $permission)->with('successMsg', '操作成功');
+            return redirect()->route('admin.permission.edit', $permission)->with('successMsg', trans('common.success_item', ['attribute' => trans('common.add')]));
         }
 
-        return redirect()->back()->withInput()->withErrors('操作失败');
+        return redirect()->back()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.add')]));
     }
 
     public function create()
@@ -47,20 +48,24 @@ class PermissionController extends Controller
     public function update(PermissionRequest $request, Permission $permission): RedirectResponse
     {
         if ($permission->update($request->validated())) {
-            return redirect()->back()->with('successMsg', '操作成功');
+            return redirect()->back()->with('successMsg', trans('common.success_item', ['attribute' => trans('common.update')]));
         }
 
-        return redirect()->back()->withInput()->withErrors('操作失败');
+        return redirect()->back()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.update')]));
     }
 
     public function destroy(Permission $permission): JsonResponse
     {
         try {
-            $permission->delete();
+            if ($permission->delete()) {
+                return response()->json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
+            }
         } catch (Exception $e) {
-            return response()->json(['status' => 'fail', 'message' => '删除失败,'.$e->getMessage()]);
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('admin.logs.rule.title')]).': '.$e->getMessage());
+
+            return response()->json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return response()->json(['status' => 'success', 'message' => '清理成功']);
+        return response()->json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 }

+ 11 - 8
app/Http/Controllers/Admin/RoleController.php

@@ -7,6 +7,7 @@ use App\Http\Requests\Admin\RoleRequest;
 use Exception;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\RedirectResponse;
+use Log;
 use Spatie\Permission\Models\Permission;
 use Spatie\Permission\Models\Role;
 
@@ -22,10 +23,10 @@ class RoleController extends Controller
         if ($role = Role::create($request->only(['name', 'description']))) {
             $role->givePermissionTo($request->input('permissions') ?? []);
 
-            return redirect()->route('admin.role.edit', $role)->with('successMsg', '操作成功');
+            return redirect()->route('admin.role.edit', $role)->with('successMsg', trans('common.success_item', ['attribute' => trans('common.add')]));
         }
 
-        return redirect()->back()->withInput()->withErrors('操作失败');
+        return redirect()->back()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.add')]));
     }
 
     public function create()
@@ -44,29 +45,31 @@ class RoleController extends Controller
     public function update(RoleRequest $request, Role $role): RedirectResponse
     {
         if ($role->name === 'Super Admin') {
-            return redirect()->back()->withInput()->withErrors('请勿修改超级管理员');
+            return redirect()->back()->withInput()->withErrors(trans('admin.role.modify_admin_error'));
         }
 
         if ($role->update($request->only(['name', 'description']))) {
             $role->syncPermissions($request->input('permissions') ?: []);
 
-            return redirect()->back()->with('successMsg', '操作成功');
+            return redirect()->back()->with('successMsg', trans('common.success_item', ['attribute' => trans('common.edit')]));
         }
 
-        return redirect()->back()->withInput()->withErrors('操作失败');
+        return redirect()->back()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.edit')]));
     }
 
     public function destroy(Role $role): JsonResponse
     {
         try {
             if ($role->name === 'Super Admin') {
-                return response()->json(['status' => 'fail', 'message' => '请勿删除超级管理员']);
+                return response()->json(['status' => 'fail', 'message' => trans('admin.role.modify_admin_error')]);
             }
             $role->delete();
         } catch (Exception $e) {
-            return response()->json(['status' => 'fail', 'message' => '删除失败,'.$e->getMessage()]);
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('model.role.attribute')]).': '.$e->getMessage());
+
+            return response()->json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return response()->json(['status' => 'success', 'message' => '清理成功']);
+        return response()->json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
     }
 }

+ 17 - 10
app/Http/Controllers/Admin/RuleController.php

@@ -10,6 +10,7 @@ use App\Models\RuleLog;
 use Exception;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
+use Log;
 use Response;
 
 class RuleController extends Controller
@@ -30,32 +31,36 @@ class RuleController extends Controller
     public function store(RuleRequest $request): JsonResponse
     {
         if (Rule::create($request->validated())) {
-            return Response::json(['status' => 'success', 'message' => '提交成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.add')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '操作失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.add')])]);
     }
 
     // 编辑审计规则
     public function update(RuleRequest $request, Rule $rule): JsonResponse
     {
         if ($rule->update($request->validated())) {
-            return Response::json(['status' => 'success', 'message' => '操作成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.edit')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '操作失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.edit')])]);
     }
 
     // 删除审计规则
     public function destroy(Rule $rule): JsonResponse
     {
         try {
-            $rule->delete();
+            if ($rule->delete()) {
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
+            }
         } catch (Exception $e) {
-            return Response::json(['status' => 'fail', 'message' => '操作失败, '.$e->getMessage()]);
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('model.rule.attribute')]).': '.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'success', 'message' => '操作成功']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 
     // 用户触发审计规则日志
@@ -88,13 +93,15 @@ class RuleController extends Controller
         try {
             $ret = RuleLog::query()->delete();
         } catch (Exception $e) {
-            return Response::json(['status' => 'fail', 'message' => '清理失败, '.$e->getMessage()]);
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('admin.logs.rule.title')]).': '.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
         if ($ret || RuleLog::doesntExist()) {
-            return Response::json(['status' => 'success', 'message' => '清理成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '清理失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 }

+ 12 - 7
app/Http/Controllers/Admin/RuleGroupController.php

@@ -9,6 +9,7 @@ use App\Models\RuleGroup;
 use Exception;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\RedirectResponse;
+use Log;
 
 class RuleGroupController extends Controller
 {
@@ -22,10 +23,10 @@ class RuleGroupController extends Controller
         if ($group = RuleGroup::create($request->only('name', 'type'))) {
             $group->rules()->attach($request->input('rules'));
 
-            return redirect(route('admin.rule.group.edit', $group))->with('successMsg', '操作成功');
+            return redirect(route('admin.rule.group.edit', $group))->with('successMsg', trans('common.success_item', ['attribute' => trans('common.add')]));
         }
 
-        return redirect()->back()->withInput()->withErrors('操作失败');
+        return redirect()->back()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.add')]));
     }
 
     public function create()
@@ -46,20 +47,24 @@ class RuleGroupController extends Controller
         if ($group->update($request->only(['name', 'type']))) {
             $group->rules()->sync($request->input('rules'));
 
-            return redirect()->back()->with('successMsg', '操作成功');
+            return redirect()->back()->with('successMsg', trans('common.success_item', ['attribute' => trans('common.edit')]));
         }
 
-        return redirect()->back()->withInput()->withErrors('操作失败');
+        return redirect()->back()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.edit')]));
     }
 
     public function destroy(RuleGroup $group): JsonResponse
     {
         try {
-            $group->delete();
+            if ($group->delete()) {
+                return response()->json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
+            }
         } catch (Exception $e) {
-            return response()->json(['status' => 'fail', 'message' => '删除失败,'.$e->getMessage()]);
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('model.rule_group.attribute')]).': '.$e->getMessage());
+
+            return response()->json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return response()->json(['status' => 'success', 'message' => '清理成功']);
+        return response()->json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 }

+ 13 - 13
app/Http/Controllers/Admin/ShopController.php

@@ -62,22 +62,22 @@ class ShopController extends Controller
         }
         try {
             if ($good = Goods::create($data)) {
-                return Redirect::route('admin.goods.edit', $good)->with('successMsg', '添加成功');
+                return Redirect::route('admin.goods.edit', $good)->with('successMsg', trans('common.success_item', ['attribute' => trans('common.add')]));
             }
         } catch (Exception $e) {
-            Log::error('添加商品信息异常:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.add'), 'attribute' => trans('model.goods.attribute')]).': '.$e->getMessage());
 
-            return Redirect::back()->withInput()->withErrors('添加商品信息失败:'.$e->getMessage());
+            return Redirect::back()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.add')]).', '.$e->getMessage());
         }
 
-        return Redirect::back()->withInput()->withErrors('添加商品信息失败');
+        return Redirect::back()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.add')]));
     }
 
     public function fileUpload(UploadedFile $file)
     { // 图片上传
         $fileName = Str::random(8).time().'.'.$file->getClientOriginalExtension();
         if (! $file->storeAs('public', $fileName)) {
-            return Redirect::back()->withInput()->withErrors('Logo存储失败');
+            return Redirect::back()->withInput()->withErrors(trans('common.failed_action_item', ['action' => trans('common.store'), 'attribute' => trans('model.goods.logo')]));
         }
 
         return 'upload/'.$fileName;
@@ -115,29 +115,29 @@ class ShopController extends Controller
             $data['is_hot'] = array_key_exists('is_hot', $data) ? 1 : 0;
             $data['status'] = array_key_exists('status', $data) ? 1 : 0;
             if ($good->update($data)) {
-                return Redirect::back()->with('successMsg', '编辑成功');
+                return Redirect::back()->with('successMsg', trans('common.success_item', ['attribute' => trans('common.edit')]));
             }
         } catch (Exception $e) {
-            Log::error('编辑商品信息失败:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.edit'), 'attribute' => trans('model.goods.attribute')]).': '.$e->getMessage());
 
-            return Redirect::back()->withErrors('编辑商品信息失败:'.$e->getMessage());
+            return Redirect::back()->withErrors(trans('common.failed_item', ['attribute' => trans('common.edit')]).', '.$e->getMessage());
         }
 
-        return Redirect::back()->withInput()->withErrors('编辑失败');
+        return Redirect::back()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.edit')]));
     }
 
     public function destroy(Goods $good): JsonResponse
     {
         try {
             if ($good->delete()) {
-                return Response::json(['status' => 'success', 'message' => '删除成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
             }
         } catch (Exception $e) {
-            Log::error('编辑商品失败:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('model.goods.attribute')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => '编辑商品失败:'.$e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '删除失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 }

+ 1 - 1
app/Http/Controllers/Admin/SubscribeController.php

@@ -74,6 +74,6 @@ class SubscribeController extends Controller
             $subscribe->update(['status' => 1, 'ban_time' => null, 'ban_desc' => null]);
         }
 
-        return Response::json(['status' => 'success', 'message' => '操作成功']);
+        return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.update')])]);
     }
 }

+ 10 - 8
app/Http/Controllers/Admin/TicketController.php

@@ -39,16 +39,16 @@ class TicketController extends Controller
         $user = User::find($data['uid']) ?: User::whereUsername($data['username'])->first();
 
         if ($user === Auth::user()) {
-            return Response::json(['status' => 'fail', 'message' => '不能对自己发起工单']);
+            return Response::json(['status' => 'fail', 'message' => trans('admin.ticket.self_send')]);
         }
 
         if ($ticket = Ticket::create(['user_id' => $user->id, 'admin_id' => auth()->id(), 'title' => $data['title'], 'content' => clean($data['content'])])) {
             $user->notify(new TicketCreated($ticket, route('replyTicket', ['id' => $ticket->id])));
 
-            return Response::json(['status' => 'success', 'message' => '工单创建成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.create')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '工单创建失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.create')])]);
     }
 
     // 回复
@@ -69,30 +69,32 @@ class TicketController extends Controller
         $reply = $ticket->reply()->create(['admin_id' => Auth::id(), 'content' => $content]);
         if ($reply) {
             // 将工单置为已回复
-            $ticket->update(['status' => 1]);
+            if ($ticket->status !== 1) {
+                $ticket->update(['status' => 1]);
+            }
 
             // 通知用户
             if (sysConfig('ticket_replied_notification')) {
                 $ticket->user->notify(new TicketReplied($reply, route('replyTicket', ['id' => $ticket->id]), true));
             }
 
-            return Response::json(['status' => 'success', 'message' => '回复成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('user.ticket.reply')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '回复失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('user.ticket.reply')])]);
     }
 
     // 关闭工单
     public function destroy(Ticket $ticket): JsonResponse
     {
         if (! $ticket->close()) {
-            return Response::json(['status' => 'fail', 'message' => '关闭失败']);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.close')])]);
         }
         // 通知用户
         if (sysConfig('ticket_closed_notification')) {
             $ticket->user->notify(new TicketClosed($ticket->id, $ticket->title, route('replyTicket', ['id' => $ticket->id]), \request('reason'), true));
         }
 
-        return Response::json(['status' => 'success', 'message' => '关闭成功']);
+        return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.close')])]);
     }
 }

+ 17 - 16
app/Http/Controllers/Admin/ToolsController.php

@@ -21,7 +21,7 @@ class ToolsController extends Controller
             $content = $request->input('content');
 
             if (empty($content)) {
-                return Response::json(['status' => 'fail', 'message' => '请在左侧填入要反解析的SS(R)链接']);
+                return Response::json(['status' => 'fail', 'message' => trans('admin.tools.decompile.content_placeholder')]);
             }
 
             // 反解析处理
@@ -43,7 +43,7 @@ class ToolsController extends Controller
             // 生成转换好的JSON文件
             //file_put_contents(public_path('downloads/decompile.json'), $txt);
 
-            return Response::json(['status' => 'success', 'data' => $txt, 'message' => '反解析成功']);
+            return Response::json(['status' => 'success', 'data' => $txt, 'message' => trans('common.success_item', ['attribute' => trans('admin.tools.decompile.attribute')])]);
         }
 
         return view('admin.tools.decompile');
@@ -62,13 +62,13 @@ class ToolsController extends Controller
             $content = $request->input('content');
 
             if (empty($content)) {
-                return Response::json(['status' => 'fail', 'message' => '请在左侧填入要转换的内容']);
+                return Response::json(['status' => 'fail', 'message' => trans('admin.tools.convert.content_placeholder')]);
             }
 
             // 校验格式
             $content = json_decode($content, true);
             if (empty($content->port_password)) {
-                return Response::json(['status' => 'fail', 'message' => '转换失败:配置信息里缺少【port_password】字段,或者该字段为空']);
+                return Response::json(['status' => 'fail', 'message' => trans('admin.tools.convert.missing_error')]);
             }
 
             // 转换成SSR格式JSON
@@ -95,7 +95,7 @@ class ToolsController extends Controller
             // 生成转换好的JSON文件
             file_put_contents(public_path('downloads/convert.json'), $json);
 
-            return Response::json(['status' => 'success', 'data' => $json, 'message' => '转换成功']);
+            return Response::json(['status' => 'success', 'data' => $json, 'message' => trans('common.success_item', ['attribute' => trans('common.convert')])]);
         }
 
         return view('admin.tools.convert');
@@ -104,19 +104,19 @@ class ToolsController extends Controller
     // 下载转换好的JSON文件
     public function download(Request $request)
     {
-        $type = $request->input('type');
+        $type = (int) $request->input('type');
         if (empty($type)) {
-            exit('参数异常');
+            exit(trans('admin.tools.convert.params_unknown'));
         }
 
-        if ($type == '1') {
+        if ($type === 1) {
             $filePath = public_path('downloads/convert.json');
         } else {
             $filePath = public_path('downloads/decompile.json');
         }
 
         if (! file_exists($filePath)) {
-            exit('文件不存在,请检查目录权限');
+            exit(trans('admin.tools.convert.file_missing'));
         }
 
         return Response::download($filePath);
@@ -127,18 +127,18 @@ class ToolsController extends Controller
     {
         if ($request->isMethod('POST')) {
             if (! $request->hasFile('uploadFile')) {
-                return Redirect::back()->withErrors('请选择要上传的文件');
+                return Redirect::back()->withErrors(trans('admin.tools.import.file_required'));
             }
 
             $file = $request->file('uploadFile');
 
             // 只能上传JSON文件
             if ($file->getClientMimeType() !== 'application/json' || $file->getClientOriginalExtension() !== 'json') {
-                return Redirect::back()->withErrors('只允许上传JSON文件');
+                return Redirect::back()->withErrors(trans('admin.tools.import.file_type_error', ['type' => 'JSON']));
             }
 
             if (! $file->isValid()) {
-                return Redirect::back()->withErrors('产生未知错误,请重新上传');
+                return Redirect::back()->withErrors(trans('admin.tools.import.file_error'));
             }
 
             $save_path = realpath(storage_path('uploads'));
@@ -149,7 +149,7 @@ class ToolsController extends Controller
             $data = file_get_contents($save_path.'/'.$new_name);
             $data = json_decode($data, true);
             if (! $data) {
-                return Redirect::back()->withErrors('内容格式解析异常,请上传符合SSR(R)配置规范的JSON文件');
+                return Redirect::back()->withErrors(trans('admin.tools.import.format_error', ['type' => 'JSON']));
             }
 
             try {
@@ -176,11 +176,12 @@ class ToolsController extends Controller
                 DB::commit();
             } catch (Exception $e) {
                 DB::rollBack();
+                Log::error(trans('common.error_action_item', ['action' => trans('common.import'), 'attribute' => trans('admin.menu.tools.import')]).': '.$e->getMessage());
 
-                return Redirect::back()->withErrors('出错了,可能是导入的配置中有端口已经存在了');
+                return Redirect::back()->withErrors(trans('common.failed_item', ['attribute' => trans('common.import')]).', '.$e->getMessage());
             }
 
-            return Redirect::back()->with('successMsg', '导入成功');
+            return Redirect::back()->with('successMsg', trans('common.success_item', ['attribute' => trans('common.import')]));
         }
 
         return view('admin.tools.import');
@@ -191,7 +192,7 @@ class ToolsController extends Controller
     {
         $file = storage_path('app/ssserver.log');
         if (! file_exists($file)) {
-            Session::flash('analysisErrorMsg', $file.' 不存在,请先创建文件');
+            Session::flash('analysisErrorMsg', trans('admin.tools.analysis.file_missing', ['file_name' => $file]));
 
             return view('admin.tools.analysis');
         }

+ 32 - 29
app/Http/Controllers/Admin/UserController.php

@@ -103,23 +103,22 @@ class UserController extends Controller
         try {
             $adminUser = Auth::getUser();
             if ($roles && ($adminUser->can('give roles') || (in_array('Super Admin', $roles, true) && $adminUser->hasRole('Super Admin')))) {
-                // 编辑用户权限
-                // 只有超级管理员才有赋予超级管理的权限
+                // 编辑用户权限, 只有超级管理员才有赋予超级管理的权限
                 $user->assignRole($roles);
             }
 
             if ($user) {
-                Helpers::addUserTrafficModifyLog($user->id, 0, $data['transfer_enable'], '后台手动添加用户');
+                Helpers::addUserTrafficModifyLog($user->id, 0, $data['transfer_enable'], trans('Manually add in dashboard.'));
 
-                return Response::json(['status' => 'success', 'message' => '添加成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.add')])]);
             }
         } catch (Exception $e) {
-            Log::error('添加用户错误:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.add'), 'attribute' => trans('model.user.attribute')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => $e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.add')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '添加失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.add')])]);
     }
 
     public function create()
@@ -156,20 +155,20 @@ class UserController extends Controller
     public function destroy(User $user): JsonResponse
     {
         if ($user->id === 1) {
-            return Response::json(['status' => 'fail', 'message' => '系统管理员不可删除']);
+            return Response::json(['status' => 'fail', 'message' => trans('admin.user.admin_deletion')]);
         }
 
         try {
             if ($user->delete()) {
-                return Response::json(['status' => 'success', 'message' => '删除成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
             }
         } catch (Exception $e) {
-            Log::error('删除用户信息异常:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('model.user.attribute')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => '删除失败'.$e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '删除失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 
     public function batchAddUsers(): ?JsonResponse
@@ -177,12 +176,14 @@ class UserController extends Controller
         try {
             for ($i = 0; $i < (int) request('amount', 1); $i++) {
                 $user = Helpers::addUser(Str::random(8).'@auto.generate', Str::random(), MiB * sysConfig('default_traffic'), (int) sysConfig('default_days'));
-                Helpers::addUserTrafficModifyLog($user->id, 0, $user->transfer_enable, trans('admin.user.massive.note'));
+                Helpers::addUserTrafficModifyLog($user->id, 0, $user->transfer_enable, trans('Batch generate user accounts in dashboard.'));
             }
 
-            return Response::json(['status' => 'success', 'message' => trans('admin.user.massive.succeed')]);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.generate')])]);
         } catch (Exception $e) {
-            return Response::json(['status' => 'fail', 'message' => trans('admin.user.massive.failed').':'.$e->getMessage()]);
+            Log::error(trans('common.error_action_item', ['action' => trans('common.generate'), 'attribute' => trans('model.user.attribute')]).': '.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.generate')]).', '.$e->getMessage()]);
         }
     }
 
@@ -192,20 +193,22 @@ class UserController extends Controller
         Session::put('admin', Auth::id());
         Session::put('user', $user->id);
 
-        return Response::json(['status' => 'success', 'message' => '身份切换成功']);
+        return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('admin.user.info.switch')])]);
     }
 
     public function resetTraffic(User $user): JsonResponse
     {
         try {
-            $user->update(['u' => 0, 'd' => 0]);
+            if ($user->update(['u' => 0, 'd' => 0])) {
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.reset')])]);
+            }
         } catch (Exception $e) {
-            Log::error('流量重置失败:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.reset'), 'attribute' => trans('model.user.usable_traffic')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => '流量重置失败']);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.reset').', '.$e->getMessage()])]);
         }
 
-        return Response::json(['status' => 'success', 'message' => '流量重置成功']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.reset')])]);
     }
 
     public function update(UserUpdateRequest $request, User $user): JsonResponse
@@ -246,19 +249,19 @@ class UserController extends Controller
             }
 
             if ($user->transfer_enable !== $data['transfer_enable']) {
-                Helpers::addUserTrafficModifyLog($user->id, $user->transfer_enable, $data['transfer_enable'], '后台手动编辑用户');
+                Helpers::addUserTrafficModifyLog($user->id, $user->transfer_enable, $data['transfer_enable'], trans('Manually edit in dashboard.'));
             }
 
             if ($user->update($data)) {
-                return Response::json(['status' => 'success', 'message' => '编辑成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.edit')])]);
             }
         } catch (Exception $e) {
-            Log::error('编辑用户信息异常:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.edit'), 'attribute' => trans('model.user.attribute')]).': '.$e->getMessage());
 
-            return Response::json(['status' => 'fail', 'message' => '编辑用户信息错误:'.$e->getMessage()]);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.edit').', '.$e->getMessage()])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '编辑失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.edit')])]);
     }
 
     public function handleUserCredit(Request $request, User $user): JsonResponse
@@ -266,17 +269,17 @@ class UserController extends Controller
         $amount = $request->input('amount');
 
         if (empty($amount)) {
-            return Response::json(['status' => 'fail', 'message' => '充值异常']);
+            return Response::json(['status' => 'fail', 'message' => trans('common.error_item', ['attribute' => trans('user.recharge')])]);
         }
 
         // 加减余额
         if ($user->updateCredit($amount)) {
-            Helpers::addUserCreditLog($user->id, null, $user->credit - $amount, $user->credit, $amount, $request->input('description') ?? '后台手动充值');  // 写入余额变动日志
+            Helpers::addUserCreditLog($user->id, null, $user->credit - $amount, $user->credit, $amount, $request->input('description') ?? 'Manually edit in dashboard.');  // 写入余额变动日志
 
-            return Response::json(['status' => 'success', 'message' => '充值成功']);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('user.recharge')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => '充值失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('user.recharge')])]);
     }
 
     public function export(User $user)

+ 13 - 8
app/Http/Controllers/Admin/UserGroupController.php

@@ -9,6 +9,7 @@ use App\Models\UserGroup;
 use Exception;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\RedirectResponse;
+use Log;
 
 class UserGroupController extends Controller
 {
@@ -22,10 +23,10 @@ class UserGroupController extends Controller
         if ($userGroup = UserGroup::create($request->only(['name']))) {
             $userGroup->nodes()->attach($request->input('nodes'));
 
-            return redirect(route('admin.user.group.edit', $userGroup))->with('successMsg', '操作成功');
+            return redirect(route('admin.user.group.edit', $userGroup))->with('successMsg', trans('common.success_item', ['attribute' => trans('common.add')]));
         }
 
-        return redirect()->back()->withInput()->withErrors('操作失败');
+        return redirect()->back()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.add')]));
     }
 
     public function create()
@@ -46,24 +47,28 @@ class UserGroupController extends Controller
         if ($group->update($request->only(['name']))) {
             $group->nodes()->sync($request->input('nodes'));
 
-            return redirect()->back()->with('successMsg', '操作成功');
+            return redirect()->back()->with('successMsg', trans('common.success_item', ['attribute' => trans('common.edit')]));
         }
 
-        return redirect()->back()->withInput()->withErrors('操作失败');
+        return redirect()->back()->withInput()->withErrors(trans('common.failed_item', ['attribute' => trans('common.edit')]));
     }
 
     public function destroy(UserGroup $group): JsonResponse
     {
         if ($group->users->isNotEmpty()) { // 校验该分组下是否存在关联账号
-            return response()->json(['status' => 'fail', 'message' => '该分组下存在关联账号,请先取消关联!']);
+            return response()->json(['status' => 'fail', 'message' => trans('common.exists_error', ['attribute' => trans('model.user_group.attribute')])]);
         }
 
         try {
-            $group->delete();
+            if ($group->delete()) {
+                return response()->json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.delete')])]);
+            }
         } catch (Exception $e) {
-            return response()->json(['status' => 'fail', 'message' => '删除失败,'.$e->getMessage()]);
+            Log::error(trans('common.error_action_item', ['action' => trans('common.delete'), 'attribute' => trans('model.user_group.attribute')]).': '.$e->getMessage());
+
+            return response()->json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')]).', '.$e->getMessage()]);
         }
 
-        return response()->json(['status' => 'success', 'message' => '清理成功']);
+        return response()->json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.delete')])]);
     }
 }

+ 16 - 17
app/Http/Controllers/AdminController.php

@@ -96,36 +96,35 @@ class AdminController extends Controller
             $obj->save();
         }
 
-        return Response::json(['status' => 'success', 'message' => trans('common.generate_item', ['attribute' => trans('common.success')])]);
+        return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.generate')])]);
     }
 
     // 导出邀请码
     public function exportInvite(): void
     {
         $inviteList = Invite::whereStatus(0)->orderBy('id')->get();
-        $filename = '邀请码'.date('Ymd').'.xlsx';
+        $filename = trans('user.invite.attribute').'_'.date('Ymd').'.xlsx';
 
         $spreadsheet = new Spreadsheet;
-        $spreadsheet->getProperties()->setCreator('ProxyPanel')->setLastModifiedBy('ProxyPanel')->setTitle('邀请码')->setSubject('邀请码');
+        $spreadsheet->getProperties()->setCreator('ProxyPanel')->setLastModifiedBy('ProxyPanel')->setTitle(trans('user.invite.attribute'))->setSubject(trans('user.invite.attribute'));
+        $spreadsheet->setActiveSheetIndex(0);
+        $sheet = $spreadsheet->getActiveSheet();
+        $sheet->setTitle(trans('user.invite.attribute'));
+        $sheet->fromArray([trans('user.invite.attribute'), trans('common.available_date')]);
 
-        try {
-            $spreadsheet->setActiveSheetIndex(0);
-            $sheet = $spreadsheet->getActiveSheet();
-            $sheet->setTitle('邀请码');
-            $sheet->fromArray(['邀请码', '有效期']);
-
-            foreach ($inviteList as $k => $vo) {
-                $sheet->fromArray([$vo->code, $vo->dateline], null, 'A'.($k + 2));
-            }
+        foreach ($inviteList as $k => $vo) {
+            $sheet->fromArray([$vo->code, $vo->dateline], null, 'A'.($k + 2));
+        }
 
-            header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); // 输出07Excel文件
-            //header('Content-Type:application/vnd.ms-excel'); // 输出Excel03版本文件
-            header('Content-Disposition: attachment;filename="'.$filename.'"');
-            header('Cache-Control: max-age=0');
+        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); // 输出07Excel文件
+        //header('Content-Type:application/vnd.ms-excel'); // 输出Excel03版本文件
+        header('Content-Disposition: attachment;filename="'.$filename.'"');
+        header('Cache-Control: max-age=0');
+        try {
             $writer = new Xlsx($spreadsheet);
             $writer->save('php://output');
         } catch (Exception $e) {
-            Log::error('导出邀请码时报错:'.$e->getMessage());
+            Log::error(trans('common.error_action_item', ['action' => trans('common.export'), 'attribute' => trans('user.invite.attribute')]).': '.$e->getMessage());
         }
     }
 

+ 2 - 2
app/Http/Controllers/Api/Client/ClientController.php

@@ -63,7 +63,7 @@ class ClientController extends Controller
             'user' => $userInfo,
             'ssrSubToken' => $user->subscribe->code,
             'user_expire' => $user_expire,
-            'subUrl' => route('sub', $user->subscribe->code),
+            'subUrl' => $user->subUrl(),
             'baseUrl' => sysConfig('subscribe_domain') ?? sysConfig('website_url'),
             'ann' => $ann,
             'avatar' => $user->avatar,
@@ -86,7 +86,7 @@ class ClientController extends Controller
             $data[] = [
                 'id' => $order->id,
                 'total_amount' => $order->amount * 100,
-                'plan' => ['name' => $order->goods()->value('name') ?? '余额充值'],
+                'plan' => ['name' => $order->goods()->value('name') ?? trans('user.recharge_credit')],
                 'status' => [-1 => 2, 0 => 0, 1 => 1, 2 => 3, 3 => 4][$order->status],
                 'created_at' => strtotime($order->created_at),
             ];

+ 23 - 41
app/Http/Controllers/AuthController.php

@@ -16,7 +16,6 @@ use App\Utils\Helpers;
 use App\Utils\IP;
 use Auth;
 use Cache;
-use Captcha;
 use Cookie;
 use Hash;
 use Hashids\Hashids;
@@ -98,43 +97,26 @@ class AuthController extends Controller
     }
 
     private function check_captcha(Request $request): RedirectResponse|bool
-    { // 校验验证码
-        switch (sysConfig('is_captcha')) {
-            case 1: // 默认图形验证码
-                if (! Captcha::check($request->input('captcha'))) {
-                    return Redirect::back()->withInput()->withErrors(trans('auth.captcha.error.failed'));
-                }
-                break;
-            case 2: // Geetest
-                $validator = Validator::make($request->all(), ['geetest_challenge' => 'required|geetest']);
-
-                if ($validator->fails()) {
-                    return Redirect::back()->withInput()->withErrors(trans('auth.captcha.error.failed'));
-                }
-                break;
-            case 3: // Google reCAPTCHA
-                $validator = Validator::make($request->all(), ['g-recaptcha-response' => 'required|NoCaptcha']);
-
-                if ($validator->fails()) {
-                    return Redirect::back()->withInput()->withErrors(trans('auth.captcha.error.failed'));
-                }
-                break;
-            case 4: // hCaptcha
-                $validator = Validator::make($request->all(), ['h-captcha-response' => 'required|HCaptcha']);
-
-                if ($validator->fails()) {
-                    return Redirect::back()->withInput()->withErrors(trans('auth.captcha.error.failed'));
-                }
-                break;
-            case 5: // Turnstile
-                $validator = Validator::make($request->all(), ['cf-turnstile-response' => ['required', 'string', new TurnstileCaptcha]]);
+    {
+        // Define the rules based on the captcha type
+        $rules = [
+            1 => ['captcha' => 'required|captcha'], // Mews\Captcha
+            2 => ['geetest_challenge' => 'required|geetest'], // Geetest
+            3 => ['g-recaptcha-response' => 'required|NoCaptcha'], // Google reCAPTCHA
+            4 => ['h-captcha-response' => 'required|HCaptcha'], // hCaptcha
+            5 => ['cf-turnstile-response' => ['required', 'string', new TurnstileCaptcha]], // Turnstile
+        ];
+
+        // Get the current captcha setting
+        $captchaType = sysConfig('is_captcha');
+
+        // Check if the captcha is enabled and has a defined rule
+        if (isset($rules[$captchaType])) {
+            $validator = Validator::make($request->all(), $rules[$captchaType]);
 
-                if ($validator->fails()) {
-                    return Redirect::back()->withInput()->withErrors($validator->errors());
-                }
-                break;
-            default: // 不启用验证码
-                break;
+            if ($validator->fails()) {
+                return Redirect::back()->withInput()->withErrors(trans('auth.captcha.error.failed'));
+            }
         }
 
         return true;
@@ -189,10 +171,10 @@ class AuthController extends Controller
             // 校验邀请码合法性
             if ($invite_code) {
                 if (Invite::whereCode($invite_code)->whereStatus(0)->doesntExist()) {
-                    return Redirect::back()->withInput($request->except('code'))->withErrors(trans('auth.invite.error.unavailable'));
+                    return Redirect::back()->withInput($request->except('code'))->withErrors(trans('auth.invite.unavailable'));
                 }
             } elseif ((int) sysConfig('is_invite_register') === 2) { // 必须使用邀请码
-                return Redirect::back()->withInput()->withErrors(trans('validation.required', ['attribute' => trans('auth.invite.attribute')]));
+                return Redirect::back()->withInput()->withErrors(trans('validation.required', ['attribute' => trans('user.invite.attribute')]));
             }
         }
 
@@ -283,7 +265,7 @@ class AuthController extends Controller
                 $user->update(['status' => 1]);
             }
 
-            Session::flash('successMsg', trans('auth.register.success'));
+            Session::flash('successMsg', trans('common.success_item', ['attribute' => trans('auth.register.attribute')]));
         }
 
         return Redirect::route('login')->withInput();
@@ -457,7 +439,7 @@ class AuthController extends Controller
 
             // 更新密码
             if (! $user->update(['password' => $password])) {
-                return Redirect::back()->withErrors(trans('auth.password.reset.error.failed'));
+                return Redirect::back()->withErrors(trans('common.failed_item', ['attribute' => trans('auth.password.reset.attribute')]));
             }
 
             // 置为已使用

+ 3 - 1
app/Http/Controllers/MessageController.php

@@ -13,8 +13,10 @@ class MessageController extends Controller
             $log = NotificationLog::whereMsgId($msgId)->latest()->firstOrFail();
             $title = $log->title;
             $content = Markdown::parse($log->content)->toHtml();
+
+            return view('components.message', compact('title', 'content'));
         }
 
-        return view('components.message', compact('title', 'content'));
+        return false;
     }
 }

+ 6 - 6
app/Http/Controllers/OAuthController.php

@@ -18,10 +18,10 @@ class OAuthController extends Controller
         $user = Auth::user();
 
         if ($user && $user->userAuths()->whereType($provider)->delete()) {
-            return redirect()->route('profile')->with('successMsg', trans('auth.oauth.unbind_success'));
+            return redirect()->route('profile')->with('successMsg', trans('common.success_item', ['attribute' => trans('user.oauth.unbind')]));
         }
 
-        return redirect()->route('profile')->withErrors(trans('auth.oauth.unbind_failed'));
+        return redirect()->route('profile')->withErrors(trans('common.failed_item', ['attribute' => trans('user.oauth.unbind')]));
     }
 
     public function bind(string $provider): RedirectResponse
@@ -36,7 +36,7 @@ class OAuthController extends Controller
         $user = Auth::user();
 
         if (! $user) {
-            return redirect()->route('profile')->withErrors(trans('auth.oauth.bind_failed'));
+            return redirect()->route('profile')->withErrors(trans('common.failed_item', ['attribute' => trans('user.oauth.bind')]));
         }
 
         return $this->bindLogic($provider, $user, $authInfo);
@@ -54,10 +54,10 @@ class OAuthController extends Controller
 
         if ($auth) {
             $user->userAuths()->whereType($provider)->update($data);
-            $message = trans('auth.oauth.rebind_success');
+            $message = trans('common.success_item', ['attribute' => trans('user.oauth.rebind')]);
         } else {
             $user->userAuths()->create($data);
-            $message = trans('auth.oauth.bind_success');
+            $message = trans('common.success_item', ['attribute' => trans('user.oauth.bind')]);
         }
 
         return redirect()->route('profile')->with('successMsg', $message);
@@ -71,7 +71,7 @@ class OAuthController extends Controller
         }
 
         if ((int) sysConfig('is_invite_register') === 2) {
-            return redirect()->route('register')->withErrors(trans('validation.required', ['attribute' => trans('auth.invite.attribute')]));
+            return redirect()->route('register')->withErrors(trans('validation.required', ['attribute' => trans('user.invite.attribute')]));
         }
 
         $registerInfo = Socialite::driver($provider)->stateless()->user();

+ 40 - 42
app/Http/Controllers/PaymentController.php

@@ -33,38 +33,36 @@ class PaymentController extends Controller
     {
         self::$method = $request->query('method') ?: $request->input('method');
 
-        Log::notice('[{method}] 回调接口:{body}', ['method' => self::$method, 'body' => var_export($request->all(), true)]);
+        Log::notice('[{method}] '.trans('admin.menu.log.payment_callback').': {body}', ['method' => self::$method, 'body' => var_export($request->all(), true)]);
 
         return self::getClient()->notify($request);
     }
 
     public static function getClient(): Gateway
     {
-        switch (self::$method) {
-            case 'credit':
-                return new Local;
-            case 'f2fpay':
-                return new F2Fpay;
-            case 'codepay':
-                return new Codepay;
-            case 'payjs':
-                return new PayJs;
-            case 'paypal':
-                return new PayPal;
-            case 'epay':
-                return new EPay;
-            case 'stripe':
-                return new Stripe;
-            case 'paybeaver':
-                return new PayBeaver;
-            case 'theadpay':
-                return new THeadPay;
-            case 'manual':
-                return new Manual;
-            default:
-                Log::emergency('未知支付:'.self::$method);
-                exit(404);
+        // Mapping of payment methods to their respective classes
+        $paymentMethods = [
+            'credit' => Local::class,
+            'f2fpay' => F2Fpay::class,
+            'codepay' => CodePay::class,
+            'payjs' => PayJs::class,
+            'paypal' => PayPal::class,
+            'epay' => EPay::class,
+            'stripe' => Stripe::class,
+            'paybeaver' => PayBeaver::class,
+            'theadpay' => THeadPay::class,
+            'manual' => Manual::class,
+        ];
+
+        // Check if the method exists in the mapping
+        if (isset($paymentMethods[self::$method])) {
+            // Instantiate and return the corresponding class
+            return new $paymentMethods[self::$method];
         }
+
+        // Log an emergency message and exit if the method is unknown
+        Log::emergency(trans('user.payment.order_creation.unknown_payment').': '.self::$method);
+        exit(404);
     }
 
     public static function getStatus(Request $request): JsonResponse
@@ -72,17 +70,17 @@ class PaymentController extends Controller
         $payment = Payment::whereTradeNo($request->input('trade_no'))->first();
         if ($payment) {
             if ($payment->status === 1) {
-                return Response::json(['status' => 'success', 'message' => '支付成功']);
+                return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('user.pay')])]);
             }
 
             if ($payment->status === -1) {
-                return Response::json(['status' => 'error', 'message' => '订单超时未支付,已自动关闭']);
+                return Response::json(['status' => 'error', 'message' => trans('user.payment.order_creation.order_timeout')]);
             }
 
-            return Response::json(['status' => 'fail', 'message' => '等待支付']);
+            return Response::json(['status' => 'fail', 'message' => trans('common.payment.status.wait')]);
         }
 
-        return Response::json(['status' => 'error', 'message' => '未知订单']);
+        return Response::json(['status' => 'error', 'message' => trans('user.payment.order_creation.unknown_order')]);
     }
 
     public function purchase(Request $request) // 创建支付订单
@@ -104,7 +102,7 @@ class PaymentController extends Controller
         } elseif ($goods_id && self::$method) { // 购买服务
             $goods = Goods::find($goods_id);
             if (! $goods || ! $goods->status) {
-                return Response::json(['status' => 'fail', 'message' => '订单创建失败:商品已下架']);
+                return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.product_unavailable')]);
             }
             $amount = $goods->price;
 
@@ -113,14 +111,14 @@ class PaymentController extends Controller
 
             // 无生效套餐,禁止购买加油包
             if ($goods->type === 1 && $activePlan) {
-                return Response::json(['status' => 'fail', 'message' => '购买加油包前,请先购买套餐']);
+                return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.plan_required')]);
             }
 
             // 单个商品限购
             if ($goods->limit_num) {
                 $count = Order::uid()->where('status', '>=', 0)->whereGoodsId($goods_id)->count();
                 if ($count >= $goods->limit_num) {
-                    return Response::json(['status' => 'fail', 'message' => '此商品限购'.$goods->limit_num.'次,您已购买'.$count.'次']);
+                    return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.order_limit', ['limit_num' => $goods->limit_num, 'count' => $count])]);
                 }
             }
 
@@ -141,24 +139,24 @@ class PaymentController extends Controller
             if (self::$method !== 'credit') {
                 // 判断是否开启在线支付
                 if (! sysConfig('is_onlinePay') && ! sysConfig('wechat_qrcode') && ! sysConfig('alipay_qrcode')) {
-                    return Response::json(['status' => 'fail', 'message' => '订单创建失败:系统并未开启在线支付功能']);
+                    return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.payment_disabled')]);
                 }
 
                 // 判断是否存在同个商品的未支付订单
                 if (Order::uid()->whereStatus(0)->exists()) {
-                    return Response::json(['status' => 'fail', 'message' => '订单创建失败:尚有未支付的订单,请先去支付']);
+                    return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.pending_order')]);
                 }
             } elseif (auth()->user()->credit < $amount) { // 验证账号余额是否充足
-                return Response::json(['status' => 'fail', 'message' => '您的余额不足,请先充值']);
+                return Response::json(['status' => 'fail', 'message' => trans('user.payment.insufficient_balance')]);
             }
 
             // 价格异常判断
             if ($amount < 0) {
-                return Response::json(['status' => 'fail', 'message' => '订单创建失败:订单总价异常']);
+                return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.price_issue')]);
             }
 
             if ($amount === 0 && self::$method !== 'credit') {
-                return Response::json(['status' => 'fail', 'message' => '订单创建失败:订单总价为0,无需使用在线支付']);
+                return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.price_zero')]);
             }
         }
 
@@ -181,7 +179,7 @@ class PaymentController extends Controller
                     $coupon->decrement('usable_times');
                 }
 
-                Helpers::addCouponLog('订单支付使用', $coupon->id, $goods_id, $newOrder->id);
+                Helpers::addCouponLog('Coupon used in order.', $coupon->id, $goods_id, $newOrder->id);
             }
 
             $request->merge(['id' => $newOrder->id, 'type' => $pay_type, 'amount' => $amount]);
@@ -189,19 +187,19 @@ class PaymentController extends Controller
             // 生成支付单
             return self::getClient()->purchase($request);
         } catch (Exception $e) {
-            Log::emergency('订单生成错误:'.$e->getMessage());
+            Log::emergency(trans('common.failed_action_item', ['action' => trans('common.create'), 'attribute' => trans('model.order.attribute')]).': '.$e->getMessage());
         }
 
-        return Response::json(['status' => 'fail', 'message' => '订单创建失败']);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_action_item', ['action' => trans('common.create'), 'attribute' => trans('model.order.attribute')])]);
     }
 
     public function close(Order $order): JsonResponse
     {
         if (! $order->close()) {
-            return Response::json(['status' => 'fail', 'message' => '关闭订单失败']);
+            return Response::json(['status' => 'fail', 'message' => trans('common.failed_action_item', ['action' => trans('common.close'), 'attribute' => trans('model.order.attribute')])]);
         }
 
-        return Response::json(['status' => 'success', 'message' => '关闭订单成功']);
+        return Response::json(['status' => 'success', 'message' => trans('common.success_action_item', ['action' => trans('common.close'), 'attribute' => trans('model.order.attribute')])]);
     }
 
     public function detail($trade_no) // 支付单详情

+ 78 - 90
app/Http/Controllers/TelegramController.php

@@ -61,22 +61,72 @@ class TelegramController extends Controller
 
     private function fromSend(): void
     {
-        switch ($this->msg->command) {
-            case '/bind':
-                $this->bind();
-                break;
-            case '/traffic':
-                $this->traffic();
-                break;
-            case '/getLatestUrl':
-                $this->getLatestUrl();
-                break;
-            case '/unbind':
-                $this->unbind();
-                break;
-            default:
-                $this->help();
+        $commands = [
+            '/bind' => 'bind',
+            '/traffic' => 'traffic',
+            '/url' => 'getUrl',
+            '/unbind' => 'unbind',
+        ];
+
+        $command = $this->msg->command;
+
+        if (isset($commands[$command])) {
+            $this->{$commands[$command]}();
+        } else {
+            $this->help();
+        }
+    }
+
+    private function help(): void
+    {
+        $msg = $this->msg;
+        if (! $msg->is_private) {
+            return;
+        }
+
+        $webName = sysConfig('website_name');
+        $accountType = sysConfig('username_type') === 'email' || sysConfig('username_type') === null ? ucfirst(trans('validation.attributes.email')) : trans('model.user.username');
+        $telegramService = new TelegramService;
+        $commands = trans('user.telegram.command.intro').": \n\n/bind `$accountType` -[".trans('user.telegram.command.bind', ['web_name' => $webName])."]\n/traffic -[".trans('user.telegram.command.traffic')."]\n/url -[".trans('user.telegram.command.web_url', ['web_name' => $webName])."]\n/unbind -[".trans('user.telegram.command.unbind').']';
+        $telegramService->sendMessage($msg->chat_id, $commands, 'markdown');
+    }
+
+    private function fromReply(): void
+    {
+        // ticket
+        if (preg_match('/[#](.*)/', $this->msg->reply_text, $match)) {
+            $this->replayTicket($match[1]);
+        }
+    }
+
+    private function replayTicket($ticketId): void
+    {
+        $msg = $this->msg;
+        if (! $msg->is_private) {
+            return;
+        }
+        $user = User::with([
+            'userAuths' => function ($query) use ($msg) {
+                $query->whereType('telegram')->whereIdentifier($msg->chat_id);
+            },
+        ])->first();
+
+        if (! $user) {
+            abort(500, trans('user.telegram.params_missing'));
+        }
+        $admin = User::role('Super Admin')->whereId($user->id)->first();
+        if ($admin) {
+            $ticket = Ticket::whereId($ticketId)->first();
+            if (! $ticket) {
+                abort(500, trans('user.telegram.ticket_missing'));
+            }
+
+            $ticket->reply()->create(['admin_id' => $admin->id, 'content' => $msg->text]);
+            if ($ticket->status !== 1) {
+                $ticket->update(['status' => 1]);
+            }
         }
+        (new TelegramService)->sendMessage($msg->chat_id, trans('user.telegram.ticket_reply', ['id' => $ticketId]), 'markdown');
     }
 
     private function bind(): void
@@ -86,21 +136,21 @@ class TelegramController extends Controller
             return;
         }
         if (! isset($msg->args[0])) {
-            abort(500, '参数有误,请携带邮箱地址发送');
+            abort(500, trans('user.telegram.params_missing'));
         }
         $user = User::whereUsername($msg->args[0])->first();
         if (! $user) {
-            abort(500, '用户不存在');
+            abort(500, trans('user.telegram.user_missing'));
         }
         if ($user->telegram_user_id) {
-            abort(500, '该账号已经绑定了Telegram账号');
+            abort(500, trans('user.telegram.bind_exists'));
         }
 
         if (! $user->userAuths()->create(['type' => 'telegram', 'identifier' => $msg->chat_id])) {
-            abort(500, '设置失败');
+            abort(500, trans('common.failed_item', ['attribute' => trans('user.oauth.bind')]));
         }
         $telegramService = new TelegramService;
-        $telegramService->sendMessage($msg->chat_id, '绑定成功');
+        $telegramService->sendMessage($msg->chat_id, trans('common.success_item', ['attribute' => trans('user.oauth.bind')]));
     }
 
     private function traffic(): void
@@ -110,12 +160,9 @@ class TelegramController extends Controller
             return;
         }
         $telegramService = new TelegramService;
-        if (! $oauth = UserOauth::query()->where([
-            'type' => 'telegram',
-            'identifier' => $msg->chat_id,
-        ])->first()) {
+        if (! $oauth = UserOauth::query()->where(['type' => 'telegram', 'identifier' => $msg->chat_id])->first()) {
             $this->help();
-            $telegramService->sendMessage($msg->chat_id, '没有查询到您的用户信息,请先绑定账号', 'markdown');
+            $telegramService->sendMessage($msg->chat_id, trans('user.telegram.bind_missing'), 'markdown');
 
             return;
         }
@@ -124,37 +171,15 @@ class TelegramController extends Controller
         $up = formatBytes($user->u);
         $down = formatBytes($user->d);
         $remaining = formatBytes($user->transfer_enable - ($user->u + $user->d));
-        $text = "🚥流量查询\n———————————————\n计划流量:`$transferEnable`\n已用上行:`$up`\n已用下行:`$down`\n剩余流量:`$remaining`";
+        $text = '🚥'.trans('user.subscribe.info.title')."\n———————————————\n".trans('user.subscribe.info.total').": `$transferEnable`\n".trans('user.subscribe.info.upload').": `$up`\n".trans('user.subscribe.info.download').": `$down`\n".trans('user.account.remain').": `$remaining`";
         $telegramService->sendMessage($msg->chat_id, $text, 'markdown');
     }
 
-    private function help(): void
+    private function getUrl(): void
     {
         $msg = $this->msg;
-        if (! $msg->is_private) {
-            return;
-        }
         $telegramService = new TelegramService;
-        $commands = [
-            '/bind 订阅地址 - 绑定你的'.sysConfig('website_name').'账号',
-            '/traffic - 查询流量信息',
-            '/getLatestUrl - 获取最新的'.sysConfig('website_name').'网址',
-            '/unbind - 解除绑定',
-        ];
-        $text = implode(PHP_EOL, $commands);
-        $telegramService->sendMessage($msg->chat_id, "你可以使用以下命令进行操作:\n\n$text", 'markdown');
-    }
-
-    private function getLatestUrl(): void
-    {
-        $msg = $this->msg;
-        $telegramService = new TelegramService;
-        $text = sprintf(
-            '%s的最新网址是:%s',
-            sysConfig('website_name'),
-            sysConfig('website_url')
-        );
-        $telegramService->sendMessage($msg->chat_id, $text, 'markdown');
+        $telegramService->sendMessage($msg->chat_id, trans('user.telegram.get_url', ['get_url' => sysConfig('website_name')]).': '.sysConfig('website_url'), 'markdown');
     }
 
     private function unbind(): void
@@ -172,50 +197,13 @@ class TelegramController extends Controller
         $telegramService = new TelegramService;
         if (! $user) {
             $this->help();
-            $telegramService->sendMessage($msg->chat_id, '没有查询到您的用户信息,请先绑定账号', 'markdown');
+            $telegramService->sendMessage($msg->chat_id, trans('user.telegram.bind_missing'), 'markdown');
 
             return;
         }
         if (! $user->userAuths()->whereType('telegram')->whereIdentifier($msg->chat_id)->delete()) {
-            abort(500, '解绑失败');
-        }
-        $telegramService->sendMessage($msg->chat_id, '解绑成功', 'markdown');
-    }
-
-    private function fromReply(): void
-    {
-        // ticket
-        if (preg_match('/[#](.*)/', $this->msg->reply_text, $match)) {
-            $this->replayTicket($match[1]);
-        }
-    }
-
-    private function replayTicket($ticketId): void
-    {
-        $msg = $this->msg;
-        if (! $msg->is_private) {
-            return;
-        }
-        $user = User::with([
-            'userAuths' => function ($query) use ($msg) {
-                $query->whereType('telegram')->whereIdentifier($msg->chat_id);
-            },
-        ])->first();
-
-        if (! $user) {
-            abort(500, '用户不存在');
-        }
-        $admin = User::role('Super Admin')->whereId($user->id)->first();
-        if ($admin) {
-            $ticket = Ticket::whereId($ticketId)->first();
-            if (! $ticket) {
-                abort(500, '工单不存在');
-            }
-            if ($ticket->status) {
-                abort(500, '工单已关闭,无法回复');
-            }
-            $ticket->reply()->create(['admin_id' => $admin->id, 'content' => $msg->text]);
+            abort(500, trans('common.failed_item', ['attribute' => trans('user.oauth.unbind')]));
         }
-        (new TelegramService)->sendMessage($msg->chat_id, "#`$ticketId` 的工单已回复成功", 'markdown');
+        $telegramService->sendMessage($msg->chat_id, trans('common.success_item', ['attribute' => trans('user.oauth.unbind')]), 'markdown');
     }
 }

+ 6 - 6
app/Http/Controllers/User/AffiliateController.php

@@ -18,7 +18,7 @@ class AffiliateController extends Controller
     public function referral()
     {
         if (ReferralLog::uid()->doesntExist() && Order::uid()->whereStatus(2)->doesntExist()) {
-            return Response::view('auth.error', ['message' => trans('user.purchase_required').'<a class="btn btn-sm btn-danger" href="/">'.trans('common.back').'</a>'], 402);
+            return Response::view('auth.error', ['message' => trans('user.purchase.required').'<a class="btn btn-sm btn-danger" href="/">'.trans('common.back').'</a>'], 402);
         }
 
         return view('user.referral', [
@@ -39,12 +39,12 @@ class AffiliateController extends Controller
     {
         // 判断账户是否过期
         if (Auth::getUser()->expiration_date < date('Y-m-d')) {
-            return Response::json(['status' => 'fail', 'title' => trans('user.referral.failed'), 'message' => trans('user.referral.msg.account')]);
+            return Response::json(['status' => 'fail', 'title' => trans('common.failed_item', ['attribute' => trans('common.request')]), 'message' => trans('user.referral.msg.account')]);
         }
 
         // 判断是否已存在申请
         if (ReferralApply::uid()->whereIn('status', [0, 1])->first()) {
-            return Response::json(['status' => 'fail', 'title' => trans('user.referral.failed'), 'message' => trans('user.referral.msg.applied')]);
+            return Response::json(['status' => 'fail', 'title' => trans('common.failed_item', ['attribute' => trans('common.request')]), 'message' => trans('user.referral.msg.applied')]);
         }
 
         // 校验可以提现金额是否超过系统设置的阀值
@@ -52,7 +52,7 @@ class AffiliateController extends Controller
         $commission /= 100;
         if ($commission < sysConfig('referral_money')) {
             return Response::json([
-                'status' => 'fail', 'title' => trans('user.referral.failed'), 'message' => trans('user.referral.msg.unfulfilled', ['amount' => Helpers::getPriceTag(sysConfig('referral_money'))]),
+                'status' => 'fail', 'title' => trans('common.failed_item', ['attribute' => trans('common.request')]), 'message' => trans('user.referral.msg.unfulfilled', ['amount' => Helpers::getPriceTag(sysConfig('referral_money'))]),
             ]);
         }
 
@@ -62,9 +62,9 @@ class AffiliateController extends Controller
         $ref->amount = $commission;
         $ref->link_logs = ReferralLog::uid()->whereStatus(0)->pluck('id')->toArray();
         if ($ref->save()) {
-            return Response::json(['status' => 'success', 'title' => trans('user.referral.success'), 'message' => trans('user.referral.msg.wait')]);
+            return Response::json(['status' => 'success', 'title' => trans('common.success_item', ['attribute' => trans('common.request')]), 'message' => trans('user.referral.msg.wait')]);
         }
 
-        return Response::json(['status' => 'fail', 'title' => trans('user.referral.failed'), 'message' => trans('user.referral.msg.error')]);
+        return Response::json(['status' => 'fail', 'title' => trans('common.failed_item', ['attribute' => trans('common.request')]), 'message' => trans('user.referral.msg.error')]);
     }
 }

+ 22 - 26
app/Http/Controllers/UserController.php

@@ -76,7 +76,7 @@ class UserController extends Controller
             'subscribe_status' => $user->subscribe->status,
             'subMsg' => $user->subscribe->ban_desc,
             'subType' => $subType,
-            'subUrl' => route('sub', $user->subscribe->code),
+            'subUrl' => $user->subUrl(),
         ], $this->dataFlowChart($user->id)));
     }
 
@@ -163,20 +163,20 @@ class UserController extends Controller
                 }
 
                 if (! $user->update(['password' => $data['new_password']])) {
-                    return Redirect::back()->withErrors(trans('common.update_action', ['action' => trans('common.failed')]));
+                    return Redirect::back()->withErrors(trans('common.failed_item', ['attribute' => trans('common.update')]));
                 }
 
-                return Redirect::back()->with('successMsg', trans('common.update_action', ['action' => trans('common.success')]));
+                return Redirect::back()->with('successMsg', trans('common.success_item', ['attribute' => trans('common.update')]));
                 // 修改代理密码
             }
 
             if ($request->has('passwd')) {
                 $passwd = $request->input('passwd');
                 if (! $user->update(['passwd' => $passwd])) {
-                    return Redirect::back()->withErrors(trans('common.update_action', ['action' => trans('common.failed')]));
+                    return Redirect::back()->withErrors(trans('common.failed_item', ['attribute' => trans('common.update')]));
                 }
 
-                return Redirect::back()->with('successMsg', trans('common.update_action', ['action' => trans('common.success')]));
+                return Redirect::back()->with('successMsg', trans('common.success_item', ['attribute' => trans('common.update')]));
             }
 
             // 修改联系方式
@@ -187,11 +187,11 @@ class UserController extends Controller
                 }
 
                 if (! $user->update($data)) {
-                    return Redirect::back()->withErrors(trans('common.update_action', ['action' => trans('common.failed')]));
+                    return Redirect::back()->withErrors(trans('common.failed_item', ['attribute' => trans('common.update')]));
                 }
             }
 
-            return Redirect::back()->with('successMsg', trans('common.update_action', ['action' => trans('common.success')]));
+            return Redirect::back()->with('successMsg', trans('common.success_item', ['attribute' => trans('common.update')]));
         }
         $auth = $user->userAuths()->pluck('type')->toArray();
 
@@ -235,18 +235,18 @@ class UserController extends Controller
         $order = Order::userActivePlan()->firstOrFail();
         $renewCost = $order->goods->renew;
         if ($user->credit < $renewCost) {
-            return Response::json(['status' => 'fail', 'message' => trans('user.reset_data.insufficient')]);
+            return Response::json(['status' => 'fail', 'message' => trans('user.payment.insufficient_balance')]);
         }
 
         $user->update(['u' => 0, 'd' => 0]);
 
         // 记录余额操作日志
-        Helpers::addUserCreditLog($user->id, null, $user->credit, $user->credit - $renewCost, -1 * $renewCost, trans('user.reset_data.logs'));
+        Helpers::addUserCreditLog($user->id, null, $user->credit, $user->credit - $renewCost, -1 * $renewCost, 'The user manually reset the data.');
 
         // 扣余额
         $user->updateCredit(-$renewCost);
 
-        return Response::json(['status' => 'success', 'message' => trans('user.reset_data.success')]);
+        return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.reset')])]);
     }
 
     // 工单
@@ -288,7 +288,7 @@ class UserController extends Controller
             }
         }
 
-        return Response::json(['status' => 'fail', 'message' => trans('common.close_item', ['attribute' => trans('common.failed')])]);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.close')])]);
     }
 
     // 订单明细
@@ -313,11 +313,9 @@ class UserController extends Controller
         if ($ticket = $user->tickets()->create(compact('title', 'content'))) {
             // 通知相关管理员
             Notification::send(User::find(1), new TicketCreated($ticket, route('admin.ticket.edit', $ticket)));
-
-            return Response::json(['status' => 'success', 'message' => trans('common.submit_item', ['attribute' => trans('common.success')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => trans('common.submit_item', ['attribute' => trans('common.failed')])]);
+        return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.submit')])]);
     }
 
     // 回复工单
@@ -336,14 +334,12 @@ class UserController extends Controller
                 ]);
             }
 
-            if ($ticket->status === 2) {
-                return Response::json(['status' => 'fail', 'message' => trans('user.ticket.failed_closed')]);
-            }
             $reply = $ticket->reply()->create(['user_id' => auth()->id(), 'content' => $content]);
             if ($reply) {
                 // 重新打开工单
-                $ticket->status = 0;
-                $ticket->save();
+                if ($ticket->status === 2) {
+                    $ticket->update(['status' => 0]);
+                }
 
                 // 通知相关管理员
                 Notification::send(User::find(1), new TicketReplied($reply, route('admin.ticket.edit', $ticket)));
@@ -366,17 +362,17 @@ class UserController extends Controller
         $id = $request->input('id');
 
         if (Ticket::uid()->whereId($id)->firstOrFail()->close()) {
-            return Response::json(['status' => 'success', 'message' => trans('common.close_item', ['attribute' => trans('common.success')])]);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.close')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => trans('common.close_item', ['attribute' => trans('common.failed')])]);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.close')])]);
     }
 
     // 邀请码
     public function invite()
     {
         if (Order::uid()->active()->where('origin_amount', '>', 0)->doesntExist()) {
-            return Response::view('auth.error', ['message' => trans('user.purchase_required').' <a class="btn btn-sm btn-danger" href="/">'.trans('common.back').'</a>'], 402);
+            return Response::view('auth.error', ['message' => trans('user.purchase.required').' <a class="btn btn-sm btn-danger" href="/">'.trans('common.back').'</a>'], 402);
         }
 
         return view('user.invite', [
@@ -401,10 +397,10 @@ class UserController extends Controller
         if ($invite) {
             $user->decrement('invite_num');
 
-            return Response::json(['status' => 'success', 'message' => trans('common.generate_item', ['attribute' => trans('common.success')])]);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.generate')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => trans('common.generate_item', ['attribute' => trans('common.failed')])]);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.generate')])]);
     }
 
     // 使用优惠券
@@ -506,10 +502,10 @@ class UserController extends Controller
         // 管理员信息重新写入user
         $user = auth()->loginUsingId(Session::pull('admin'));
         if ($user) {
-            return Response::json(['status' => 'success', 'message' => trans('common.toggle_action', ['action' => trans('common.success')])]);
+            return Response::json(['status' => 'success', 'message' => trans('common.success_item', ['attribute' => trans('common.toggle')])]);
         }
 
-        return Response::json(['status' => 'fail', 'message' => trans('common.toggle_action', ['action' => trans('common.failed')])]);
+        return Response::json(['status' => 'fail', 'message' => trans('common.failed_item', ['attribute' => trans('common.toggle')])]);
     }
 
     public function charge(Request $request): ?JsonResponse

+ 4 - 4
app/Models/Marketing.php

@@ -18,10 +18,10 @@ class Marketing extends Model
     {
         return Attribute::make(
             get: fn () => match ($this->status) {
-                -1 => '失败',
-                0 => '待推送',
-                1 => '成功',
-                default => '',
+                -1 => trans('common.failed'),
+                0 => trans('common.status.pending_dispatch'),
+                1 => trans('common.success'),
+                default => trans('common.status.unknown'),
             },
         );
     }

+ 1 - 1
app/Models/Order.php

@@ -207,6 +207,6 @@ class Order extends Model
     // 支付方式
     public function getPayWayLabelAttribute(): string
     {
-        return config('common.payment.labels')[$this->pay_way] ?? '未知';
+        return config('common.payment.labels')[$this->pay_way] ?? trans('common.status.unknown');
     }
 }

+ 1 - 1
app/Models/ReferralLog.php

@@ -61,7 +61,7 @@ class ReferralLog extends Model
             get: fn () => match ($this->status) {
                 1 => '<span class="badge badge-sm badge-info">'.trans('common.status.applying').'</span>',
                 2 => '<span class="badge badge-sm badge-default">'.trans('common.status.withdrawn').'</span>',
-                default => '<span class="badge badge-sm badge-success">'.trans('common.status.unwithdrawn').'</span>',
+                default => '<span class="badge badge-sm badge-success">'.trans('common.status.withdrawal_pending').'</span>',
             },
         );
     }

+ 1 - 1
app/Notifications/Custom.php

@@ -68,7 +68,7 @@ class Custom extends Notification implements ShouldQueue
         return [
             'title' => $this->title,
             'content' => $this->content,
-            'group' => '自定义信息',
+            'group' => trans('common.bark.custom'),
             'icon' => asset('assets/images/notification/custom.png'),
             'sound' => 'newmail',
             'url_type' => 'markdown',

+ 2 - 2
app/Notifications/NodeOffline.php

@@ -35,7 +35,7 @@ class NodeOffline extends Notification implements ShouldQueue
     {
         $content = '';
         foreach ($this->data as $node) {
-            $content .= "- {$node['name']} {$node['host']}\r\n";
+            $content .= "- {$node['name']} {$node['host']}".PHP_EOL;
         }
 
         return $content;
@@ -55,7 +55,7 @@ class NodeOffline extends Notification implements ShouldQueue
         return [
             'title' => trans('notification.node_offline'),
             'content' => $this->stringMessage(),
-            'group' => '节点状态',
+            'group' => trans('common.bark.node_status'),
             'icon' => asset('assets/images/notification/offline.png'),
         ];
     }

+ 8 - 7
app/Notifications/PaymentConfirm.php

@@ -32,7 +32,8 @@ class PaymentConfirm extends Notification
     {
         $order = $this->order;
         $goods = $this->order->goods;
-        $message = sprintf("🛒 人工支付\n———————————————\n\t\tℹ️ 账号:%s\n\t\t💰 金额:%1.2f\n\t\t📦 商品:%s\n\t\t", $order->user->username, $order->amount, $goods->name ?? '余额充值');
+        $message = sprintf('🛒 '.trans('common.payment.manual')."\n———————————————\n\t\tℹ️ ".trans('common.account').": %s\n\t\t💰 ".trans('user.shop.price').":%1.2f\n\t\t📦 ".trans('model.goods.attribute').": %s\n\t\t", $order->user->username,
+            $order->amount, $goods->name ?? trans('user.recharge_credit'));
         foreach (User::role('Super Admin')->get() as $admin) {
             if (! $admin->telegram_user_id) {
                 continue;
@@ -55,22 +56,22 @@ class PaymentConfirm extends Notification
         $goods = $this->order->goods;
 
         return [
-            'title' => '🛒 人工支付',
+            'title' => '🛒 '.trans('common.payment.manual'),
             'body' => [
                 [
-                    'keyname' => 'ℹ️ 账号',
+                    'keyname' => 'ℹ️ '.trans('common.account'),
                     'value' => $order->user->username,
                 ],
                 [
-                    'keyname' => '💰 金额',
+                    'keyname' => '💰 '.trans('user.shop.price'),
                     'value' => sprintf('%1.2f', $order->amount),
                 ],
                 [
-                    'keyname' => '📦 商品',
-                    'value' => $goods->name ?? '余额充值',
+                    'keyname' => '📦 '.trans('model.goods.attribute'),
+                    'value' => $goods->name ?? trans('user.recharge_credit'),
                 ],
             ],
-            'markdown' => '- ℹ️ 账号: '.$order->user->username.PHP_EOL.'- 💰 金额: '.sprintf('%1.2f', $order->amount).PHP_EOL.'- 📦 商品: '.($goods->name ?? '余额充值'),
+            'markdown' => '- ℹ️ '.trans('common.account').': '.$order->user->username.PHP_EOL.'- 💰 '.trans('user.shop.price').': '.sprintf('%1.2f', $order->amount).PHP_EOL.'- 📦 '.trans('user.shop.price').': '.($goods->name ?? trans('user.recharge_credit')),
             'button' => [
                 route('payment.notify', ['method' => 'manual', 'sign' => $this->sign, 'status' => 0]),
                 route('payment.notify', ['method' => 'manual', 'sign' => $this->sign, 'status' => 1]),

+ 1 - 1
app/Notifications/TicketClosed.php

@@ -50,7 +50,7 @@ class TicketClosed extends Notification implements ShouldQueue
         return [
             'title' => trans('notification.close_ticket', ['id' => $this->ticketId, 'title' => $this->title]),
             'content' => $this->reason,
-            'group' => '工单',
+            'group' => trans('user.ticket.attribute'),
             'icon' => asset('assets/images/notification/ticket.png'),
             'url' => $this->url,
         ];

+ 2 - 2
app/Notifications/TicketCreated.php

@@ -58,7 +58,7 @@ class TicketCreated extends Notification implements ShouldQueue
 
     private function markdownMessage($ticket): string
     {
-        return "📮工单提醒 #$ticket->id\n———————————————\n主题:\n`$ticket->title`\n内容:\n`$ticket->content`";
+        return '📮'.trans('admin.system.ticket_created_notification')." #$ticket->id\n———————————————\n".trans('validation.attributes.title').": \n`$ticket->title`\n".trans('validation.attributes.content').": \n`$ticket->content`";
     }
 
     public function toBark($notifiable): array
@@ -66,7 +66,7 @@ class TicketCreated extends Notification implements ShouldQueue
         return [
             'title' => trans('notification.new_ticket', ['title' => $this->ticket->title]),
             'content' => trans('notification.ticket_content').strip_tags($this->ticket->content),
-            'group' => '工单',
+            'group' => trans('user.ticket.attribute'),
             'icon' => asset('assets/images/notification/ticket.png'),
             'url' => $this->url,
         ];

+ 2 - 2
app/Notifications/TicketReplied.php

@@ -58,7 +58,7 @@ class TicketReplied extends Notification implements ShouldQueue
 
     private function markdownMessage(TicketReply $reply): string
     {
-        return "📮工单回复提醒 #{$reply->ticket->id}\n———————————————\n主题:\n`{$reply->ticket->title}`\n内容:\n`$reply->content`";
+        return '📮'.trans('admin.system.ticket_replied_notification')." #{$reply->ticket->id}\n———————————————\n".trans('validation.attributes.title').": \n`{$reply->ticket->title}`\n".trans('validation.attributes.content').": \n`$reply->content`";
     }
 
     public function toBark($notifiable): array
@@ -66,7 +66,7 @@ class TicketReplied extends Notification implements ShouldQueue
         return [
             'title' => trans('notification.reply_ticket', ['title' => $this->reply->ticket->title]),
             'content' => trans('notification.ticket_content').strip_tags($this->reply->content),
-            'group' => '工单',
+            'group' => trans('user.ticket.attribute'),
             'icon' => asset('assets/images/notification/ticket.png'),
             'url' => $this->url,
         ];

+ 2 - 2
app/Observers/OrderObserver.php

@@ -27,7 +27,7 @@ class OrderObserver
                 'level' => 0,
                 'enable' => 0,
             ]);
-            Helpers::addUserTrafficModifyLog($user->id, $user->transfer_enable, 0, __('[Service Timer] Service Expiration'), $order->id);
+            Helpers::addUserTrafficModifyLog($user->id, $user->transfer_enable, 0, trans('[Service Timer] Service Expiration'), $order->id);
 
             Order::userActivePackage($order->user_id)->update(['is_expire' => 1]); // 过期生效中的加油包
             $this->activatePrepaidPlan($order->user_id); // 激活预支付套餐
@@ -73,7 +73,7 @@ class OrderObserver
     private function returnCoupon(Order $order, Coupon $coupon): void
     { // 退回优惠券
         if ($coupon->type !== 3 && ! $coupon->isExpired()) {
-            Helpers::addCouponLog('订单取消, 自动退回', $order->coupon_id, $order->goods_id, $order->id);
+            Helpers::addCouponLog('Order canceled, coupon reinstated.', $order->coupon_id, $order->goods_id, $order->id);
             $coupon->update(['usable_times' => $coupon->usable_times + 1, 'status' => 0]);
         }
     }

+ 1 - 2
app/Services/ArticleService.php

@@ -12,8 +12,7 @@ class ArticleService
     {
         $siteName = sysConfig('website_name');
         $siteUrl = sysConfig('website_url');
-        $subscribe = auth()->user()->subscribe;
-        $subUrl = route('sub', $subscribe->code);
+        $subUrl = auth()->user()?->subUrl();
 
         self::$valuables = [
             '{{siteName}}' => $siteName,

+ 4 - 4
app/Services/CouponService.php

@@ -123,15 +123,15 @@ class CouponService
         $coupon = Coupon::whereSn($this->code)->whereType(3)->first();
         if ($coupon && $coupon->status === 0) {
             try {
-                Helpers::addUserCreditLog($user->id, null, $user->credit, $user->credit + $coupon->value, $coupon->value,
-                    trans('user.recharge').' - ['.trans('admin.coupon.type.charge').':'.$coupon->sn.']'); // 写入用户余额变动日志
                 $user->updateCredit($coupon->value); // 余额充值
+                Helpers::addUserCreditLog($user->id, null, $user->credit, $user->credit + $coupon->value, $coupon->value, 'Recharge using a recharge voucher.'); // 写入用户余额变动日志
+
                 $coupon->used(); // 更改卡券状态
-                Helpers::addCouponLog(trans('user.recharge_credit'), $coupon->id); // 写入卡券使用日志
+                Helpers::addCouponLog('Used for credit recharge.', $coupon->id); // 写入卡券使用日志
 
                 return true;
             } catch (Exception $exception) {
-                Log::emergency('[重置券处理出现错误] '.$exception->getMessage());
+                Log::emergency(trans('common.error_action_item', ['action' => trans('common.apply'), 'attribute' => trans('model.coupon.attribute')]).': '.$exception->getMessage());
             }
         }
 

+ 3 - 3
app/Services/OrderService.php

@@ -62,7 +62,7 @@ class OrderService
         $ret = self::$user->updateCredit($this->order->origin_amount);
         // 余额变动记录日志
         if ($ret) {
-            Helpers::addUserCreditLog($this->order->user_id, $this->order->id, $credit, self::$user->credit, $this->order->amount, '用户通过'.$this->order->pay_way.'充值余额');
+            Helpers::addUserCreditLog($this->order->user_id, $this->order->id, $credit, self::$user->credit, $this->order->amount, 'The user topped up the balance.');
         }
 
         return $ret;
@@ -71,7 +71,7 @@ class OrderService
     private function activatePackage(): bool
     { // 激活流量包
         if (self::$user->incrementData(self::$goods->traffic * MiB)) {
-            return Helpers::addUserTrafficModifyLog($this->order->user_id, self::$user->transfer_enable - self::$goods->traffic * MiB, self::$user->transfer_enable, '['.$this->order->pay_way.']加上用户购买的套餐流量', $this->order->id);
+            return Helpers::addUserTrafficModifyLog($this->order->user_id, self::$user->transfer_enable - self::$goods->traffic * MiB, self::$user->transfer_enable, trans('[:payment] plus the user’s purchased data plan.', ['payment' => $this->order->pay_way]));
         }
 
         return false;
@@ -94,7 +94,7 @@ class OrderService
         }
 
         if (self::$user->update(array_merge($this->resetTimeAndData(), $updateData))) {
-            return Helpers::addUserTrafficModifyLog($this->order->user_id, $oldData, self::$user->transfer_enable, '【'.$this->order->pay_way.'】加上用户购买的套餐流量', $this->order->id);
+            return Helpers::addUserTrafficModifyLog($this->order->user_id, $oldData, self::$user->transfer_enable, trans('[:payment] plus the user’s purchased data plan.', ['payment' => $this->order->pay_way]), $this->order->id);
         }
 
         return false;

+ 1 - 1
app/Utils/Clients/Surge.php

@@ -57,7 +57,7 @@ class Surge implements Client
             $subscribeInfo = "title=$webName, content=";
         }
 
-        return str_replace(['$subscribe_info', '$subs_link', '$subs_domain', '$proxies', '$proxy_group'], [$subscribeInfo, route('sub', $user->subscribe->code), $_SERVER['HTTP_HOST'], $proxyProfiles['proxies'], $proxyProfiles['names']],
+        return str_replace(['$subscribe_info', '$subs_link', '$subs_domain', '$proxies', '$proxy_group'], [$subscribeInfo, $user->subUrl(), $_SERVER['HTTP_HOST'], $proxyProfiles['proxies'], $proxyProfiles['names']],
             $config);
     }
 }

+ 1 - 1
app/Utils/Payments/CodePay.php

@@ -32,7 +32,7 @@ class CodePay extends PaymentService implements Gateway
         $url = sysConfig('codepay_url').http_build_query($data);
         $payment->update(['url' => $url]);
 
-        return Response::json(['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']);
+        return Response::json(['status' => 'success', 'url' => $url, 'message' => trans('user.payment.order_creation.success')]);
     }
 
     public function notify(Request $request): void

+ 1 - 1
app/Utils/Payments/EPay.php

@@ -33,7 +33,7 @@ class EPay extends PaymentService implements Gateway
         $url = sysConfig('epay_url').'submit.php?'.http_build_query($data);
         $payment->update(['url' => $url]);
 
-        return Response::json(['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']);
+        return Response::json(['status' => 'success', 'url' => $url, 'message' => trans('user.payment.order_creation.success')]);
     }
 
     public function notify(Request $request): void

+ 1 - 1
app/Utils/Payments/F2Fpay.php

@@ -46,7 +46,7 @@ class F2Fpay extends PaymentService implements Gateway
             exit;
         }
 
-        return Response::json(['status' => 'success', 'data' => $payment->trade_no, 'message' => '创建订单成功!']);
+        return Response::json(['status' => 'success', 'data' => $payment->trade_no, 'message' => trans('user.payment.order_creation.success')]);
     }
 
     public function notify(Request $request): void

+ 2 - 2
app/Utils/Payments/Local.php

@@ -22,12 +22,12 @@ class Local extends PaymentService implements Gateway
         if ($user && $goods) {
             $user->update(['credit' => $user->credit - $order->amount]);
             // 记录余额操作日志
-            Helpers::addUserCreditLog($user->id, $order->id, $user->credit + $order->amount, $user->credit, -1 * $order->amount, '购买商品'.$goods->name);
+            Helpers::addUserCreditLog($user->id, $order->id, $user->credit + $order->amount, $user->credit, -1 * $order->amount, 'Purchased an item.');
         }
 
         $order->complete();
 
-        return Response::json(['status' => 'success', 'message' => '购买完成!']);
+        return Response::json(['status' => 'success', 'message' => trans('user.purchase.completed')]);
     }
 
     public function notify(Request $request): void

+ 2 - 2
app/Utils/Payments/Manual.php

@@ -21,7 +21,7 @@ class Manual extends PaymentService implements Gateway
         $url = route('manual.checkout', ['payment' => $payment->trade_no]);
         $payment->update(['url' => $url]);
 
-        return Response::json(['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']);
+        return Response::json(['status' => 'success', 'url' => $url, 'message' => trans('user.payment.order_creation.success')]);
     }
 
     public function redirectPage(string $trade_no): View
@@ -43,7 +43,7 @@ class Manual extends PaymentService implements Gateway
         $payment = Payment::uid()->with(['order'])->whereTradeNo($trade_no)->firstOrFail();
         $payment->order->update(['status' => 1]);
 
-        return Response::json(['status' => 'success', 'message' => '我们将在【24小时】内对购买/充值的款项进行开通!请耐心等待']);
+        return Response::json(['status' => 'success', 'message' => trans('user.payment.order_creation.info')]);
     }
 
     public function notify(Request $request)

+ 3 - 3
app/Utils/Payments/PayBeaver.php

@@ -45,21 +45,21 @@ class PayBeaver extends PaymentService implements Gateway
         if (! isset($result['message']) && isset($result['data']['pay_url'])) {
             $payment->update(['url' => $result['data']['pay_url']]);
 
-            return Response::json(['status' => 'success', 'url' => $result['data']['pay_url'], 'message' => '创建订单成功!']);
+            return Response::json(['status' => 'success', 'url' => $result['data']['pay_url'], 'message' => trans('user.payment.order_creation.success')]);
         }
 
         $payment->failed();
         if (isset($result['message'])) {
             Log::alert('【海狸支付】创建订单错误:'.$result['message']);
 
-            return Response::json(['status' => 'fail', 'message' => '创建订单失败:'.$result['message']]);
+            return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.failed')]);
         }
 
         if (! isset($result['data']['pay_url'])) {
             Log::alert('【海狸支付】创建订单错误:未获取到支付链接'.var_export($result, true));
         }
 
-        return Response::json(['status' => 'fail', 'message' => '创建订单失败:未知错误']);
+        return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.failed')]);
     }
 
     private function createOrder(array $params): array

+ 1 - 1
app/Utils/Payments/PayJs.php

@@ -38,7 +38,7 @@ class PayJs extends PaymentService implements Gateway
         $payment->update(['qr_code' => 1, 'url' => $result]);
 
         //$this->addPamentCallback($payment->trade_no, null, $payment->amount * 100);
-        return Response::json(['status' => 'success', 'data' => $payment->trade_no, 'message' => '创建订单成功!']);
+        return Response::json(['status' => 'success', 'data' => $payment->trade_no, 'message' => trans('user.payment.order_creation.success')]);
     }
 
     public function notify(Request $request): void

+ 2 - 2
app/Utils/Payments/PayPal.php

@@ -62,13 +62,13 @@ class PayPal extends PaymentService implements Gateway
         if (isset($response['id']) && $response['id'] != null) {
             Log::error('【Paypal】处理错误:'.var_export($response, true));
 
-            return Response::json(['status' => 'fail', 'message' => '创建订单失败,请使用其他方式或通知管理员!']);
+            return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.failed')]);
         }
         $payment->update(['url' => $response['paypal_link']]);
 
         foreach ($response['links'] as $links) {
             if ($links['rel'] === 'approve') {
-                return Response::json(['status' => 'success', 'url' => $links['href'], 'message' => '创建订单成功!']);
+                return Response::json(['status' => 'success', 'url' => $links['href'], 'message' => trans('user.payment.order_creation.success')]);
             }
         }
 

+ 5 - 5
app/Utils/Payments/Stripe.php

@@ -49,22 +49,22 @@ class Stripe extends PaymentService implements Gateway
                     Log::warning('创建订单错误:未知错误');
                     $payment->failed();
 
-                    return Response::json(['status' => 'fail', 'message' => '创建订单失败:未知错误']);
+                    return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.failed')]);
                 }
                 $payment->update(['qr_code' => 1, 'url' => $source['wechat']['qr_code_url']]);
 
-                return Response::json(['status' => 'success', 'data' => $payment->trade_no, 'message' => '创建订单成功!']);
+                return Response::json(['status' => 'success', 'data' => $payment->trade_no, 'message' => trans('user.payment.order_creation.success')]);
             }
 
             if (! $source['redirect']['url']) {
                 Log::warning('创建订单错误:未知错误');
                 $payment->failed();
 
-                return response()->json(['code' => 0, 'msg' => '创建订单失败:未知错误']);
+                return response()->json(['code' => 0, 'msg' => trans('user.payment.order_creation.failed')]);
             }
             $payment->update(['url' => $source['redirect']['url']]);
 
-            return Response::json(['status' => 'success', 'url' => $source['redirect']['url'], 'message' => '创建订单成功!']);
+            return Response::json(['status' => 'success', 'url' => $source['redirect']['url'], 'message' => trans('user.payment.order_creation.success')]);
         }
 
         $data = $this->getCheckoutSessionData($payment->trade_no, $payment->amount, $type);
@@ -75,7 +75,7 @@ class Stripe extends PaymentService implements Gateway
             $url = route('stripe.checkout', ['session_id' => $session->id]);
             $payment->update(['url' => $url]);
 
-            return Response::json(['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']);
+            return Response::json(['status' => 'success', 'url' => $url, 'message' => trans('user.payment.order_creation.success')]);
         } catch (Exception $e) {
             Log::error('【Stripe】错误: '.$e->getMessage());
             exit;

+ 2 - 2
app/Utils/Payments/THeadPay.php

@@ -31,7 +31,7 @@ class THeadPay extends PaymentService implements Gateway
             if ($result['status'] === 'success') {
                 $payment->update(['qr_code' => 1, 'url' => $result['code_url']]);
 
-                return Response::json(['status' => 'success', 'data' => $payment->trade_no, 'message' => '创建订单成功!']);
+                return Response::json(['status' => 'success', 'data' => $payment->trade_no, 'message' => trans('user.payment.order_creation.success')]);
             }
             $payment->failed();
             Log::error('【平头哥支付】 返回错误信息:'.$result['message']);
@@ -39,7 +39,7 @@ class THeadPay extends PaymentService implements Gateway
 
         Log::alert('【平头哥支付】 支付渠道建立订单出现问题!');
 
-        return Response::json(['status' => 'fail', 'message' => '创建在线订单失败,请工单通知管理员!']);
+        return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.failed')]);
     }
 
     private function sign(array $params): string

+ 12 - 1
resources/lang/de.json

@@ -126,5 +126,16 @@
   "You are receiving this email because we received a password reset request for your account.": "Sie erhalten diese E-Mail, weil wir einen Antrag auf eine Zurücksetzung Ihres Passworts bekommen haben.",
   "You have not responded this ticket in :num hours, System has closed your ticket.": "Sie haben auf dieses Ticket innerhalb von :num Stunden nicht geantwortet, das System hat Ihr Ticket geschlossen.",
   "You must have a valid subscription to view the content in this area!": "Sie müssen ein gültiges Abonnement haben, um den Inhalt in diesem Bereich zu sehen!",
-  "Your subscription has been disabled by the administrator, please contact the administrator to restore it": "Ihr Abonnement wurde vom Administrator deaktiviert, bitte kontaktieren Sie den Administrator, um es wiederherzustellen."
+  "Your subscription has been disabled by the administrator, please contact the administrator to restore it": "Ihr Abonnement wurde vom Administrator deaktiviert, bitte kontaktieren Sie den Administrator, um es wiederherzustellen.",
+  "Manually add in dashboard.": "Manuell im Dashboard hinzufügen",
+  "Manually edit in dashboard.": "Manuell im Dashboard bearbeiten",
+  "Batch generate user accounts in dashboard.": "Benutzerkonten im Hintergrund massenweise erstellen",
+  "Coupon used in order.": "Gutschein im Auftrag verwendet",
+  "Order canceled, coupon reinstated.": "Bestellung storniert, Gutschein wiederhergestellt",
+  "Used for credit recharge.": "Zur Aufladung des Guthabens verwendet",
+  "The user manually reset the data.": "Benutzer hat Daten zurückgesetzt",
+  "Recharge using a recharge voucher.": "Mit einem Aufladegutschein aufladen",
+  "The user topped up the balance.": "Der Benutzer hat das Guthaben aufgeladen",
+  "Purchased an item.": "Einen Artikel gekauft",
+  "[:payment] plus the user’s purchased data plan.": "[:payment] plus das vom Benutzer gekaufte Datenpaket"
 }

File diff suppressed because it is too large
+ 363 - 494
resources/lang/de/admin.php


+ 1 - 12
resources/lang/de/auth.php

@@ -40,27 +40,18 @@ return [
     ],
     'failed' => 'Diese Kombination aus Zugangsdaten wurde nicht in unserer Datenbank gefunden.',
     'invite' => [
-        'attribute' => 'Einladungscode',
-        'error' => [
-            'unavailable' => 'Ungültiger Einladungscode, bitte erneut versuchen.',
-        ],
         'get' => 'Einladungscode erhalten',
         'not_required' => 'Kein Einladungscode erforderlich, Sie können sich direkt registrieren!',
+        'unavailable' => 'Ungültiger Einladungscode, bitte erneut versuchen.',
     ],
     'login' => 'Anmelden',
     'logout' => 'Abmelden',
     'maintenance' => 'Wartung',
     'maintenance_tip' => 'In Wartung',
     'oauth' => [
-        'bind_failed' => 'Bindung fehlgeschlagen',
-        'bind_success' => 'Bindung erfolgreich',
         'login_failed' => 'Drittanbieter-Anmeldung fehlgeschlagen!',
-        'rebind_success' => 'Neubindung erfolgreich',
         'register' => 'Schnellregistrierung',
-        'register_failed' => 'Registrierung fehlgeschlagen',
         'registered' => 'Bereits registriert, bitte direkt anmelden.',
-        'unbind_failed' => 'Entbindung fehlgeschlagen',
-        'unbind_success' => 'Entbindung erfolgreich',
     ],
     'one-click_login' => 'Ein-Klick-Anmeldung',
     'optional' => 'Optional',
@@ -73,7 +64,6 @@ return [
             'error' => [
                 'demo' => 'Ändern des Administratorpassworts im Demomodus nicht möglich.',
                 'disabled' => 'Passwortzurücksetzung deaktiviert, bitte kontaktieren Sie :email für Unterstützung.',
-                'failed' => 'Passwortzurücksetzung fehlgeschlagen.',
                 'same' => 'Das neue Passwort darf nicht mit dem alten übereinstimmen, bitte erneut eingeben.',
                 'throttle' => 'Sie können das Passwort nur :time Mal in 24 Stunden zurücksetzen, bitte nicht zu häufig operieren.',
                 'wrong' => 'Falsches Passwort, bitte erneut versuchen.',
@@ -91,7 +81,6 @@ return [
         ],
         'failed' => 'Registrierung fehlgeschlagen, bitte später erneut versuchen.',
         'promotion' => 'Noch kein Konto? Bitte gehen Sie zu ',
-        'success' => 'Erfolgreich registriert',
     ],
     'remember_me' => 'Angemeldet bleiben',
     'request' => 'Anfordern',

+ 97 - 89
resources/lang/de/common.php

@@ -3,141 +3,149 @@
 declare(strict_types=1);
 
 return [
-    'hour' => '{1} Stunde|{2} Uhr',
     'account' => 'Konto',
+    'action' => 'Aktion',
+    'active_item' => 'Aktivieren :attribute',
+    'add' => 'Hinzufügen',
+    'advance' => 'Fortgeschritten',
+    'all' => 'Alle',
+    'applied' => ':attribute angewendet',
+    'apply' => 'Anwenden',
     'available_date' => 'Gültigkeitszeitraum',
-    'created_at' => 'Erstellungsdatum',
-    'expired_at' => 'Ablaufdatum',
-    'updated_at' => 'Zuletzt aktualisiert',
-    'latest_at' => 'Letzte Aktivität',
+    'avatar' => 'Avatar',
     'back' => 'Zurück',
     'back_to' => 'Zurück zu :page',
+    'bark' => [
+        'custom' => 'Benutzerdefinierte Informationen',
+        'node_status' => 'Knotenzustand',
+    ],
     'cancel' => 'Abbrechen',
+    'change' => 'Ändern',
     'close' => 'Schließen',
     'close_item' => 'Schließen :attribute',
     'confirm' => 'Bestätigen',
     'continue' => 'Fortsetzen',
-    'open' => 'Öffnen',
-    'send' => 'Senden',
-    'view' => 'Ansehen',
-    'reset' => 'Zurücksetzen',
+    'convert' => 'Konvertieren',
     'copy' => [
         'attribute' => 'Kopieren',
-        'success' => 'Erfolgreich kopiert',
         'failed' => 'Kopieren fehlgeschlagen, bitte manuell kopieren',
+        'success' => 'Erfolgreich kopiert',
     ],
-    'add' => 'Hinzufügen',
-    'free' => 'Kostenlos',
-    'change' => 'Ändern',
-    'submit' => 'Absenden',
-    'submit_item' => 'Absenden :attribute',
-    'generate' => 'Erzeugen',
-    'generate_item' => 'Erzeugen :attribute',
-    'to_safari' => [0 => 'Klicken Sie auf die obere rechte Ecke', 1 => ', dann wählen Sie', 2 => 'In Safari öffnen', 3 => ' um diese Seite korrekt anzuzeigen!'],
-    'update_browser' => [0 => 'Sie verwenden einen ', 1 => 'veralteten', 2 => ' Browser. Bitte', 3 => 'aktualisieren Sie Ihren Browser', 4 => ' für das beste Erlebnis'],
-    'apply' => 'Anwenden',
-    'avatar' => 'Avatar',
+    'create' => 'Erstellen',
+    'created_at' => 'Erstellungsdatum',
     'customize' => 'Anpassen',
-    'all' => 'Alle',
-    'default' => 'Standard',
-    'download' => 'Herunterladen',
-    'goto' => 'Gehe zu',
-    'warning' => 'Warnung',
-    'success' => 'Erfolg',
-    'success_item' => ':attribute erfolgreich',
-    'failed' => 'Fehlgeschlagen',
-    'failed_item' => ':attribute fehlgeschlagen',
-    'update' => 'Aktualisieren',
-    'update_action' => 'Aktualisieren :action',
-    'none' => 'Keine',
-    'new' => 'Neu',
-    'sorry' => 'Entschuldigung',
-    'applied' => ':attribute angewendet',
-    'active_item' => 'Aktivieren :attribute',
-    'error' => 'Fehler',
-    'toggle' => 'Umschalten',
-    'toggle_action' => 'Umschalten :action',
-    'request_url' => 'Anfrage-URL',
-    'function' => [
-        'navigation' => 'Navigation',
-        'menubar' => 'Menüleiste',
-        'fullscreen' => 'Vollbild',
-    ],
     'days' => [
         'attribute' => '{1} Tag|{2} Tage',
+        'next' => 'Nächster Tag',
         'weekend' => 'Wochenende',
         'work' => 'Wochentag',
-        'next' => 'Nächster Tag',
     ],
-    'qrcode' => ':attribute QR-Code',
+    'default' => 'Standard',
+    'delete' => 'Löschen',
     'deleted' => 'Gelöscht',
     'deleted_item' => ':attribute gelöscht',
-    'print' => 'Drucken',
-    'unlimited' => 'Unbegrenzt',
-    'payment' => [
-        'credit' => 'Guthaben',
-        'alipay' => 'Alipay',
-        'qq' => 'QQ Wallet',
-        'wechat' => 'WeChat Pay',
-        'crypto' => 'Kryptowährung',
-        'manual' => 'Manuelle Zahlung',
-        'status' => [
-            'wait' => 'Warten auf Zahlung',
-        ],
+    'developing' => 'In Entwicklung! Bleiben Sie dran',
+    'download' => 'Herunterladen',
+    'edit' => 'Bearbeiten',
+    'error' => 'Fehler',
+    'error_action_item' => ':action:attribute-Fehler',
+    'error_item' => ':attribute-Fehler',
+    'exists_error' => 'Unter :attribute gibt es verknüpfte Konten. Bitte trennen Sie diese zuerst!',
+    'expired_at' => 'Ablaufdatum',
+    'export' => 'Exportieren',
+    'failed' => 'Fehlgeschlagen',
+    'failed_action_item' => ':action:attribute fehlgeschlagen',
+    'failed_item' => ':attribute fehlgeschlagen',
+    'free' => 'Kostenlos',
+    'function' => [
+        'fullscreen' => 'Vollbild',
+        'menubar' => 'Menüleiste',
+        'navigation' => 'Navigation',
     ],
+    'generate' => 'Erzeugen',
+    'generate_item' => 'Erzeugen :attribute',
+    'goto' => 'Gehe zu',
+    'hour' => '{1} Stunde|{2} Uhr',
+    'import' => 'Importieren',
+    'latest_at' => 'Letzte Aktivität',
+    'more' => 'Mehr',
+    'new' => 'Neu',
+    'none' => 'Keine',
+    'open' => 'Öffnen',
+    'or' => 'oder',
     'order' => [
         'status' => [
             'canceled' => 'Storniert',
             'completed' => 'Abgeschlossen',
-            'prepaid' => 'Vorausbezahlt',
             'ongoing' => 'Laufend',
+            'prepaid' => 'Vorausbezahlt',
             'review' => 'Zur Überprüfung',
         ],
     ],
+    'payment' => [
+        'alipay' => 'Alipay',
+        'credit' => 'Guthaben',
+        'crypto' => 'Kryptowährung',
+        'manual' => 'Manuelle Zahlung',
+        'qq' => 'QQ Wallet',
+        'wechat' => 'WeChat Pay',
+    ],
+    'print' => 'Drucken',
+    'qrcode' => ':attribute QR-Code',
+    'random_generate' => 'Leer lassen, um zufällig zu generieren',
     'recommend' => 'Empfehlen',
-    'advance' => 'Fortgeschritten',
-    'action' => 'Aktion',
+    'request' => 'Anfrage',
+    'request_failed' => 'Anfrage fehlgeschlagen, bitte erneut versuchen',
+    'request_url' => 'Anfrage-URL',
+    'reset' => 'Zurücksetzen',
     'search' => 'Suchen',
-    'edit' => 'Bearbeiten',
-    'delete' => 'Löschen',
+    'send' => 'Senden',
+    'sorry' => 'Entschuldigung',
     'status' => [
+        'applying' => 'Anwendung läuft',
         'attribute' => 'Status',
-        'inactive' => 'Inaktiv',
-        'disabled' => 'Deaktiviert',
+        'available' => 'Verfügbar',
         'banned' => 'Gesperrt',
-        'normal' => 'Normal',
+        'closed' => 'Geschlossen',
+        'disabled' => 'Deaktiviert',
         'enabled' => 'Aktiviert',
         'expire' => 'Abgelaufen',
+        'inactive' => 'Inaktiv',
         'limited' => 'Begrenzt',
-        'run_out' => 'Datenverbrauch aufgebraucht',
-        'unused' => 'Nicht verwendet',
-        'used' => 'Verwendet',
-        'closed' => 'Geschlossen',
-        'applying' => 'Anwendung läuft',
-        'withdrawn' => 'Abgehoben',
-        'unwithdrawn' => 'Nicht abgehoben',
-        'reply' => 'Beantwortet',
+        'normal' => 'Normal',
+        'paid' => 'Bezahlt',
+        'pass' => 'Bestanden',
+        'payment_pending' => 'Zahlung ausstehend',
         'pending' => 'Ausstehend',
-        'unknown' => 'Unbekannt',
-        'available' => 'Verfügbar',
+        'pending_dispatch' => 'Ausstehende Lieferung',
         'reject' => 'Ablehnen',
         'rejected' => 'Abgelehnt',
+        'reply' => 'Beantwortet',
         'review' => 'Zur Überprüfung',
         'reviewed' => 'Überprüft',
-        'paid' => 'Bezahlt',
-        'payment_pending' => 'Zahlung ausstehend',
-        'pass' => 'Bestanden',
+        'run_out' => 'Datenverbrauch aufgebraucht',
         'send_to_credit' => 'Zum Guthaben hinzufügen',
-        'waiting_tobe_send' => 'Warten auf Versand',
+        'unknown' => 'Unbekannt',
+        'unused' => 'Nicht verwendet',
+        'used' => 'Verwendet',
+        'withdrawal_pending' => 'Nicht abgehoben',
+        'withdrawn' => 'Abgehoben',
     ],
     'stay_unchanged' => 'Leer lassen, um unverändert zu bleiben',
-    'random_generate' => 'Leer lassen, um zufällig zu generieren',
-    'request_failed' => 'Anfrage fehlgeschlagen, bitte erneut versuchen',
-    'convert' => 'Konvertieren',
-    'import' => 'Importieren',
-    'or' => 'oder',
-    'more' => 'Mehr',
+    'storage_logo' => 'Logo-Speicher',
+    'store' => 'Speicher',
+    'submit' => 'Absenden',
+    'success' => 'Erfolg',
+    'success_action_item' => ':action:attribute erfolgreich',
+    'success_item' => ':attribute erfolgreich',
     'to' => 'zu',
     'to_be_send' => 'Zu senden',
-    'developing' => 'In Entwicklung! Bleiben Sie dran',
+    'to_safari' => 'Klicken Sie auf das <i class="icon wb-more-horizontal" aria-hidden="true"></i>-Symbol in der oberen rechten Ecke und wählen Sie "In <img class="w-30 h-30 vertical-align-middle m-3" src="https://gw.alicdn.com/tfs/TB1xwiUNpXXXXaIXXXXXXXXXXXX-55-55.png" alt="Safari" /> Safari öffnen", um unsere Website ordnungsgemäß zu besuchen!',
+    'toggle' => 'Umschalten',
+    'toggle_action' => 'Umschalten :action',
+    'unlimited' => 'Unbegrenzt',
+    'update' => 'Aktualisieren',
+    'updated_at' => 'Zuletzt aktualisiert',
+    'view' => 'Ansehen',
+    'warning' => 'Warnung',
 ];

+ 13 - 13
resources/lang/de/errors.php

@@ -8,29 +8,29 @@ return [
         'bots' => 'Bot-Zugriff erkannt, Zugriff verweigert',
         'china' => 'China-IP oder Proxy-Zugriff erkannt, Zugriff verweigert',
         'oversea' => 'Übersee-IP oder Proxy-Zugriff erkannt, Zugriff verweigert',
-        'unknown' => 'Unbekannter verbotener Zugriffsmodus! Bitte ändern Sie den [Zugriffsbeschränkung] in den Systemeinstellungen!',
         'redirect' => '(:ip :url) wurde beim Zugriff über einen Abonnement-Link erkannt, erzwungene Weiterleitung.',
+        'unknown' => 'Unbekannter verbotener Zugriffsmodus! Bitte ändern Sie den [Zugriffsbeschränkung] in den Systemeinstellungen!',
     ],
+    'get_ip' => 'Fehler beim Abrufen der IP-Informationen',
     'log' => 'Protokoll',
     'refresh' => 'Aktualisieren',
     'refresh_page' => 'Bitte aktualisieren Sie die Seite und versuchen Sie es erneut',
     'report' => 'Der Fehler trug einen Bericht: ',
-    'safe_enter' => 'Sicherer Eingang',
     'safe_code' => 'Bitte geben Sie den Sicherheitscode ein',
-    'title' => '⚠️ Fehler ausgelöst',
-    'unsafe_enter' => 'Unsicherer Eingang',
-    'visit' => 'Bitte besuchen Sie',
-    'whoops' => 'Hoppla!',
-    'get_ip' => 'Fehler beim Abrufen der IP-Informationen',
+    'safe_enter' => 'Sicherer Eingang',
     'subscribe' => [
-        'unknown' => 'Ungültiger Abonnementlink! Bitte holen Sie sich einen neuen!',
-        'sub_banned' => 'Abonnement gesperrt! Besuchen Sie die Website für Details',
-        'user' => 'Ungültige URL, Konto existiert nicht!',
-        'user_disabled' => 'Konto deaktiviert! Kontaktieren Sie den Support!',
         'banned_until' => 'Konto bis :time gesperrt, bitte warten Sie auf die Freischaltung!',
-        'out' => 'KEINE DATEN MEHR! Bitte kaufen Sie mehr oder setzen Sie die Daten zurück!',
         'expired' => 'Konto abgelaufen! Bitte erneuern Sie Ihr Abonnement!',
-        'question' => 'Konto-Probleme!? Besuchen Sie die Website für Details',
         'none' => 'Keine verfügbaren Knoten',
+        'out' => 'KEINE DATEN MEHR! Bitte kaufen Sie mehr oder setzen Sie die Daten zurück!',
+        'question' => 'Konto-Probleme!? Besuchen Sie die Website für Details',
+        'sub_banned' => 'Abonnement gesperrt! Besuchen Sie die Website für Details',
+        'unknown' => 'Ungültiger Abonnementlink! Bitte holen Sie sich einen neuen!',
+        'user' => 'Ungültige URL, Konto existiert nicht!',
+        'user_disabled' => 'Konto deaktiviert! Kontaktieren Sie den Support!',
     ],
+    'title' => '⚠️ Fehler ausgelöst',
+    'unsafe_enter' => 'Unsicherer Eingang',
+    'visit' => 'Bitte besuchen Sie',
+    'whoops' => 'Hoppla!',
 ];

+ 151 - 150
resources/lang/de/model.php

@@ -3,105 +3,114 @@
 declare(strict_types=1);
 
 return [
-    'user' => [
-        'id' => 'Benutzer-ID',
-        'attribute' => 'Benutzer',
-        'nickname' => 'Spitzname',
-        'username' => 'Benutzername',
-        'password' => 'Passwort',
-        'credit' => 'Guthaben',
-        'invite_num' => 'Verfügbare Einladungen',
-        'reset_date' => 'Datenrückstellungsdatum',
-        'port' => 'Port',
-        'traffic_used' => 'Verwendete Daten',
-        'service' => 'Proxy-Dienst',
-        'group' => 'Gruppe',
-        'account_status' => 'Kontostatus',
-        'proxy_status' => 'Proxy-Status',
-        'expired_date' => 'Ablaufdatum',
-        'role' => 'Rolle',
-        'wechat' => 'WeChat',
-        'qq' => 'QQ',
-        'remark' => 'Bemerkung',
-        'uuid' => 'VMess UUID',
-        'proxy_passwd' => 'Proxy-Passwort',
-        'proxy_method' => 'Verschlüsselung',
-        'usable_traffic' => 'Verfügbare Daten',
-        'proxy_protocol' => 'Protokoll',
-        'proxy_obfs' => 'Verschleierung',
-        'speed_limit' => 'Geschwindigkeitsbegrenzung',
-        'inviter' => 'Einlader',
-        'created_date' => 'Registrierungsdatum',
+    'aff' => [
+        'amount' => 'Bestellbetrag',
+        'commission' => 'Provision',
+        'created_at' => 'Bestellt am',
+        'invitee' => 'Käufer',
+        'updated_at' => 'Bearbeitet am',
+    ],
+    'article' => [
+        'attribute' => 'Artikel',
+        'category' => 'Kategorie',
+        'created_at' => 'Veröffentlicht am',
+        'language' => 'Sprache',
+        'logo' => 'Cover',
+        'updated_at' => 'Aktualisiert am',
     ],
     'common' => [
+        'description' => 'Beschreibung',
         'extend' => 'Erweiterte Informationen',
+        'level' => 'Stufe',
         'sort' => 'Sortieren',
-        'description' => 'Beschreibung',
         'type' => 'Typ',
-        'level' => 'Stufe',
     ],
     'country' => [
         'code' => 'Ländercode',
         'icon' => 'Flagge',
         'name' => 'Ländername',
     ],
-    'subscribe' => [
-        'code' => 'Abonnementcode',
-        'req_times' => 'Anfragenanzahl',
-        'updated_at' => 'Letzte Anfrage',
-        'ban_time' => 'Sperrzeit',
-        'ban_desc' => 'Sperrgrund',
-        'req_ip' => 'Anfrage-IP',
-        'req_header' => 'Anfrage-Header',
+    'coupon' => [
+        'attribute' => 'Gutschein',
+        'groups' => 'Gruppenbeschränkung',
+        'levels' => 'Stufenbeschränkung',
+        'logo' => 'Logo',
+        'minimum' => 'Mindestbestellwert',
+        'name' => 'Name',
+        'newbie' => 'Nur für neue Benutzer',
+        'num' => 'Anzahl',
+        'priority' => 'Priorität',
+        'services_blacklist' => 'Blacklist-Produkte',
+        'services_whitelist' => 'Whitelist-Produkte',
+        'sn' => 'Code',
+        'usable_times' => 'Verwendungsbeschränkung',
+        'used' => 'Persönliche Begrenzung',
+        'users_blacklist' => 'Blacklist-Benutzer',
+        'users_whitelist' => 'Whitelist-Benutzer',
+        'value' => 'Wert',
     ],
-    'oauth' => [
-        'type' => 'Kanal',
-        'identifier' => 'Kennung',
+    'goods' => [
+        'attribute' => 'Produkt',
+        'available_date' => 'Gültigkeitszeitraum',
+        'category' => 'Kategorie',
+        'color' => 'Farbe',
+        'hot' => 'Bestseller',
+        'info' => 'Benutzerdefinierte Informationen',
+        'invite_num' => 'Bonus-Einladungen',
+        'limit_num' => 'Kaufbegrenzung',
+        'logo' => 'Logo',
+        'name' => 'Name',
+        'period' => 'Reset-Zyklus',
+        'price' => 'Preis',
+        'renew' => 'Datenverlängerungspreis',
+        'traffic' => 'Datenvolumen',
+        'user_limit' => 'Benutzergeschwindigkeitsbegrenzung',
     ],
-    'user_group' => [
-        'attribute' => 'Benutzergruppe',
-        'name' => 'Gruppenname',
-        'nodes' => 'Knoten',
+    'ip' => [
+        'info' => 'Standort',
+        'network_type' => 'Netzwerktyp',
     ],
     'node' => [
         'attribute' => 'Knoten',
-        'id' => 'Knoten-ID',
-        'name' => 'Name',
-        'domain' => 'Domain',
-        'static' => 'Status',
-        'online_user' => 'Online-Benutzer',
+        'client_limit' => 'Gerätebegrenzung',
+        'country' => 'Land',
         'data_consume' => 'Datenverbrauch',
         'data_rate' => 'Datenrate',
         'ddns' => 'DDNS',
+        'detection' => 'Blockierungserkennung',
+        'display' => 'Anzeige & Abonnement',
+        'domain' => 'Domain',
+        'id' => 'Knoten-ID',
         'ipv4' => 'IPv4',
         'ipv6' => 'IPv6',
-        'push_port' => 'Push-Port',
-        'rule_group' => 'Regelgruppe',
-        'traffic_limit' => 'Geschwindigkeitsbegrenzung',
-        'client_limit' => 'Gerätebegrenzung',
         'label' => 'Label',
-        'country' => 'Land',
-        'udp' => 'UDP',
-        'display' => 'Anzeige & Abonnement',
-        'detection' => 'Blockierungserkennung',
         'method' => 'Verschlüsselung',
-        'protocol' => 'Protokoll',
-        'protocol_param' => 'Protokollparameter',
+        'name' => 'Name',
+        'next_renewal_date' => 'Nächstes Verlängerungsdatum',
         'obfs' => 'Obfs',
         'obfs_param' => 'Obfs-Parameter',
-        'single' => 'Einzelport',
-        'transfer' => 'Relay',
+        'online_user' => 'Online-Benutzer',
+        'protocol' => 'Protokoll',
+        'protocol_param' => 'Protokollparameter',
+        'push_port' => 'Push-Port',
+        'relay_port' => 'Relay-Port',
+        'renewal_cost' => 'Rechnungsbetrag',
         'service_port' => 'Service-Port',
+        'single' => 'Einzelport',
         'single_passwd' => '[Einzel] Passwort',
+        'static' => 'Status',
+        'subscription_term' => 'Abonnementdauer',
+        'traffic_limit' => 'Geschwindigkeitsbegrenzung',
+        'transfer' => 'Relay',
+        'udp' => 'UDP',
         'v2_alter_id' => 'Alter ID',
-        'v2_net' => 'Netzwerk',
         'v2_cover' => 'Cover',
         'v2_host' => 'Host',
+        'v2_net' => 'Netzwerk',
         'v2_path' => 'Pfad | Schlüssel',
         'v2_sni' => 'SNI',
         'v2_tls' => 'TLS',
         'v2_tls_provider' => 'TLS-Konfiguration',
-        'relay_port' => 'Relay-Port',
     ],
     'node_auth' => [
         'attribute' => 'Knotenauthentifizierung',
@@ -111,36 +120,44 @@ return [
     'node_cert' => [
         'attribute' => 'Domain-Zertifikat',
         'domain' => 'Domain',
+        'expired_date' => 'Ablaufdatum',
+        'issuer' => 'Aussteller',
         'key' => 'Schlüssel',
         'pem' => 'PEM',
-        'issuer' => 'Aussteller',
         'signed_date' => 'Ausstellungsdatum',
-        'expired_date' => 'Ablaufdatum',
+    ],
+    'notification' => [
+        'address' => 'Empfänger',
+        'created_at' => 'Gesendet am',
+        'status' => 'Status',
+    ],
+    'oauth' => [
+        'identifier' => 'Kennung',
+        'type' => 'Kanal',
     ],
     'order' => [
         'attribute' => 'Bestellung',
         'id' => 'Bestellnummer',
         'original_price' => 'Originalpreis',
-        'price' => 'Tatsächlicher Preis',
         'pay_way' => 'Zahlungsmethode',
+        'price' => 'Tatsächlicher Preis',
         'status' => 'Status',
     ],
-    'goods' => [
-        'attribute' => 'Produkt',
+    'permission' => [
+        'attribute' => 'Berechtigung',
+        'description' => 'Beschreibung',
+        'name' => 'Routenname',
+    ],
+    'referral' => [
+        'amount' => 'Betrag',
+        'created_at' => 'Beantragt am',
+        'id' => 'Antragsnummer',
+        'user' => 'Antragsteller',
+    ],
+    'role' => [
+        'attribute' => 'Rolle',
         'name' => 'Name',
-        'price' => 'Preis',
-        'category' => 'Kategorie',
-        'renew' => 'Datenverlängerungspreis',
-        'user_limit' => 'Benutzergeschwindigkeitsbegrenzung',
-        'period' => 'Reset-Zyklus',
-        'traffic' => 'Datenvolumen',
-        'invite_num' => 'Bonus-Einladungen',
-        'limit_num' => 'Kaufbegrenzung',
-        'available_date' => 'Gültigkeitszeitraum',
-        'hot' => 'Bestseller',
-        'color' => 'Farbe',
-        'logo' => 'Logo',
-        'info' => 'Benutzerdefinierte Informationen',
+        'permissions' => 'Berechtigungen',
     ],
     'rule' => [
         'attribute' => 'Regel',
@@ -150,83 +167,67 @@ return [
     'rule_group' => [
         'attribute' => 'Regelgruppe',
         'name' => 'Name',
-        'type' => 'Typ',
         'rules' => 'Regeln',
+        'type' => 'Typ',
     ],
-    'role' => [
-        'attribute' => 'Rolle',
-        'name' => 'Name',
-        'permissions' => 'Berechtigungen',
-    ],
-    'permission' => [
-        'attribute' => 'Berechtigung',
-        'description' => 'Beschreibung',
-        'name' => 'Routenname',
-    ],
-    'article' => [
-        'attribute' => 'Artikel',
-        'category' => 'Kategorie',
-        'language' => 'Sprache',
-        'logo' => 'Cover',
-        'created_at' => 'Veröffentlicht am',
-        'updated_at' => 'Aktualisiert am',
-    ],
-    'coupon' => [
-        'attribute' => 'Gutschein',
-        'name' => 'Name',
-        'sn' => 'Code',
-        'logo' => 'Logo',
-        'value' => 'Wert',
-        'priority' => 'Priorität',
-        'usable_times' => 'Verwendungsbeschränkung',
-        'minimum' => 'Mindestbestellwert',
-        'used' => 'Persönliche Begrenzung',
-        'levels' => 'Stufenbeschränkung',
-        'groups' => 'Gruppenbeschränkung',
-        'users_whitelist' => 'Whitelist-Benutzer',
-        'users_blacklist' => 'Blacklist-Benutzer',
-        'services_whitelist' => 'Whitelist-Produkte',
-        'services_blacklist' => 'Blacklist-Produkte',
-        'newbie' => 'Nur für neue Benutzer',
-        'num' => 'Anzahl',
+    'subscribe' => [
+        'ban_desc' => 'Sperrgrund',
+        'ban_time' => 'Sperrzeit',
+        'code' => 'Abonnementcode',
+        'req_header' => 'Anfrage-Header',
+        'req_ip' => 'Anfrage-IP',
+        'req_times' => 'Anfragenanzahl',
+        'updated_at' => 'Letzte Anfrage',
     ],
-    'aff' => [
-        'invitee' => 'Käufer',
-        'amount' => 'Bestellbetrag',
-        'commission' => 'Provision',
-        'updated_at' => 'Bearbeitet am',
-        'created_at' => 'Bestellt am',
+    'user' => [
+        'account_status' => 'Kontostatus',
+        'attribute' => 'Benutzer',
+        'created_date' => 'Registrierungsdatum',
+        'credit' => 'Guthaben',
+        'expired_date' => 'Ablaufdatum',
+        'id' => 'Benutzer-ID',
+        'invite_num' => 'Verfügbare Einladungen',
+        'inviter' => 'Einlader',
+        'nickname' => 'Spitzname',
+        'password' => 'Passwort',
+        'port' => 'Port',
+        'proxy_method' => 'Verschlüsselung',
+        'proxy_obfs' => 'Verschleierung',
+        'proxy_passwd' => 'Proxy-Passwort',
+        'proxy_protocol' => 'Protokoll',
+        'proxy_status' => 'Proxy-Status',
+        'qq' => 'QQ',
+        'remark' => 'Bemerkung',
+        'reset_date' => 'Datenrückstellungsdatum',
+        'role' => 'Rolle',
+        'service' => 'Proxy-Dienst',
+        'speed_limit' => 'Geschwindigkeitsbegrenzung',
+        'traffic_used' => 'Verwendete Daten',
+        'usable_traffic' => 'Verfügbare Daten',
+        'username' => 'Benutzername',
+        'uuid' => 'VMess UUID',
+        'wechat' => 'WeChat',
     ],
-    'referral' => [
-        'created_at' => 'Beantragt am',
-        'user' => 'Antragsteller',
+    'user_credit' => [
+        'after' => 'Nachher',
         'amount' => 'Betrag',
-        'id' => 'Antragsnummer',
+        'before' => 'Vorher',
+        'created_at' => 'Geändert am',
     ],
-    'notification' => [
-        'address' => 'Empfänger',
-        'created_at' => 'Gesendet am',
-        'status' => 'Status',
+    'user_data_modify' => [
+        'after' => 'Nachher',
+        'before' => 'Vorher',
+        'created_at' => 'Geändert am',
     ],
-    'ip' => [
-        'network_type' => 'Netzwerktyp',
-        'info' => 'Standort',
+    'user_group' => [
+        'attribute' => 'Benutzergruppe',
+        'name' => 'Gruppenname',
+        'nodes' => 'Knoten',
     ],
     'user_traffic' => [
-        'upload' => 'Upload',
         'download' => 'Download',
-        'total' => 'Gesamt',
         'log_time' => 'Protokolliert am',
-    ],
-    'user_data_modify' => [
-        'before' => 'Vorher',
-        'after' => 'Nachher',
-        'created_at' => 'Geändert am',
-    ],
-    'user_credit' => [
-        'before' => 'Vorher',
-        'after' => 'Nachher',
-        'amount' => 'Betrag',
-        'created_at' => 'Geändert am',
+        'total' => 'Gesamt',
+        'upload' => 'Upload',
     ],
 ];

+ 33 - 19
resources/lang/de/notification.php

@@ -3,35 +3,49 @@
 declare(strict_types=1);
 
 return [
-    'attribute' => 'Benachrichtigung',
-    'new' => '{1} Sie haben :num neue Nachricht|[1,*] Sie haben :num neue Nachrichten',
-    'empty' => 'Sie haben keine neuen Nachrichten',
-    'payment_received' => 'Zahlung erhalten, Betrag: :amount. Bestelldetails anzeigen',
     'account_expired' => 'Erinnerung an das Ablaufen des Kontos',
-    'account_expired_content' => 'Ihr Konto läuft in :days Tagen ab. Bitte erneuern Sie es rechtzeitig, um die Dienste weiterhin nutzen zu können.',
     'account_expired_blade' => 'Ihr Konto läuft in :days Tagen ab, bitte erneuern Sie es rechtzeitig',
+    'account_expired_content' => 'Ihr Konto läuft in :days Tagen ab. Bitte erneuern Sie es rechtzeitig, um die Dienste weiterhin nutzen zu können.',
     'active_email' => 'Bitte verifizieren Sie innerhalb von 30 Minuten',
+    'attribute' => 'Benachrichtigung',
+    'block_report' => 'Blockierungsbericht:',
     'close_ticket' => 'Ticket :id: :title wurde geschlossen',
-    'view_web' => 'Website anzeigen',
-    'view_ticket' => 'Ticket anzeigen',
+    'data_anomaly' => 'Warnung: Datenanomalie',
+    'data_anomaly_content' => 'Benutzer :id: [Upload: :upload | Download: :download | Gesamt: :total] in der letzten Stunde',
+    'details' => 'Einzelheiten anzeigen',
+    'details_btn' => 'Bitte klicken Sie auf die Schaltfläche unten, um die Einzelheiten anzuzeigen.',
+    'ding_bot_limit' => 'Jeder Bot darf maximal 20 Nachrichten pro Minute in die Gruppe senden. Bei Überschreiten dieses Limits wird eine Drosselung von 10 Minuten angewendet.',
+    'empty' => 'Sie haben keine neuen Nachrichten',
+    'error' => '[:channel] Nachrichtenschub mit Ausnahme: :reason',
+    'get_access_token_failed' => 'Fehler beim Abrufen des Zugriffstokens!\nMit Anforderungsparametern: :body',
+    'into_maintenance' => 'Automatisch in den Wartungsmodus wechseln',
+    'new' => '{1} Sie haben :num neue Nachricht|[1,*] Sie haben :num neue Nachrichten',
     'new_ticket' => 'Neues Ticket erhalten: :title',
-    'reply_ticket' => 'Ticket beantwortet: :title',
-    'ticket_content' => 'Ticketinhalt:',
+    'next_check_time' => 'Nächste Knotensperrungserkennung: :time',
+    'node' => [
+        'download' => 'Download',
+        'total' => 'Gesamt',
+        'upload' => 'Upload',
+    ],
     'node_block' => 'Warnung: Node-Blockierung',
     'node_offline' => 'Warnung: Node offline',
     'node_offline_content' => 'Folgende Nodes sind möglicherweise offline:',
-    'block_report' => 'Blockierungsbericht:',
-    'traffic_warning' => 'Warnung: Datenverbrauch',
+    'node_renewal' => 'Erinnerung zur Verlängerung des Knotens',
+    'node_renewal_blade' => 'Die folgenden Knoten stehen kurz vor dem Ablauf. Bitte verlängern Sie rechtzeitig: :nodes',
+    'node_renewal_content' => 'Die folgenden Knoten stehen kurz vor dem Ablauf. Bitte verlängern Sie vor Ablauf, um Unterbrechungen des Dienstes zu vermeiden.',
+    'payment_received' => 'Zahlung erhalten, Betrag: :amount. Bestelldetails anzeigen',
+    'reply_ticket' => 'Ticket beantwortet: :title',
+    'reset_failed' => '[Tägliche Aufgabe] Benutzer :uid - :username Datenrücksetzung fehlgeschlagen',
+    'serverChan_exhausted' => 'Das heutige Limit wurde erschöpft!',
+    'serverChan_limit' => 'Frequenz pro Minute zu hoch. Bitte optimieren Sie die Benachrichtigungseinstellungen!',
+    'sign_failed' => 'Die sichere Signaturprüfung ist fehlgeschlagen',
+    'ticket_content' => 'Ticketinhalt:',
     'traffic_remain' => ':percent% des Datenvolumens verbraucht, bitte beachten',
     'traffic_tips' => 'Bitte beachten Sie das Datum der Datenrücksetzung und nutzen Sie das Datenvolumen rational, oder erneuern Sie es nach dem Verbrauch',
-    'verification_account' => 'Konto-Verifizierung',
+    'traffic_warning' => 'Warnung: Datenverbrauch',
     'verification' => 'Ihr Verifizierungscode lautet:',
+    'verification_account' => 'Konto-Verifizierung',
     'verification_limit' => 'Bitte innerhalb von :minutes Minuten verifizieren',
-    'data_anomaly' => 'Warnung: Datenanomalie',
-    'data_anomaly_content' => 'Benutzer :id: [Upload: :upload | Download: :download | Gesamt: :total] in der letzten Stunde',
-    'node' => [
-        'upload' => 'Upload',
-        'download' => 'Download',
-        'total' => 'Gesamt',
-    ],
+    'view_ticket' => 'Ticket anzeigen',
+    'view_web' => 'Website anzeigen',
 ];

+ 10 - 0
resources/lang/de/setup.php

@@ -0,0 +1,10 @@
+<?php
+
+declare(strict_types=1);
+
+return [
+    'demo_reset' => 'Sie sind im Demo-Modus. Möchten Sie die Datenbank zurücksetzen?',
+    'update_cache' => 'Cache aktualisieren...',
+    'update_complete' => 'Aktualisierung abgeschlossen!',
+    'update_db' => 'Datenbank aktualisieren...',
+];

+ 185 - 146
resources/lang/de/user.php

@@ -4,234 +4,273 @@ declare(strict_types=1);
 
 return [
     'account' => [
+        'connect_password' => 'Proxy-Verbindungspasswort',
         'credit' => 'Kontoguthaben',
-        'status' => 'Kontostatus',
-        'level' => 'Kontolevel',
         'group' => 'Gruppe',
-        'speed_limit' => 'Geschwindigkeitsbegrenzung',
-        'remain' => 'Verbleibende Daten',
-        'time' => 'Paketdauer',
         'last_login' => 'Letzte Anmeldung',
-        'reset' => '{0} Daten werden in <code id="restTime">:days</code> zurückgesetzt|{1} :days Tag bis zur Datenrücksetzung|[2,*] :days Tage bis zur Datenrücksetzung',
-        'connect_password' => 'Proxy-Verbindungspasswort',
+        'level' => 'Kontolevel',
         'reason' => [
-            'normal' => 'Konto ist normal',
             'expired' => 'Ihr Paket ist abgelaufen',
+            'normal' => 'Konto ist normal',
             'overused' => 'Sie haben das Limit von <code>:data</code> GB für diesen Zeitraum überschritten<br/> Die Begrenzung wird in <code id="banedTime">:min</code> Minuten aufgehoben',
             'traffic_exhausted' => 'Datenvolumen ist aufgebraucht',
             'unknown' => 'Unbekannter Grund, bitte versuchen Sie, den Browser zu aktualisieren! Wenn das Problem weiterhin besteht, kontaktieren Sie den Support.',
         ],
+        'remain' => 'Verbleibende Daten',
+        'reset' => '{0} Daten werden in <code id="restTime">:days</code> zurückgesetzt|{1} :days Tag bis zur Datenrücksetzung|[2,*] :days Tage bis zur Datenrücksetzung',
+        'speed_limit' => 'Geschwindigkeitsbegrenzung',
+        'status' => 'Kontostatus',
+        'time' => 'Paketdauer',
     ],
+    'attribute' => [
+        'address' => 'Standort',
+        'data' => 'Daten',
+        'ip' => 'IP-Adresse',
+        'isp' => 'ISP',
+        'node' => 'Knoten',
+    ],
+    'bought_at' => 'Kaufdatum',
+    'clients' => 'Clients',
+    'contact' => 'Kontakt',
+    'coupon' => [
+        'discount' => 'Rabatt',
+        'error' => [
+            'expired' => 'Gutschein abgelaufen',
+            'inactive' => 'Gutschein nicht aktiv',
+            'minimum' => 'Mindestbetrag ist :amount',
+            'overused' => 'Kann nur :times mal verwendet werden',
+            'run_out' => 'Gutschein aufgebraucht',
+            'services' => 'Artikel nicht für Rabatt berechtigt, überprüfen Sie die Aktionsbedingungen',
+            'unknown' => 'Ungültiger Gutschein',
+            'unmet' => 'Bedingungen nicht erfüllt',
+            'used' => 'Gutschein bereits verwendet',
+            'users' => 'Konto nicht für die Aktion berechtigt',
+            'wait' => 'Wird um :time aktiv, bitte warten!',
+        ],
+        'input' => 'Gutscheincode eingeben',
+    ],
+    'current_role' => 'Aktuelle Rolle als',
+    'error_response' => 'Ein Fehler ist aufgetreten, bitte versuchen Sie es später erneut.',
     'home' => [
+        'announcement' => 'Ankündigungen',
         'attendance' => [
             'attribute' => 'Einchecken',
             'disable' => 'Einchecken deaktiviert',
             'done' => 'Sie haben bereits eingecheckt. Kommen Sie morgen wieder!',
-            'success' => 'Sie haben :data Daten erhalten',
             'failed' => 'Systemfehler',
+            'success' => 'Sie haben :data Daten erhalten',
         ],
-        'traffic_logs' => 'Datenprotokolle',
-        'announcement' => 'Ankündigungen',
-        'wechat_push' => 'WeChat-Benachrichtigungen',
         'chat_group' => 'Chat-Gruppe',
         'empty_announcement' => 'Keine Ankündigungen',
+        'traffic_logs' => 'Datenprotokolle',
+        'wechat_push' => 'WeChat-Benachrichtigungen',
     ],
-    'purchase_to_unlock' => 'Zum Freischalten kaufen',
-    'purchase_required' => 'Diese Funktion ist für nicht zahlende Benutzer deaktiviert. Bitte',
-    'attribute' => [
-        'node' => 'Knoten',
-        'data' => 'Daten',
-        'ip' => 'IP-Adresse',
-        'isp' => 'ISP',
-        'address' => 'Standort',
+    'invite' => [
+        'attribute' => 'Einladungscode',
+        'counts' => 'Insgesamt <code>:num</code> Einladungscodes',
+        'generate_failed' => 'Generierung fehlgeschlagen: Kontingent überschritten',
+        'logs' => 'Einladungsprotokolle',
+        'promotion' => 'Sowohl Sie als auch der Eingeladene erhalten <mark>:traffic</mark> Daten, wenn sie sich mit Ihrem Code registrieren; Sie erhalten <mark>:referral_percent%</mark> Provision, wenn sie einen Kauf tätigen.',
+        'tips' => '<strong>:num</strong> Einladungen verbleiben, Codes verfallen :days Tage nach Erstellung',
+    ],
+    'invitee' => 'Eingeladener',
+    'inviter' => 'Einladender',
+    'invoice' => [
+        'active_prepaid_question' => 'Prepaid-Paket frühzeitig aktivieren?',
+        'active_prepaid_tips' => 'Nach der Aktivierung:<br>Ihr aktueller Plan wird sofort ablaufen<br>Das Ablaufdatum des neuen Plans wird ab heute neu berechnet',
+        'amount' => 'Betrag',
+        'attribute' => 'Bestellung',
+        'detail' => 'Bestelldetails',
+    ],
+    'knowledge' => [
+        'basic' => 'Grundlagen',
+        'title' => 'Wissensdatenbank',
     ],
-    'purchase_promotion' => 'Jetzt Dienst kaufen!',
     'menu' => [
+        'admin_dashboard' => 'Dashboard',
         'help' => 'Hilfe',
         'home' => 'Startseite',
         'invites' => 'Einladen',
         'invoices' => 'Rechnungen',
         'nodes' => 'Knoten',
+        'profile' => 'Profil',
         'promotion' => 'Empfehlung',
         'shop' => 'Shop',
-        'profile' => 'Profil',
         'tickets' => 'Tickets',
-        'admin_dashboard' => 'Dashboard',
     ],
-    'contact' => 'Kontakt',
+    'node' => [
+        'info' => 'Konfigurationsinfo',
+        'rate' => ':ratio-facher Datenverbrauch',
+        'setting' => 'Proxy-Einstellungen',
+        'unstable' => 'Instabil/Wartung',
+    ],
     'oauth' => [
+        'bind' => 'Binden',
         'bind_title' => 'Soziales Konto binden',
         'not_bind' => 'Nicht gebunden',
-        'bind' => 'Binden',
         'rebind' => 'Neu binden',
         'unbind' => 'Entbinden',
     ],
-    'coupon' => [
-        'discount' => 'Rabatt',
-        'error' => [
-            'unknown' => 'Ungültiger Gutschein',
-            'used' => 'Gutschein bereits verwendet',
-            'expired' => 'Gutschein abgelaufen',
-            'run_out' => 'Gutschein aufgebraucht',
-            'inactive' => 'Gutschein nicht aktiv',
-            'wait' => 'Wird um :time aktiv, bitte warten!',
-            'unmet' => 'Bedingungen nicht erfüllt',
-            'minimum' => 'Mindestbetrag ist :amount',
-            'overused' => 'Kann nur :times mal verwendet werden',
-            'users' => 'Konto nicht für die Aktion berechtigt',
-            'services' => 'Artikel nicht für Rabatt berechtigt, überprüfen Sie die Aktionsbedingungen',
+    'pay' => 'Bezahlen',
+    'payment' => [
+        'close_tips' => 'Schließen Sie die Zahlung innerhalb von <code>:minutes</code> Minuten ab, sonst wird die Bestellung automatisch geschlossen',
+        'creating' => 'Zahlung wird erstellt...',
+        'error' => 'Ungültiger Aufladebetrag',
+        'insufficient_balance' => 'Ihr Guthaben ist unzureichend. Bitte laden Sie es zuerst auf.',
+        'manual' => [
+            'hint' => 'Nach dem Scannen des QR-Codes zur Zahlung folgen Sie bitte der Reihenfolge der Schritte, bis Sie auf „Abschicken“ klicken, um die Zahlung abzuschließen.',
+            'next' => 'Weiter',
+            'payment_tips' => 'Bitte den genauen Betrag zahlen (keine Rückerstattung bei Überzahlung, Nachzahlung bei Unterzahlung)',
+            'pre' => 'Zurück',
+            'red_packet' => 'Alipay-Rotpaket',
+            'steps' => [
+                'complete' => [
+                    'description' => 'Warten auf manuelle Zahlungsüberprüfung',
+                    'title' => 'Abschluss',
+                ],
+                'notice' => [
+                    'description' => 'Wie man manuell bezahlt',
+                    'title' => 'Hinweise',
+                ],
+                'payment' => [
+                    'description' => 'QR-Code erhalten und bezahlen',
+                    'title' => 'Bezahlen',
+                ],
+                'remark' => [
+                    'description' => 'Geben Sie Ihr Login-Konto zur manuellen Überprüfung ein',
+                    'title' => 'Kontobemerkung',
+                ],
+            ],
         ],
+        'method' => 'Zahlungsmethode',
+        'mobile_tips' => '<strong>Mobile Benutzer:</strong> Halten Sie den QR-Code gedrückt -> Bild speichern -> Zahlungs-App öffnen -> Bild scannen, um zu bezahlen',
+        'order_creation' => [
+            'failed' => 'Erstellung der Bestellung fehlgeschlagen. Bitte versuchen Sie eine andere Zahlungsmethode!',
+            'info' => 'Wir werden Ihre Bestellung/Ihre Aufladung innerhalb von [24 Stunden] aktivieren! Bitte haben Sie Geduld.',
+            'order_limit' => 'Dieser Artikel ist auf :limit_num Käufe begrenzt. Sie haben bereits :count Mal gekauft.',
+            'order_timeout' => 'Die Bestellung ist abgelaufen und wurde aufgrund fehlender Zahlung automatisch geschlossen.',
+            'payment_disabled' => 'Bestellerstellung fehlgeschlagen: Die Online-Zahlungsfunktion ist nicht aktiviert.',
+            'pending_order' => 'Bestellerstellung fehlgeschlagen: Es gibt noch unbezahlte Bestellungen. Bitte schließen Sie diese Zahlungen zuerst ab.',
+            'plan_required' => 'Bitte kaufen Sie ein Paket, bevor Sie das Aufladepaket erwerben.',
+            'price_issue' => 'Bestellerstellung fehlgeschlagen: Ungewöhnlicher Gesamtpreis der Bestellung',
+            'price_zero' => 'Bestellerstellung fehlgeschlagen: Der Gesamtpreis der Bestellung beträgt 0; eine Online-Zahlung ist nicht erforderlich.',
+            'product_unavailable' => 'Bestellerstellung fehlgeschlagen: Der Artikel wurde aus dem Verkauf genommen.',
+            'success' => 'Bestellung erfolgreich erstellt!',
+            'unknown_order' => 'Unbekannte Bestellung',
+            'unknown_payment' => 'Unbekannte Zahlungsmethode',
+        ],
+        'qrcode_tips' => 'Bitte scannen Sie mit <strong class="red-600">:software</strong>',
+        'redirect_stripe' => 'Weiterleitung zu Stripe',
     ],
-    'error_response' => 'Ein Fehler ist aufgetreten, bitte versuchen Sie es später erneut.',
-    'invite' => [
-        'attribute' => 'Einladungscode',
-        'counts' => 'Insgesamt <code>:num</code> Einladungscodes',
-        'tips' => '<strong>:num</strong> Einladungen verbleiben, Codes verfallen :days Tage nach Erstellung',
-        'logs' => 'Einladungsprotokolle',
-        'promotion' => 'Sowohl Sie als auch der Eingeladene erhalten <mark>:traffic</mark> Daten, wenn sie sich mit Ihrem Code registrieren; Sie erhalten <mark>:referral_percent%</mark> Provision, wenn sie einen Kauf tätigen.',
-        'generate_failed' => 'Generierung fehlgeschlagen: Kontingent überschritten',
-    ],
-    'reset_data' => [
-        'action' => 'Daten zurücksetzen',
-        'cost' => 'Kosten: <code>:amount</code>',
-        'cost_tips' => 'Das Zurücksetzen wird :amount abziehen!',
-        'insufficient' => 'Unzureichendes Guthaben, bitte aufladen',
-        'logs' => 'Benutzer hat Daten zurückgesetzt',
-        'success' => 'Zurücksetzung erfolgreich',
+    'purchase' => [
+        'completed' => 'Kauf abgeschlossen!',
+        'promotion' => 'Jetzt Dienst kaufen!',
+        'required' => 'Diese Funktion ist für nicht zahlende Benutzer deaktiviert. Bitte',
+        'to_unlock' => 'Freischalten durch Kauf',
     ],
+    'recharge' => 'Aufladen',
+    'recharge_credit' => 'Guthaben aufladen',
+    'recharging' => 'Aufladen...',
     'referral' => [
         'link' => 'Empfehlungslink',
-        'total' => 'Gesamtprovision: :amount (:total Mal), kann ab :money ausgezahlt werden',
         'logs' => 'Provisionsprotokolle',
-        'failed' => 'Anfrage fehlgeschlagen',
-        'success' => 'Anfrage erfolgreich',
         'msg' => [
             'account' => 'Konto abgelaufen, bitte zuerst ein Paket kaufen',
             'applied' => 'Bestehende Anfrage, bitte warten Sie auf die Bearbeitung',
+            'error' => 'Fehler bei der Erstellung der Bestellung, versuchen Sie es später erneut oder kontaktieren Sie den Support',
             'unfulfilled' => 'Benötigt :amount zur Auszahlung, weiter so!',
             'wait' => 'Bitte warten Sie auf die Genehmigung des Administrators',
-            'error' => 'Fehler bei der Erstellung der Bestellung, versuchen Sie es später erneut oder kontaktieren Sie den Support',
         ],
+        'total' => 'Gesamtprovision: :amount (:total Mal), kann ab :money ausgezahlt werden',
     ],
-    'inviter' => 'Einladender',
-    'invitee' => 'Eingeladener',
     'registered_at' => 'Registrierungsdatum',
-    'bought_at' => 'Kaufdatum',
-    'payment_method' => 'Zahlungsmethode',
-    'pay' => 'Bezahlen',
-    'input_coupon' => 'Gutscheincode eingeben',
-    'recharge' => 'Aufladen',
-    'recharge_credit' => 'Guthaben aufladen',
-    'recharging' => 'Aufladen...',
-    'withdraw_commission' => 'Provision abheben',
-    'withdraw_at' => 'Abhebungsdatum',
-    'withdraw_logs' => 'Abhebungsprotokolle',
-    'withdraw' => 'Abheben',
+    'reset_data' => [
+        'action' => 'Daten zurücksetzen',
+        'cost' => 'Kosten: <code>:amount</code>',
+        'cost_tips' => 'Das Zurücksetzen wird :amount abziehen!',
+    ],
     'scan_qrcode' => 'QR-Code mit Client scannen',
+    'service' => [
+        'country_count' => 'Deckt <code>:num</code> Länder oder Regionen ab',
+        'node_count' => '<code>:num</code> hochwertige Knoten',
+        'unlimited' => 'Unbegrenzte Geschwindigkeit',
+    ],
     'shop' => [
-        'hot' => 'Beliebt',
-        'limited' => 'Begrenzt',
+        'buy' => 'Kaufen',
+        'call4help' => 'Kontaktieren Sie den Support, wenn Sie Fragen haben',
         'change_amount' => 'Aufladebetrag',
         'change_amount_help' => 'Aufladebetrag eingeben',
-        'buy' => 'Kaufen',
+        'conflict' => 'Konflikt',
+        'conflict_tips' => '<p>Der aktuelle Kauf wird als <code>Prepaid-Paket</code> festgelegt</p><ol><li>Das Prepaid-Paket wird automatisch aktiviert, nachdem das aktuelle Paket abläuft</li><li>Sie können es nach der Zahlung manuell aktivieren</li></ol>',
         'description' => 'Beschreibung',
-        'service' => 'Dienst',
+        'hot' => 'Beliebt',
+        'limited' => 'Begrenzt',
         'pay_credit' => 'Mit Guthaben bezahlen',
         'pay_online' => 'Online bezahlen',
         'price' => 'Preis',
         'quantity' => 'Menge',
+        'service' => 'Dienst',
         'subtotal' => 'Zwischensumme',
         'total' => 'Gesamt',
-        'conflict' => 'Konflikt',
-        'conflict_tips' => '<p>Der aktuelle Kauf wird als <code>Prepaid-Paket</code> festgelegt</p><ol><li>Das Prepaid-Paket wird automatisch aktiviert, nachdem das aktuelle Paket abläuft</li><li>Sie können es nach der Zahlung manuell aktivieren</li></ol>',
-        'call4help' => 'Kontaktieren Sie den Support, wenn Sie Fragen haben',
-    ],
-    'service' => [
-        'node_count' => '<code>:num</code> hochwertige Knoten',
-        'country_count' => 'Deckt <code>:num</code> Länder oder Regionen ab',
-        'unlimited' => 'Unbegrenzte Geschwindigkeit',
-    ],
-    'payment' => [
-        'error' => 'Ungültiger Aufladebetrag',
-        'creating' => 'Zahlung wird erstellt...',
-        'redirect_stripe' => 'Weiterleitung zu Stripe',
-        'qrcode_tips' => 'Bitte scannen Sie mit <strong class="red-600">:software</strong>',
-        'close_tips' => 'Schließen Sie die Zahlung innerhalb von <code>:minutes</code> Minuten ab, sonst wird die Bestellung automatisch geschlossen',
-        'mobile_tips' => '<strong>Mobile Benutzer:</strong> Halten Sie den QR-Code gedrückt -> Bild speichern -> Zahlungs-App öffnen -> Bild scannen, um zu bezahlen',
-    ],
-    'invoice' => [
-        'attribute' => 'Bestellung',
-        'detail' => 'Bestelldetails',
-        'amount' => 'Betrag',
-        'active_prepaid_question' => 'Prepaid-Paket frühzeitig aktivieren?',
-        'active_prepaid_tips' => 'Nach der Aktivierung:<br>Ihr aktueller Plan wird sofort ablaufen<br>Das Ablaufdatum des neuen Plans wird ab heute neu berechnet',
-    ],
-    'node' => [
-        'info' => 'Konfigurationsinfo',
-        'setting' => 'Proxy-Einstellungen',
-        'unstable' => 'Instabil/Wartung',
-        'rate' => ':ratio-facher Datenverbrauch',
     ],
     'subscribe' => [
-        'link' => 'Abonnement-Link',
-        'tips' => 'Warnung: Dieser Link ist nur für den persönlichen Gebrauch. Bitte nicht weitergeben, sonst kann Ihr Konto wegen abnormaler Nutzung gesperrt werden.',
-        'exchange_warning' => 'Das Ändern des Abonnement-Links wird:\n1. Den aktuellen Link sofort ungültig machen\n2. Das Verbindungspasswort ändern',
         'custom' => 'Benutzerdefiniertes Abonnement',
-        'ss_only' => 'Nur SS abonnieren',
-        'ssr_only' => 'Nur SSR (inkl. SS) abonnieren',
-        'v2ray_only' => 'Nur V2Ray abonnieren',
-        'trojan_only' => 'Nur Trojan abonnieren',
         'error' => 'Fehler beim Ändern des Abonnement-Links',
+        'exchange_warning' => 'Das Ändern des Abonnement-Links wird:\n1. Den aktuellen Link sofort ungültig machen\n2. Das Verbindungspasswort ändern',
         'info' => [
-            'title' => 'Kontoübersicht [Nicht in Echtzeit]',
-            'upload' => 'Upload',
             'download' => 'Download',
+            'title' => 'Kontoübersicht [Nicht in Echtzeit]',
             'total' => 'Plan-Daten',
+            'upload' => 'Upload',
         ],
+        'link' => 'Abonnement-Link',
+        'ss_only' => 'Nur SS abonnieren',
+        'ssr_only' => 'Nur SSR (inkl. SS) abonnieren',
+        'tips' => 'Warnung: Dieser Link ist nur für den persönlichen Gebrauch. Bitte nicht weitergeben, sonst kann Ihr Konto wegen abnormaler Nutzung gesperrt werden.',
+        'trojan_only' => 'Nur Trojan abonnieren',
+        'v2ray_only' => 'Nur V2Ray abonnieren',
+    ],
+    'telegram' => [
+        'bind_exists' => 'Dieses Konto ist bereits mit einem Telegram-Konto verknüpft.',
+        'bind_missing' => 'Keine Benutzerinformationen gefunden. Bitte verknüpfen Sie zuerst Ihr Konto.',
+        'command' => [
+            'bind' => 'Verknüpfen Sie Ihr :web_name-Konto',
+            'intro' => 'Sie können die folgenden Befehle verwenden',
+            'traffic' => 'Datenverbrauch überprüfen',
+            'unbind' => 'Trennen',
+            'web_url' => 'Holen Sie sich die neueste :web_name-URL',
+        ],
+        'get_url' => 'Die neueste URL für :web_name lautet',
+        'params_missing' => 'Ungültige Parameter. Bitte fügen Sie Ihre E-Mail-Adresse bei und senden Sie erneut.',
+        'ticket_missing' => 'Ticket existiert nicht',
+        'ticket_reply' => 'Antwort auf Ticket #`:id` war erfolgreich',
+        'traffic_query' => 'Datenverbrauchsanfrage',
+        'user_missing' => 'Benutzer existiert nicht',
     ],
     'ticket' => [
         'attribute' => 'Ticket',
-        'submit_tips' => 'Ticket wirklich einreichen?',
-        'reply_confirm' => 'Antwort auf Ticket wirklich senden?',
-        'close_tips' => 'Ticket wirklich schließen?',
-        'close' => 'Ticket schließen',
-        'failed_closed' => 'Fehler: Bereits geschlossen',
-        'reply_placeholder' => 'Schreiben Sie etwas...',
-        'reply' => 'Antworten',
         'close_msg' => 'Ticket ID :id vom Benutzer geschlossen',
-        'title_placeholder' => 'Beschreiben Sie kurz Ihr Problem',
+        'close_tips' => 'Ticket wirklich schließen?',
         'content_placeholder' => 'Beschreiben Sie Ihr Problem detailliert, damit wir Ihnen besser helfen können',
+        'error' => 'Unbekannter Fehler! Bitte kontaktieren Sie den Support',
         'new' => 'Neues Ticket erstellen',
-        'service_hours' => 'Kundendienstzeiten',
         'online_hour' => 'Online-Zeiten',
+        'reply' => 'Antworten',
+        'reply_confirm' => 'Antwort auf Ticket wirklich senden?',
+        'reply_placeholder' => 'Schreiben Sie etwas...',
+        'service_hours' => 'Kundendienstzeiten',
         'service_tips' => 'Bitte verwenden Sie nur <code>eine</code> Kontaktmethode, um den Support zu erreichen! Mehrfache Anfragen verzögern die Antwortzeit.',
-        'error' => 'Unbekannter Fehler! Bitte kontaktieren Sie den Support',
+        'submit_tips' => 'Ticket wirklich einreichen?',
+        'title_placeholder' => 'Beschreiben Sie kurz Ihr Problem',
     ],
     'traffic_logs' => [
-        'hourly' => 'Heutiger Datenverbrauch',
         'daily' => 'Datenverbrauch diesen Monat',
+        'hourly' => 'Heutiger Datenverbrauch',
         'tips' => 'Hinweis: Es gibt eine Verzögerung bei der Aktualisierung der Datenstatistiken.',
     ],
-    'clients' => 'Clients',
     'tutorials' => 'Anleitungen',
-    'current_role' => 'Aktuelle Rolle als',
-    'knowledge' => [
-        'title' => 'Wissensdatenbank',
-        'basic' => 'Grundlagen',
-    ],
-    'manual' => [
-        'red_packet' => 'Alipay-Rotpaket',
-        'hint' => 'Nach dem Scannen des QR-Codes klicken Sie weiter auf [Weiter], bis Sie auf [Einreichen] klicken, um die Zahlung abzuschließen!',
-        'step_1' => 'Hinweise',
-        'step_1_title' => 'Wie man manuell bezahlt',
-        'step_2' => 'Zahlung',
-        'step_2_title' => 'QR-Code erhalten und bezahlen',
-        'step_3' => 'Abschluss',
-        'step_3_title' => 'Auf manuelle Überprüfung warten',
-        'remark' => 'Kontobemerkung',
-        'remark_content' => 'Bitte geben Sie Ihren Kontobenutzernamen an, um eine genaue manuelle Überprüfung zu gewährleisten',
-        'payment_hint' => 'Bitte den genauen Betrag zahlen (keine Rückerstattung bei Überzahlung, Nachzahlung bei Unterzahlung)',
-        'pre' => 'Zurück',
-        'next' => 'Weiter',
-    ],
+    'withdraw' => 'Abheben',
+    'withdraw_at' => 'Abhebungsdatum',
+    'withdraw_commission' => 'Provision abheben',
+    'withdraw_logs' => 'Abhebungsprotokolle',
 ];

+ 12 - 1
resources/lang/en.json

@@ -126,5 +126,16 @@
   "You are receiving this email because we received a password reset request for your account.": "You are receiving this email because we received a password reset request for your account.",
   "You have not responded this ticket in :num hours, System has closed your ticket.": "You have not responded this ticket in :num hours, System has closed your ticket.",
   "You must have a valid subscription to view the content in this area!": "You must have a valid subscription to view the content in this area!",
-  "Your subscription has been disabled by the administrator, please contact the administrator to restore it": "Your subscription has been disabled by the administrator, please contact the administrator to restore it."
+  "Your subscription has been disabled by the administrator, please contact the administrator to restore it": "Your subscription has been disabled by the administrator, please contact the administrator to restore it.",
+  "Manually add in dashboard.": "Manually add in dashboard.",
+  "Manually edit in dashboard.": "Manually edit in dashboard.",
+  "Batch generate user accounts in dashboard.": "Batch generate user accounts in dashboard.",
+  "Coupon used in order.": "Coupon used in order.",
+  "Order canceled, coupon reinstated.": "Order canceled, coupon reinstated.",
+  "Used for credit recharge.": "Used for credit recharge.",
+  "The user manually reset the data.": "The user manually reset the data.",
+  "Recharge using a recharge voucher.": "Recharge using a recharge voucher.",
+  "The user topped up the balance.": "The user topped up the balance.",
+  "Purchased an item.": "Purchased an item.",
+  "[:payment] plus the user’s purchased data plan.": "[:payment] plus the user’s purchased data plan."
 }

File diff suppressed because it is too large
+ 363 - 494
resources/lang/en/admin.php


+ 1 - 12
resources/lang/en/auth.php

@@ -40,27 +40,18 @@ return [
     ],
     'failed' => 'Invalid credentials.',
     'invite' => [
-        'attribute' => 'Invitation Code',
-        'error' => [
-            'unavailable' => 'Invalid invitation code, please try again.',
-        ],
         'get' => 'Get invitation code',
         'not_required' => 'No invitation code required, you can register directly!',
+        'unavailable' => 'Invalid invitation code, please try again.',
     ],
     'login' => 'Login',
     'logout' => 'Logout',
     'maintenance' => 'Maintenance',
     'maintenance_tip' => 'Under maintenance',
     'oauth' => [
-        'bind_failed' => 'Binding failed',
-        'bind_success' => 'Binding successful',
         'login_failed' => 'Third-party login failed!',
-        'rebind_success' => 'Rebinding successful',
         'register' => 'Quick Register',
-        'register_failed' => 'Registration failed',
         'registered' => 'Already registered, please login directly.',
-        'unbind_failed' => 'Unbinding failed',
-        'unbind_success' => 'Unbinding successful',
     ],
     'one-click_login' => 'One-Click Login',
     'optional' => 'Optional',
@@ -73,7 +64,6 @@ return [
             'error' => [
                 'demo' => 'Cannot change admin password in demo mode.',
                 'disabled' => 'Password reset disabled, please contact :email for assistance.',
-                'failed' => 'Password reset failed.',
                 'same' => 'New password cannot be the same as old one, please re-enter.',
                 'throttle' => 'You can only reset password :time times in 24 hours, do not operate too frequently.',
                 'wrong' => 'Incorrect password, please try again.',
@@ -91,7 +81,6 @@ return [
         ],
         'failed' => 'Registration failed, please try again later.',
         'promotion' => 'No account yet? Please go to ',
-        'success' => 'Registration successful',
     ],
     'remember_me' => 'Remember Me',
     'request' => 'Request',

+ 97 - 89
resources/lang/en/common.php

@@ -3,141 +3,149 @@
 declare(strict_types=1);
 
 return [
-    'hour' => '{1} Hour|{2} O\'clock',
     'account' => 'Account',
+    'action' => 'Action',
+    'active_item' => 'Activate :attribute',
+    'add' => 'Add',
+    'advance' => 'Advance',
+    'all' => 'All',
+    'applied' => ':attribute applied',
+    'apply' => 'Apply',
     'available_date' => 'Validity Period',
-    'created_at' => 'Date Created',
-    'expired_at' => 'Expiry Date',
-    'updated_at' => 'Last Updated',
-    'latest_at' => 'Last Activity',
+    'avatar' => 'Avatar',
     'back' => 'Back',
     'back_to' => 'Back to :page',
+    'bark' => [
+        'custom' => 'Custom message',
+        'node_status' => 'Node Status',
+    ],
     'cancel' => 'Cancel',
+    'change' => 'Change',
     'close' => 'Close',
     'close_item' => 'Close :attribute',
     'confirm' => 'Confirm',
     'continue' => 'Continue',
-    'open' => 'Open',
-    'send' => 'Send',
-    'view' => 'View',
-    'reset' => 'Reset',
+    'convert' => 'Convert',
     'copy' => [
         'attribute' => 'Copy',
-        'success' => 'Copied successfully',
         'failed' => 'Copy failed, please copy manually',
+        'success' => 'Copied successfully',
     ],
-    'add' => 'Add',
-    'free' => 'Free',
-    'change' => 'Change',
-    'submit' => 'Submit',
-    'submit_item' => 'Submit :attribute',
-    'generate' => 'Generate',
-    'generate_item' => 'Generate :attribute',
-    'to_safari' => [0 => 'Click the upper right corner', 1 => ', then choose', 2 => 'Open in Safari', 3 => ' to properly access this site!'],
-    'update_browser' => [0 => 'You are using an ', 1 => 'outdated', 2 => ' browser. Please', 3 => 'upgrade your browser', 4 => 'for the best experience'],
-    'apply' => 'Apply',
-    'avatar' => 'Avatar',
+    'create' => 'Create',
+    'created_at' => 'Date Created',
     'customize' => 'Customize',
-    'all' => 'All',
-    'default' => 'Default',
-    'download' => 'Download',
-    'goto' => 'Go to',
-    'warning' => 'Warning',
-    'success' => 'Success',
-    'success_item' => ':attribute succeeded',
-    'failed' => 'Failed',
-    'failed_item' => ':attribute failed',
-    'update' => 'Update',
-    'update_action' => 'Update :action',
-    'none' => 'None',
-    'new' => 'New',
-    'sorry' => 'Sorry',
-    'applied' => ':attribute applied',
-    'active_item' => 'Activate :attribute',
-    'error' => 'Error',
-    'toggle' => 'Toggle',
-    'toggle_action' => 'Toggle :action',
-    'request_url' => 'Request URL',
-    'function' => [
-        'navigation' => 'Navigation',
-        'menubar' => 'Menubar',
-        'fullscreen' => 'Fullscreen',
-    ],
     'days' => [
         'attribute' => '{1} Days|{2} Day',
+        'next' => 'Next Day',
         'weekend' => 'Weekend',
         'work' => 'Weekday',
-        'next' => 'Next Day',
     ],
-    'qrcode' => ':attribute QR Code',
+    'default' => 'Default',
+    'delete' => 'Delete',
     'deleted' => 'Deleted',
     'deleted_item' => ':attribute deleted',
-    'print' => 'Print',
-    'unlimited' => 'Unlimited',
-    'payment' => [
-        'credit' => 'Credit',
-        'alipay' => 'Alipay',
-        'qq' => 'QQ Wallet',
-        'wechat' => 'WeChat Pay',
-        'crypto' => 'Cryptocurrency',
-        'manual' => 'Manual Payment',
-        'status' => [
-            'wait' => 'Pending Payment',
-        ],
+    'developing' => 'Under development! Stay tuned',
+    'download' => 'Download',
+    'edit' => 'Edit',
+    'error' => 'Error',
+    'error_action_item' => ':action :attribute error',
+    'error_item' => ':attribute Error',
+    'exists_error' => 'There are associated accounts under this :attribute. Please remove the associations first!',
+    'expired_at' => 'Expiry Date',
+    'export' => 'Export',
+    'failed' => 'Failed',
+    'failed_action_item' => ':action :attribute failed',
+    'failed_item' => ':attribute failed',
+    'free' => 'Free',
+    'function' => [
+        'fullscreen' => 'Fullscreen',
+        'menubar' => 'Menubar',
+        'navigation' => 'Navigation',
     ],
+    'generate' => 'Generate',
+    'generate_item' => 'Generate :attribute',
+    'goto' => 'Go to',
+    'hour' => '{1} Hour|{2} O\'clock',
+    'import' => 'Import',
+    'latest_at' => 'Last Activity',
+    'more' => 'More',
+    'new' => 'New',
+    'none' => 'None',
+    'open' => 'Open',
+    'or' => 'or',
     'order' => [
         'status' => [
             'canceled' => 'Canceled',
             'completed' => 'Completed',
-            'prepaid' => 'Prepaid',
             'ongoing' => 'Ongoing',
+            'prepaid' => 'Prepaid',
             'review' => 'Pending Review',
         ],
     ],
+    'payment' => [
+        'alipay' => 'Alipay',
+        'credit' => 'Credit',
+        'crypto' => 'Cryptocurrency',
+        'manual' => 'Manual Payment',
+        'qq' => 'QQ Wallet',
+        'wechat' => 'WeChat Pay',
+    ],
+    'print' => 'Print',
+    'qrcode' => ':attribute QR Code',
+    'random_generate' => 'Leave empty to generate randomly',
     'recommend' => 'Recommend',
-    'advance' => 'Advance',
-    'action' => 'Action',
+    'request' => 'Request',
+    'request_failed' => 'Request failed, please retry',
+    'request_url' => 'Request URL',
+    'reset' => 'Reset',
     'search' => 'Search',
-    'edit' => 'Edit',
-    'delete' => 'Delete',
+    'send' => 'Send',
+    'sorry' => 'Sorry',
     'status' => [
+        'applying' => 'Applying',
         'attribute' => 'Status',
-        'inactive' => 'Inactive',
-        'disabled' => 'Disabled',
+        'available' => 'Available',
         'banned' => 'Banned',
-        'normal' => 'Normal',
+        'closed' => 'Closed',
+        'disabled' => 'Disabled',
         'enabled' => 'Enabled',
         'expire' => 'Expired',
+        'inactive' => 'Inactive',
         'limited' => 'Limited',
-        'run_out' => 'Data Used Up',
-        'unused' => 'Unused',
-        'used' => 'Used',
-        'closed' => 'Closed',
-        'applying' => 'Applying',
-        'withdrawn' => 'Withdrawn',
-        'unwithdrawn' => 'Unwithdrawn',
-        'reply' => 'Replied',
+        'normal' => 'Normal',
+        'paid' => 'Paid',
+        'pass' => 'Pass',
+        'payment_pending' => 'Payment Pending',
         'pending' => 'Pending',
-        'unknown' => 'Unknown',
-        'available' => 'Available',
+        'pending_dispatch' => 'Pending delivery',
         'reject' => 'Reject',
         'rejected' => 'Rejected',
+        'reply' => 'Replied',
         'review' => 'Pending Review',
         'reviewed' => 'Reviewed',
-        'paid' => 'Paid',
-        'payment_pending' => 'Payment Pending',
-        'pass' => 'Pass',
+        'run_out' => 'Data Used Up',
         'send_to_credit' => 'Add to Credit',
-        'waiting_tobe_send' => 'Waiting to be Sent',
+        'unknown' => 'Unknown',
+        'unused' => 'Unused',
+        'used' => 'Used',
+        'withdrawal_pending' => 'Unwithdrawn',
+        'withdrawn' => 'Withdrawn',
     ],
     'stay_unchanged' => 'Leave empty to stay unchanged',
-    'random_generate' => 'Leave empty to generate randomly',
-    'request_failed' => 'Request failed, please retry',
-    'convert' => 'Convert',
-    'import' => 'Import',
-    'or' => 'or',
-    'more' => 'More',
+    'storage_logo' => 'Logo Storage',
+    'store' => 'Storage',
+    'submit' => 'Submit',
+    'success' => 'Success',
+    'success_action_item' => ':action :attribute success',
+    'success_item' => ':attribute succeeded',
     'to' => 'to',
     'to_be_send' => 'To be sent',
-    'developing' => 'Under development! Stay tuned',
+    'to_safari' => 'Click the <i class="icon wb-more-horizontal" aria-hidden="true"></i> icon in the upper right corner, then select Open in <img class="w-30 h-30 vertical-align-middle m-3" src="https://gw.alicdn.com/tfs/TB1xwiUNpXXXXaIXXXXXXXXXXXX-55-55.png" alt="Safari" /> Safari to access our site properly!',
+    'toggle' => 'Toggle',
+    'toggle_action' => 'Toggle :action',
+    'unlimited' => 'Unlimited',
+    'update' => 'Update',
+    'updated_at' => 'Last Updated',
+    'view' => 'View',
+    'warning' => 'Warning',
 ];

+ 13 - 13
resources/lang/en/errors.php

@@ -8,29 +8,29 @@ return [
         'bots' => 'Detected bot access, access denied',
         'china' => 'Detected China IP or proxy access, access denied',
         'oversea' => 'Detected overseas IP or proxy access, access denied',
-        'unknown' => 'Unknown forbidden access mode! Please modify the [Access Restriction] in the system settings!',
         'redirect' => 'Detected (:ip :url) accessing through a subscription link, forcing a redirect.',
+        'unknown' => 'Unknown forbidden access mode! Please modify the [Access Restriction] in the system settings!',
     ],
+    'get_ip' => 'Failed to retrieve IP information',
     'log' => 'Log',
     'refresh' => 'Refresh',
     'refresh_page' => 'Please refresh the page and try again',
     'report' => 'The error carried a report: ',
-    'safe_enter' => 'Safe Entrance',
     'safe_code' => 'Please enter the safe code',
-    'title' => '⚠️ Error Triggered',
-    'unsafe_enter' => 'Unsafe Entrance',
-    'visit' => 'Please visit',
-    'whoops' => 'Whoops!',
-    'get_ip' => 'Failed to retrieve IP information',
+    'safe_enter' => 'Safe Entrance',
     'subscribe' => [
-        'unknown' => 'Invalid subscription link! Please obtain a new one!',
-        'sub_banned' => 'Subscription banned! Visit the website for details',
-        'user' => 'Invalid URL, account does not exist!',
-        'user_disabled' => 'Account Disabled! Contact Support!',
         'banned_until' => 'Account banned until :time, please wait for unlock!',
-        'out' => 'OUT OF DATA! Please purchase more or reset data!',
         'expired' => 'Account expired! Please renew your subscription!',
-        'question' => 'Account issues!? Visit the website for details',
         'none' => 'No available nodes',
+        'out' => 'OUT OF DATA! Please purchase more or reset data!',
+        'question' => 'Account issues!? Visit the website for details',
+        'sub_banned' => 'Subscription banned! Visit the website for details',
+        'unknown' => 'Invalid subscription link! Please obtain a new one!',
+        'user' => 'Invalid URL, account does not exist!',
+        'user_disabled' => 'Account Disabled! Contact Support!',
     ],
+    'title' => '⚠️ Error Triggered',
+    'unsafe_enter' => 'Unsafe Entrance',
+    'visit' => 'Please visit',
+    'whoops' => 'Whoops!',
 ];

+ 151 - 150
resources/lang/en/model.php

@@ -3,105 +3,114 @@
 declare(strict_types=1);
 
 return [
-    'user' => [
-        'id' => 'User ID',
-        'attribute' => 'User',
-        'nickname' => 'Nickname',
-        'username' => 'Username',
-        'password' => 'Password',
-        'credit' => 'Balance',
-        'invite_num' => 'Available Invitations',
-        'reset_date' => 'Data Reset Date',
-        'port' => 'Port',
-        'traffic_used' => 'Data Used',
-        'service' => 'Proxy',
-        'group' => 'Group',
-        'account_status' => 'Account Status',
-        'proxy_status' => 'Proxy Status',
-        'expired_date' => 'Expiration Date',
-        'role' => 'Role',
-        'wechat' => 'WeChat',
-        'qq' => 'QQ',
-        'remark' => 'Note',
-        'uuid' => 'VMess UUID',
-        'proxy_passwd' => 'Proxy Password',
-        'proxy_method' => 'Encryption',
-        'usable_traffic' => 'Data Allowance',
-        'proxy_protocol' => 'Protocol',
-        'proxy_obfs' => 'Obfuscation',
-        'speed_limit' => 'Speed Limit',
-        'inviter' => 'Inviter',
-        'created_date' => 'Registration Date',
+    'aff' => [
+        'amount' => 'Order Amount',
+        'commission' => 'Commission',
+        'created_at' => 'Ordered On',
+        'invitee' => 'Buyer',
+        'updated_at' => 'Processed On',
+    ],
+    'article' => [
+        'attribute' => 'Article',
+        'category' => 'Category',
+        'created_at' => 'Published On',
+        'language' => 'Language',
+        'logo' => 'Cover',
+        'updated_at' => 'Updated On',
     ],
     'common' => [
+        'description' => 'Description',
         'extend' => 'Extended Info',
+        'level' => 'Level',
         'sort' => 'Sort',
-        'description' => 'Description',
         'type' => 'Type',
-        'level' => 'Level',
     ],
     'country' => [
         'code' => 'Country Code',
         'icon' => 'Flag',
         'name' => 'Country Name',
     ],
-    'subscribe' => [
-        'code' => 'Sub Code',
-        'req_times' => 'Request Times',
-        'updated_at' => 'Last Request',
-        'ban_time' => 'Ban Time',
-        'ban_desc' => 'Ban Reason',
-        'req_ip' => 'Request IP',
-        'req_header' => 'Access Header',
+    'coupon' => [
+        'attribute' => 'Coupon',
+        'groups' => 'Group Limit',
+        'levels' => 'Level Limit',
+        'logo' => 'Logo',
+        'minimum' => 'Minimum Spend',
+        'name' => 'Name',
+        'newbie' => 'New User Only',
+        'num' => 'Quantity',
+        'priority' => 'Priority',
+        'services_blacklist' => 'Blacklist Goods',
+        'services_whitelist' => 'Whitelist Goods',
+        'sn' => 'Code',
+        'usable_times' => 'Usage Limit',
+        'used' => 'Personal Limit',
+        'users_blacklist' => 'Blacklist Users',
+        'users_whitelist' => 'Whitelist Users',
+        'value' => 'Value',
     ],
-    'oauth' => [
-        'type' => 'Channel',
-        'identifier' => 'Identifier',
+    'goods' => [
+        'attribute' => 'Goods',
+        'available_date' => 'Validity Period',
+        'category' => 'Category',
+        'color' => 'Color',
+        'hot' => 'Bestseller',
+        'info' => 'Custom Info',
+        'invite_num' => 'Bonus Invitations',
+        'limit_num' => 'Purchase Limit',
+        'logo' => 'Logo',
+        'name' => 'Name',
+        'period' => 'Reset Cycle',
+        'price' => 'Price',
+        'renew' => 'Data Renewal Price',
+        'traffic' => 'Data Allowance',
+        'user_limit' => 'User Speed Limit',
     ],
-    'user_group' => [
-        'attribute' => 'User Group',
-        'name' => 'Group Name',
-        'nodes' => 'Nodes',
+    'ip' => [
+        'info' => 'Location',
+        'network_type' => 'Network Type',
     ],
     'node' => [
         'attribute' => 'Node',
-        'id' => 'Node ID',
-        'name' => 'Name',
-        'domain' => 'Domain',
-        'static' => 'Alive Status',
-        'online_user' => 'Online Users',
+        'client_limit' => 'Client Limit',
+        'country' => 'Country',
         'data_consume' => 'Data Usage',
         'data_rate' => 'Data Ratio',
         'ddns' => 'DDNS',
+        'detection' => 'Block Detection',
+        'display' => 'Display & Subscribe',
+        'domain' => 'Domain',
+        'id' => 'Node ID',
         'ipv4' => 'IPv4',
         'ipv6' => 'IPv6',
-        'push_port' => 'Push Port',
-        'rule_group' => 'Rule Group',
-        'traffic_limit' => 'Speed Limit',
-        'client_limit' => 'Client Limit',
         'label' => 'Label',
-        'country' => 'Country',
-        'udp' => 'UDP',
-        'display' => 'Display & Subscribe',
-        'detection' => 'Block Detection',
         'method' => 'Encryption',
-        'protocol' => 'Protocol',
-        'protocol_param' => 'Protocol Param',
+        'name' => 'Name',
+        'next_renewal_date' => 'Next Renewal Date',
         'obfs' => 'Obfs',
         'obfs_param' => 'Obfs Param',
-        'single' => 'Single Port',
-        'transfer' => 'Relay',
+        'online_user' => 'Online Users',
+        'protocol' => 'Protocol',
+        'protocol_param' => 'Protocol Param',
+        'push_port' => 'Push Port',
+        'relay_port' => 'Relay Port',
+        'renewal_cost' => 'Renewal Cost',
         'service_port' => 'Service Port',
+        'single' => 'Single Port',
         'single_passwd' => '[Single] Password',
+        'static' => 'Alive Status',
+        'subscription_term' => 'Subscription Term',
+        'traffic_limit' => 'Speed Limit',
+        'transfer' => 'Relay',
+        'udp' => 'UDP',
         'v2_alter_id' => 'Alter ID',
-        'v2_net' => 'Network',
         'v2_cover' => 'Cover',
         'v2_host' => 'Host',
+        'v2_net' => 'Network',
         'v2_path' => 'Path | Key',
         'v2_sni' => 'SNI',
         'v2_tls' => 'TLS',
         'v2_tls_provider' => 'TLS Config',
-        'relay_port' => 'Relay Port',
     ],
     'node_auth' => [
         'attribute' => 'Node Auth',
@@ -111,36 +120,44 @@ return [
     'node_cert' => [
         'attribute' => 'Domain Cert',
         'domain' => 'Domain',
+        'expired_date' => 'Expired Date',
+        'issuer' => 'Issuer',
         'key' => 'KEY',
         'pem' => 'PEM',
-        'issuer' => 'Issuer',
         'signed_date' => 'Signed Date',
-        'expired_date' => 'Expired Date',
+    ],
+    'notification' => [
+        'address' => 'Recipient',
+        'created_at' => 'Sent On',
+        'status' => 'Status',
+    ],
+    'oauth' => [
+        'identifier' => 'Identifier',
+        'type' => 'Channel',
     ],
     'order' => [
         'attribute' => 'Order',
         'id' => 'Order ID',
         'original_price' => 'Original Price',
-        'price' => 'Actual Price',
         'pay_way' => 'Payment',
+        'price' => 'Actual Price',
         'status' => 'Status',
     ],
-    'goods' => [
-        'attribute' => 'Goods',
+    'permission' => [
+        'attribute' => 'Permission',
+        'description' => 'Description',
+        'name' => 'Route Name',
+    ],
+    'referral' => [
+        'amount' => 'Amount',
+        'created_at' => 'Applied On',
+        'id' => 'Application ID',
+        'user' => 'Applicant',
+    ],
+    'role' => [
+        'attribute' => 'Role',
         'name' => 'Name',
-        'price' => 'Price',
-        'category' => 'Category',
-        'renew' => 'Data Renewal Price',
-        'user_limit' => 'User Speed Limit',
-        'period' => 'Reset Cycle',
-        'traffic' => 'Data Allowance',
-        'invite_num' => 'Bonus Invitations',
-        'limit_num' => 'Purchase Limit',
-        'available_date' => 'Validity Period',
-        'hot' => 'Bestseller',
-        'color' => 'Color',
-        'logo' => 'Logo',
-        'info' => 'Custom Info',
+        'permissions' => 'Permissions',
     ],
     'rule' => [
         'attribute' => 'Rule',
@@ -150,83 +167,67 @@ return [
     'rule_group' => [
         'attribute' => 'Rule Group',
         'name' => 'Name',
-        'type' => 'Type',
         'rules' => 'Rules',
+        'type' => 'Type',
     ],
-    'role' => [
-        'attribute' => 'Role',
-        'name' => 'Name',
-        'permissions' => 'Permissions',
-    ],
-    'permission' => [
-        'attribute' => 'Permission',
-        'description' => 'Description',
-        'name' => 'Route Name',
-    ],
-    'article' => [
-        'attribute' => 'Article',
-        'category' => 'Category',
-        'language' => 'Language',
-        'logo' => 'Cover',
-        'created_at' => 'Published On',
-        'updated_at' => 'Updated On',
-    ],
-    'coupon' => [
-        'attribute' => 'Coupon',
-        'name' => 'Name',
-        'sn' => 'Code',
-        'logo' => 'Logo',
-        'value' => 'Value',
-        'priority' => 'Priority',
-        'usable_times' => 'Usage Limit',
-        'minimum' => 'Minimum Spend',
-        'used' => 'Personal Limit',
-        'levels' => 'Level Limit',
-        'groups' => 'Group Limit',
-        'users_whitelist' => 'Whitelist Users',
-        'users_blacklist' => 'Blacklist Users',
-        'services_whitelist' => 'Whitelist Goods',
-        'services_blacklist' => 'Blacklist Goods',
-        'newbie' => 'New User Only',
-        'num' => 'Quantity',
+    'subscribe' => [
+        'ban_desc' => 'Ban Reason',
+        'ban_time' => 'Ban Time',
+        'code' => 'Sub Code',
+        'req_header' => 'Access Header',
+        'req_ip' => 'Request IP',
+        'req_times' => 'Request Times',
+        'updated_at' => 'Last Request',
     ],
-    'aff' => [
-        'invitee' => 'Buyer',
-        'amount' => 'Order Amount',
-        'commission' => 'Commission',
-        'updated_at' => 'Processed On',
-        'created_at' => 'Ordered On',
+    'user' => [
+        'account_status' => 'Account Status',
+        'attribute' => 'User',
+        'created_date' => 'Registration Date',
+        'credit' => 'Balance',
+        'expired_date' => 'Expiration Date',
+        'id' => 'User ID',
+        'invite_num' => 'Available Invitations',
+        'inviter' => 'Inviter',
+        'nickname' => 'Nickname',
+        'password' => 'Password',
+        'port' => 'Port',
+        'proxy_method' => 'Encryption',
+        'proxy_obfs' => 'Obfuscation',
+        'proxy_passwd' => 'Proxy Password',
+        'proxy_protocol' => 'Protocol',
+        'proxy_status' => 'Proxy Status',
+        'qq' => 'QQ',
+        'remark' => 'Note',
+        'reset_date' => 'Data Reset Date',
+        'role' => 'Role',
+        'service' => 'Proxy',
+        'speed_limit' => 'Speed Limit',
+        'traffic_used' => 'Data Used',
+        'usable_traffic' => 'Data Allowance',
+        'username' => 'Username',
+        'uuid' => 'VMess UUID',
+        'wechat' => 'WeChat',
     ],
-    'referral' => [
-        'created_at' => 'Applied On',
-        'user' => 'Applicant',
+    'user_credit' => [
+        'after' => 'After',
         'amount' => 'Amount',
-        'id' => 'Application ID',
+        'before' => 'Before',
+        'created_at' => 'Changed At',
     ],
-    'notification' => [
-        'address' => 'Recipient',
-        'created_at' => 'Sent On',
-        'status' => 'Status',
+    'user_data_modify' => [
+        'after' => 'After',
+        'before' => 'Before',
+        'created_at' => 'Changed At',
     ],
-    'ip' => [
-        'network_type' => 'Network Type',
-        'info' => 'Location',
+    'user_group' => [
+        'attribute' => 'User Group',
+        'name' => 'Group Name',
+        'nodes' => 'Nodes',
     ],
     'user_traffic' => [
-        'upload' => 'Upload',
         'download' => 'Download',
-        'total' => 'Total',
         'log_time' => 'Logged At',
-    ],
-    'user_data_modify' => [
-        'before' => 'Before',
-        'after' => 'After',
-        'created_at' => 'Changed At',
-    ],
-    'user_credit' => [
-        'before' => 'Before',
-        'after' => 'After',
-        'amount' => 'Amount',
-        'created_at' => 'Changed At',
+        'total' => 'Total',
+        'upload' => 'Upload',
     ],
 ];

+ 33 - 19
resources/lang/en/notification.php

@@ -3,35 +3,49 @@
 declare(strict_types=1);
 
 return [
-    'attribute' => 'Notification',
-    'new' => '{1} :num new message|[1,*] :num new messages',
-    'empty' => 'You have no new messages',
-    'payment_received' => 'Payment received, amount: :amount. View order details',
     'account_expired' => 'Account expiration reminder',
-    'account_expired_content' => 'Your account will expire in :days days. Please renew promptly to continue using our services.',
     'account_expired_blade' => 'Account will expire in :days days, please renew promptly',
+    'account_expired_content' => 'Your account will expire in :days days. Please renew promptly to continue using our services.',
     'active_email' => 'Please complete verification within 30 minutes',
+    'attribute' => 'Notification',
+    'block_report' => 'Block report:',
     'close_ticket' => 'Ticket :id: :title closed',
-    'view_web' => 'View website',
-    'view_ticket' => 'View ticket',
+    'data_anomaly' => 'Data anomaly user warning',
+    'data_anomaly_content' => 'User :id: [Upload: :upload | Download: :download | Total: :total] in the last hour',
+    'details' => 'View Details',
+    'details_btn' => 'Please click the button below to view the details.',
+    'ding_bot_limit' => 'Each bot can send up to 20 messages per minute to the group. If this limit is exceeded, throttling will be applied for 10 minutes.',
+    'empty' => 'You have no new messages',
+    'error' => '[:channel] Message push with exception: :reason',
+    'get_access_token_failed' => 'Failed to obtain access token!\nWith request parameters: :body',
+    'into_maintenance' => 'Automatically enter maintenance mode',
+    'new' => '{1} :num new message|[1,*] :num new messages',
     'new_ticket' => 'New ticket received: :title',
-    'reply_ticket' => 'Ticket replied: :title',
-    'ticket_content' => 'Ticket content:',
+    'next_check_time' => 'Next node blockage detection time: :time',
+    'node' => [
+        'download' => 'Download',
+        'total' => 'Total',
+        'upload' => 'Upload',
+    ],
     'node_block' => 'Node block warning',
     'node_offline' => 'Node offline warning',
     'node_offline_content' => 'Abnormal nodes, may be offline:',
-    'block_report' => 'Block report:',
-    'traffic_warning' => 'Data usage warning',
+    'node_renewal' => 'Node Renewal Reminder',
+    'node_renewal_blade' => 'The following nodes are about to expire. Please renew in advance:',
+    'node_renewal_content' => 'The following nodes are about to expire. Please renew before the expiration to avoid service interruption.',
+    'payment_received' => 'Payment received, amount: :amount. View order details',
+    'reply_ticket' => 'Ticket replied: :title',
+    'reset_failed' => '[Daily Task]User :uid - :username Data Reset Failed',
+    'serverChan_exhausted' => 'Today\'s limit has been exhausted!',
+    'serverChan_limit' => 'Frequency too high per minute. Please optimize the notification settings!',
+    'sign_failed' => 'Secure signature verification failed',
+    'ticket_content' => 'Ticket content:',
     'traffic_remain' => ':percent% of data used, please pay attention',
     'traffic_tips' => 'Please note the data reset date and use data rationally, or renew after exhausted',
-    'verification_account' => 'Account verification',
+    'traffic_warning' => 'Data usage warning',
     'verification' => 'Your verification code:',
+    'verification_account' => 'Account verification',
     'verification_limit' => 'Please verify within :minutes minutes',
-    'data_anomaly' => 'Data anomaly user warning',
-    'data_anomaly_content' => 'User :id: [Upload: :upload | Download: :download | Total: :total] in the last hour',
-    'node' => [
-        'upload' => 'Upload',
-        'download' => 'Download',
-        'total' => 'Total',
-    ],
+    'view_ticket' => 'View ticket',
+    'view_web' => 'View website',
 ];

+ 10 - 0
resources/lang/en/setup.php

@@ -0,0 +1,10 @@
+<?php
+
+declare(strict_types=1);
+
+return [
+    'demo_reset' => 'You have been detected in Demo mode, do you reset the database?',
+    'update_cache' => 'Update cache...',
+    'update_complete' => 'Update Completed! ',
+    'update_db' => 'Update Database...',
+];

+ 189 - 150
resources/lang/en/user.php

@@ -4,234 +4,273 @@ declare(strict_types=1);
 
 return [
     'account' => [
+        'connect_password' => 'Proxy Connection Password',
         'credit' => 'Account Balance',
-        'status' => 'Account Status',
-        'level' => 'Account Level',
         'group' => 'Group',
-        'speed_limit' => 'Speed Limit',
-        'remain' => 'Remaining Data',
-        'time' => 'Plan Duration',
         'last_login' => 'Last Login',
-        'reset' => '{0} Data will reset in <code id="restTime">:days</code> |{1} :days day left to reset data |[2,*] :days days left to reset data',
-        'connect_password' => 'Proxy Connection Password',
+        'level' => 'Account Level',
         'reason' => [
-            'normal' => 'Account is normal',
             'expired' => 'Your plan has expired',
+            'normal' => 'Account is normal',
             'overused' => 'You have exceeded the <code>:data</code> GB limit for this period<br/> Limit will be lifted in <code id="banedTime">:min</code> minutes',
             'traffic_exhausted' => 'Data has been exhausted',
             'unknown' => 'Unknown reason, please try refreshing the browser! If the problem persists, contact support.',
         ],
+        'remain' => 'Remaining Data',
+        'reset' => '{0} Data will reset in <code id="restTime">:days</code> |{1} :days day left to reset data |[2,*] :days days left to reset data',
+        'speed_limit' => 'Speed Limit',
+        'status' => 'Account Status',
+        'time' => 'Plan Duration',
     ],
+    'attribute' => [
+        'address' => 'Location',
+        'data' => 'Data',
+        'ip' => 'IP Address',
+        'isp' => 'ISP',
+        'node' => 'Node',
+    ],
+    'bought_at' => 'Purchase Date',
+    'clients' => 'Clients',
+    'contact' => 'Contact',
+    'coupon' => [
+        'discount' => 'Discount',
+        'error' => [
+            'expired' => 'Coupon expired',
+            'inactive' => 'Coupon not active',
+            'minimum' => 'Minimum amount is :amount',
+            'overused' => 'Can only be used :times times',
+            'run_out' => 'Coupon exhausted',
+            'services' => 'Goods not eligible for discount, check promotional terms',
+            'unknown' => 'Invalid coupon',
+            'unmet' => 'Conditions not met',
+            'used' => 'Coupon already used',
+            'users' => 'Account not eligible for promotion',
+            'wait' => 'Will be active at :time, please wait!',
+        ],
+        'input' => 'Please enter the recharge coupon code',
+    ],
+    'current_role' => 'Current Role as',
+    'error_response' => 'An error occurred, please try again later.',
     'home' => [
+        'announcement' => 'Announcements',
         'attendance' => [
             'attribute' => 'Check In',
             'disable' => 'Check-in disabled',
             'done' => 'You have already checked in. Come back tomorrow!',
-            'success' => 'You received :data data',
             'failed' => 'System error',
+            'success' => 'You received :data data',
         ],
-        'traffic_logs' => 'Data Records',
-        'announcement' => 'Announcements',
-        'wechat_push' => 'WeChat Notifications',
         'chat_group' => 'Chat Group',
         'empty_announcement' => 'No announcements',
+        'traffic_logs' => 'Data Records',
+        'wechat_push' => 'WeChat Notifications',
     ],
-    'purchase_to_unlock' => 'Purchase to Unlock',
-    'purchase_required' => 'This feature is disabled for non-paying users. Please',
-    'attribute' => [
-        'node' => 'Node',
-        'data' => 'Data',
-        'ip' => 'IP Address',
-        'isp' => 'ISP',
-        'address' => 'Location',
+    'invite' => [
+        'attribute' => 'Invitation Code',
+        'counts' => 'Total of <code>:num</code> invitation codes',
+        'generate_failed' => 'Failed to generate: Quota exceeded',
+        'logs' => 'Invitation Logs',
+        'promotion' => 'Both you and the invitee will receive <mark>:traffic</mark> data when they register with your code; You will earn <mark>:referral_percent%</mark> commission when they make a purchase.',
+        'tips' => '<strong>:num</strong> invitations remaining, codes expire :days days after creation',
+    ],
+    'invitee' => 'Invitee',
+    'inviter' => 'Inviter',
+    'invoice' => [
+        'active_prepaid_question' => 'Activate prepaid package early?',
+        'active_prepaid_tips' => 'After activation:<br>Your current plan will immediately expire<br>The new plan\'s expiration date will be recalculated from today',
+        'amount' => 'Amount',
+        'attribute' => 'Order',
+        'detail' => 'Order Details',
+    ],
+    'knowledge' => [
+        'basic' => 'Basic',
+        'title' => 'Knowledge Base',
     ],
-    'purchase_promotion' => 'Purchase Service Now!',
     'menu' => [
+        'admin_dashboard' => 'Dashboard',
         'help' => 'Help',
         'home' => 'Home',
         'invites' => 'Invite',
         'invoices' => 'Invoice',
         'nodes' => 'Nodes',
+        'profile' => 'Profile',
         'promotion' => 'Referral',
         'shop' => 'Shop',
-        'profile' => 'Profile',
         'tickets' => 'Tickets',
-        'admin_dashboard' => 'Dashboard',
     ],
-    'contact' => 'Contact',
+    'node' => [
+        'info' => 'Configuration Info',
+        'rate' => ':ratio times data consumption',
+        'setting' => 'Proxy Settings',
+        'unstable' => 'Unstable/Maintenance',
+    ],
     'oauth' => [
-        'bind_title' => 'Bind Social Account',
-        'not_bind' => 'Not Bound',
-        'bind' => 'Bind',
-        'rebind' => 'Rebind',
-        'unbind' => 'Unbind',
+        'bind' => 'Link',
+        'bind_title' => 'Link Your Social Account',
+        'not_bind' => 'Not Linked',
+        'rebind' => 'Re-link',
+        'unbind' => 'Unlink',
     ],
-    'coupon' => [
-        'discount' => 'Discount',
-        'error' => [
-            'unknown' => 'Invalid coupon',
-            'used' => 'Coupon already used',
-            'expired' => 'Coupon expired',
-            'run_out' => 'Coupon exhausted',
-            'inactive' => 'Coupon not active',
-            'wait' => 'Will be active at :time, please wait!',
-            'unmet' => 'Conditions not met',
-            'minimum' => 'Minimum amount is :amount',
-            'overused' => 'Can only be used :times times',
-            'users' => 'Account not eligible for promotion',
-            'services' => 'Goods not eligible for discount, check promotional terms',
+    'pay' => 'Pay',
+    'payment' => [
+        'close_tips' => 'Complete the payment within <code>:minutes</code> minutes, or the order will close automatically',
+        'creating' => 'Creating payment...',
+        'error' => 'Invalid recharge amount',
+        'insufficient_balance' => 'Your balance is insufficient. Please recharge first.',
+        'manual' => [
+            'hint' => 'After scanning the QR code to pay, please follow the steps until you click Submit to complete the payment.',
+            'next' => 'Next',
+            'payment_tips' => 'When making the payment, please pay the exact amount (no refunds for overpayment, additional payment required if underpaid).',
+            'pre' => 'Previous',
+            'red_packet' => 'Alipay Red Packet',
+            'steps' => [
+                'complete' => [
+                    'description' => 'Waiting for manual payment verification',
+                    'title' => 'Completion',
+                ],
+                'notice' => [
+                    'description' => 'How to make a manual payment',
+                    'title' => 'Notes',
+                ],
+                'payment' => [
+                    'description' => 'Get the payment QR code and pay',
+                    'title' => 'Payment',
+                ],
+                'remark' => [
+                    'description' => 'Enter your login account for manual verification',
+                    'title' => 'Add a note',
+                ],
+            ],
         ],
+        'method' => 'Payment Method',
+        'mobile_tips' => '<strong>Mobile Users:</strong> Long press the QR code -> Save image -> Open payment app -> Scan image to pay',
+        'order_creation' => [
+            'failed' => 'Order creation failed. Please try a different payment method!',
+            'info' => 'We will review your purchase/recharge within [24 hours]! Please be patient.',
+            'order_limit' => 'This item is limited to :limit_num purchases. You have already bought :count times.',
+            'order_timeout' => 'The order timed out and was automatically closed due to non-payment.',
+            'payment_disabled' => 'Order creation failed: Online payment feature is not enabled.',
+            'pending_order' => 'Order creation failed: There are pending orders. Please complete those payments first.',
+            'plan_required' => 'Please purchase a plan before buying the recharge package.',
+            'price_issue' => 'Order creation failed: Abnormal total order price',
+            'price_zero' => 'Order creation failed: The total order price is 0; online payment is not required.',
+            'product_unavailable' => 'Order creation failed: The item has been removed from sale.',
+            'success' => 'Order created successfully!',
+            'unknown_order' => 'Unknown order',
+            'unknown_payment' => 'Unknown payment method',
+        ],
+        'qrcode_tips' => 'Please scan with <strong class="red-600">:software</strong>',
+        'redirect_stripe' => 'Redirecting to Stripe',
     ],
-    'error_response' => 'An error occurred, please try again later.',
-    'invite' => [
-        'attribute' => 'Invitation Code',
-        'counts' => 'Total of <code>:num</code> invitation codes',
-        'tips' => '<strong>:num</strong> invitations remaining, codes expire :days days after creation',
-        'logs' => 'Invitation Logs',
-        'promotion' => 'Both you and the invitee will receive <mark>:traffic</mark> data when they register with your code; You will earn <mark>:referral_percent%</mark> commission when they make a purchase.',
-        'generate_failed' => 'Failed to generate: Quota exceeded',
-    ],
-    'reset_data' => [
-        'action' => 'Reset Data',
-        'cost' => 'Cost: <code>:amount</code>',
-        'cost_tips' => 'The reset will deduct :amount!',
-        'insufficient' => 'Insufficient balance, please top up',
-        'logs' => 'User reset data',
-        'success' => 'Reset successful',
+    'purchase' => [
+        'completed' => 'Purchase completed!',
+        'promotion' => 'Don\'t miss out—buy our services today!',
+        'required' => 'This feature is available to paid users only. Please',
+        'to_unlock' => 'Unlock with Purchase',
     ],
+    'recharge' => 'Recharge',
+    'recharge_credit' => 'Credit Recharge',
+    'recharging' => 'Recharging...',
     'referral' => [
         'link' => 'Referral Link',
-        'total' => 'Total commission: :amount (:total times), can withdraw when over :money',
         'logs' => 'Commission Logs',
-        'failed' => 'Request failed',
-        'success' => 'Request successful',
         'msg' => [
             'account' => 'Account expired, please purchase a plan first',
             'applied' => 'Existing request, please wait for processing',
+            'error' => 'Error creating order, try again later or contact support',
             'unfulfilled' => 'Need :amount to withdraw, keep going!',
             'wait' => 'Please wait for admin approval',
-            'error' => 'Error creating order, try again later or contact support',
         ],
+        'total' => 'Total commission: :amount (:total times), can withdraw when over :money',
     ],
-    'inviter' => 'Inviter',
-    'invitee' => 'Invitee',
     'registered_at' => 'Registration Date',
-    'bought_at' => 'Purchase Date',
-    'payment_method' => 'Payment Method',
-    'pay' => 'Pay',
-    'input_coupon' => 'Enter coupon code',
-    'recharge' => 'Recharge',
-    'recharge_credit' => 'Credit Recharge',
-    'recharging' => 'Recharging...',
-    'withdraw_commission' => 'Withdraw Commission',
-    'withdraw_at' => 'Withdrawal Date',
-    'withdraw_logs' => 'Withdrawal Logs',
-    'withdraw' => 'Withdraw',
+    'reset_data' => [
+        'action' => 'Reset Data',
+        'cost' => 'Cost: <code>:amount</code>',
+        'cost_tips' => 'The reset will deduct :amount!',
+    ],
     'scan_qrcode' => 'Scan QR code with client',
+    'service' => [
+        'country_count' => 'Covers <code>:num</code> countries or regions',
+        'node_count' => '<code>:num</code> high-quality nodes',
+        'unlimited' => 'Unlimited speed',
+    ],
     'shop' => [
-        'hot' => 'Hot',
-        'limited' => 'Limited',
+        'buy' => 'Buy',
+        'call4help' => 'Contact support if you have any questions',
         'change_amount' => 'Recharge Amount',
         'change_amount_help' => 'Enter recharge amount',
-        'buy' => 'Buy',
+        'conflict' => 'Conflict',
+        'conflict_tips' => '<p>The current purchase will be set as a <code>prepaid plan</code></p><ol><li>Prepaid plan will automatically activate after current plan expires</li><li>You can manually activate it after payment</li></ol>',
         'description' => 'Description',
-        'service' => 'Service',
+        'hot' => 'Hot',
+        'limited' => 'Limited',
         'pay_credit' => 'Pay with Credit',
         'pay_online' => 'Pay Online',
         'price' => 'Price',
         'quantity' => 'Quantity',
+        'service' => 'Service',
         'subtotal' => 'Subtotal',
         'total' => 'Total',
-        'conflict' => 'Conflict',
-        'conflict_tips' => '<p>The current purchase will be set as a <code>prepaid plan</code></p><ol><li>Prepaid plan will automatically activate after current plan expires</li><li>You can manually activate it after payment</li></ol>',
-        'call4help' => 'Contact support if you have any questions',
-    ],
-    'service' => [
-        'node_count' => '<code>:num</code> high-quality nodes',
-        'country_count' => 'Covers <code>:num</code> countries or regions',
-        'unlimited' => 'Unlimited speed',
-    ],
-    'payment' => [
-        'error' => 'Invalid recharge amount',
-        'creating' => 'Creating payment...',
-        'redirect_stripe' => 'Redirecting to Stripe',
-        'qrcode_tips' => 'Please scan with <strong class="red-600">:software</strong>',
-        'close_tips' => 'Complete the payment within <code>:minutes</code> minutes, or the order will close automatically',
-        'mobile_tips' => '<strong>Mobile Users:</strong> Long press the QR code -> Save image -> Open payment app -> Scan image to pay',
-    ],
-    'invoice' => [
-        'attribute' => 'Order',
-        'detail' => 'Order Details',
-        'amount' => 'Amount',
-        'active_prepaid_question' => 'Activate prepaid package early?',
-        'active_prepaid_tips' => 'After activation:<br>Your current plan will immediately expire<br>The new plan\'s expiration date will be recalculated from today',
-    ],
-    'node' => [
-        'info' => 'Configuration Info',
-        'setting' => 'Proxy Settings',
-        'unstable' => 'Unstable/Maintenance',
-        'rate' => ':ratio times data consumption',
     ],
     'subscribe' => [
-        'link' => 'Subscription Link',
-        'tips' => 'Warning: This link is for personal use only. Do not share it, or your account may be banned for abnormal usage.',
-        'exchange_warning' => 'Changing the subscription link will:\n1. Revoke the current link immediately\n2. Change the connection password',
         'custom' => 'Custom Subscription',
-        'ss_only' => 'Subscribe SS only',
-        'ssr_only' => 'Subscribe SSR (incl. SS) only',
-        'v2ray_only' => 'Subscribe V2Ray only',
-        'trojan_only' => 'Subscribe Trojan only',
         'error' => 'Error changing subscription link',
+        'exchange_warning' => 'Changing the subscription link will:\n1. Revoke the current link immediately\n2. Change the connection password',
         'info' => [
-            'title' => 'Account Summary [Non-Realtime]',
-            'upload' => 'Upload',
             'download' => 'Download',
+            'title' => 'Account Summary [Non-Realtime]',
             'total' => 'Plan Data',
+            'upload' => 'Upload',
+        ],
+        'link' => 'Subscription Link',
+        'ss_only' => 'Subscribe SS only',
+        'ssr_only' => 'Subscribe SSR (incl. SS) only',
+        'tips' => 'Warning: This link is for personal use only. Do not share it, or your account may be banned for abnormal usage.',
+        'trojan_only' => 'Subscribe Trojan only',
+        'v2ray_only' => 'Subscribe V2Ray only',
+    ],
+    'telegram' => [
+        'bind_exists' => 'This account is already linked to a Telegram account.',
+        'bind_missing' => 'No user information found. Please link your account first.',
+        'command' => [
+            'bind' => 'Link your :web_name account',
+            'intro' => 'You can use the following commands',
+            'traffic' => 'Check data usage',
+            'unbind' => 'Unlink',
+            'web_url' => 'Get the latest :web_name URL',
         ],
+        'get_url' => 'The latest URL for :web_name is',
+        'params_missing' => 'Invalid parameters. Please include your email address and resend.',
+        'ticket_missing' => 'Ticket does not exist',
+        'ticket_reply' => 'Reply to ticket #`:id` was successful',
+        'traffic_query' => 'Data usage query',
+        'user_missing' => 'User does not exist',
     ],
     'ticket' => [
         'attribute' => 'Ticket',
-        'submit_tips' => 'Confirm submit ticket?',
-        'reply_confirm' => 'Confirm reply ticket?',
-        'close_tips' => 'Confirm close ticket?',
-        'close' => 'Close Ticket',
-        'failed_closed' => 'Error: Already closed',
-        'reply_placeholder' => 'Write something...',
-        'reply' => 'Reply',
         'close_msg' => 'Ticket ID :id closed by user',
-        'title_placeholder' => 'Briefly describe your issue',
+        'close_tips' => 'Confirm close ticket?',
         'content_placeholder' => 'Provide detailed description of your issue to help us assist you better',
+        'error' => 'Unknown error! Please contact support',
         'new' => 'Create New Ticket',
-        'service_hours' => 'Customer Service Hours',
         'online_hour' => 'Online Hours',
+        'reply' => 'Reply',
+        'reply_confirm' => 'Confirm reply ticket?',
+        'reply_placeholder' => 'Write something...',
+        'service_hours' => 'Customer Service Hours',
         'service_tips' => 'Please use only <code>one</code> contact method to reach support! Repeated requests will delay response time.',
-        'error' => 'Unknown error! Please contact support',
+        'submit_tips' => 'Confirm submit ticket?',
+        'title_placeholder' => 'Briefly describe your issue',
     ],
     'traffic_logs' => [
-        'hourly' => 'Today\'s Data Usage',
         'daily' => 'This Month\'s Data Usage',
+        'hourly' => 'Today\'s Data Usage',
         'tips' => 'Note: There is a delay in data statistics updates.',
     ],
-    'clients' => 'Clients',
     'tutorials' => 'Tutorials',
-    'current_role' => 'Current Role as',
-    'knowledge' => [
-        'title' => 'Knowledge Base',
-        'basic' => 'Basic',
-    ],
-    'manual' => [
-        'red_packet' => 'Alipay Red Packet',
-        'hint' => 'After scanning the QR code, continue clicking [Next] until [Submit] to complete the payment!',
-        'step_1' => 'Notes',
-        'step_1_title' => 'How to Pay Manually',
-        'step_2' => 'Payment',
-        'step_2_title' => 'Get QR code and pay',
-        'step_3' => 'Completion',
-        'step_3_title' => 'Wait for manual verification',
-        'remark' => 'Account Remark',
-        'remark_content' => 'Please provide your account username for accurate manual verification',
-        'payment_hint' => 'Please pay the exact amount (no refund for overpayment, top up for underpayment)',
-        'pre' => 'Previous',
-        'next' => 'Next',
-    ],
+    'withdraw' => 'Withdraw',
+    'withdraw_at' => 'Withdrawal Date',
+    'withdraw_commission' => 'Withdraw Commission',
+    'withdraw_logs' => 'Withdrawal Logs',
 ];

+ 12 - 1
resources/lang/fa.json

@@ -126,5 +126,16 @@
   "You are receiving this email because we received a password reset request for your account.": "شما این ایمیل را به دلیل درخواست رمزعبور جدید دریافت کرده‌اید.",
   "You have not responded this ticket in :num hours, System has closed your ticket.": "شما در :num ساعت به این تیکت پاسخ نداده‌اید، سیستم تیکت شما را بسته است.",
   "You must have a valid subscription to view the content in this area!": "برای مشاهده محتوای این منطقه باید اشتراک معتبر داشته باشید!",
-  "Your subscription has been disabled by the administrator, please contact the administrator to restore it": "اشتراک شما توسط مدیر غیرفعال شده است، لطفاً برای بازیابی آن با مدیر تماس بگیرید."
+  "Your subscription has been disabled by the administrator, please contact the administrator to restore it": "اشتراک شما توسط مدیر غیرفعال شده است، لطفاً برای بازیابی آن با مدیر تماس بگیرید.",
+  "Manually add in dashboard.": "به صورت دستی در داشبورد اضافه کنید",
+  "Manually edit in dashboard.": "به صورت دستی در داشبورد ویرایش کنید",
+  "Batch generate user accounts in dashboard.": "ایجاد حساب‌های کاربری به صورت گروهی در پس‌زمینه",
+  "Coupon used in order.": "کوپن در سفارش استفاده شده است",
+  "Order canceled, coupon reinstated.": "سفارش لغو شد و کوپن بازگردانی شد",
+  "Used for credit recharge.": "برای شارژ اعتبار استفاده می‌شود",
+  "The user manually reset the data.": "کاربر داده را بازنشانی کرد",
+  "Recharge using a recharge voucher.": "با استفاده از کوپن شارژ، اعتبار را شارژ کنید",
+  "The user topped up the balance.": "کاربر اعتبار را شارژ کرد",
+  "Purchased an item.": "کالایی خریداری شد",
+  "[:payment] plus the user’s purchased data plan.": "[:payment] به همراه بسته داده‌ای که کاربر خریداری کرده است"
 }

File diff suppressed because it is too large
+ 363 - 494
resources/lang/fa/admin.php


+ 1 - 12
resources/lang/fa/auth.php

@@ -40,27 +40,18 @@ return [
     ],
     'failed' => 'مشخصات وارد شده با اطلاعات ما سازگار نیست.',
     'invite' => [
-        'attribute' => 'کد دعوت',
-        'error' => [
-            'unavailable' => 'کد دعوت نامعتبر است، لطفاً دوباره تلاش کنید.',
-        ],
         'get' => 'دریافت کد دعوت',
         'not_required' => 'نیازی به کد دعوت نیست، می‌توانید مستقیماً ثبت نام کنید!',
+        'unavailable' => 'کد دعوت نامعتبر است، لطفاً دوباره تلاش کنید.',
     ],
     'login' => 'ورود',
     'logout' => 'خروج',
     'maintenance' => 'نگهداری',
     'maintenance_tip' => 'در حال نگهداری',
     'oauth' => [
-        'bind_failed' => 'اتصال ناموفق بود',
-        'bind_success' => 'اتصال موفقیت‌آمیز بود',
         'login_failed' => 'ورود با شخص ثالث ناموفق بود!',
-        'rebind_success' => 'اتصال مجدد موفقیت‌آمیز بود',
         'register' => 'ثبت نام سریع',
-        'register_failed' => 'ثبت نام ناموفق بود',
         'registered' => 'قبلاً ثبت نام کرده‌اید، لطفاً مستقیماً وارد شوید.',
-        'unbind_failed' => 'قطع اتصال ناموفق بود',
-        'unbind_success' => 'قطع اتصال موفقیت‌آمیز بود',
     ],
     'one-click_login' => 'ورود با یک کلیک',
     'optional' => 'اختیاری',
@@ -73,7 +64,6 @@ return [
             'error' => [
                 'demo' => 'در حالت دمو نمی‌توان رمز عبور ادمین را تغییر داد.',
                 'disabled' => 'بازنشانی رمز عبور غیر فعال شده است، لطفاً برای کمک با :email تماس بگیرید.',
-                'failed' => 'بازنشانی رمز عبور ناموفق بود.',
                 'same' => 'رمز عبور جدید نمی‌تواند با رمز عبور قدیمی یکسان باشد، لطفاً دوباره وارد کنید.',
                 'throttle' => 'شما می‌توانید فقط :time بار در 24 ساعت رمز عبور را بازنشانی کنید، لطفاً عملیات را تکرار نکنید.',
                 'wrong' => 'رمز عبور اشتباه است، لطفاً دوباره تلاش کنید.',
@@ -91,7 +81,6 @@ return [
         ],
         'failed' => 'ثبت نام ناموفق بود، لطفاً بعداً دوباره تلاش کنید.',
         'promotion' => 'هنوز حساب کاربری ندارید؟ لطفاً به ',
-        'success' => 'ثبت نام موفقیت‌آمیز بود',
     ],
     'remember_me' => 'مرا به خاطر بسپار',
     'request' => 'درخواست',

+ 97 - 89
resources/lang/fa/common.php

@@ -3,141 +3,149 @@
 declare(strict_types=1);
 
 return [
-    'hour' => '{1} ساعت|{2} ساعت',
     'account' => 'حساب',
+    'action' => 'عملیات',
+    'active_item' => 'فعال کردن :attribute',
+    'add' => 'اضافه کردن',
+    'advance' => 'پیشرفته',
+    'all' => 'همه',
+    'applied' => ':attribute اعمال شد',
+    'apply' => 'اعمال',
     'available_date' => 'دوره اعتبار',
-    'created_at' => 'تاریخ ایجاد',
-    'expired_at' => 'تاریخ انقضا',
-    'updated_at' => 'آخرین بروزرسانی',
-    'latest_at' => 'آخرین فعالیت',
+    'avatar' => 'آواتار',
     'back' => 'بازگشت',
     'back_to' => 'بازگشت به :page',
+    'bark' => [
+        'custom' => 'اطلاعات سفارشی',
+        'node_status' => 'وضعیت گره',
+    ],
     'cancel' => 'لغو',
+    'change' => 'تغییر',
     'close' => 'بستن',
     'close_item' => 'بستن :attribute',
     'confirm' => 'تأیید',
     'continue' => 'ادامه',
-    'open' => 'باز کردن',
-    'send' => 'ارسال',
-    'view' => 'مشاهده',
-    'reset' => 'بازنشانی',
+    'convert' => 'تبدیل',
     'copy' => [
         'attribute' => 'کپی',
-        'success' => 'کپی با موفقیت انجام شد',
         'failed' => 'کپی ناموفق بود، لطفاً دستی کپی کنید',
+        'success' => 'کپی با موفقیت انجام شد',
     ],
-    'add' => 'اضافه کردن',
-    'free' => 'رایگان',
-    'change' => 'تغییر',
-    'submit' => 'ارسال',
-    'submit_item' => 'ارسال :attribute',
-    'generate' => 'تولید',
-    'generate_item' => 'تولید :attribute',
-    'to_safari' => [0 => 'روی گوشه بالا سمت راست کلیک کنید', 1 => '، سپس انتخاب کنید', 2 => 'باز کردن در Safari', 3 => ' تا بتوانید به درستی به این سایت دسترسی پیدا کنید!'],
-    'update_browser' => [0 => 'شما از یک مرورگر', 1 => 'قدیمی', 2 => ' استفاده می‌کنید. لطفاً', 3 => 'مرورگر خود را ارتقا دهید', 4 => 'برای بهترین تجربه'],
-    'apply' => 'اعمال',
-    'avatar' => 'آواتار',
+    'create' => 'ایجاد کردن',
+    'created_at' => 'تاریخ ایجاد',
     'customize' => 'شخصی‌سازی',
-    'all' => 'همه',
-    'default' => 'پیش‌فرض',
-    'download' => 'دانلود',
-    'goto' => 'برو به',
-    'warning' => 'هشدار',
-    'success' => 'موفقیت',
-    'success_item' => ':attribute موفق شد',
-    'failed' => 'ناموفق',
-    'failed_item' => ':attribute ناموفق بود',
-    'update' => 'بروزرسانی',
-    'update_action' => 'بروزرسانی :action',
-    'none' => 'هیچ',
-    'new' => 'جدید',
-    'sorry' => 'متأسفیم',
-    'applied' => ':attribute اعمال شد',
-    'active_item' => 'فعال کردن :attribute',
-    'error' => 'خطا',
-    'toggle' => 'تغییر وضعیت',
-    'toggle_action' => 'تغییر وضعیت :action',
-    'request_url' => 'آدرس درخواست',
-    'function' => [
-        'navigation' => 'ناوبری',
-        'menubar' => 'نوار منو',
-        'fullscreen' => 'تمام صفحه',
-    ],
     'days' => [
         'attribute' => '{1} روز|{2} روز',
+        'next' => 'روز بعد',
         'weekend' => 'آخر هفته',
         'work' => 'روز کاری',
-        'next' => 'روز بعد',
     ],
-    'qrcode' => 'کد QR :attribute',
+    'default' => 'پیش‌فرض',
+    'delete' => 'حذف',
     'deleted' => 'حذف شد',
     'deleted_item' => ':attribute حذف شد',
-    'print' => 'چاپ',
-    'unlimited' => 'نامحدود',
-    'payment' => [
-        'credit' => 'اعتبار',
-        'alipay' => 'علی‌پی',
-        'qq' => 'کیف پول QQ',
-        'wechat' => 'پرداخت وی‌چت',
-        'crypto' => 'ارز دیجیتال',
-        'manual' => 'پرداخت دستی',
-        'status' => [
-            'wait' => 'در انتظار پرداخت',
-        ],
+    'developing' => 'در حال توسعه! منتظر بمانید',
+    'download' => 'دانلود',
+    'edit' => 'ویرایش',
+    'error' => 'خطا',
+    'error_action_item' => 'خطای:action:attribute',
+    'error_item' => 'خطای :attribute',
+    'exists_error' => 'حساب‌های مرتبطی تحت :attribute وجود دارد. لطفاً ابتدا ارتباطات را لغو کنید!',
+    'expired_at' => 'تاریخ انقضا',
+    'export' => 'صادر کردن',
+    'failed' => 'ناموفق',
+    'failed_action_item' => ':action :attribute ناموفق بود',
+    'failed_item' => ':attribute ناموفق بود',
+    'free' => 'رایگان',
+    'function' => [
+        'fullscreen' => 'تمام صفحه',
+        'menubar' => 'نوار منو',
+        'navigation' => 'ناوبری',
     ],
+    'generate' => 'تولید',
+    'generate_item' => 'تولید :attribute',
+    'goto' => 'برو به',
+    'hour' => '{1} ساعت|{2} ساعت',
+    'import' => 'وارد کردن',
+    'latest_at' => 'آخرین فعالیت',
+    'more' => 'بیشتر',
+    'new' => 'جدید',
+    'none' => 'هیچ',
+    'open' => 'باز کردن',
+    'or' => 'یا',
     'order' => [
         'status' => [
             'canceled' => 'لغو شده',
             'completed' => 'تکمیل شده',
-            'prepaid' => 'پیش‌پرداخت',
             'ongoing' => 'در حال استفاده',
+            'prepaid' => 'پیش‌پرداخت',
             'review' => 'در انتظار بررسی',
         ],
     ],
+    'payment' => [
+        'alipay' => 'علی‌پی',
+        'credit' => 'اعتبار',
+        'crypto' => 'ارز دیجیتال',
+        'manual' => 'پرداخت دستی',
+        'qq' => 'کیف پول QQ',
+        'wechat' => 'پرداخت وی‌چت',
+    ],
+    'print' => 'چاپ',
+    'qrcode' => 'کد QR :attribute',
+    'random_generate' => 'خالی بگذارید تا به صورت تصادفی تولید شود',
     'recommend' => 'توصیه',
-    'advance' => 'پیشرفته',
-    'action' => 'عملیات',
+    'request' => 'درخواست',
+    'request_failed' => 'درخواست ناموفق بود، لطفاً دوباره تلاش کنید',
+    'request_url' => 'آدرس درخواست',
+    'reset' => 'بازنشانی',
     'search' => 'جستجو',
-    'edit' => 'ویرایش',
-    'delete' => 'حذف',
+    'send' => 'ارسال',
+    'sorry' => 'متأسفیم',
     'status' => [
+        'applying' => 'در حال درخواست',
         'attribute' => 'وضعیت',
-        'inactive' => 'غیرفعال',
-        'disabled' => 'غیرفعال',
+        'available' => 'در دسترس',
         'banned' => 'ممنوع',
-        'normal' => 'عادی',
+        'closed' => 'بسته شده',
+        'disabled' => 'غیرفعال',
         'enabled' => 'فعال',
         'expire' => 'منقضی شده',
+        'inactive' => 'غیرفعال',
         'limited' => 'محدود',
-        'run_out' => 'تمام شده',
-        'unused' => 'استفاده نشده',
-        'used' => 'استفاده شده',
-        'closed' => 'بسته شده',
-        'applying' => 'در حال درخواست',
-        'withdrawn' => 'برداشت شده',
-        'unwithdrawn' => 'برداشت نشده',
-        'reply' => 'پاسخ داده شده',
+        'normal' => 'عادی',
+        'paid' => 'پرداخت شده',
+        'pass' => 'قبول',
+        'payment_pending' => 'در انتظار پرداخت',
         'pending' => 'در انتظار',
-        'unknown' => 'ناشناخته',
-        'available' => 'در دسترس',
+        'pending_dispatch' => 'در انتظار تحویل',
         'reject' => 'رد',
         'rejected' => 'رد شده',
+        'reply' => 'پاسخ داده شده',
         'review' => 'در انتظار بررسی',
         'reviewed' => 'بررسی شده',
-        'paid' => 'پرداخت شده',
-        'payment_pending' => 'در انتظار پرداخت',
-        'pass' => 'قبول',
+        'run_out' => 'تمام شده',
         'send_to_credit' => 'اضافه به اعتبار',
-        'waiting_tobe_send' => 'در انتظار ارسال',
+        'unknown' => 'ناشناخته',
+        'unused' => 'استفاده نشده',
+        'used' => 'استفاده شده',
+        'withdrawal_pending' => 'برداشت نشده',
+        'withdrawn' => 'برداشت شده',
     ],
     'stay_unchanged' => 'خالی بگذارید تا تغییر نکند',
-    'random_generate' => 'خالی بگذارید تا به صورت تصادفی تولید شود',
-    'request_failed' => 'درخواست ناموفق بود، لطفاً دوباره تلاش کنید',
-    'convert' => 'تبدیل',
-    'import' => 'وارد کردن',
-    'or' => 'یا',
-    'more' => 'بیشتر',
+    'storage_logo' => 'ذخیره‌سازی لوگو',
+    'store' => 'ذخیره‌سازی',
+    'submit' => 'ارسال',
+    'success' => 'موفقیت',
+    'success_action_item' => ':action :attribute با موفقیت',
+    'success_item' => ':attribute موفق شد',
     'to' => 'به',
     'to_be_send' => 'در انتظار ارسال',
-    'developing' => 'در حال توسعه! منتظر بمانید',
+    'to_safari' => 'روی آیکون <i class="icon wb-more-horizontal" aria-hidden="true"></i> در بالای سمت راست کلیک کنید، سپس انتخاب کنید "باز کردن در <img class="w-30 h-30 vertical-align-middle m-3" src="https://gw.alicdn.com/tfs/TB1xwiUNpXXXXaIXXXXXXXXXXXX-55-55.png" alt="Safari" /> Safari" تا به درستی به سایت ما دسترسی پیدا کنید!',
+    'toggle' => 'تغییر وضعیت',
+    'toggle_action' => 'تغییر وضعیت :action',
+    'unlimited' => 'نامحدود',
+    'update' => 'بروزرسانی',
+    'updated_at' => 'آخرین بروزرسانی',
+    'view' => 'مشاهده',
+    'warning' => 'هشدار',
 ];

+ 13 - 13
resources/lang/fa/errors.php

@@ -8,29 +8,29 @@ return [
         'bots' => 'دسترسی ربات شناسایی شد، دسترسی ممنوع',
         'china' => 'دسترسی IP یا پروکسی چین شناسایی شد، دسترسی ممنوع',
         'oversea' => 'دسترسی IP یا پروکسی خارج از کشور شناسایی شد، دسترسی ممنوع',
-        'unknown' => 'حالت دسترسی ممنوع ناشناخته! لطفاً [حالت مسدودسازی] را در تنظیمات سیستم تغییر دهید!',
         'redirect' => '(:ip :url) از طریق پیوند اشتراک دسترسی شناسایی شد، تغییر مسیر اجباری.',
+        'unknown' => 'حالت دسترسی ممنوع ناشناخته! لطفاً [حالت مسدودسازی] را در تنظیمات سیستم تغییر دهید!',
     ],
+    'get_ip' => 'دریافت اطلاعات IP ناموفق بود',
     'log' => 'لاگ',
     'refresh' => 'تازه‌سازی',
     'refresh_page' => 'لطفاً صفحه را تازه‌سازی کنید و دوباره تلاش کنید',
     'report' => 'خطا حاوی گزارشی بود: ',
-    'safe_enter' => 'ورود امن',
     'safe_code' => 'لطفاً کد ایمنی را وارد کنید',
-    'title' => '⚠️ خطا رخ داد',
-    'unsafe_enter' => 'ورود ناامن',
-    'visit' => 'لطفاً مراجعه کنید به',
-    'whoops' => 'اوپس!',
-    'get_ip' => 'دریافت اطلاعات IP ناموفق بود',
+    'safe_enter' => 'ورود امن',
     'subscribe' => [
-        'unknown' => 'لینک اشتراک نامعتبر است! لطفاً لینک جدیدی دریافت کنید!',
-        'sub_banned' => 'اشتراک ممنوع شده! برای جزئیات به وب‌سایت مراجعه کنید',
-        'user' => 'URL نامعتبر است، حساب وجود ندارد!',
-        'user_disabled' => 'حساب غیرفعال شده است! با پشتیبانی تماس بگیرید!',
         'banned_until' => 'حساب تا :time ممنوع شده، لطفاً برای باز شدن صبر کنید!',
-        'out' => 'داده تمام شده! لطفاً بیشتر خریداری کنید یا داده را بازنشانی کنید!',
         'expired' => 'حساب منقضی شده! لطفاً اشتراک خود را تمدید کنید!',
-        'question' => 'مشکلات حساب؟! برای جزئیات به وب‌سایت مراجعه کنید',
         'none' => 'هیچ گره‌ای در دسترس نیست',
+        'out' => 'داده تمام شده! لطفاً بیشتر خریداری کنید یا داده را بازنشانی کنید!',
+        'question' => 'مشکلات حساب؟! برای جزئیات به وب‌سایت مراجعه کنید',
+        'sub_banned' => 'اشتراک ممنوع شده! برای جزئیات به وب‌سایت مراجعه کنید',
+        'unknown' => 'لینک اشتراک نامعتبر است! لطفاً لینک جدیدی دریافت کنید!',
+        'user' => 'URL نامعتبر است، حساب وجود ندارد!',
+        'user_disabled' => 'حساب غیرفعال شده است! با پشتیبانی تماس بگیرید!',
     ],
+    'title' => '⚠️ خطا رخ داد',
+    'unsafe_enter' => 'ورود ناامن',
+    'visit' => 'لطفاً مراجعه کنید به',
+    'whoops' => 'اوپس!',
 ];

+ 152 - 151
resources/lang/fa/model.php

@@ -3,105 +3,114 @@
 declare(strict_types=1);
 
 return [
-    'user' => [
-        'id' => 'شناسه کاربر',
-        'attribute' => 'کاربر',
-        'nickname' => 'نام مستعار',
-        'username' => 'نام کاربری',
-        'password' => 'رمز عبور',
-        'credit' => 'اعتبار',
-        'invite_num' => 'تعداد دعوت‌های موجود',
-        'reset_date' => 'تاریخ بازنشانی داده',
-        'port' => 'پورت',
-        'traffic_used' => 'داده استفاده شده',
-        'service' => 'پروکسی',
-        'group' => 'گروه',
-        'account_status' => 'وضعیت حساب',
-        'proxy_status' => 'وضعیت پروکسی',
-        'expired_date' => 'تاریخ انقضا',
-        'role' => 'نقش',
-        'wechat' => 'وی‌چت',
-        'qq' => 'QQ',
-        'remark' => 'یادداشت',
-        'uuid' => 'VMess UUID',
-        'proxy_passwd' => 'رمز پروکسی',
-        'proxy_method' => 'رمزنگاری',
-        'usable_traffic' => 'مقدار داده مجاز',
-        'proxy_protocol' => 'پروتکل',
-        'proxy_obfs' => 'پنهان‌سازی',
-        'speed_limit' => 'محدودیت سرعت',
-        'inviter' => 'دعوت‌کننده',
-        'created_date' => 'تاریخ ثبت‌نام',
+    'aff' => [
+        'amount' => 'مقدار سفارش',
+        'commission' => 'کمیسیون',
+        'created_at' => 'سفارش شده در',
+        'invitee' => 'خریدار',
+        'updated_at' => 'پردازش شده در',
+    ],
+    'article' => [
+        'attribute' => 'مقاله',
+        'category' => 'دسته‌بندی',
+        'created_at' => 'منتشر شده در',
+        'language' => 'زبان',
+        'logo' => 'کاور',
+        'updated_at' => 'بروزرسانی شده در',
     ],
     'common' => [
+        'description' => 'توضیحات',
         'extend' => 'اطلاعات گسترش یافته',
+        'level' => 'سطح',
         'sort' => 'مرتب‌سازی',
-        'description' => 'توضیحات',
         'type' => 'نوع',
-        'level' => 'سطح',
     ],
     'country' => [
         'code' => 'کد کشور',
         'icon' => 'پرچم',
         'name' => 'نام کشور',
     ],
-    'subscribe' => [
-        'code' => 'کد اشتراک',
-        'req_times' => 'تعداد درخواست‌ها',
-        'updated_at' => 'آخرین درخواست',
-        'ban_time' => 'زمان ممنوعیت',
-        'ban_desc' => 'دلیل ممنوعیت',
-        'req_ip' => 'IP درخواست',
-        'req_header' => 'هدر دسترسی',
+    'coupon' => [
+        'attribute' => 'کوپن',
+        'groups' => 'محدودیت گروه',
+        'levels' => 'محدودیت سطح',
+        'logo' => 'لوگو',
+        'minimum' => 'حداقل هزینه',
+        'name' => 'نام',
+        'newbie' => 'فقط برای کاربران جدید',
+        'num' => 'تعداد',
+        'priority' => 'اولویت',
+        'services_blacklist' => 'کالاهای ممنوع',
+        'services_whitelist' => 'کالاهای مجاز',
+        'sn' => 'کد',
+        'usable_times' => 'تعداد استفاده',
+        'used' => 'محدودیت شخصی',
+        'users_blacklist' => 'کاربران ممنوع',
+        'users_whitelist' => 'کاربران مجاز',
+        'value' => 'مقدار',
     ],
-    'oauth' => [
-        'type' => 'کانال',
-        'identifier' => 'شناسه',
+    'goods' => [
+        'attribute' => 'کالا',
+        'available_date' => 'دوره اعتبار',
+        'category' => 'دسته‌بندی',
+        'color' => 'رنگ',
+        'hot' => 'پرفروش',
+        'info' => 'اطلاعات سفارشی',
+        'invite_num' => 'دعوت‌نامه‌های اضافی',
+        'limit_num' => 'محدودیت خرید',
+        'logo' => 'لوگو',
+        'name' => 'نام',
+        'period' => 'دوره بازنشانی',
+        'price' => 'قیمت',
+        'renew' => 'قیمت بازنشانی داده',
+        'traffic' => 'مقدار داده مجاز',
+        'user_limit' => 'محدودیت سرعت کاربر',
     ],
-    'user_group' => [
-        'attribute' => 'گروه کاربری',
-        'name' => 'نام گروه',
-        'nodes' => 'گره‌ها',
+    'ip' => [
+        'info' => 'مکان',
+        'network_type' => 'نوع شبکه',
     ],
     'node' => [
         'attribute' => 'گره',
-        'id' => 'شناسه گره',
-        'name' => 'نام',
-        'domain' => 'دامنه',
-        'static' => 'وضعیت زنده بودن',
-        'online_user' => 'کاربران آنلاین',
+        'client_limit' => 'محدودیت کاربر',
+        'country' => 'کشور',
         'data_consume' => 'مصرف داده',
         'data_rate' => 'نسبت داده',
         'ddns' => 'DDNS',
+        'detection' => 'تشخیص مسدود شدن',
+        'display' => 'نمایش و اشتراک',
+        'domain' => 'دامنه',
+        'id' => 'شناسه گره',
         'ipv4' => 'IPv4',
         'ipv6' => 'IPv6',
-        'push_port' => 'پورت ارسال',
-        'rule_group' => 'گروه قوانین',
-        'traffic_limit' => 'محدودیت سرعت',
-        'client_limit' => 'محدودیت کاربر',
         'label' => 'برچسب',
-        'country' => 'کشور',
-        'udp' => 'UDP',
-        'display' => 'نمایش و اشتراک',
-        'detection' => 'تشخیص مسدود شدن',
         'method' => 'رمزنگاری',
-        'protocol' => 'پروتکل',
-        'protocol_param' => 'پارامتر پروتکل',
+        'name' => 'نام',
+        'next_renewal_date' => 'تاریخ تمدید بعدی',
         'obfs' => 'پنهان‌سازی',
         'obfs_param' => 'پارامتر پنهان‌سازی',
-        'single' => 'پورت تکی',
-        'transfer' => 'رله',
+        'online_user' => 'کاربران آنلاین',
+        'protocol' => 'پروتکل',
+        'protocol_param' => 'پارامتر پروتکل',
+        'push_port' => 'پورت ارسال',
+        'relay_port' => 'پورت رله',
+        'renewal_cost' => 'مبلغ صورتحساب',
         'service_port' => 'پورت سرویس',
+        'single' => 'پورت تکی',
         'single_passwd' => '[تکی] رمز عبور',
+        'static' => 'وضعیت زنده بودن',
+        'subscription_term' => 'مدت اشتراک',
+        'traffic_limit' => 'محدودیت سرعت',
+        'transfer' => 'رله',
+        'udp' => 'UDP',
         'v2_alter_id' => 'شناسه جایگزین',
-        'v2_net' => 'شبکه',
         'v2_cover' => 'پوشش',
         'v2_host' => 'میزبان',
+        'v2_net' => 'شبکه',
         'v2_path' => 'مسیر | کلید',
         'v2_sni' => 'SNI',
         'v2_tls' => 'TLS',
         'v2_tls_provider' => 'پیکربندی TLS',
-        'relay_port' => 'پورت رله',
     ],
     'node_auth' => [
         'attribute' => 'احراز هویت گره',
@@ -111,36 +120,44 @@ return [
     'node_cert' => [
         'attribute' => 'گواهینامه دامنه',
         'domain' => 'دامنه',
+        'expired_date' => 'تاریخ انقضا',
+        'issuer' => 'صادر کننده',
         'key' => 'کلید',
         'pem' => 'PEM',
-        'issuer' => 'صادر کننده',
         'signed_date' => 'تاریخ امضا',
-        'expired_date' => 'تاریخ انقضا',
+    ],
+    'notification' => [
+        'address' => 'گیرنده',
+        'created_at' => 'ارسال شده در',
+        'status' => 'وضعیت',
+    ],
+    'oauth' => [
+        'identifier' => 'شناسه',
+        'type' => 'کانال',
     ],
     'order' => [
         'attribute' => 'سفارش',
         'id' => 'شناسه سفارش',
         'original_price' => 'قیمت اولیه',
-        'price' => 'قیمت واقعی',
         'pay_way' => 'روش پرداخت',
+        'price' => 'قیمت واقعی',
         'status' => 'وضعیت',
     ],
-    'goods' => [
-        'attribute' => 'کالا',
+    'permission' => [
+        'attribute' => 'مجوز',
+        'description' => 'توضیحات',
+        'name' => 'نام مسیر',
+    ],
+    'referral' => [
+        'amount' => 'مقدار',
+        'created_at' => 'درخواست شده در',
+        'id' => 'شناسه درخواست',
+        'user' => 'درخواست کننده',
+    ],
+    'role' => [
+        'attribute' => 'نقش',
         'name' => 'نام',
-        'price' => 'قیمت',
-        'category' => 'دسته‌بندی',
-        'renew' => 'قیمت بازنشانی داده',
-        'user_limit' => 'محدودیت سرعت کاربر',
-        'period' => 'دوره بازنشانی',
-        'traffic' => 'مقدار داده مجاز',
-        'invite_num' => 'دعوت‌نامه‌های اضافی',
-        'limit_num' => 'محدودیت خرید',
-        'available_date' => 'دوره اعتبار',
-        'hot' => 'پرفروش',
-        'color' => 'رنگ',
-        'logo' => 'لوگو',
-        'info' => 'اطلاعات سفارشی',
+        'permissions' => 'مجوزها',
     ],
     'rule' => [
         'attribute' => 'قانون',
@@ -150,83 +167,67 @@ return [
     'rule_group' => [
         'attribute' => 'گروه قوانین',
         'name' => 'نام',
-        'type' => 'نوع',
         'rules' => 'قوانین',
+        'type' => 'نوع',
     ],
-    'role' => [
-        'attribute' => 'نقش',
-        'name' => 'نام',
-        'permissions' => 'مجوزها',
-    ],
-    'permission' => [
-        'attribute' => 'مجوز',
-        'description' => 'توضیحات',
-        'name' => 'نام مسیر',
-    ],
-    'article' => [
-        'attribute' => 'مقاله',
-        'category' => 'دسته‌بندی',
-        'language' => 'زبان',
-        'logo' => 'کاور',
-        'created_at' => 'منتشر شده در',
-        'updated_at' => 'بروزرسانی شده در',
-    ],
-    'coupon' => [
-        'attribute' => 'کوپن',
-        'name' => 'نام',
-        'sn' => 'کد',
-        'logo' => 'لوگو',
-        'value' => 'مقدار',
-        'priority' => 'اولویت',
-        'usable_times' => 'تعداد استفاده',
-        'minimum' => 'حداقل هزینه',
-        'used' => 'محدودیت شخصی',
-        'levels' => 'محدودیت سطح',
-        'groups' => 'محدودیت گروه',
-        'users_whitelist' => 'کاربران مجاز',
-        'users_blacklist' => 'کاربران ممنوع',
-        'services_whitelist' => 'کالاهای مجاز',
-        'services_blacklist' => 'کالاهای ممنوع',
-        'newbie' => 'فقط برای کاربران جدید',
-        'num' => 'تعداد',
+    'subscribe' => [
+        'ban_desc' => 'دلیل ممنوعیت',
+        'ban_time' => 'زمان ممنوعیت',
+        'code' => 'کد اشتراک',
+        'req_header' => 'هدر دسترسی',
+        'req_ip' => 'IP درخواست',
+        'req_times' => 'تعداد درخواست‌ها',
+        'updated_at' => 'آخرین درخواست',
     ],
-    'aff' => [
-        'invitee' => 'خریدار',
-        'amount' => 'مقدار سفارش',
-        'commission' => 'کمیسیون',
-        'updated_at' => 'پردازش شده در',
-        'created_at' => 'سفارش شده در',
+    'user' => [
+        'account_status' => 'وضعیت حساب',
+        'attribute' => 'کاربر',
+        'created_date' => 'تاریخ ثبت‌نام',
+        'credit' => 'اعتبار',
+        'expired_date' => 'تاریخ انقضا',
+        'id' => 'شناسه کاربر',
+        'invite_num' => 'تعداد دعوت‌های موجود',
+        'inviter' => 'دعوت‌کننده',
+        'nickname' => 'نام مستعار',
+        'password' => 'رمز عبور',
+        'port' => 'پورت',
+        'proxy_method' => 'رمزنگاری',
+        'proxy_obfs' => 'پنهان‌سازی',
+        'proxy_passwd' => 'رمز پروکسی',
+        'proxy_protocol' => 'پروتکل',
+        'proxy_status' => 'وضعیت پروکسی',
+        'qq' => 'QQ',
+        'remark' => 'یادداشت',
+        'reset_date' => 'تاریخ بازنشانی داده',
+        'role' => 'نقش',
+        'service' => 'پروکسی',
+        'speed_limit' => 'محدودیت سرعت',
+        'traffic_used' => 'داده استفاده شده',
+        'usable_traffic' => 'مقدار داده مجاز',
+        'username' => 'نام کاربری',
+        'uuid' => 'VMess UUID',
+        'wechat' => 'وی‌چت',
     ],
-    'referral' => [
-        'created_at' => 'درخواست شده در',
-        'user' => 'درخواست کننده',
-        'amount' => 'مقدار',
-        'id' => 'شناسه درخواست',
+    'user_credit' => [
+        'after' => 'بعد از تغییر',
+        'amount' => 'مقدار تغییر',
+        'before' => 'قبل از تغییر',
+        'created_at' => 'زمان تغییر',
     ],
-    'notification' => [
-        'address' => 'گیرنده',
-        'created_at' => 'ارسال شده در',
-        'status' => 'وضعیت',
+    'user_data_modify' => [
+        'after' => 'بعد از تغییر',
+        'before' => 'قبل از تغییر',
+        'created_at' => 'زمان تغییر',
     ],
-    'ip' => [
-        'network_type' => 'نوع شبکه',
-        'info' => 'مکان',
+    'user_group' => [
+        'attribute' => 'گروه کاربری',
+        'name' => 'نام گروه',
+        'nodes' => 'گره‌ها',
     ],
     'user_traffic' => [
-        'upload' => 'آپلود',
         'download' => 'دانلود',
-        'total' => 'کل',
         'log_time' => 'زمان ثبت',
-    ],
-    'user_data_modify' => [
-        'before' => 'قبل از تغییر',
-        'after' => 'بعد از تغییر',
-        'created_at' => 'زمان تغییر',
-    ],
-    'user_credit' => [
-        'before' => 'قبل از تغییر',
-        'after' => 'بعد از تغییر',
-        'amount' => 'مقدار تغییر',
-        'created_at' => 'زمان تغییر',
+        'total' => 'کل',
+        'upload' => 'آپلود',
     ],
 ];

+ 33 - 19
resources/lang/fa/notification.php

@@ -3,35 +3,49 @@
 declare(strict_types=1);
 
 return [
-    'attribute' => 'اعلان',
-    'new' => 'شما :num پیام جدید دارید',
-    'empty' => 'شما در حال حاضر هیچ پیام جدیدی ندارید',
-    'payment_received' => 'پرداخت سفارش شما با مبلغ :amount با موفقیت انجام شد، لطفاً برای مشاهده جزئیات سفارش کلیک کنید',
     'account_expired' => 'یادآوری انقضای حساب',
-    'account_expired_content' => 'حساب شما در :days روز آینده منقضی خواهد شد، لطفاً برای جلوگیری از هرگونه مشکل در استفاده به موقع تمدید کنید',
     'account_expired_blade' => 'حساب شما در :days روز آینده منقضی خواهد شد، لطفاً به موقع تمدید کنید',
+    'account_expired_content' => 'حساب شما در :days روز آینده منقضی خواهد شد، لطفاً برای جلوگیری از هرگونه مشکل در استفاده به موقع تمدید کنید',
     'active_email' => 'لطفاً در عرض 30 دقیقه تأیید را تکمیل کنید',
+    'attribute' => 'اعلان',
+    'block_report' => 'گزارش مسدود شدن:',
     'close_ticket' => 'تیکت شماره :id با عنوان :title بسته شده است',
-    'view_web' => 'بازدید از وب‌سایت ما',
-    'view_ticket' => 'مشاهده وضعیت این تیکت',
+    'data_anomaly' => 'هشدار کاربر با داده غیرعادی',
+    'data_anomaly_content' => 'کاربر :id: [آپلود: :upload | دانلود: :download | مجموع: :total] در ساعت گذشته',
+    'details' => 'مشاهده جزئیات',
+    'details_btn' => 'لطفاً روی دکمه زیر کلیک کنید تا جزئیات را مشاهده کنید.',
+    'ding_bot_limit' => 'هر ربات می‌تواند حداکثر 20 پیام در دقیقه به گروه ارسال کند. اگر این حد تجاوز شود، محدودیت برای 10 دقیقه اعمال می‌شود.',
+    'empty' => 'شما در حال حاضر هیچ پیام جدیدی ندارید',
+    'error' => '[:channel] ارسال پیام با استثنا: :reason',
+    'get_access_token_failed' => 'دریافت توکن دسترسی با شکست مواجه شد!\nبا پارامترهای درخواست: :body',
+    'into_maintenance' => 'به‌طور خودکار وارد حالت نگهداری شوید',
+    'new' => 'شما :num پیام جدید دارید',
     'new_ticket' => 'تیکت جدید شما با عنوان :title دریافت شد، لطفاً برای مشاهده مراجعه کنید',
-    'reply_ticket' => 'پاسخ تیکت: :title',
-    'ticket_content' => 'محتوای تیکت:',
+    'next_check_time' => 'زمان بعدی بررسی انسداد گره: :time',
+    'node' => [
+        'download' => 'دانلود',
+        'total' => 'مجموع',
+        'upload' => 'آپلود',
+    ],
     'node_block' => 'هشدار مسدود شدن گره',
     'node_offline' => 'هشدار آفلاین بودن گره',
     'node_offline_content' => 'گره‌های زیر غیرعادی هستند و ممکن است آفلاین باشند:',
-    'block_report' => 'گزارش مسدود شدن:',
-    'traffic_warning' => 'هشدار استفاده از داده',
+    'node_renewal' => 'یادآوری تمدید گره',
+    'node_renewal_blade' => 'گره‌های زیر در حال نزدیک شدن به تاریخ انقضا هستند. لطفاً به‌موقع تمدید کنید: :nodes',
+    'node_renewal_content' => 'گره‌های زیر در حال نزدیک شدن به تاریخ انقضا هستند. لطفاً قبل از انقضا تمدید کنید تا از قطع خدمات جلوگیری شود.',
+    'payment_received' => 'پرداخت سفارش شما با مبلغ :amount با موفقیت انجام شد، لطفاً برای مشاهده جزئیات سفارش کلیک کنید',
+    'reply_ticket' => 'پاسخ تیکت: :title',
+    'reset_failed' => '[وظیفه روزانه] کاربر :uid - :username بازنشانی داده‌ها ناموفق بود',
+    'serverChan_exhausted' => 'حد مجاز امروز به پایان رسید!',
+    'serverChan_limit' => 'فرکانس در هر دقیقه بیش از حد بالا است. لطفاً تنظیمات اعلان را بهینه کنید!',
+    'sign_failed' => 'تأیید امضای امنیتی ناموفق بود',
+    'ticket_content' => 'محتوای تیکت:',
     'traffic_remain' => 'شما :percent% از داده خود را استفاده کرده‌اید، لطفاً توجه کنید',
     'traffic_tips' => 'لطفاً به تاریخ بازنشانی داده توجه کنید و داده‌ها را به صورت منطقی استفاده کنید یا پس از اتمام، مجدداً شارژ کنید',
-    'verification_account' => 'تأیید حساب',
+    'traffic_warning' => 'هشدار استفاده از داده',
     'verification' => 'کد تأیید شما:',
+    'verification_account' => 'تأیید حساب',
     'verification_limit' => 'لطفاً در عرض :minutes دقیقه تأیید را تکمیل کنید',
-    'data_anomaly' => 'هشدار کاربر با داده غیرعادی',
-    'data_anomaly_content' => 'کاربر :id: [آپلود: :upload | دانلود: :download | مجموع: :total] در ساعت گذشته',
-    'node' => [
-        'upload' => 'آپلود',
-        'download' => 'دانلود',
-        'total' => 'مجموع',
-    ],
+    'view_ticket' => 'مشاهده وضعیت این تیکت',
+    'view_web' => 'بازدید از وب‌سایت ما',
 ];

+ 10 - 0
resources/lang/fa/setup.php

@@ -0,0 +1,10 @@
+<?php
+
+declare(strict_types=1);
+
+return [
+    'demo_reset' => 'شناسایی شد که شما در حالت دمو هستید. آیا می‌خواهید پایگاه داده را بازنشانی کنید؟',
+    'update_cache' => 'به‌روزرسانی کش...',
+    'update_complete' => 'به‌روزرسانی کامل شد!',
+    'update_db' => 'به‌روزرسانی پایگاه داده...',
+];

+ 185 - 146
resources/lang/fa/user.php

@@ -4,234 +4,273 @@ declare(strict_types=1);
 
 return [
     'account' => [
+        'connect_password' => 'رمز اتصال پروکسی',
         'credit' => 'موجودی حساب',
-        'status' => 'وضعیت حساب',
-        'level' => 'سطح حساب',
         'group' => 'گروه',
-        'speed_limit' => 'محدودیت سرعت',
-        'remain' => 'داده باقیمانده',
-        'time' => 'مدت طرح',
         'last_login' => 'آخرین ورود',
-        'reset' => '{0} داده در <code id="restTime">:days</code> بازنشانی می‌شود |{1} :days روز تا بازنشانی داده باقی مانده است |[2,*] :days روز تا بازنشانی داده باقی مانده است',
-        'connect_password' => 'رمز اتصال پروکسی',
+        'level' => 'سطح حساب',
         'reason' => [
-            'normal' => 'حساب عادی است',
             'expired' => 'طرح شما منقضی شده است',
+            'normal' => 'حساب عادی است',
             'overused' => 'شما از حد <code>:data</code> گیگابایت برای این دوره فراتر رفته‌اید<br/> محدودیت در <code id="banedTime">:min</code> دقیقه برداشته می‌شود',
             'traffic_exhausted' => 'داده تمام شده است',
             'unknown' => 'دلیل ناشناخته، لطفاً مرورگر را تازه‌سازی کنید! اگر مشکل ادامه داشت، با پشتیبانی تماس بگیرید.',
         ],
+        'remain' => 'داده باقیمانده',
+        'reset' => '{0} داده در <code id="restTime">:days</code> بازنشانی می‌شود |{1} :days روز تا بازنشانی داده باقی مانده است |[2,*] :days روز تا بازنشانی داده باقی مانده است',
+        'speed_limit' => 'محدودیت سرعت',
+        'status' => 'وضعیت حساب',
+        'time' => 'مدت طرح',
     ],
+    'attribute' => [
+        'address' => 'مکان',
+        'data' => 'داده',
+        'ip' => 'آدرس IP',
+        'isp' => 'ISP',
+        'node' => 'گره',
+    ],
+    'bought_at' => 'تاریخ خرید',
+    'clients' => 'کلاینت‌ها',
+    'contact' => 'تماس',
+    'coupon' => [
+        'discount' => 'تخفیف',
+        'error' => [
+            'expired' => 'کوپن منقضی شده',
+            'inactive' => 'کوپن فعال نیست',
+            'minimum' => 'حداقل مبلغ :amount است',
+            'overused' => 'فقط می‌توان :times بار استفاده کرد',
+            'run_out' => 'کوپن تمام شده',
+            'services' => 'کالاها واجد شرایط تخفیف نیستند، شرایط تبلیغ را بررسی کنید',
+            'unknown' => 'کوپن نامعتبر',
+            'unmet' => 'شرایط استفاده رعایت نشده',
+            'used' => 'کوپن قبلاً استفاده شده',
+            'users' => 'حساب واجد شرایط برای تبلیغ نیست',
+            'wait' => 'در :time فعال خواهد شد، لطفاً صبر کنید!',
+        ],
+        'input' => 'کد کوپن را وارد کنید',
+    ],
+    'current_role' => 'نقش فعلی به عنوان',
+    'error_response' => 'خطایی رخ داده است، لطفاً بعداً دوباره امتحان کنید.',
     'home' => [
+        'announcement' => 'اعلانات',
         'attendance' => [
             'attribute' => 'ثبت حضور',
             'disable' => 'ثبت حضور غیرفعال است',
             'done' => 'شما قبلاً ثبت حضور کرده‌اید. فردا برگردید!',
-            'success' => 'شما :data داده دریافت کردید',
             'failed' => 'خطای سیستم',
+            'success' => 'شما :data داده دریافت کردید',
         ],
-        'traffic_logs' => 'سوابق داده',
-        'announcement' => 'اعلانات',
-        'wechat_push' => 'اعلانات وی‌چت',
         'chat_group' => 'گروه چت',
         'empty_announcement' => 'هیچ اعلانی وجود ندارد',
+        'traffic_logs' => 'سوابق داده',
+        'wechat_push' => 'اعلانات وی‌چت',
     ],
-    'purchase_to_unlock' => 'خرید برای باز کردن',
-    'purchase_required' => 'این ویژگی برای کاربران غیرپرداختی غیرفعال است. لطفاً',
-    'attribute' => [
-        'node' => 'گره',
-        'data' => 'داده',
-        'ip' => 'آدرس IP',
-        'isp' => 'ISP',
-        'address' => 'مکان',
+    'invite' => [
+        'attribute' => 'کد دعوت',
+        'counts' => 'مجموع <code>:num</code> کد دعوت',
+        'generate_failed' => 'تولید ناموفق: سهمیه تمام شده',
+        'logs' => 'سوابق دعوت',
+        'promotion' => 'هم شما و هم دعوت‌شونده <mark>:traffic</mark> داده دریافت خواهید کرد وقتی که با کد شما ثبت نام کنند؛ شما <mark>:referral_percent%</mark> کمیسیون دریافت خواهید کرد وقتی که آنها خرید کنند.',
+        'tips' => '<strong>:num</strong> دعوت باقی مانده، کدها :days روز پس از ایجاد منقضی می‌شوند',
+    ],
+    'invitee' => 'دعوت‌شونده',
+    'inviter' => 'دعوت‌کننده',
+    'invoice' => [
+        'active_prepaid_question' => 'فعال سازی بسته پیش پرداخت زودتر؟',
+        'active_prepaid_tips' => 'پس از فعال‌سازی:<br>طرح فعلی شما بلافاصله منقضی می‌شود<br>تاریخ انقضای طرح جدید از امروز محاسبه می‌شود',
+        'amount' => 'مقدار',
+        'attribute' => 'سفارش',
+        'detail' => 'جزئیات سفارش',
+    ],
+    'knowledge' => [
+        'basic' => 'پایه',
+        'title' => 'پایگاه دانش',
     ],
-    'purchase_promotion' => 'همین حالا خدمات را خریداری کنید!',
     'menu' => [
+        'admin_dashboard' => 'داشبورد',
         'help' => 'کمک',
         'home' => 'خانه',
         'invites' => 'دعوت',
         'invoices' => 'فاکتور',
         'nodes' => 'گره‌ها',
+        'profile' => 'پروفایل',
         'promotion' => 'ارجاع',
         'shop' => 'فروشگاه',
-        'profile' => 'پروفایل',
         'tickets' => 'تیکت‌ها',
-        'admin_dashboard' => 'داشبورد',
     ],
-    'contact' => 'تماس',
+    'node' => [
+        'info' => 'اطلاعات پیکربندی',
+        'rate' => ':ratio برابر مصرف داده',
+        'setting' => 'تنظیمات پروکسی',
+        'unstable' => 'ناپایدار/در حال نگهداری',
+    ],
     'oauth' => [
+        'bind' => 'اتصال',
         'bind_title' => 'اتصال حساب اجتماعی',
         'not_bind' => 'متصل نشده',
-        'bind' => 'اتصال',
         'rebind' => 'اتصال مجدد',
         'unbind' => 'لغو اتصال',
     ],
-    'coupon' => [
-        'discount' => 'تخفیف',
-        'error' => [
-            'unknown' => 'کوپن نامعتبر',
-            'used' => 'کوپن قبلاً استفاده شده',
-            'expired' => 'کوپن منقضی شده',
-            'run_out' => 'کوپن تمام شده',
-            'inactive' => 'کوپن فعال نیست',
-            'wait' => 'در :time فعال خواهد شد، لطفاً صبر کنید!',
-            'unmet' => 'شرایط استفاده رعایت نشده',
-            'minimum' => 'حداقل مبلغ :amount است',
-            'overused' => 'فقط می‌توان :times بار استفاده کرد',
-            'users' => 'حساب واجد شرایط برای تبلیغ نیست',
-            'services' => 'کالاها واجد شرایط تخفیف نیستند، شرایط تبلیغ را بررسی کنید',
+    'pay' => 'پرداخت',
+    'payment' => [
+        'close_tips' => 'پرداخت را در عرض <code>:minutes</code> دقیقه کامل کنید، در غیر این صورت سفارش به‌طور خودکار بسته می‌شود',
+        'creating' => 'در حال ایجاد پرداخت...',
+        'error' => 'مبلغ شارژ نامعتبر',
+        'insufficient_balance' => 'موجودی شما کافی نیست. لطفاً ابتدا اعتبار خود را شارژ کنید.',
+        'manual' => [
+            'hint' => 'پس از اسکن کد QR برای پرداخت، لطفاً مراحل را دنبال کنید تا زمانی که بر روی "ارسال" کلیک کنید و پرداخت را تکمیل کنید.',
+            'next' => 'بعدی',
+            'payment_tips' => 'لطفاً مبلغ دقیق را پرداخت کنید (بازپرداخت برای پرداخت اضافی وجود ندارد، برای پرداخت کمتر باید شارژ کنید)',
+            'pre' => 'قبلی',
+            'red_packet' => 'بسته قرمز Alipay',
+            'steps' => [
+                'complete' => [
+                    'description' => 'در انتظار تأیید دستی پرداخت',
+                    'title' => 'تکمیل',
+                ],
+                'notice' => [
+                    'description' => 'چگونه به صورت دستی پرداخت کنیم',
+                    'title' => 'توجهات',
+                ],
+                'payment' => [
+                    'description' => 'دریافت کد QR و پرداخت',
+                    'title' => 'پرداخت',
+                ],
+                'remark' => [
+                    'description' => 'نام کاربری خود را برای تأیید دستی وارد کنید',
+                    'title' => 'یادداشت حساب',
+                ],
+            ],
         ],
+        'method' => 'روش پرداخت',
+        'mobile_tips' => '<strong>کاربران موبایل:</strong> کد QR را فشار طولانی دهید -> تصویر را ذخیره کنید -> برنامه پرداخت را باز کنید -> تصویر را برای پرداخت اسکن کنید',
+        'order_creation' => [
+            'failed' => 'ایجاد سفارش ناموفق بود. لطفاً روش پرداخت دیگری را امتحان کنید!',
+            'info' => 'ما در مدت [24 ساعت] پرداخت/شارژ شما را فعال خواهیم کرد! لطفاً صبور باشید.',
+            'order_limit' => 'این کالا محدود به :limit_num خرید است. شما تاکنون :count بار خرید کرده‌اید.',
+            'order_timeout' => 'سفارش به دلیل عدم پرداخت به طور خودکار بسته شد.',
+            'payment_disabled' => 'ایجاد سفارش ناموفق بود: قابلیت پرداخت آنلاین فعال نیست.',
+            'pending_order' => 'ایجاد سفارش ناموفق بود: سفارشات پرداخت نشده وجود دارد. لطفاً ابتدا آن‌ها را تکمیل کنید.',
+            'plan_required' => 'لطفاً قبل از خرید بسته شارژ، یک پلن خریداری کنید.',
+            'price_issue' => 'ایجاد سفارش ناموفق بود: قیمت کل سفارش غیرعادی است',
+            'price_zero' => 'ایجاد سفارش ناموفق بود: قیمت کل سفارش 0 است؛ نیازی به پرداخت آنلاین نیست.',
+            'product_unavailable' => 'ایجاد سفارش ناموفق بود: کالا از فروش خارج شده است.',
+            'success' => 'سفارش با موفقیت ایجاد شد!',
+            'unknown_order' => 'سفارش نامشخص',
+            'unknown_payment' => 'روش پرداخت ناشناخته',
+        ],
+        'qrcode_tips' => 'لطفاً با <strong class="red-600">:software</strong> اسکن کنید',
+        'redirect_stripe' => 'انتقال به صفحه پرداخت Stripe',
     ],
-    'error_response' => 'خطایی رخ داده است، لطفاً بعداً دوباره امتحان کنید.',
-    'invite' => [
-        'attribute' => 'کد دعوت',
-        'counts' => 'مجموع <code>:num</code> کد دعوت',
-        'tips' => '<strong>:num</strong> دعوت باقی مانده، کدها :days روز پس از ایجاد منقضی می‌شوند',
-        'logs' => 'سوابق دعوت',
-        'promotion' => 'هم شما و هم دعوت‌شونده <mark>:traffic</mark> داده دریافت خواهید کرد وقتی که با کد شما ثبت نام کنند؛ شما <mark>:referral_percent%</mark> کمیسیون دریافت خواهید کرد وقتی که آنها خرید کنند.',
-        'generate_failed' => 'تولید ناموفق: سهمیه تمام شده',
-    ],
-    'reset_data' => [
-        'action' => 'بازنشانی داده',
-        'cost' => 'هزینه: <code>:amount</code>',
-        'cost_tips' => 'بازنشانی داده :amount کسر خواهد کرد!',
-        'insufficient' => 'موجودی کافی نیست، لطفاً موجودی خود را شارژ کنید',
-        'logs' => 'کاربر داده را بازنشانی کرد',
-        'success' => 'بازنشانی موفقیت‌آمیز',
+    'purchase' => [
+        'completed' => 'خرید با موفقیت انجام شد!',
+        'promotion' => 'همین حالا خدمات را خریداری کنید!',
+        'required' => 'این ویژگی برای کاربران غیرپرداختی غیرفعال است. لطفاً',
+        'to_unlock' => 'خرید برای باز کردن قفل',
     ],
+    'recharge' => 'شارژ',
+    'recharge_credit' => 'شارژ اعتبار',
+    'recharging' => 'در حال شارژ...',
     'referral' => [
         'link' => 'لینک ارجاع',
-        'total' => 'مجموع کمیسیون: :amount (:total بار)، می‌توانید پس از رسیدن به :money برداشت کنید',
         'logs' => 'سوابق کمیسیون',
-        'failed' => 'درخواست ناموفق',
-        'success' => 'درخواست موفق',
         'msg' => [
             'account' => 'حساب منقضی شده، لطفاً ابتدا یک طرح خریداری کنید',
             'applied' => 'درخواست موجود است، لطفاً منتظر پردازش باشید',
+            'error' => 'خطا در ایجاد سفارش، بعداً دوباره امتحان کنید یا با پشتیبانی تماس بگیرید',
             'unfulfilled' => 'نیاز به :amount برای برداشت، ادامه بده!',
             'wait' => 'لطفاً منتظر تأیید مدیر باشید',
-            'error' => 'خطا در ایجاد سفارش، بعداً دوباره امتحان کنید یا با پشتیبانی تماس بگیرید',
         ],
+        'total' => 'مجموع کمیسیون: :amount (:total بار)، می‌توانید پس از رسیدن به :money برداشت کنید',
     ],
-    'inviter' => 'دعوت‌کننده',
-    'invitee' => 'دعوت‌شونده',
     'registered_at' => 'تاریخ ثبت‌نام',
-    'bought_at' => 'تاریخ خرید',
-    'payment_method' => 'روش پرداخت',
-    'pay' => 'پرداخت',
-    'input_coupon' => 'کد کوپن را وارد کنید',
-    'recharge' => 'شارژ',
-    'recharge_credit' => 'شارژ اعتبار',
-    'recharging' => 'در حال شارژ...',
-    'withdraw_commission' => 'برداشت کمیسیون',
-    'withdraw_at' => 'تاریخ برداشت',
-    'withdraw_logs' => 'سوابق برداشت',
-    'withdraw' => 'برداشت',
+    'reset_data' => [
+        'action' => 'بازنشانی داده',
+        'cost' => 'هزینه: <code>:amount</code>',
+        'cost_tips' => 'بازنشانی داده :amount کسر خواهد کرد!',
+    ],
     'scan_qrcode' => 'با استفاده از کلاینت کد QR را اسکن کنید',
+    'service' => [
+        'country_count' => 'پوشش <code>:num</code> کشور یا منطقه',
+        'node_count' => '<code>:num</code> گره با کیفیت بالا',
+        'unlimited' => 'بدون محدودیت سرعت',
+    ],
     'shop' => [
-        'hot' => 'داغ',
-        'limited' => 'محدود',
+        'buy' => 'خرید',
+        'call4help' => 'اگر سوالی دارید با پشتیبانی تماس بگیرید',
         'change_amount' => 'مبلغ شارژ',
         'change_amount_help' => 'مبلغ شارژ را وارد کنید',
-        'buy' => 'خرید',
+        'conflict' => 'تضاد',
+        'conflict_tips' => '<p>خرید فعلی به عنوان <code>طرح پیش پرداخت</code> تنظیم خواهد شد</p><ol><li>طرح پیش پرداخت پس از انقضای طرح فعلی به طور خودکار فعال می‌شود</li><li>شما می‌توانید پس از پرداخت آن را به صورت دستی فعال کنید</li></ol>',
         'description' => 'توضیحات',
-        'service' => 'خدمات',
+        'hot' => 'داغ',
+        'limited' => 'محدود',
         'pay_credit' => 'پرداخت با اعتبار',
         'pay_online' => 'پرداخت آنلاین',
         'price' => 'قیمت',
         'quantity' => 'تعداد',
+        'service' => 'خدمات',
         'subtotal' => 'جمع کل',
         'total' => 'مجموع',
-        'conflict' => 'تضاد',
-        'conflict_tips' => '<p>خرید فعلی به عنوان <code>طرح پیش پرداخت</code> تنظیم خواهد شد</p><ol><li>طرح پیش پرداخت پس از انقضای طرح فعلی به طور خودکار فعال می‌شود</li><li>شما می‌توانید پس از پرداخت آن را به صورت دستی فعال کنید</li></ol>',
-        'call4help' => 'اگر سوالی دارید با پشتیبانی تماس بگیرید',
-    ],
-    'service' => [
-        'node_count' => '<code>:num</code> گره با کیفیت بالا',
-        'country_count' => 'پوشش <code>:num</code> کشور یا منطقه',
-        'unlimited' => 'بدون محدودیت سرعت',
-    ],
-    'payment' => [
-        'error' => 'مبلغ شارژ نامعتبر',
-        'creating' => 'در حال ایجاد پرداخت...',
-        'redirect_stripe' => 'انتقال به صفحه پرداخت Stripe',
-        'qrcode_tips' => 'لطفاً با <strong class="red-600">:software</strong> اسکن کنید',
-        'close_tips' => 'پرداخت را در عرض <code>:minutes</code> دقیقه کامل کنید، در غیر این صورت سفارش به‌طور خودکار بسته می‌شود',
-        'mobile_tips' => '<strong>کاربران موبایل:</strong> کد QR را فشار طولانی دهید -> تصویر را ذخیره کنید -> برنامه پرداخت را باز کنید -> تصویر را برای پرداخت اسکن کنید',
-    ],
-    'invoice' => [
-        'attribute' => 'سفارش',
-        'detail' => 'جزئیات سفارش',
-        'amount' => 'مقدار',
-        'active_prepaid_question' => 'فعال سازی بسته پیش پرداخت زودتر؟',
-        'active_prepaid_tips' => 'پس از فعال‌سازی:<br>طرح فعلی شما بلافاصله منقضی می‌شود<br>تاریخ انقضای طرح جدید از امروز محاسبه می‌شود',
-    ],
-    'node' => [
-        'info' => 'اطلاعات پیکربندی',
-        'setting' => 'تنظیمات پروکسی',
-        'unstable' => 'ناپایدار/در حال نگهداری',
-        'rate' => ':ratio برابر مصرف داده',
     ],
     'subscribe' => [
-        'link' => 'لینک اشتراک',
-        'tips' => 'هشدار: این لینک فقط برای استفاده شخصی است. آن را به اشتراک نگذارید، در غیر این صورت حساب شما به دلیل استفاده غیرعادی مسدود می‌شود.',
-        'exchange_warning' => 'تغییر لینک اشتراک باعث می‌شود:\n1. لینک فعلی بلافاصله لغو شود\n2. رمز اتصال تغییر کند',
         'custom' => 'اشتراک سفارشی',
-        'ss_only' => 'فقط اشتراک SS',
-        'ssr_only' => 'فقط اشتراک SSR (شامل SS)',
-        'v2ray_only' => 'فقط اشتراک V2Ray',
-        'trojan_only' => 'فقط اشتراک Trojan',
         'error' => 'خطا در تغییر لینک اشتراک',
+        'exchange_warning' => 'تغییر لینک اشتراک باعث می‌شود:\n1. لینک فعلی بلافاصله لغو شود\n2. رمز اتصال تغییر کند',
         'info' => [
-            'title' => 'خلاصه حساب [غیر زمان واقعی]',
-            'upload' => 'آپلود',
             'download' => 'دانلود',
+            'title' => 'خلاصه حساب [غیر زمان واقعی]',
             'total' => 'داده طرح',
+            'upload' => 'آپلود',
         ],
+        'link' => 'لینک اشتراک',
+        'ss_only' => 'فقط اشتراک SS',
+        'ssr_only' => 'فقط اشتراک SSR (شامل SS)',
+        'tips' => 'هشدار: این لینک فقط برای استفاده شخصی است. آن را به اشتراک نگذارید، در غیر این صورت حساب شما به دلیل استفاده غیرعادی مسدود می‌شود.',
+        'trojan_only' => 'فقط اشتراک Trojan',
+        'v2ray_only' => 'فقط اشتراک V2Ray',
+    ],
+    'telegram' => [
+        'bind_exists' => 'این حساب قبلاً به یک حساب تلگرام متصل است.',
+        'bind_missing' => 'اطلاعات کاربر شما پیدا نشد. لطفاً ابتدا حساب خود را پیوند دهید.',
+        'command' => [
+            'bind' => 'حساب :web_name خود را پیوند دهید',
+            'intro' => 'شما می‌توانید از دستورات زیر استفاده کنید',
+            'traffic' => 'بررسی مصرف داده‌ها',
+            'unbind' => 'قطع ارتباط',
+            'web_url' => 'دریافت جدیدترین URL :web_name',
+        ],
+        'get_url' => 'جدیدترین URL برای :web_name عبارت است از',
+        'params_missing' => 'پارامترها نامعتبر هستند. لطفاً آدرس ایمیل خود را ضمیمه کرده و دوباره ارسال کنید.',
+        'ticket_missing' => 'تیکت وجود ندارد',
+        'ticket_reply' => 'پاسخ به تیکت #`:id` با موفقیت انجام شد',
+        'traffic_query' => 'بررسی مصرف داده‌ها',
+        'user_missing' => 'کاربر وجود ندارد',
     ],
     'ticket' => [
         'attribute' => 'تیکت',
-        'submit_tips' => 'تأیید ارسال تیکت؟',
-        'reply_confirm' => 'تأیید پاسخ به تیکت؟',
-        'close_tips' => 'تأیید بستن تیکت؟',
-        'close' => 'بستن تیکت',
-        'failed_closed' => 'خطا: قبلاً بسته شده است',
-        'reply_placeholder' => 'چیزی بنویسید...',
-        'reply' => 'پاسخ',
         'close_msg' => 'تیکت ID :id توسط کاربر بسته شد',
-        'title_placeholder' => 'به طور خلاصه مشکل خود را توضیح دهید',
+        'close_tips' => 'تأیید بستن تیکت؟',
         'content_placeholder' => 'توضیحات دقیق مشکل خود را ارائه دهید تا ما بتوانیم بهتر به شما کمک کنیم',
+        'error' => 'خطای ناشناخته! لطفاً با پشتیبانی تماس بگیرید',
         'new' => 'ایجاد تیکت جدید',
-        'service_hours' => 'ساعات خدمات مشتری',
         'online_hour' => 'ساعات آنلاین',
+        'reply' => 'پاسخ',
+        'reply_confirm' => 'تأیید پاسخ به تیکت؟',
+        'reply_placeholder' => 'چیزی بنویسید...',
+        'service_hours' => 'ساعات خدمات مشتری',
         'service_tips' => 'لطفاً فقط از <code>یک</code> روش تماس برای تماس با پشتیبانی استفاده کنید! درخواست‌های مکرر زمان پاسخگویی را به تأخیر می‌اندازد.',
-        'error' => 'خطای ناشناخته! لطفاً با پشتیبانی تماس بگیرید',
+        'submit_tips' => 'تأیید ارسال تیکت؟',
+        'title_placeholder' => 'به طور خلاصه مشکل خود را توضیح دهید',
     ],
     'traffic_logs' => [
-        'hourly' => 'مصرف داده امروز',
         'daily' => 'مصرف داده این ماه',
+        'hourly' => 'مصرف داده امروز',
         'tips' => 'توجه: به‌روزرسانی آمار داده‌ها با تأخیر انجام می‌شود.',
     ],
-    'clients' => 'کلاینت‌ها',
     'tutorials' => 'آموزش‌ها',
-    'current_role' => 'نقش فعلی به عنوان',
-    'knowledge' => [
-        'title' => 'پایگاه دانش',
-        'basic' => 'پایه',
-    ],
-    'manual' => [
-        'red_packet' => 'بسته قرمز Alipay',
-        'hint' => 'پس از اسکن کد QR، ادامه دهید و روی [بعدی] کلیک کنید تا زمانی که روی [ارسال] کلیک کنید تا پرداخت تکمیل شود!',
-        'step_1' => 'توجهات',
-        'step_1_title' => 'چگونه به صورت دستی پرداخت کنیم',
-        'step_2' => 'پرداخت',
-        'step_2_title' => 'دریافت کد QR و پرداخت',
-        'step_3' => 'تکمیل',
-        'step_3_title' => 'منتظر تأیید دستی باشید',
-        'remark' => 'یادداشت حساب',
-        'remark_content' => 'لطفاً نام کاربری حساب خود را برای تأیید دقیق دستی ارائه دهید',
-        'payment_hint' => 'لطفاً مبلغ دقیق را پرداخت کنید (بازپرداخت برای پرداخت اضافی وجود ندارد، برای پرداخت کمتر باید شارژ کنید)',
-        'pre' => 'قبلی',
-        'next' => 'بعدی',
-    ],
+    'withdraw' => 'برداشت',
+    'withdraw_at' => 'تاریخ برداشت',
+    'withdraw_commission' => 'برداشت کمیسیون',
+    'withdraw_logs' => 'سوابق برداشت',
 ];

+ 12 - 1
resources/lang/ja.json

@@ -126,5 +126,16 @@
   "You are receiving this email because we received a password reset request for your account.": "パスワード再設定のリクエストを受け付けました。",
   "You have not responded this ticket in :num hours, System has closed your ticket.": ":num 時間以内にこのチケットに返信しなかったため、システムがチケットを閉じました。",
   "You must have a valid subscription to view the content in this area!": "このエリアのコンテンツを表示するには、有効なサブスクリプションが必要です!",
-  "Your subscription has been disabled by the administrator, please contact the administrator to restore it": "お客様のサブスクリプションは管理者によって無効にされました。復元するには管理者に連絡してください。"
+  "Your subscription has been disabled by the administrator, please contact the administrator to restore it": "お客様のサブスクリプションは管理者によって無効にされました。復元するには管理者に連絡してください。",
+  "Manually add in dashboard.": "ダッシュボードで手動で追加",
+  "Manually edit in dashboard.": "ダッシュボードで手動で編集",
+  "Batch generate user accounts in dashboard.": "バックグラウンドでユーザーアカウントを一括生成",
+  "Coupon used in order.": "注文でクーポンが使用されました",
+  "Order canceled, coupon reinstated.": "注文がキャンセルされ、クーポンが復元されました",
+  "Used for credit recharge.": "残高のチャージに使用される",
+  "The user manually reset the data.": "ユーザーデータリセット記録",
+  "Recharge using a recharge voucher.": "チャージ券を使ってチャージする",
+  "The user topped up the balance.": "ユーザーが残高をチャージしました",
+  "Purchased an item.": "商品を購入しました",
+  "[:payment] plus the user’s purchased data plan.": "[:payment] にユーザーが購入したデータプランを追加"
 }

Some files were not shown because too many files changed in this diff