diff --git a/go.mod b/go.mod index a014b0c7..43ac4d44 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/gin-contrib/sessions v1.0.2 github.com/gin-gonic/gin v1.10.0 github.com/goccy/go-json v0.10.5 + github.com/google/uuid v1.6.0 github.com/mymmrac/telego v0.32.0 github.com/nicksnyder/go-i18n/v2 v2.5.1 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 diff --git a/web/service/tgbot.go b/web/service/tgbot.go index 9e217124..5ee17065 100644 --- a/web/service/tgbot.go +++ b/web/service/tgbot.go @@ -1,12 +1,16 @@ package service import ( + "crypto/rand" "embed" + "encoding/base64" "errors" "fmt" + "math/big" "net" "net/url" "os" + "regexp" "strconv" "strings" "time" @@ -20,8 +24,7 @@ import ( "x-ui/web/locale" "x-ui/xray" - "slices" - + "github.com/google/uuid" "github.com/mymmrac/telego" th "github.com/mymmrac/telego/telegohandler" tu "github.com/mymmrac/telego/telegoutil" @@ -30,14 +33,38 @@ import ( ) var ( - bot *telego.Bot - botHandler *th.BotHandler - adminIds []int64 - isRunning bool - hostname string - hashStorage *global.HashStorage + bot *telego.Bot + botHandler *th.BotHandler + adminIds []int64 + isRunning bool + hostname string + hashStorage *global.HashStorage + handler *th.Handler + + // clients data to adding new client + receiver_inbound_ID int + client_Id string + client_Flow string + client_Email string + client_LimitIP int + client_TotalGB int64 + client_ExpiryTime int64 + client_Enable bool + client_TgID string + client_SubID string + client_Comment string + client_Reset int + client_Security string + client_ShPassword string + client_TrPassword string + client_Method string + ) + +var userStates = make(map[int64]string) + + type LoginStatus byte const ( @@ -46,6 +73,8 @@ const ( EmptyTelegramUserID = int64(0) ) + + type Tgbot struct { inboundService InboundService settingService SettingService @@ -54,6 +83,7 @@ type Tgbot struct { lastStatus *Status } + func (t *Tgbot) NewTgbot() *Tgbot { return new(Tgbot) } @@ -223,36 +253,113 @@ func (t *Tgbot) OnReceive() { botHandler, _ = th.NewBotHandler(bot, updates) botHandler.HandleMessage(func(_ *telego.Bot, message telego.Message) { + delete(userStates, message.Chat.ID) t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.keyboardClosed"), tu.ReplyKeyboardRemove()) }, th.TextEqual(t.I18nBot("tgbot.buttons.closeKeyboard"))) botHandler.HandleMessage(func(_ *telego.Bot, message telego.Message) { + delete(userStates, message.Chat.ID) t.answerCommand(&message, message.Chat.ID, checkAdmin(message.From.ID)) }, th.AnyCommand()) botHandler.HandleCallbackQuery(func(_ *telego.Bot, query telego.CallbackQuery) { + delete(userStates,query.Message.GetChat().ID) t.answerCallback(&query, checkAdmin(query.From.ID)) }, th.AnyCallbackQueryWithMessage()) botHandler.HandleMessage(func(_ *telego.Bot, message telego.Message) { - if message.UsersShared != nil { - if checkAdmin(message.From.ID) { - for _, sharedUser := range message.UsersShared.Users { - userID := sharedUser.UserID - needRestart, err := t.inboundService.SetClientTelegramUserID(message.UsersShared.RequestID, userID) - if needRestart { - t.xrayService.SetToNeedRestart() - } - output := "" - if err != nil { - output += t.I18nBot("tgbot.messages.selectUserFailed") - } else { - output += t.I18nBot("tgbot.messages.userSaved") - } - t.SendMsgToTgbot(message.Chat.ID, output, tu.ReplyKeyboardRemove()) + if userState, exists := userStates[message.Chat.ID]; exists { + switch userState { + case "awaiting_id": + client_Id = strings.TrimSpace(message.Text) + if t.isSingleWord(client_Id) { + userStates[message.Chat.ID] = "awaiting_id" + + cancel_btn_markup := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"), + ), + ) + + t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.messages.incorrect_input"), cancel_btn_markup) + } else { + t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.received_id"), 3, tu.ReplyKeyboardRemove()) + delete(userStates, message.Chat.ID) + } + case "awaiting_password_tr": + client_TrPassword = strings.TrimSpace(message.Text) + if t.isSingleWord(client_TrPassword) { + userStates[message.Chat.ID] = "awaiting_password_tr" + + cancel_btn_markup := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"), + ), + ) + + t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.messages.incorrect_input"), cancel_btn_markup) + } else { + t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.received_password"), 3, tu.ReplyKeyboardRemove()) + delete(userStates, message.Chat.ID) + } + case "awaiting_password_sh": + client_ShPassword = strings.TrimSpace(message.Text) + if t.isSingleWord(client_ShPassword) { + userStates[message.Chat.ID] = "awaiting_password_sh" + + cancel_btn_markup := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"), + ), + ) + + t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.messages.incorrect_input"), cancel_btn_markup) + } else { + t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.received_password"), 3, tu.ReplyKeyboardRemove()) + delete(userStates, message.Chat.ID) + } + case "awaiting_email": + client_Email = strings.TrimSpace(message.Text) + if t.isSingleWord(client_Email) { + userStates[message.Chat.ID] = "awaiting_email" + + cancel_btn_markup := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"), + ), + ) + + t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.messages.incorrect_input"), cancel_btn_markup) + } else { + t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.received_email"), 3, tu.ReplyKeyboardRemove()) + delete(userStates, message.Chat.ID) + } + case "awaiting_comment": + client_Comment = strings.TrimSpace(message.Text) + t.SendMsgToTgbotDeleteAfter(message.Chat.ID, t.I18nBot("tgbot.messages.received_comment"), 3, tu.ReplyKeyboardRemove()) + delete(userStates, message.Chat.ID) + } + + } else { + if message.UsersShared != nil { + if checkAdmin(message.From.ID) { + for _, sharedUser := range message.UsersShared.Users { + userID := sharedUser.UserID + needRestart, err := t.inboundService.SetClientTelegramUserID(message.UsersShared.RequestID, userID) + if needRestart { + t.xrayService.SetToNeedRestart() + } + output := "" + if err != nil { + output += t.I18nBot("tgbot.messages.selectUserFailed") + } else { + output += t.I18nBot("tgbot.messages.userSaved") + } + t.SendMsgToTgbot(message.Chat.ID, output, tu.ReplyKeyboardRemove()) + } + } else { + t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.noResult"), tu.ReplyKeyboardRemove()) } - } else { - t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.noResult"), tu.ReplyKeyboardRemove()) } } }, th.AnyMessage()) @@ -344,9 +451,31 @@ func (t *Tgbot) sendResponse(chatId int64, msg string, onlyMessage, isAdmin bool } } + +func (t *Tgbot) randomLowerAndNum(length int) string { + charset := "abcdefghijklmnopqrstuvwxyz0123456789" + bytes := make([]byte, length) + for i := range bytes { + randomIndex, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charset)))) + bytes[i] = charset[randomIndex.Int64()] + } + return string(bytes) +} + + +func (t *Tgbot) randomShadowSocksPassword() string { + array := make([]byte, 32) + _, err := rand.Read(array) + if err != nil { + return t.randomLowerAndNum(32) + } + return base64.StdEncoding.EncodeToString(array) +} + + func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool) { chatId := callbackQuery.Message.GetChat().ID - + if isAdmin { // get query from hash storage decodedQuery, err := t.decodeQuery(callbackQuery.Data) @@ -507,6 +636,78 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool } t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation")) t.searchClient(chatId, email, callbackQuery.Message.GetMessageID()) + case "add_client_limit_traffic_c": + limitTraffic, _ := strconv.Atoi(dataArray[1]) + client_TotalGB = int64(limitTraffic) * 1024 * 1024 * 1024 + messageId := callbackQuery.Message.GetMessageID() + inbound, err := t.inboundService.GetInbound(receiver_inbound_ID) + if err != nil { + t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error()) + return + } + message_text, err := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol) + + t.addClient(chatId,message_text,messageId) + t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation")) + case "add_client_limit_traffic_in": + if len(dataArray) >= 2 { + oldInputNumber, err := strconv.Atoi(dataArray[1]) + inputNumber := oldInputNumber + if err == nil { + if len(dataArray) == 3 { + num, err := strconv.Atoi(dataArray[2]) + if err == nil { + if num == -2 { + inputNumber = 0 + } else if num == -1 { + if inputNumber > 0 { + inputNumber = (inputNumber / 10) + } + } else { + inputNumber = (inputNumber * 10) + num + } + } + if inputNumber == oldInputNumber { + t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation")) + return + } + if inputNumber >= 999999 { + t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation")) + return + } + } + inlineKeyboard := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("add_client_default_traffic_exp")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmNumberAdd", "Num=="+strconv.Itoa(inputNumber))).WithCallbackData(t.encodeQuery("add_client_limit_traffic_c "+strconv.Itoa(inputNumber))), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("1").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 1")), + tu.InlineKeyboardButton("2").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 2")), + tu.InlineKeyboardButton("3").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 3")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("4").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 4")), + tu.InlineKeyboardButton("5").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 5")), + tu.InlineKeyboardButton("6").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 6")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("7").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 7")), + tu.InlineKeyboardButton("8").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 8")), + tu.InlineKeyboardButton("9").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 9")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("🔄").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" -2")), + tu.InlineKeyboardButton("0").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" 0")), + tu.InlineKeyboardButton("⬅️").WithCallbackData(t.encodeQuery("add_client_limit_traffic_in "+strconv.Itoa(inputNumber)+" -1")), + ), + ) + t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard) + return + } + } case "reset_exp": inlineKeyboard := tu.InlineKeyboard( tu.InlineKeyboardRow( @@ -638,6 +839,90 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool } t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation")) t.searchClient(chatId, email, callbackQuery.Message.GetMessageID()) + case "add_client_reset_exp_c": + client_ExpiryTime = 0 + days, _ := strconv.Atoi(dataArray[1]) + var date int64 = 0 + if client_ExpiryTime > 0 { + if client_ExpiryTime-time.Now().Unix()*1000 < 0 { + date = -int64(days * 24 * 60 * 60000) + } else { + date = client_ExpiryTime + int64(days*24*60*60000) + } + } else { + date = client_ExpiryTime - int64(days*24*60*60000) + } + client_ExpiryTime = date + + messageId := callbackQuery.Message.GetMessageID() + inbound, err := t.inboundService.GetInbound(receiver_inbound_ID) + if err != nil { + t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error()) + return + } + message_text, err := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol) + + t.addClient(chatId,message_text,messageId) + t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation")) + case "add_client_reset_exp_in": + if len(dataArray) >= 2 { + oldInputNumber, err := strconv.Atoi(dataArray[1]) + inputNumber := oldInputNumber + if err == nil { + if len(dataArray) == 3 { + num, err := strconv.Atoi(dataArray[2]) + if err == nil { + if num == -2 { + inputNumber = 0 + } else if num == -1 { + if inputNumber > 0 { + inputNumber = (inputNumber / 10) + } + } else { + inputNumber = (inputNumber * 10) + num + } + } + if inputNumber == oldInputNumber { + t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation")) + return + } + if inputNumber >= 999999 { + t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.errorOperation")) + return + } + } + inlineKeyboard := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("add_client_default_traffic_exp")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.confirmNumber", "Num=="+strconv.Itoa(inputNumber))).WithCallbackData(t.encodeQuery("add_client_reset_exp_c "+strconv.Itoa(inputNumber))), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("1").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 1")), + tu.InlineKeyboardButton("2").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 2")), + tu.InlineKeyboardButton("3").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 3")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("4").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 4")), + tu.InlineKeyboardButton("5").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 5")), + tu.InlineKeyboardButton("6").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 6")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("7").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 7")), + tu.InlineKeyboardButton("8").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 8")), + tu.InlineKeyboardButton("9").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 9")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("🔄").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" -2")), + tu.InlineKeyboardButton("0").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" 0")), + tu.InlineKeyboardButton("⬅️").WithCallbackData(t.encodeQuery("add_client_reset_exp_in "+strconv.Itoa(inputNumber)+" -1")), + ), + ) + t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard) + return + } + } case "ip_limit": inlineKeyboard := tu.InlineKeyboard( tu.InlineKeyboardRow( @@ -838,7 +1123,40 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool return } t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseClient", "Inbound=="+inbound.Remark), clients) + case "add_client_to": + // assign default values to clients variables + client_Id = uuid.New().String() + client_Flow = "" + client_Email = t.randomLowerAndNum(8) + client_LimitIP = 0 + client_TotalGB = 0 + client_ExpiryTime = 0 + client_Enable = true + client_TgID = "" + client_SubID = t.randomLowerAndNum(16) + client_Comment = "" + client_Reset = 0 + client_Security="auto" + client_ShPassword=t.randomShadowSocksPassword() + client_TrPassword=t.randomLowerAndNum(10) + client_Method="" + inboundId := dataArray[1] + inboundIdInt, err := strconv.Atoi(inboundId) + if err != nil { + t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error()) + return + } + receiver_inbound_ID = inboundIdInt + inbound, err := t.inboundService.GetInbound(inboundIdInt) + if err != nil { + t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error()) + return + } + + message_text, err := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol) + + t.addClient(chatId, message_text) } return } else { @@ -892,11 +1210,325 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool case "commands": t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.commands")) t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.commands.helpAdminCommands")) + case "add_client": + // assign default values to clients variables + client_Id = uuid.New().String() + client_Flow = "" + client_Email = t.randomLowerAndNum(8) + client_LimitIP = 0 + client_TotalGB = 0 + client_ExpiryTime = 0 + client_Enable = true + client_TgID = "" + client_SubID = t.randomLowerAndNum(16) + client_Comment = "" + client_Reset = 0 + client_Security="auto" + client_ShPassword=t.randomShadowSocksPassword() + client_TrPassword=t.randomLowerAndNum(10) + client_Method="" + + inbounds, err := t.getInboundsAddClient() + if err != nil { + t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error()) + return + } + t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.buttons.addClient")) + t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.answers.chooseInbound"), inbounds) + case "add_client_refresh": + messageId := callbackQuery.Message.GetMessageID() + inbound, err := t.inboundService.GetInbound(receiver_inbound_ID) + if err != nil { + t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error()) + return + } + message_text, err := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol) + + t.addClient(chatId,message_text,messageId) + t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.clientRefreshSuccess", "Email=="+client_Email)) + case "add_client_ch_default_email": + userStates[chatId] = "awaiting_email" + cancel_btn_markup := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"), + ), + ) + prompt_message := t.I18nBot("tgbot.messages.email_prompt", "ClientEmail=="+client_Email) + t.SendMsgToTgbot(chatId, prompt_message, cancel_btn_markup) + case "add_client_ch_default_id": + userStates[chatId] = "awaiting_id" + cancel_btn_markup := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"), + ), + ) + prompt_message := t.I18nBot("tgbot.messages.id_prompt", "ClientId=="+client_Id) + t.SendMsgToTgbot(chatId, prompt_message, cancel_btn_markup) + case "add_client_ch_default_pass_tr": + userStates[chatId] = "awaiting_password_tr" + cancel_btn_markup := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"), + ), + ) + prompt_message := t.I18nBot("tgbot.messages.pass_prompt", "ClientPassword=="+client_TrPassword) + t.SendMsgToTgbot(chatId, prompt_message, cancel_btn_markup) + case "add_client_ch_default_pass_sh": + userStates[chatId] = "awaiting_password_sh" + cancel_btn_markup := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"), + ), + ) + prompt_message := t.I18nBot("tgbot.messages.pass_prompt", "ClientPassword=="+client_ShPassword) + t.SendMsgToTgbot(chatId, prompt_message, cancel_btn_markup) + case "add_client_ch_default_comment": + userStates[chatId] = "awaiting_comment" + cancel_btn_markup := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.use_default")).WithCallbackData("add_client_default_info"), + ), + ) + prompt_message := t.I18nBot("tgbot.messages.comment_prompt", "ClientComment=="+client_Comment) + t.SendMsgToTgbot(chatId, prompt_message, cancel_btn_markup) + case "add_client_ch_default_traffic": + inlineKeyboard := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData(t.encodeQuery("add_client_default_traffic_exp")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 0")), + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("add_client_limit_traffic_in 0")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("1 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 1")), + tu.InlineKeyboardButton("5 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 5")), + tu.InlineKeyboardButton("10 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 10")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("20 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 20")), + tu.InlineKeyboardButton("30 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 30")), + tu.InlineKeyboardButton("40 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 40")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("50 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 50")), + tu.InlineKeyboardButton("60 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 60")), + tu.InlineKeyboardButton("80 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 80")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton("100 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 100")), + tu.InlineKeyboardButton("150 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 150")), + tu.InlineKeyboardButton("200 GB").WithCallbackData(t.encodeQuery("add_client_limit_traffic_c 200")), + ), + ) + t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard) + case "add_client_ch_default_exp": + inlineKeyboard := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancelReset")).WithCallbackData(t.encodeQuery("add_client_default_traffic_exp")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.unlimited")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 0")), + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.custom")).WithCallbackData(t.encodeQuery("add_client_reset_exp_in 0")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 7 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 7")), + tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 10 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 10")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 14 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 14")), + tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 20 "+t.I18nBot("tgbot.days")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 20")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 1 "+t.I18nBot("tgbot.month")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 30")), + tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 3 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 90")), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 6 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 180")), + tu.InlineKeyboardButton(t.I18nBot("tgbot.add")+" 12 "+t.I18nBot("tgbot.months")).WithCallbackData(t.encodeQuery("add_client_reset_exp_c 365")), + ), + ) + t.editMessageCallbackTgBot(chatId, callbackQuery.Message.GetMessageID(), inlineKeyboard) + case "add_client_default_info": + t.SendMsgToTgbotDeleteAfter(chatId, t.I18nBot("tgbot.messages.using_default_value"), 3, tu.ReplyKeyboardRemove()) + delete(userStates, chatId) + case "add_client_cancel": + delete(userStates, chatId) + t.SendMsgToTgbotDeleteAfter(chatId, t.I18nBot("tgbot.messages.cancel"), 5, tu.ReplyKeyboardRemove()) + case "add_client_default_traffic_exp": + messageId := callbackQuery.Message.GetMessageID() + inbound, err := t.inboundService.GetInbound(receiver_inbound_ID) + if err != nil { + t.sendCallbackAnswerTgBot(callbackQuery.ID, err.Error()) + return + } + message_text, err := t.BuildInboundClientDataMessage(inbound.Remark, inbound.Protocol) + t.addClient(chatId,message_text,messageId) + t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.canceled", "Email=="+client_Email)) + case "add_client_submit_disable": + client_Enable = false + _, err := t.SubmitAddClient() + if err != nil { + errorMessage := fmt.Sprintf("%v", err) + t.SendMsgToTgbot(chatId, t.I18nBot("tgbot.messages.error_add_client", "error=="+errorMessage), tu.ReplyKeyboardRemove()) + } else { + t.sendCallbackAnswerTgBot(callbackQuery.ID, t.I18nBot("tgbot.answers.successfulOperation")) + } } } + +func (t *Tgbot) BuildInboundClientDataMessage(inbound_remark string ,protocol model.Protocol) (string, error) { + var message string + + currentTime := time.Now() + timestampMillis := currentTime.UnixNano() / int64(time.Millisecond) + + expiryTime := "" + diff := client_ExpiryTime/1000 - timestampMillis + if client_ExpiryTime == 0 { + expiryTime = t.I18nBot("tgbot.unlimited") + } else if diff > 172800 { + expiryTime = time.Unix((client_ExpiryTime / 1000), 0).Format("2006-01-02 15:04:05") + } else if client_ExpiryTime < 0 { + expiryTime = fmt.Sprintf("%d %s", client_ExpiryTime/-86400000, t.I18nBot("tgbot.days")) + } else { + expiryTime = fmt.Sprintf("%d %s", diff/3600, t.I18nBot("tgbot.hours")) + } + + traffic_value := "" + if client_TotalGB == 0 { + traffic_value = "♾️ Unlimited(Reset)" + }else { + traffic_value = common.FormatTraffic(client_TotalGB) + } + + switch protocol { + case model.VMESS, model.VLESS: + message = t.I18nBot("tgbot.messages.inbound_client_data_id", "InboundRemark=="+inbound_remark,"ClientId=="+client_Id,"ClientEmail=="+client_Email,"ClientTraffic=="+traffic_value,"ClientExp=="+expiryTime,"ClientComment=="+client_Comment) + + case model.Trojan: + message = t.I18nBot("tgbot.messages.inbound_client_data_pass", "InboundRemark=="+inbound_remark,"ClientPass=="+client_TrPassword,"ClientEmail=="+client_Email,"ClientTraffic=="+traffic_value,"ClientExp=="+expiryTime,"ClientComment=="+client_Comment) + + case model.Shadowsocks: + message = t.I18nBot("tgbot.messages.inbound_client_data_pass", "InboundRemark=="+inbound_remark,"ClientPass=="+client_ShPassword,"ClientEmail=="+client_Email,"ClientTraffic=="+traffic_value,"ClientExp=="+expiryTime,"ClientComment=="+client_Comment) + + default: + return "", errors.New("unknown protocol") + } + + return message, nil +} + + +func (t *Tgbot) BuildJSONForProtocol(protocol model.Protocol) (string, error) { + var jsonString string + + switch protocol { + case model.VMESS: + jsonString = fmt.Sprintf(`{ + "clients": [{ + "id": "%s", + "security": "%s", + "email": "%s", + "limitIp": %d, + "totalGB": %d, + "expiryTime": %d, + "enable": %t, + "tgId": "%s", + "subId": "%s", + "comment": "%s", + "reset": %d + }] + }`, client_Id, client_Security, client_Email, client_LimitIP, client_TotalGB, client_ExpiryTime, client_Enable, client_TgID, client_SubID, client_Comment, client_Reset) + + case model.VLESS: + jsonString = fmt.Sprintf(`{ + "clients": [{ + "id": "%s", + "flow": "%s", + "email": "%s", + "limitIp": %d, + "totalGB": %d, + "expiryTime": %d, + "enable": %t, + "tgId": "%s", + "subId": "%s", + "comment": "%s", + "reset": %d + }] + }`, client_Id, client_Flow, client_Email, client_LimitIP, client_TotalGB, client_ExpiryTime, client_Enable, client_TgID, client_SubID, client_Comment, client_Reset) + + case model.Trojan: + jsonString = fmt.Sprintf(`{ + "clients": [{ + "password": "%s", + "email": "%s", + "limitIp": %d, + "totalGB": %d, + "expiryTime": %d, + "enable": %t, + "tgId": "%s", + "subId": "%s", + "comment": "%s", + "reset": %d + }] + }`, client_TrPassword, client_Email, client_LimitIP, client_TotalGB, client_ExpiryTime, client_Enable, client_TgID, client_SubID, client_Comment, client_Reset) + + case model.Shadowsocks: + jsonString = fmt.Sprintf(`{ + "clients": [{ + "method": "%s", + "password": "%s", + "email": "%s", + "limitIp": %d, + "totalGB": %d, + "expiryTime": %d, + "enable": %t, + "tgId": "%s", + "subId": "%s", + "comment": "%s", + "reset": %d + }] + }`, client_Method, client_ShPassword, client_Email, client_LimitIP, client_TotalGB, client_ExpiryTime, client_Enable, client_TgID, client_SubID, client_Comment, client_Reset) + + default: + return "", errors.New("unknown protocol") + } + + return jsonString, nil +} + + +func (t *Tgbot) SubmitAddClient() (bool, error) { + + + inbound, err := t.inboundService.GetInbound(receiver_inbound_ID) + if err != nil { + logger.Warning("getIboundClients run failed:", err) + return false, errors.New(t.I18nBot("tgbot.answers.getInboundsFailed")) + } + + + + jsonString, err := t.BuildJSONForProtocol(inbound.Protocol) + + newInbound := &model.Inbound{ + Id: receiver_inbound_ID, + Settings: jsonString, + } + + + return t.inboundService.AddInboundClient(newInbound) +} + func checkAdmin(tgId int64) bool { - return slices.Contains(adminIds, tgId) + for _, adminId := range adminIds { + if adminId == tgId { + return true + } + } + return false } func (t *Tgbot) SendAnswer(chatId int64, msg string, isAdmin bool) { @@ -915,7 +1547,10 @@ func (t *Tgbot) SendAnswer(chatId int64, msg string, isAdmin bool) { tu.InlineKeyboardRow( tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.commands")).WithCallbackData(t.encodeQuery("commands")), tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.onlines")).WithCallbackData(t.encodeQuery("onlines")), + ), + tu.InlineKeyboardRow( tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.allClients")).WithCallbackData(t.encodeQuery("get_inbounds")), + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.addClient")).WithCallbackData(t.encodeQuery("add_client")), ), // TODOOOOOOOOOOOOOO: Add restart button here. ) @@ -1161,35 +1796,75 @@ func (t *Tgbot) getInboundUsages() string { } return info } - func (t *Tgbot) getInbounds() (*telego.InlineKeyboardMarkup, error) { inbounds, err := t.inboundService.GetAllInbounds() - var buttons []telego.InlineKeyboardButton - if err != nil { logger.Warning("GetAllInbounds run failed:", err) return nil, errors.New(t.I18nBot("tgbot.answers.getInboundsFailed")) - } else { - if len(inbounds) > 0 { - for _, inbound := range inbounds { - status := "❌" - if inbound.Enable { - status = "✅" - } - buttons = append(buttons, tu.InlineKeyboardButton(fmt.Sprintf("%v - %v", inbound.Remark, status)).WithCallbackData(t.encodeQuery("get_clients "+strconv.Itoa(inbound.Id)))) - } - } else { - logger.Warning("GetAllInbounds run failed:", err) - return nil, errors.New(t.I18nBot("tgbot.answers.getInboundsFailed")) - } - } - cols := 0 - if len(buttons) < 6 { - cols = 3 - } else { + + if len(inbounds) == 0 { + logger.Warning("No inbounds found") + return nil, errors.New(t.I18nBot("tgbot.answers.getInboundsFailed")) + } + + var buttons []telego.InlineKeyboardButton + for _, inbound := range inbounds { + status := "❌" + if inbound.Enable { + status = "✅" + } + callbackData := t.encodeQuery(fmt.Sprintf("%s %d","get_clients", inbound.Id)) + buttons = append(buttons, tu.InlineKeyboardButton(fmt.Sprintf("%v - %v", inbound.Remark, status)).WithCallbackData(callbackData)) + } + + cols := 1 + if len(buttons) >= 6 { cols = 2 } + + keyboard := tu.InlineKeyboardGrid(tu.InlineKeyboardCols(cols, buttons...)) + return keyboard, nil +} + +func (t *Tgbot) getInboundsAddClient() (*telego.InlineKeyboardMarkup, error) { + inbounds, err := t.inboundService.GetAllInbounds() + if err != nil { + logger.Warning("GetAllInbounds run failed:", err) + return nil, errors.New(t.I18nBot("tgbot.answers.getInboundsFailed")) + } + + if len(inbounds) == 0 { + logger.Warning("No inbounds found") + return nil, errors.New(t.I18nBot("tgbot.answers.getInboundsFailed")) + } + + excludedProtocols := map[model.Protocol]bool{ + model.DOKODEMO: true, + model.Socks: true, + model.WireGuard: true, + model.HTTP: true, + } + + var buttons []telego.InlineKeyboardButton + for _, inbound := range inbounds { + if excludedProtocols[inbound.Protocol] { + continue + } + + status := "❌" + if inbound.Enable { + status = "✅" + } + callbackData := t.encodeQuery(fmt.Sprintf("%s %d","add_client_to", inbound.Id)) + buttons = append(buttons, tu.InlineKeyboardButton(fmt.Sprintf("%v - %v", inbound.Remark, status)).WithCallbackData(callbackData)) + } + + cols := 1 + if len(buttons) >= 6 { + cols = 2 + } + keyboard := tu.InlineKeyboardGrid(tu.InlineKeyboardCols(cols, buttons...)) return keyboard, nil } @@ -1484,6 +2159,100 @@ func (t *Tgbot) searchClient(chatId int64, email string, messageID ...int) { } } +func (t *Tgbot) addClient(chatId int64, msg string, messageID ...int) { + inbound, err := t.inboundService.GetInbound(receiver_inbound_ID) + if err != nil { + t.SendMsgToTgbot(chatId, err.Error()) + return + } + + protocol := inbound.Protocol + + switch protocol { + case model.VMESS, model.VLESS: + inlineKeyboard := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.refresh")).WithCallbackData("add_client_refresh"), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.change_email")).WithCallbackData("add_client_ch_default_email"), + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.change_id")).WithCallbackData("add_client_ch_default_id"), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.limitTraffic")).WithCallbackData("add_client_ch_default_traffic"), + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.resetExpire")).WithCallbackData("add_client_ch_default_exp"), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.change_comment")).WithCallbackData("add_client_ch_default_comment"), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.submitDisable")).WithCallbackData("add_client_submit_disable"), + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData("add_client_cancel"), + ), + ) + if len(messageID) > 0 { + t.editMessageTgBot(chatId, messageID[0], msg, inlineKeyboard) + } else { + t.SendMsgToTgbot(chatId, msg, inlineKeyboard) + } + case model.Trojan: + inlineKeyboard := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.refresh")).WithCallbackData("add_client_refresh"), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.change_email")).WithCallbackData("add_client_ch_default_email"), + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.change_password")).WithCallbackData("add_client_ch_default_pass_tr"), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.limitTraffic")).WithCallbackData("add_client_ch_default_traffic"), + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.resetExpire")).WithCallbackData("add_client_ch_default_exp"), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.change_comment")).WithCallbackData("add_client_ch_default_comment"), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.submitDisable")).WithCallbackData("add_client_submit_disable"), + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData("add_client_cancel"), + ), + ) + if len(messageID) > 0 { + t.editMessageTgBot(chatId, messageID[0], msg, inlineKeyboard) + } else { + t.SendMsgToTgbot(chatId, msg, inlineKeyboard) + } + + case model.Shadowsocks: + inlineKeyboard := tu.InlineKeyboard( + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.refresh")).WithCallbackData("add_client_refresh"), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.change_email")).WithCallbackData("add_client_ch_default_email"), + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.change_password")).WithCallbackData("add_client_ch_default_pass_sh"), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.limitTraffic")).WithCallbackData("add_client_ch_default_traffic"), + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.resetExpire")).WithCallbackData("add_client_ch_default_exp"), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.change_comment")).WithCallbackData("add_client_ch_default_comment"), + ), + tu.InlineKeyboardRow( + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.submitDisable")).WithCallbackData("add_client_submit_disable"), + tu.InlineKeyboardButton(t.I18nBot("tgbot.buttons.cancel")).WithCallbackData("add_client_cancel"), + ), + ) + + if len(messageID) > 0 { + t.editMessageTgBot(chatId, messageID[0], msg, inlineKeyboard) + } else { + t.SendMsgToTgbot(chatId, msg, inlineKeyboard) + } + } + +} + func (t *Tgbot) searchInbound(chatId int64, remark string) { inbounds, err := t.inboundService.SearchInbounds(remark) if err != nil { @@ -1689,7 +2458,12 @@ func (t *Tgbot) notifyExhausted() { } func int64Contains(slice []int64, item int64) bool { - return slices.Contains(slice, item) + for _, s := range slice { + if s == item { + return true + } + } + return false } func (t *Tgbot) onlineClients(chatId int64, messageID ...int) { @@ -1849,3 +2623,49 @@ func (t *Tgbot) editMessageTgBot(chatId int64, messageID int, text string, inlin logger.Warning(err) } } + + +func (t *Tgbot) SendMsgToTgbotDeleteAfter(chatId int64, msg string, delayInSeconds int, replyMarkup ...telego.ReplyMarkup) { + // Determine if replyMarkup was passed; otherwise, set it to nil + var replyMarkupParam telego.ReplyMarkup + if len(replyMarkup) > 0 { + replyMarkupParam = replyMarkup[0] // Use the first element + } + + // Send the message + sentMsg, err := bot.SendMessage(&telego.SendMessageParams{ + ChatID: tu.ID(chatId), + Text: msg, + ReplyMarkup: replyMarkupParam, // Use the correct replyMarkup value + }) + if err != nil { + logger.Warning("Failed to send message:", err) + return + } + + // Delete the sent message after the specified number of seconds + go func() { + time.Sleep(time.Duration(delayInSeconds) * time.Second) // Wait for the specified delay + t.deleteMessageTgBot(chatId, sentMsg.MessageID) // Delete the message + delete(userStates, chatId) + }() +} + +func (t *Tgbot) deleteMessageTgBot(chatId int64, messageID int) { + params := telego.DeleteMessageParams{ + ChatID: tu.ID(chatId), + MessageID: messageID, + } + if err := bot.DeleteMessage(¶ms); err != nil { + logger.Warning("Failed to delete message:", err) + } else { + logger.Info("Message deleted successfully") + } +} + +func (t *Tgbot) isSingleWord(text string) bool { + text = strings.TrimSpace(text) + re := regexp.MustCompile(`\s+`) + return re.MatchString(text) +} + diff --git a/web/translation/translate.en_US.toml b/web/translation/translate.en_US.toml index f0e22180..d7c70064 100644 --- a/web/translation/translate.en_US.toml +++ b/web/translation/translate.en_US.toml @@ -582,6 +582,21 @@ "yes" = "✅ Yes" "no" = "❌ No" +"received_id" = "🔑📥 ID updated. Press refresh to see changes." +"received_password" = "🔑📥 Password updated. Press refresh to see changes." +"received_email" = "📧📥 Email updated. Press refresh to see changes." +"received_comment" = "💬📥 Comment updated. Press refresh to see changes." +"id_prompt" = "🔑 Default ID: {{ .ClientId }}\n\nEnter your id." +"pass_prompt" = "🔑 Default Password: {{ .ClientPassword }}\n\nEnter your password." +"email_prompt" = "📧 Default Email: {{ .ClientEmail }}\n\nEnter your email." +"comment_prompt" = "💬 Default Comment: {{ .ClientComment }}\n\nEnter your Comment." +"inbound_client_data_id" = "🔄 Inbound: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Email: {{ .ClientEmail }}\n📊 Traffic: {{ .ClientTraffic }}\n📅 Expire Date: {{ .ClientExp }}\n💬 Comment: {{ .ClientComment }}\n\nYou can add the client to inbound now!" +"inbound_client_data_pass" = "🔄 Inbound: {{ .InboundRemark }}\n\n🔑 Password: {{ .ClientPass }}\n📧 Email: {{ .ClientEmail }}\n📊 Traffic: {{ .ClientTraffic }}\n📅 Expire Date: {{ .ClientExp }}\n💬 Comment: {{ .ClientComment }}\n\nYou can add the client to inbound now!" +"cancel" = "❌ Process Canceled! \n\nYou can /start again anytime. 🔄" +"error_add_client" = "⚠️ Error:\n\n {{ .error }}" +"using_default_value" = "Okay, I'll stick with the default value. 😊" +"incorrect_input" ="Your input is not valid.\nThe phrases should be continuous without spaces.\nCorrect example: aaaaaa\nIncorrect example: aaa aaa 🚫" + [tgbot.buttons] "closeKeyboard" = "❌ Close Keyboard" "cancel" = "❌ Cancel" @@ -616,6 +631,14 @@ "getBanLogs" = "Get Ban Logs" "allClients" = "All Clients" +"addClient" = "Add Client" +"submitDisable" = "Submit As Disable ✅" +"use_default" = "🏷️ Use default" +"change_id" = "⚙️🔑 ID" +"change_password" = "⚙️🔑 Password" +"change_email" = "⚙️📧 Email" +"change_comment" = "⚙️💬 Comment" + [tgbot.answers] "successfulOperation" = "✅ Operation successful!" "errorOperation" = "❗ Error in operation." diff --git a/web/translation/translate.es_ES.toml b/web/translation/translate.es_ES.toml index 57237e95..074475a8 100644 --- a/web/translation/translate.es_ES.toml +++ b/web/translation/translate.es_ES.toml @@ -584,6 +584,22 @@ "yes" = "✅ Sí" "no" = "❌ No" +"received_id" = "🔑📥 ID actualizado. Presiona actualizar para ver los cambios." +"received_password" = "🔑📥 Contraseña actualizada. Presiona actualizar para ver los cambios." +"received_email" = "📧📥 Correo electrónico actualizado. Presiona actualizar para ver los cambios." +"received_comment" = "💬📥 Comentario actualizado. Presiona actualizar para ver los cambios." +"id_prompt" = "🔑 ID predeterminado: {{ .ClientId }}\n\nIntroduce tu ID." +"pass_prompt" = "🔑 Contraseña predeterminada: {{ .ClientPassword }}\n\nIntroduce tu contraseña." +"email_prompt" = "📧 Correo electrónico predeterminado: {{ .ClientEmail }}\n\nIntroduce tu correo electrónico." +"comment_prompt" = "💬 Comentario predeterminado: {{ .ClientComment }}\n\nIntroduce tu comentario." +"inbound_client_data_id" = "🔄 Entrada: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Email: {{ .ClientEmail }}\n📊 Tráfico: {{ .ClientTraffic }}\n📅 Fecha de vencimiento: {{ .ClientExp }}\n💬 Comentario: {{ .ClientComment }}\n\n¡Ahora puedes agregar al cliente a la entrada!" +"inbound_client_data_pass" = "🔄 Entrada: {{ .InboundRemark }}\n\n🔑 Contraseña: {{ .ClientPass }}\n📧 Email: {{ .ClientEmail }}\n📊 Tráfico: {{ .ClientTraffic }}\n📅 Fecha de vencimiento: {{ .ClientExp }}\n💬 Comentario: {{ .ClientComment }}\n\n¡Ahora puedes agregar al cliente a la entrada!" +"cancel" = "❌ ¡Proceso cancelado! \n\nPuedes /start de nuevo en cualquier momento. 🔄" +"error_add_client" = "⚠️ Error:\n\n {{ .error }}" +"using_default_value" = "Está bien, me quedaré con el valor predeterminado. 😊" +"incorrect_input" ="Tu entrada no es válida.\nLas frases deben ser continuas sin espacios.\nEjemplo correcto: aaaaaa\nEjemplo incorrecto: aaa aaa 🚫" + + [tgbot.buttons] "closeKeyboard" = "❌ Cerrar Teclado" "cancel" = "❌ Cancelar" @@ -618,6 +634,15 @@ "getBanLogs" = "Registros de prohibición" "allClients" = "Todos los Clientes" +"addClient" = "Añadir Cliente" +"submitDisable" = "Enviar como Deshabilitado ✅" +"use_default" = "🏷️ Usar predeterminado" +"change_id" = "⚙️🔑 ID" +"change_password" = "⚙️🔑 Contraseña" +"change_email" = "⚙️📧 Correo electrónico" +"change_comment" = "⚙️💬 Comentario" + + [tgbot.answers] "successfulOperation" = "✅ ¡Exitosa!" "errorOperation" = "❗ Error en la Operación." diff --git a/web/translation/translate.fa_IR.toml b/web/translation/translate.fa_IR.toml index 9251daa8..7faa48c5 100644 --- a/web/translation/translate.fa_IR.toml +++ b/web/translation/translate.fa_IR.toml @@ -584,6 +584,22 @@ "yes" = "✅ بله" "no" = "❌ خیر" +"received_id" = "🔑📥 شناسه به‌روزرسانی شد. برای مشاهده تغییرات، دکمه تازه‌سازی را فشار دهید." +"received_password" = "🔑📥 رمز عبور به‌روزرسانی شد. برای مشاهده تغییرات، دکمه تازه‌سازی را فشار دهید." +"received_email" = "📧📥 ایمیل به‌روزرسانی شد. برای مشاهده تغییرات، دکمه تازه‌سازی را فشار دهید." +"received_comment" = "💬📥 نظر به‌روزرسانی شد. برای مشاهده تغییرات، دکمه تازه‌سازی را فشار دهید." +"id_prompt" = "🔑 شناسه پیش‌فرض: {{ .ClientId }}\n\nشناسه خود را وارد کنید." +"pass_prompt" = "🔑 رمز عبور پیش‌فرض: {{ .ClientPassword }}\n\nرمز عبور خود را وارد کنید." +"email_prompt" = "📧 ایمیل پیش‌فرض: {{ .ClientEmail }}\n\nایمیل خود را وارد کنید." +"comment_prompt" = "💬 نظر پیش‌فرض: {{ .ClientComment }}\n\nنظر خود را وارد کنید." +"inbound_client_data_id" = "🔄 ورودی: {{ .InboundRemark }}\n\n🔑 شناسه: {{ .ClientId }}\n📧 ایمیل: {{ .ClientEmail }}\n📊 ترافیک: {{ .ClientTraffic }}\n📅 تاریخ انقضا: {{ .ClientExp }}\n💬 نظر: {{ .ClientComment }}\n\nحالا می‌توانید مشتری را به ورودی اضافه کنید!" +"inbound_client_data_pass" = "🔄 ورودی: {{ .InboundRemark }}\n\n🔑 رمز عبور: {{ .ClientPass }}\n📧 ایمیل: {{ .ClientEmail }}\n📊 ترافیک: {{ .ClientTraffic }}\n📅 تاریخ انقضا: {{ .ClientExp }}\n💬 نظر: {{ .ClientComment }}\n\nحالا می‌توانید مشتری را به ورودی اضافه کنید!" +"cancel" = "❌ فرآیند لغو شد! \n\nمی‌توانید هر زمان که خواستید /start را دوباره اجرا کنید. 🔄" +"error_add_client" = "⚠️ خطا:\n\n {{ .error }}" +"using_default_value" = "باشه، از مقدار پیش‌فرض استفاده می‌کنم. 😊" +"incorrect_input" ="ورودی شما معتبر نیست.\nعبارت‌ها باید بدون فاصله باشند.\nمثال صحیح: aaaaaa\nمثال نادرست: aaa aaa 🚫" + + [tgbot.buttons] "closeKeyboard" = "❌ بستن کیبورد" "cancel" = "❌ لغو" @@ -618,6 +634,15 @@ "getBanLogs" = "گزارش های بلوک را دریافت کنید" "allClients" = "همه مشتریان" +"addClient" = "اضافه کردن مشتری" +"submitDisable" = "ارسال به عنوان غیرفعال ✅" +"use_default" = "🏷️ استفاده از پیش‌فرض" +"change_id" = "⚙️🔑 شناسه" +"change_password" = "⚙️🔑 رمز عبور" +"change_email" = "⚙️📧 ایمیل" +"change_comment" = "⚙️💬 نظر" + + [tgbot.answers] "successfulOperation" = "✅ انجام شد!" "errorOperation" = "❗ خطا در عملیات." diff --git a/web/translation/translate.id_ID.toml b/web/translation/translate.id_ID.toml index 39d18814..edf9b3fb 100644 --- a/web/translation/translate.id_ID.toml +++ b/web/translation/translate.id_ID.toml @@ -583,6 +583,22 @@ "yes" = "✅ Ya" "no" = "❌ Tidak" +"received_id" = "🔑📥 ID diperbarui. Tekan segarkan untuk melihat perubahan." +"received_password" = "🔑📥 Kata sandi diperbarui. Tekan segarkan untuk melihat perubahan." +"received_email" = "📧📥 Email diperbarui. Tekan segarkan untuk melihat perubahan." +"received_comment" = "💬📥 Komentar diperbarui. Tekan segarkan untuk melihat perubahan." +"id_prompt" = "🔑 ID Default: {{ .ClientId }}\n\nMasukkan ID Anda." +"pass_prompt" = "🔑 Kata Sandi Default: {{ .ClientPassword }}\n\nMasukkan kata sandi Anda." +"email_prompt" = "📧 Email Default: {{ .ClientEmail }}\n\nMasukkan email Anda." +"comment_prompt" = "💬 Komentar Default: {{ .ClientComment }}\n\nMasukkan komentar Anda." +"inbound_client_data_id" = "🔄 Masuk: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Email: {{ .ClientEmail }}\n📊 Lalu Lintas: {{ .ClientTraffic }}\n📅 Tanggal Kedaluwarsa: {{ .ClientExp }}\n💬 Komentar: {{ .ClientComment }}\n\nSekarang Anda bisa menambahkan klien ke masuk!" +"inbound_client_data_pass" = "🔄 Masuk: {{ .InboundRemark }}\n\n🔑 Kata Sandi: {{ .ClientPass }}\n📧 Email: {{ .ClientEmail }}\n📊 Lalu Lintas: {{ .ClientTraffic }}\n📅 Tanggal Kedaluwarsa: {{ .ClientExp }}\n💬 Komentar: {{ .ClientComment }}\n\nSekarang Anda bisa menambahkan klien ke masuk!" +"cancel" = "❌ Proses Dibatalkan! \n\nAnda dapat /start lagi kapan saja. 🔄" +"error_add_client" = "⚠️ Kesalahan:\n\n {{ .error }}" +"using_default_value" = "Oke, saya akan tetap menggunakan nilai default. 😊" +"incorrect_input" ="Masukan Anda tidak valid.\nFrasa harus berlanjut tanpa spasi.\nContoh benar: aaaaaa\nContoh salah: aaa aaa 🚫" + + [tgbot.buttons] "closeKeyboard" = "❌ Tutup Papan Ketik" "cancel" = "❌ Batal" @@ -617,6 +633,15 @@ "getBanLogs" = "Dapatkan Log Pemblokiran" "allClients" = "Semua Klien" +"addClient" = "Tambah Klien" +"submitDisable" = "Kirim Sebagai Nonaktif ✅" +"use_default" = "🏷️ Gunakan default" +"change_id" = "⚙️🔑 ID" +"change_password" = "⚙️🔑 Kata Sandi" +"change_email" = "⚙️📧 Email" +"change_comment" = "⚙️💬 Komentar" + + [tgbot.answers] "successfulOperation" = "✅ Operasi berhasil!" "errorOperation" = "❗ Kesalahan dalam operasi." diff --git a/web/translation/translate.ja_JP.toml b/web/translation/translate.ja_JP.toml index 7daab9ca..17c25ccf 100644 --- a/web/translation/translate.ja_JP.toml +++ b/web/translation/translate.ja_JP.toml @@ -584,6 +584,22 @@ "yes" = "✅ はい" "no" = "❌ いいえ" +"received_id" = "🔑📥 IDが更新されました。更新ボタンを押して変更を確認してください。" +"received_password" = "🔑📥 パスワードが更新されました。更新ボタンを押して変更を確認してください。" +"received_email" = "📧📥 メールが更新されました。更新ボタンを押して変更を確認してください。" +"received_comment" = "💬📥 コメントが更新されました。更新ボタンを押して変更を確認してください。" +"id_prompt" = "🔑 デフォルトID: {{ .ClientId }}\n\nIDを入力してください。" +"pass_prompt" = "🔑 デフォルトパスワード: {{ .ClientPassword }}\n\nパスワードを入力してください。" +"email_prompt" = "📧 デフォルトメール: {{ .ClientEmail }}\n\nメールを入力してください。" +"comment_prompt" = "💬 デフォルトコメント: {{ .ClientComment }}\n\nコメントを入力してください。" +"inbound_client_data_id" = "🔄 入力: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 メール: {{ .ClientEmail }}\n📊 トラフィック: {{ .ClientTraffic }}\n📅 期限日: {{ .ClientExp }}\n💬 コメント: {{ .ClientComment }}\n\n今すぐクライアントをインバウンドに追加できます!" +"inbound_client_data_pass" = "🔄 入力: {{ .InboundRemark }}\n\n🔑 パスワード: {{ .ClientPass }}\n📧 メール: {{ .ClientEmail }}\n📊 トラフィック: {{ .ClientTraffic }}\n📅 期限日: {{ .ClientExp }}\n💬 コメント: {{ .ClientComment }}\n\n今すぐクライアントをインバウンドに追加できます!" +"cancel" = "❌ プロセスがキャンセルされました!\n\nいつでも /start で再開できます。 🔄" +"error_add_client" = "⚠️ エラー:\n\n {{ .error }}" +"using_default_value" = "わかりました、デフォルト値を使用します。 😊" +"incorrect_input" ="入力が無効です。\nフレーズはスペースなしで続けて入力してください。\n正しい例: aaaaaa\n間違った例: aaa aaa 🚫" + + [tgbot.buttons] "closeKeyboard" = "❌ キーボードを閉じる" "cancel" = "❌ キャンセル" @@ -618,6 +634,15 @@ "getBanLogs" = "禁止ログ" "allClients" = "すべてのクライアント" +"addClient" = "クライアントを追加" +"submitDisable" = "無効として送信 ✅" +"use_default" = "🏷️ デフォルトを使用" +"change_id" = "⚙️🔑 ID" +"change_password" = "⚙️🔑 パスワード" +"change_email" = "⚙️📧 メール" +"change_comment" = "⚙️💬 コメント" + + [tgbot.answers] "successfulOperation" = "✅ 成功!" "errorOperation" = "❗ 操作エラー。" diff --git a/web/translation/translate.pt_BR.toml b/web/translation/translate.pt_BR.toml index 9c3fbd4e..043c9747 100644 --- a/web/translation/translate.pt_BR.toml +++ b/web/translation/translate.pt_BR.toml @@ -584,6 +584,22 @@ "yes" = "✅ Sim" "no" = "❌ Não" +"received_id" = "🔑📥 ID atualizado. Pressione atualizar para ver as mudanças." +"received_password" = "🔑📥 Senha atualizada. Pressione atualizar para ver as mudanças." +"received_email" = "📧📥 E-mail atualizado. Pressione atualizar para ver as mudanças." +"received_comment" = "💬📥 Comentário atualizado. Pressione atualizar para ver as mudanças." +"id_prompt" = "🔑 ID Padrão: {{ .ClientId }}\n\nDigite seu ID." +"pass_prompt" = "🔑 Senha Padrão: {{ .ClientPassword }}\n\nDigite sua senha." +"email_prompt" = "📧 E-mail Padrão: {{ .ClientEmail }}\n\nDigite seu e-mail." +"comment_prompt" = "💬 Comentário Padrão: {{ .ClientComment }}\n\nDigite seu comentário." +"inbound_client_data_id" = "🔄 Entrada: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Email: {{ .ClientEmail }}\n📊 Tráfego: {{ .ClientTraffic }}\n📅 Data de expiração: {{ .ClientExp }}\n💬 Comentário: {{ .ClientComment }}\n\nAgora você pode adicionar o cliente à entrada!" +"inbound_client_data_pass" = "🔄 Entrada: {{ .InboundRemark }}\n\n🔑 Senha: {{ .ClientPass }}\n📧 Email: {{ .ClientEmail }}\n📊 Tráfego: {{ .ClientTraffic }}\n📅 Data de expiração: {{ .ClientExp }}\n💬 Comentário: {{ .ClientComment }}\n\nAgora você pode adicionar o cliente à entrada!" +"cancel" = "❌ Processo Cancelado! \n\nVocê pode iniciar novamente a qualquer momento com /start. 🔄" +"error_add_client" = "⚠️ Erro:\n\n {{ .error }}" +"using_default_value" = "Tudo bem, vou manter o valor padrão. 😊" +"incorrect_input" ="Sua entrada não é válida.\nAs frases devem ser contínuas, sem espaços.\nExemplo correto: aaaaaa\nExemplo incorreto: aaa aaa 🚫" + + [tgbot.buttons] "closeKeyboard" = "❌ Fechar teclado" "cancel" = "❌ Cancelar" @@ -618,6 +634,15 @@ "getBanLogs" = "Obter logs de banimento" "allClients" = "Todos os clientes" +"addClient" = "Adicionar Cliente" +"submitDisable" = "Enviar como Desativado ✅" +"use_default" = "🏷️ Usar padrão" +"change_id" = "⚙️🔑 ID" +"change_password" = "⚙️🔑 Senha" +"change_email" = "⚙️📧 E-mail" +"change_comment" = "⚙️💬 Comentário" + + [tgbot.answers] "successfulOperation" = "✅ Operação bem-sucedida!" "errorOperation" = "❗ Erro na operação." diff --git a/web/translation/translate.ru_RU.toml b/web/translation/translate.ru_RU.toml index db9ef864..c19057e1 100644 --- a/web/translation/translate.ru_RU.toml +++ b/web/translation/translate.ru_RU.toml @@ -584,6 +584,22 @@ "yes" = "✅ Да" "no" = "❌ Нет" +"received_id" = "🔑📥 ID обновлён. Нажмите обновить, чтобы увидеть изменения." +"received_password" = "🔑📥 Пароль обновлён. Нажмите обновить, чтобы увидеть изменения." +"received_email" = "📧📥 Электронная почта обновлена. Нажмите обновить, чтобы увидеть изменения." +"received_comment" = "💬📥 Комментарий обновлён. Нажмите обновить, чтобы увидеть изменения." +"id_prompt" = "🔑 Стандартный ID: {{ .ClientId }}\n\nВведите ваш ID." +"pass_prompt" = "🔑 Стандартный пароль: {{ .ClientPassword }}\n\nВведите ваш пароль." +"email_prompt" = "📧 Стандартный email: {{ .ClientEmail }}\n\nВведите ваш email." +"comment_prompt" = "💬 Стандартный комментарий: {{ .ClientComment }}\n\nВведите ваш комментарий." +"inbound_client_data_id" = "🔄 Входящие: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Email: {{ .ClientEmail }}\n📊 Трафик: {{ .ClientTraffic }}\n📅 Дата истечения: {{ .ClientExp }}\n💬 Комментарий: {{ .ClientComment }}\n\nТеперь вы можете добавить клиента во входящие!" +"inbound_client_data_pass" = "🔄 Входящие: {{ .InboundRemark }}\n\n🔑 Пароль: {{ .ClientPass }}\n📧 Email: {{ .ClientEmail }}\n📊 Трафик: {{ .ClientTraffic }}\n📅 Дата истечения: {{ .ClientExp }}\n💬 Комментарий: {{ .ClientComment }}\n\nТеперь вы можете добавить клиента во входящие!" +"cancel" = "❌ Процесс отменён! \n\nВы можете снова начать с /start в любое время. 🔄" +"error_add_client" = "⚠️ Ошибка:\n\n {{ .error }}" +"using_default_value" = "Хорошо, оставлю значение по умолчанию. 😊" +"incorrect_input" ="Ваш ввод недействителен.\nФразы должны быть непрерывными без пробелов.\nПравильный пример: aaaaaa\nНеправильный пример: aaa aaa 🚫" + + [tgbot.buttons] "closeKeyboard" = "❌ Закрыть клавиатуру" "cancel" = "❌ Отмена" @@ -618,6 +634,15 @@ "getBanLogs" = "Журнал блокировок" "allClients" = "Все клиенты" +"addClient" = "Добавить клиента" +"submitDisable" = "Отправить как отключенный ✅" +"use_default" = "🏷️ Использовать по умолчанию" +"change_id" = "⚙️🔑 ID" +"change_password" = "⚙️🔑 Пароль" +"change_email" = "⚙️📧 Электронная почта" +"change_comment" = "⚙️💬 Комментарий" + + [tgbot.answers] "successfulOperation" = "✅ Успешно!" "errorOperation" = "❗ Ошибка в операции." diff --git a/web/translation/translate.tr_TR.toml b/web/translation/translate.tr_TR.toml index f460473d..48451a80 100644 --- a/web/translation/translate.tr_TR.toml +++ b/web/translation/translate.tr_TR.toml @@ -584,6 +584,22 @@ "yes" = "✅ Evet" "no" = "❌ Hayır" +"received_id" = "🔑📥 Kimlik güncellendi. Değişiklikleri görmek için yenileye basın." +"received_password" = "🔑📥 Şifre güncellendi. Değişiklikleri görmek için yenileye basın." +"received_email" = "📧📥 E-posta güncellendi. Değişiklikleri görmek için yenileye basın." +"received_comment" = "💬📥 Yorum güncellendi. Değişiklikleri görmek için yenileye basın." +"id_prompt" = "🔑 Varsayılan Kimlik: {{ .ClientId }}\n\nKimliğinizi girin." +"pass_prompt" = "🔑 Varsayılan Şifre: {{ .ClientPassword }}\n\nŞifrenizi girin." +"email_prompt" = "📧 Varsayılan E-posta: {{ .ClientEmail }}\n\nE-postanızı girin." +"comment_prompt" = "💬 Varsayılan Yorum: {{ .ClientComment }}\n\nYorumunuzu girin." +"inbound_client_data_id" = "🔄 Giriş: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 E-posta: {{ .ClientEmail }}\n📊 Trafik: {{ .ClientTraffic }}\n📅 Son Kullanım Tarihi: {{ .ClientExp }}\n💬 Yorum: {{ .ClientComment }}\n\nŞimdi müşteriyi girişe ekleyebilirsiniz!" +"inbound_client_data_pass" = "🔄 Giriş: {{ .InboundRemark }}\n\n🔑 Şifre: {{ .ClientPass }}\n📧 E-posta: {{ .ClientEmail }}\n📊 Trafik: {{ .ClientTraffic }}\n📅 Son Kullanım Tarihi: {{ .ClientExp }}\n💬 Yorum: {{ .ClientComment }}\n\nŞimdi müşteriyi girişe ekleyebilirsiniz!" +"cancel" = "❌ İşlem iptal edildi! \n\nİstediğiniz zaman /start ile yeniden başlayabilirsiniz. 🔄" +"error_add_client" = "⚠️ Hata:\n\n {{ .error }}" +"using_default_value" = "Tamam, varsayılan değeri kullanacağım. 😊" +"incorrect_input" ="Girdiğiniz değer geçerli değil.\nKelime öbekleri boşluk olmadan devam etmelidir.\nDoğru örnek: aaaaaa\nYanlış örnek: aaa aaa 🚫" + + [tgbot.buttons] "closeKeyboard" = "❌ Klavyeyi Kapat" "cancel" = "❌ İptal" @@ -618,6 +634,15 @@ "getBanLogs" = "Yasak Günlüklerini Al" "allClients" = "Tüm Müşteriler" +"addClient" = "Müşteri Ekle" +"submitDisable" = "Devre Dışı Olarak Gönder ✅" +"use_default" = "🏷️ Varsayılanı Kullan" +"change_id" = "⚙️🔑 ID" +"change_password" = "⚙️🔑 Şifre" +"change_email" = "⚙️📧 E-posta" +"change_comment" = "⚙️💬 Yorum" + + [tgbot.answers] "successfulOperation" = "✅ İşlem başarılı!" "errorOperation" = "❗ İşlemde hata." diff --git a/web/translation/translate.uk_UA.toml b/web/translation/translate.uk_UA.toml index b0206ce5..aad559c9 100644 --- a/web/translation/translate.uk_UA.toml +++ b/web/translation/translate.uk_UA.toml @@ -584,6 +584,22 @@ "yes" = "✅ Так" "no" = "❌ Ні" +"received_id" = "🔑📥 ID оновлено. Натисніть оновити, щоб побачити зміни." +"received_password" = "🔑📥 Пароль оновлено. Натисніть оновити, щоб побачити зміни." +"received_email" = "📧📥 Електронна пошта оновлена. Натисніть оновити, щоб побачити зміни." +"received_comment" = "💬📥 Коментар оновлено. Натисніть оновити, щоб побачити зміни." +"id_prompt" = "🔑 Стандартний ID: {{ .ClientId }}\n\nВведіть ваш ID." +"pass_prompt" = "🔑 Стандартний пароль: {{ .ClientPassword }}\n\nВведіть ваш пароль." +"email_prompt" = "📧 Стандартний email: {{ .ClientEmail }}\n\nВведіть ваш email." +"comment_prompt" = "💬 Стандартний коментар: {{ .ClientComment }}\n\nВведіть ваш коментар." +"inbound_client_data_id" = "🔄 Вхідні: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Email: {{ .ClientEmail }}\n📊 Трафік: {{ .ClientTraffic }}\n📅 Термін придатності: {{ .ClientExp }}\n💬 Коментар: {{ .ClientComment }}\n\nТепер ви можете додати клієнта до вхідних!" +"inbound_client_data_pass" = "🔄 Вхідні: {{ .InboundRemark }}\n\n🔑 Пароль: {{ .ClientPass }}\n📧 Email: {{ .ClientEmail }}\n📊 Трафік: {{ .ClientTraffic }}\n📅 Термін придатності: {{ .ClientExp }}\n💬 Коментар: {{ .ClientComment }}\n\nТепер ви можете додати клієнта до вхідних!" +"cancel" = "❌ Процес скасовано! \n\nВи можете знову розпочати, використовуючи /start у будь-який час. 🔄" +"error_add_client" = "⚠️ Помилка:\n\n {{ .error }}" +"using_default_value" = "Гаразд, залишу значення за замовчуванням. 😊" +"incorrect_input" ="Ваш ввід невірний.\nФрази повинні бути без пробілів.\nПравильний приклад: aaaaaa\nНеправильний приклад: aaa aaa 🚫" + + [tgbot.buttons] "closeKeyboard" = "❌ Закрити клавіатуру" "cancel" = "❌ Скасувати" @@ -618,6 +634,15 @@ "getBanLogs" = "Отримати журнали заборон" "allClients" = "Всі Клієнти" +"addClient" = "Додати клієнта" +"submitDisable" = "Надіслати як вимкнене ✅" +"use_default" = "🏷️ Використовувати за замовчуванням" +"change_id" = "⚙️🔑 ID" +"change_password" = "⚙️🔑 Пароль" +"change_email" = "⚙️📧 Електронна пошта" +"change_comment" = "⚙️💬 Коментар" + + [tgbot.answers] "successfulOperation" = "✅ Операція успішна!" "errorOperation" = "❗ Помилка в роботі." diff --git a/web/translation/translate.vi_VN.toml b/web/translation/translate.vi_VN.toml index 2e21ed69..45ec1eff 100644 --- a/web/translation/translate.vi_VN.toml +++ b/web/translation/translate.vi_VN.toml @@ -584,6 +584,22 @@ "yes" = "✅ Có" "no" = "❌ Không" +"received_id" = "🔑📥 ID đã được cập nhật. Nhấn làm mới để xem thay đổi." +"received_password" = "🔑📥 Mật khẩu đã được cập nhật. Nhấn làm mới để xem thay đổi." +"received_email" = "📧📥 Email đã được cập nhật. Nhấn làm mới để xem thay đổi." +"received_comment" = "💬📥 Bình luận đã được cập nhật. Nhấn làm mới để xem thay đổi." +"id_prompt" = "🔑 ID mặc định: {{ .ClientId }}\n\nVui lòng nhập ID của bạn." +"pass_prompt" = "🔑 Mật khẩu mặc định: {{ .ClientPassword }}\n\nVui lòng nhập mật khẩu của bạn." +"email_prompt" = "📧 Email mặc định: {{ .ClientEmail }}\n\nVui lòng nhập email của bạn." +"comment_prompt" = "💬 Bình luận mặc định: {{ .ClientComment }}\n\nVui lòng nhập bình luận của bạn." +"inbound_client_data_id" = "🔄 Vào: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 Email: {{ .ClientEmail }}\n📊 Lưu lượng: {{ .ClientTraffic }}\n📅 Ngày hết hạn: {{ .ClientExp }}\n💬 Bình luận: {{ .ClientComment }}\n\nBạn có thể thêm khách hàng vào vào ngay bây giờ!" +"inbound_client_data_pass" = "🔄 Vào: {{ .InboundRemark }}\n\n🔑 Mật khẩu: {{ .ClientPass }}\n📧 Email: {{ .ClientEmail }}\n📊 Lưu lượng: {{ .ClientTraffic }}\n📅 Ngày hết hạn: {{ .ClientExp }}\n💬 Bình luận: {{ .ClientComment }}\n\nBạn có thể thêm khách hàng vào vào ngay bây giờ!" +"cancel" = "❌ Quá trình đã bị hủy! \n\nBạn có thể bắt đầu lại bất cứ lúc nào bằng cách nhập /start. 🔄" +"error_add_client" = "⚠️ Lỗi:\n\n {{ .error }}" +"using_default_value" = "Được rồi, tôi sẽ sử dụng giá trị mặc định. 😊" +"incorrect_input" ="Dữ liệu bạn nhập không hợp lệ.\nCác chuỗi phải liền mạch và không có dấu cách.\nVí dụ đúng: aaaaaa\nVí dụ sai: aaa aaa 🚫" + + [tgbot.buttons] "closeKeyboard" = "❌ Đóng Bàn Phím" "cancel" = "❌ Hủy" @@ -618,6 +634,15 @@ "getBanLogs" = "Cấm nhật ký" "allClients" = "Tất cả Khách hàng" +"addClient" = "Thêm Khách Hàng" +"submitDisable" = "Gửi Dưới Dạng Tắt ✅" +"use_default" = "🏷️ Sử dụng mặc định" +"change_id" = "⚙️🔑 ID" +"change_password" = "⚙️🔑 Mật khẩu" +"change_email" = "⚙️📧 Email" +"change_comment" = "⚙️💬 Bình luận" + + [tgbot.answers] "successfulOperation" = "✅ Thành công!" "errorOperation" = "❗ Lỗi Trong Quá Trình Thực Hiện." diff --git a/web/translation/translate.zh_CN.toml b/web/translation/translate.zh_CN.toml index 861268d4..13e19c6b 100644 --- a/web/translation/translate.zh_CN.toml +++ b/web/translation/translate.zh_CN.toml @@ -584,6 +584,22 @@ "yes" = "✅ 是的" "no" = "❌ 没有" +"received_id" = "🔑📥 ID 已更新。请按刷新查看更改。" +"received_password" = "🔑📥 密码已更新。请按刷新查看更改。" +"received_email" = "📧📥 邮箱已更新。请按刷新查看更改。" +"received_comment" = "💬📥 评论已更新。请按刷新查看更改。" +"id_prompt" = "🔑 默认 ID: {{ .ClientId }}\n\n请输入您的 ID。" +"pass_prompt" = "🔑 默认密码: {{ .ClientPassword }}\n\n请输入您的密码。" +"email_prompt" = "📧 默认邮箱: {{ .ClientEmail }}\n\n请输入您的邮箱。" +"comment_prompt" = "💬 默认评论: {{ .ClientComment }}\n\n请输入您的评论。" +"inbound_client_data_id" = "🔄 入站: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 邮箱: {{ .ClientEmail }}\n📊 流量: {{ .ClientTraffic }}\n📅 过期日期: {{ .ClientExp }}\n💬 评论: {{ .ClientComment }}\n\n您现在可以将客户添加到入站!" +"inbound_client_data_pass" = "🔄 入站: {{ .InboundRemark }}\n\n🔑 密码: {{ .ClientPass }}\n📧 邮箱: {{ .ClientEmail }}\n📊 流量: {{ .ClientTraffic }}\n📅 过期日期: {{ .ClientExp }}\n💬 评论: {{ .ClientComment }}\n\n您现在可以将客户添加到入站!" +"cancel" = "❌ 进程已取消!\n\n您可以随时使用 /start 重新开始。 🔄" +"error_add_client" = "⚠️ 错误:\n\n {{ .error }}" +"using_default_value" = "好的,我会使用默认值。 😊" +"incorrect_input" ="您的输入无效。\n短语应连续输入,不能有空格。\n正确示例: aaaaaa\n错误示例: aaa aaa 🚫" + + [tgbot.buttons] "closeKeyboard" = "❌ 关闭键盘" "cancel" = "❌ 取消" @@ -618,6 +634,15 @@ "getBanLogs" = "禁止日志" "allClients" = "所有客户" +"addClient" = "添加客户" +"submitDisable" = "提交为禁用 ✅" +"use_default" = "🏷️ 使用默认" +"change_id" = "⚙️🔑 ID" +"change_password" = "⚙️🔑 密码" +"change_email" = "⚙️📧 邮箱" +"change_comment" = "⚙️💬 评论" + + [tgbot.answers] "successfulOperation" = "✅ 成功!" "errorOperation" = "❗ 操作错误。" diff --git a/web/translation/translate.zh_TW.toml b/web/translation/translate.zh_TW.toml index ff030320..7cc7eb5a 100644 --- a/web/translation/translate.zh_TW.toml +++ b/web/translation/translate.zh_TW.toml @@ -584,6 +584,22 @@ "yes" = "✅ 是的" "no" = "❌ 沒有" +"received_id" = "🔑📥 ID 已更新。請按刷新查看變更。" +"received_password" = "🔑📥 密碼已更新。請按刷新查看變更。" +"received_email" = "📧📥 電子郵件已更新。請按刷新查看變更。" +"received_comment" = "💬📥 評論已更新。請按刷新查看變更。" +"id_prompt" = "🔑 預設 ID: {{ .ClientId }}\n\n請輸入您的 ID。" +"pass_prompt" = "🔑 預設密碼: {{ .ClientPassword }}\n\n請輸入您的密碼。" +"email_prompt" = "📧 預設電子郵件: {{ .ClientEmail }}\n\n請輸入您的電子郵件。" +"comment_prompt" = "💬 預設評論: {{ .ClientComment }}\n\n請輸入您的評論。" +"inbound_client_data_id" = "🔄 入站: {{ .InboundRemark }}\n\n🔑 ID: {{ .ClientId }}\n📧 電子郵件: {{ .ClientEmail }}\n📊 流量: {{ .ClientTraffic }}\n📅 到期日: {{ .ClientExp }}\n💬 評論: {{ .ClientComment }}\n\n您現在可以將客戶新增至入站!" +"inbound_client_data_pass" = "🔄 入站: {{ .InboundRemark }}\n\n🔑 密碼: {{ .ClientPass }}\n📧 電子郵件: {{ .ClientEmail }}\n📊 流量: {{ .ClientTraffic }}\n📅 到期日: {{ .ClientExp }}\n💬 評論: {{ .ClientComment }}\n\n您現在可以將客戶新增至入站!" +"cancel" = "❌ 程序已取消!\n\n您可以隨時使用 /start 重新開始。 🔄" +"error_add_client" = "⚠️ 錯誤:\n\n {{ .error }}" +"using_default_value" = "好的,我會使用預設值。 😊" +"incorrect_input" ="您的輸入無效。\n短語應連續輸入,不能有空格。\n正確示例: aaaaaa\n錯誤示例: aaa aaa 🚫" + + [tgbot.buttons] "closeKeyboard" = "❌ 關閉鍵盤" "cancel" = "❌ 取消" @@ -618,6 +634,15 @@ "getBanLogs" = "禁止日誌" "allClients" = "所有客戶" +"addClient" = "新增客戶" +"submitDisable" = "提交為停用 ✅" +"use_default" = "🏷️ 使用預設" +"change_id" = "⚙️🔑 ID" +"change_password" = "⚙️🔑 密碼" +"change_email" = "⚙️📧 電子郵件" +"change_comment" = "⚙️💬 評論" + + [tgbot.answers] "successfulOperation" = "✅ 成功!" "errorOperation" = "❗ 操作錯誤。"