diff --git a/client/bot/handlers/config.go b/client/bot/handlers/config.go index b739887..ad9f0d2 100644 --- a/client/bot/handlers/config.go +++ b/client/bot/handlers/config.go @@ -8,19 +8,21 @@ import ( "github.com/celestix/gotgproto/dispatcher" "github.com/celestix/gotgproto/ext" "github.com/gotd/td/tg" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/database" "github.com/krau/SaveAny-Bot/pkg/enums/fnamest" "github.com/krau/SaveAny-Bot/pkg/tcbdata" ) func handleConfigCmd(ctx *ext.Context, update *ext.Update) error { - ctx.Reply(update, ext.ReplyTextString("请选择要配置的选项"), &ext.ReplyOpts{ + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgConfigPromptSelectOption)), &ext.ReplyOpts{ Markup: &tg.ReplyInlineMarkup{ Rows: []tg.KeyboardButtonRow{ { Buttons: []tg.KeyboardButtonClass{ &tg.KeyboardButtonCallback{ - Text: "文件名策略", + Text: i18n.T(i18nk.BotMsgConfigButtonFilenameStrategy), Data: fmt.Appendf(nil, "%s %s", tcbdata.TypeConfig, "fnamest"), }, }, @@ -37,7 +39,7 @@ func handleConfigCallback(ctx *ext.Context, update *ext.Update) error { ctx.AnswerCallback(&tg.MessagesSetBotCallbackAnswerRequest{ QueryID: update.CallbackQuery.GetQueryID(), Alert: true, - Message: "无效的回调数据", + Message: i18n.T(i18nk.BotMsgConfigErrorInvalidCallbackData), CacheTime: 5, }) return dispatcher.EndGroups @@ -72,7 +74,9 @@ func handleConfigFnameSTCallback(ctx *ext.Context, update *ext.Update) error { } ctx.EditMessage(userID, &tg.MessagesEditMessageRequest{ ID: update.CallbackQuery.GetMsgID(), - Message: fmt.Sprintf("已将文件名策略设置为: %s", fnamest.FnameSTDisplay[st]), + Message: i18n.T(i18nk.BotMsgConfigInfoFilenameStrategySet, map[string]any{ + "Strategy": fnamest.FnameSTDisplay[st], + }), }) return dispatcher.EndGroups } @@ -97,7 +101,9 @@ func handleConfigFnameSTCallback(ctx *ext.Context, update *ext.Update) error { } ctx.EditMessage(userID, &tg.MessagesEditMessageRequest{ ID: update.CallbackQuery.GetMsgID(), - Message: fmt.Sprintf("请选择文件名策略, 当前策略: %s", fnamest.FnameSTDisplay[currentSt]), + Message: i18n.T(i18nk.BotMsgConfigPromptSelectFilenameStrategy, map[string]any{ + "Strategy": fnamest.FnameSTDisplay[currentSt], + }), ReplyMarkup: markup, }) return dispatcher.EndGroups @@ -111,34 +117,27 @@ func handleConfigFnameTmpl(ctx *ext.Context, update *ext.Update) error { } args := strings.Fields(string(update.EffectiveMessage.Text)) if len(args) <= 1 { - text := `使用该命令设置文件名模板, 示例: -/fnametmpl 图片_{{.msgid}}_{{.msgdate}}.jpg - -可用变量: -- {{.msgid}}: 消息ID -- {{.msgtags}}: 消息中的标签, 将以下划线分隔输出 -- {{.msggen}}: 根据消息生成的文件名 -- {{.msgdate}}: 消息日期, 格式 YYYY-MM-DD_HH-MM-SS -- {{.origname}}: 媒体的原始文件名 (如果有) -- {{.chatid}}: 消息的聊天ID -` + text := i18n.T(i18nk.BotMsgConfigFnametmplHelp, nil) if user.FilenameTemplate != "" { - text += fmt.Sprintf("\n\n当前模板: %s", user.FilenameTemplate) + text += "\n\n" + i18n.T(i18nk.BotMsgConfigInfoCurrentTemplatePrefix, map[string]any{ + "Template": user.FilenameTemplate, + }) } - text += "\n\n模板仅在文件名策略设置为 '自定义模板' 时生效, 且模板解析错误时会回退到默认文件名" ctx.Reply(update, ext.ReplyTextString(text), nil) return dispatcher.EndGroups } newTmpl := strings.Join(args[1:], " ") _, err = template.New("filename").Parse(newTmpl) if err != nil { - ctx.Reply(update, ext.ReplyTextString("无效的模板, 请检查语法\n"+err.Error()), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgConfigErrorInvalidTemplate, map[string]any{ + "Error": err.Error(), + })), nil) return dispatcher.EndGroups } user.FilenameTemplate = newTmpl if err := database.UpdateUser(ctx, user); err != nil { return err } - ctx.Reply(update, ext.ReplyTextString("已更新文件名模板"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgConfigInfoTemplateUpdated, nil)), nil) return dispatcher.EndGroups } diff --git a/client/bot/handlers/dir.go b/client/bot/handlers/dir.go index 6e11310..5cb4f25 100644 --- a/client/bot/handlers/dir.go +++ b/client/bot/handlers/dir.go @@ -8,6 +8,8 @@ import ( "github.com/celestix/gotgproto/ext" "github.com/charmbracelet/log" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/database" "github.com/krau/SaveAny-Bot/storage" ) @@ -19,7 +21,7 @@ func handleDirCmd(ctx *ext.Context, update *ext.Update) error { dirs, err := database.GetUserDirsByChatID(ctx, userChatID) if err != nil { logger.Errorf("Failed to get user directories: %s", err) - ctx.Reply(update, ext.ReplyTextString("获取用户文件夹失败"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgDirErrorGetUserDirsFailed)), nil) return dispatcher.EndGroups } if len(args) < 2 { @@ -29,7 +31,7 @@ func handleDirCmd(ctx *ext.Context, update *ext.Update) error { user, err := database.GetUserByChatID(ctx, update.GetUserChat().GetID()) if err != nil { logger.Errorf("Failed to get user: %s", err) - ctx.Reply(update, ext.ReplyTextString("获取用户失败"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgDirErrorGetUserFailed)), nil) return dispatcher.EndGroups } switch args[1] { @@ -46,10 +48,10 @@ func handleDirCmd(ctx *ext.Context, update *ext.Update) error { if err := database.CreateDirForUser(ctx, user.ID, args[2], args[3]); err != nil { logger.Errorf("Failed to create directory: %s", err) - ctx.Reply(update, ext.ReplyTextString("创建文件夹失败"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgDirErrorCreateDirFailed)), nil) return dispatcher.EndGroups } - ctx.Reply(update, ext.ReplyTextString("文件夹添加成功"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgDirInfoCreateDirSuccess)), nil) case "del": // /dir del 3 if len(args) < 3 { @@ -58,17 +60,17 @@ func handleDirCmd(ctx *ext.Context, update *ext.Update) error { } dirID, err := strconv.Atoi(args[2]) if err != nil { - ctx.Reply(update, ext.ReplyTextString("文件夹ID无效"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgDirErrorInvalidDirId)), nil) return dispatcher.EndGroups } if err := database.DeleteDirByID(ctx, uint(dirID)); err != nil { logger.Errorf("Failed to delete directory: %s", err) - ctx.Reply(update, ext.ReplyTextString("删除文件夹失败"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgDirErrorDeleteDirFailed)), nil) return dispatcher.EndGroups } - ctx.Reply(update, ext.ReplyTextString("文件夹删除成功"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgDirInfoDeleteDirSuccess)), nil) default: - ctx.Reply(update, ext.ReplyTextString("未知操作"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgDirErrorUnknownOperation)), nil) } return dispatcher.EndGroups } diff --git a/client/bot/handlers/dl.go b/client/bot/handlers/dl.go index 3806c18..63f783f 100644 --- a/client/bot/handlers/dl.go +++ b/client/bot/handlers/dl.go @@ -1,7 +1,6 @@ package handlers import ( - "fmt" "net/url" "strings" @@ -9,6 +8,8 @@ import ( "github.com/charmbracelet/log" "github.com/duke-git/lancet/v2/slice" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/pkg/enums/tasktype" "github.com/krau/SaveAny-Bot/pkg/tcbdata" "github.com/krau/SaveAny-Bot/storage" @@ -18,7 +19,7 @@ func handleDlCmd(ctx *ext.Context, update *ext.Update) error { logger := log.FromContext(ctx) args := strings.Split(update.EffectiveMessage.Text, " ") if len(args) < 2 { - ctx.Reply(update, ext.ReplyTextString("用法: /dl <链接1> <链接2> ..."), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgDlUsage)), nil) return nil } links := args[1:] @@ -32,7 +33,7 @@ func handleDlCmd(ctx *ext.Context, update *ext.Update) error { } links = slice.Compact(links) if len(links) == 0 { - ctx.Reply(update, ext.ReplyTextString("没有有效的链接可供下载"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgDlErrorNoValidLinks)), nil) return nil } markup, err := msgelem.BuildAddSelectStorageKeyboard(storage.GetUserStorages(ctx, update.GetUserChat().GetID()), tcbdata.Add{ @@ -42,7 +43,9 @@ func handleDlCmd(ctx *ext.Context, update *ext.Update) error { if err != nil { return err } - ctx.Reply(update, ext.ReplyTextString(fmt.Sprintf("共 %d 个文件, 请选择存储位置", len(links))), &ext.ReplyOpts{ + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgDlInfoFilesSelectStorage, map[string]any{ + "Count": len(links), + })), &ext.ReplyOpts{ Markup: markup, }) return nil diff --git a/client/bot/handlers/link.go b/client/bot/handlers/link.go index 550260b..d4369b1 100644 --- a/client/bot/handlers/link.go +++ b/client/bot/handlers/link.go @@ -1,14 +1,14 @@ package handlers import ( - "fmt" - "github.com/celestix/gotgproto/dispatcher" "github.com/celestix/gotgproto/ext" "github.com/charmbracelet/log" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/dirutil" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/shortcut" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/pkg/tcbdata" "github.com/krau/SaveAny-Bot/storage" ) @@ -25,7 +25,9 @@ func handleMessageLink(ctx *ext.Context, update *ext.Update) error { req, err := msgelem.BuildAddOneSelectStorageMessage(ctx, stors, files[0], replied.ID) if err != nil { logger.Errorf("Failed to build storage selection message: %s", err) - editReplied("构建存储选择消息失败: "+err.Error(), nil) + editReplied(i18n.T(i18nk.BotMsgCommonErrorBuildStorageSelectMessageFailed, map[string]any{ + "Error": err.Error(), + }), nil) return dispatcher.EndGroups } ctx.EditMessage(update.EffectiveChat().GetID(), req) @@ -36,10 +38,14 @@ func handleMessageLink(ctx *ext.Context, update *ext.Update) error { }) if err != nil { logger.Errorf("Failed to build storage selection keyboard: %s", err) - editReplied("构建存储选择键盘失败: "+err.Error(), nil) + editReplied(i18n.T(i18nk.BotMsgCommonErrorBuildStorageSelectKeyboardFailed, map[string]any{ + "Error": err.Error(), + }), nil) return dispatcher.EndGroups } - editReplied(fmt.Sprintf("找到 %d 个文件, 请选择存储位置", len(files)), markup) + editReplied(i18n.T(i18nk.BotMsgCommonInfoFoundFilesSelectStorage, map[string]any{ + "Count": len(files), + }), markup) return dispatcher.EndGroups } diff --git a/client/bot/handlers/media.go b/client/bot/handlers/media.go index 5e06b26..6a7e554 100644 --- a/client/bot/handlers/media.go +++ b/client/bot/handlers/media.go @@ -8,6 +8,8 @@ import ( "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/mediautil" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/shortcut" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/database" "github.com/krau/SaveAny-Bot/storage" ) @@ -35,7 +37,9 @@ func handleMediaMessage(ctx *ext.Context, update *ext.Update) error { req, err := msgelem.BuildAddOneSelectStorageMessage(ctx, stors, file, msg.ID) if err != nil { logger.Errorf("Failed to build storage selection message: %s", err) - ctx.Reply(update, ext.ReplyTextString("构建存储选择消息失败: "+err.Error()), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgCommonErrorBuildStorageSelectMessageFailed, map[string]any{ + "Error": err.Error(), + })), nil) return dispatcher.EndGroups } ctx.EditMessage(update.EffectiveChat().GetID(), req) diff --git a/client/bot/handlers/media_group.go b/client/bot/handlers/media_group.go index 112af20..2b11738 100644 --- a/client/bot/handlers/media_group.go +++ b/client/bot/handlers/media_group.go @@ -1,7 +1,6 @@ package handlers import ( - "fmt" "sync" "time" @@ -12,6 +11,8 @@ import ( "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/mediautil" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/shortcut" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/common/utils/tgutil" "github.com/krau/SaveAny-Bot/config" "github.com/krau/SaveAny-Bot/pkg/tcbdata" @@ -89,7 +90,7 @@ func processMediaGroup(ctx *ext.Context, update *ext.Update, groupID int64) { logger.Debugf("Processing media group %d with %d items", groupID, len(items)) userId := update.GetUserChat().GetID() - msg, err := ctx.Reply(update, ext.ReplyTextString("正在保存文件..."), nil) + msg, err := ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgMediaGroupInfoSavingFiles, nil)), nil) if err != nil { logger.Errorf("Failed to reply: %s", err) return @@ -114,13 +115,17 @@ func processMediaGroup(ctx *ext.Context, update *ext.Update, groupID int64) { logger.Errorf("Failed to build storage selection keyboard: %s", err) ctx.EditMessage(userId, &tg.MessagesEditMessageRequest{ ID: msg.ID, - Message: "构建存储选择键盘失败: " + err.Error(), + Message: i18n.T(i18nk.BotMsgMediaGroupErrorBuildStorageSelectKeyboardFailed, map[string]any{ + "Error": err.Error(), + }), }) return } ctx.EditMessage(userId, &tg.MessagesEditMessageRequest{ - ID: msg.ID, - Message: fmt.Sprintf("共 %d 个文件, 请选择存储位置", len(items)), + ID: msg.ID, + Message: i18n.T(i18nk.BotMsgMediaGroupInfoGroupFoundFilesSelectStorage, map[string]any{ + "Count": len(items), + }), ReplyMarkup: markup, }) } diff --git a/client/bot/handlers/middleware.go b/client/bot/handlers/middleware.go index 1840f10..1ef1dd0 100644 --- a/client/bot/handlers/middleware.go +++ b/client/bot/handlers/middleware.go @@ -5,6 +5,8 @@ import ( "github.com/celestix/gotgproto/ext" "github.com/duke-git/lancet/v2/slice" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/dirutil" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/config" "github.com/krau/SaveAny-Bot/database" "github.com/krau/SaveAny-Bot/storage" @@ -13,11 +15,7 @@ import ( func checkPermission(ctx *ext.Context, update *ext.Update) error { userID := update.GetUserChat().GetID() if !slice.Contain(config.C().GetUsersID(), userID) { - const noPermissionText string = ` -您不在白名单中, 无法使用此 Bot. -您可以部署自己的实例: https://github.com/krau/SaveAny-Bot -` - ctx.Reply(update, ext.ReplyTextString(noPermissionText), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgCommonErrorNoPermission, nil)), nil) return dispatcher.EndGroups } @@ -29,25 +27,31 @@ func handleSilentMode(next func(*ext.Context, *ext.Update) error, handler func(* userID := update.GetUserChat().GetID() user, err := database.GetUserByChatID(ctx, userID) if err != nil { - ctx.Reply(update, ext.ReplyTextString("获取用户信息失败: "+err.Error()), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgCommonErrorGetUserInfoFailed, map[string]any{ + "Error": err.Error(), + })), nil) return dispatcher.EndGroups } if !user.Silent { return next(ctx, update) } if user.DefaultStorage == "" { - ctx.Reply(update, ext.ReplyTextString("您已开启静默模式, 但未设置默认存储端, 请先使用 /storage 设置"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgCommonErrorDefaultStorageNotSet, nil)), nil) return next(ctx, update) } stor, err := storage.GetStorageByUserIDAndName(ctx, userID, user.DefaultStorage) if err != nil { - ctx.Reply(update, ext.ReplyTextString("获取默认存储失败: "+err.Error()), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgCommonErrorGetStorageFailed, map[string]any{ + "Error": err.Error(), + })), nil) return dispatcher.EndGroups } if user.DefaultDir != 0 { dir, err := database.GetDirByID(ctx, user.DefaultDir) if err != nil { - ctx.Reply(update, ext.ReplyTextString("获取默认文件夹失败: "+err.Error()), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgCommonErrorGetDirFailed, map[string]any{ + "Error": err.Error(), + })), nil) return next(ctx, update) } ctx.Context = dirutil.WithContext(ctx.Context, dir) diff --git a/client/bot/handlers/parse.go b/client/bot/handlers/parse.go index fa4acf4..808727c 100644 --- a/client/bot/handlers/parse.go +++ b/client/bot/handlers/parse.go @@ -14,6 +14,8 @@ import ( "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/dirutil" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/shortcut" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/common/utils/fsutil" "github.com/krau/SaveAny-Bot/common/utils/tgutil" "github.com/krau/SaveAny-Bot/parsers" @@ -33,7 +35,7 @@ func handleTextMessage(ctx *ext.Context, u *ext.Update) error { if !ok { return dispatcher.EndGroups } - msg, err := ctx.Reply(u, ext.ReplyTextString("正在解析..."), nil) + msg, err := ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParseInfoParsing, nil)), nil) if err != nil { return err } @@ -44,7 +46,9 @@ func handleTextMessage(ctx *ext.Context, u *ext.Update) error { } if err != nil { logger.Error("Failed to parse text", "error", err) - ctx.Reply(u, ext.ReplyTextString("Failed to parse text: "+err.Error()), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParseErrorParseTextFailed, map[string]any{ + "Error": err.Error(), + })), nil) return dispatcher.EndGroups } logger.Debug("Parsed item from text message", "title", item.Title, "url", item.URL) @@ -55,13 +59,17 @@ func handleTextMessage(ctx *ext.Context, u *ext.Update) error { }) if err != nil { logger.Errorf("Failed to build storage selection keyboard: %s", err) - ctx.Reply(u, ext.ReplyTextString("Failed to build storage selection keyboard: "+err.Error()), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParseErrorBuildStorageSelectKeyboardFailed, map[string]any{ + "Error": err.Error(), + })), nil) return dispatcher.EndGroups } text, entities, err := msgelem.BuildParsedTextEntity(*item) if err != nil { logger.Errorf("Failed to build parsed text entity: %s", err) - ctx.Reply(u, ext.ReplyTextString("Failed to build parsed text entity: "+err.Error()), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParseErrorBuildParsedTextEntityFailed, map[string]any{ + "Error": err.Error(), + })), nil) return dispatcher.EndGroups } ctx.EditMessage(userID, &tg.MessagesEditMessageRequest{ @@ -87,7 +95,9 @@ func handleSilentSaveText(ctx *ext.Context, u *ext.Update) error { } if err != nil { logger.Error("Failed to parse text", "error", err) - ctx.Reply(u, ext.ReplyTextString("Failed to parse text: "+err.Error()), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParseErrorParseTextFailed, map[string]any{ + "Error": err.Error(), + })), nil) return dispatcher.EndGroups } logger.Debug("Parsed item from text message", "title", item.Title, "url", item.URL) @@ -95,7 +105,9 @@ func handleSilentSaveText(ctx *ext.Context, u *ext.Update) error { text, entities, err := msgelem.BuildParsedTextEntity(*item) if err != nil { logger.Errorf("Failed to build parsed text entity: %s", err) - ctx.Reply(u, ext.ReplyTextString("Failed to build parsed text entity: "+err.Error()), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParseErrorBuildParsedTextEntityFailed, map[string]any{ + "Error": err.Error(), + })), nil) return dispatcher.EndGroups } msg, err := ctx.SendMessage(userID, &tg.MessagesSendMessageRequest{ diff --git a/client/bot/handlers/parser.go b/client/bot/handlers/parser.go index 914655e..7f4d7ae 100644 --- a/client/bot/handlers/parser.go +++ b/client/bot/handlers/parser.go @@ -7,17 +7,15 @@ import ( "github.com/celestix/gotgproto/dispatcher" "github.com/celestix/gotgproto/ext" "github.com/gotd/td/tg" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/config" "github.com/krau/SaveAny-Bot/parsers" ) func handleParserCmd(ctx *ext.Context, u *ext.Update) error { args := strings.Split(u.EffectiveMessage.Text, " ") - help := ` -用法: - -/parser install <回复一个文件> - 安装解析器 -` + help := i18n.T(i18nk.BotMsgParserHelpText, nil) if len(args) < 2 { ctx.Reply(u, ext.ReplyTextString(help), nil) return nil @@ -36,35 +34,35 @@ func handleParserCmd(ctx *ext.Context, u *ext.Update) error { func handleParserInstallCmd(ctx *ext.Context, u *ext.Update) error { if !config.C().Parser.PluginEnable { - ctx.Reply(u, ext.ReplyTextString("解析器插件功能未启用"), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParserPluginNotEnabled, nil)), nil) return dispatcher.EndGroups } if u.EffectiveMessage.ReplyToMessage == nil || u.EffectiveMessage.ReplyToMessage.Media == nil { - ctx.Reply(u, ext.ReplyTextString("请回复一个包含解析器文件的消息"), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParserPromptReplyWithParserFile, nil)), nil) return dispatcher.EndGroups } media := u.EffectiveMessage.ReplyToMessage.Media document, ok := media.(*tg.MessageMediaDocument) if !ok { - ctx.Reply(u, ext.ReplyTextString("回复的消息不包含有效的文件"), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParserErrorNoValidFileInReply, nil)), nil) return dispatcher.EndGroups } value, ok := document.GetDocument() if !ok { - ctx.Reply(u, ext.ReplyTextString("回复的消息不包含有效的文件"), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParserErrorNoValidFileInReply, nil)), nil) return dispatcher.EndGroups } doc, ok := value.AsNotEmpty() if !ok { - ctx.Reply(u, ext.ReplyTextString("回复的消息不包含有效的文件"), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParserErrorNoValidFileInReply, nil)), nil) return dispatcher.EndGroups } if !strings.HasPrefix(doc.MimeType, "text/") { - ctx.Reply(u, ext.ReplyTextString("错误的文件类型"), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParserErrorWrongFileType, nil)), nil) return dispatcher.EndGroups } if doc.Size > 1024*1024*10 { - ctx.Reply(u, ext.ReplyTextString("文件过大"), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParserErrorFileTooLarge, nil)), nil) return dispatcher.EndGroups } var fileName string @@ -75,23 +73,29 @@ func handleParserInstallCmd(ctx *ext.Context, u *ext.Update) error { } } if fileName == "" { - ctx.Reply(u, ext.ReplyTextString("无法获取文件名"), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParserErrorGetFilenameFailed, nil)), nil) return dispatcher.EndGroups } if !strings.HasSuffix(fileName, ".js") { - ctx.Reply(u, ext.ReplyTextString("仅支持 .js 文件作为解析器"), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParserErrorOnlyJsSupported, nil)), nil) return dispatcher.EndGroups } data := bytes.NewBuffer(nil) _, err := ctx.DownloadMedia(media, ext.DownloadOutputStream{Writer: data}, nil) if err != nil { - ctx.Reply(u, ext.ReplyTextString("文件下载失败: "+err.Error()), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParserErrorDownloadFileFailed, map[string]any{ + "Error": err.Error(), + })), nil) return dispatcher.EndGroups } if err := parsers.AddPlugin(ctx, data.String(), fileName); err != nil { - ctx.Reply(u, ext.ReplyTextString("插件安装失败: "+err.Error()), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParserErrorInstallPluginFailed, map[string]any{ + "Error": err.Error(), + })), nil) return dispatcher.EndGroups } - ctx.Reply(u, ext.ReplyTextString("插件安装成功: "+fileName), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgParserInfoInstallPluginSuccess, map[string]any{ + "Name": fileName, + })), nil) return dispatcher.EndGroups } diff --git a/client/bot/handlers/rule.go b/client/bot/handlers/rule.go index 4814962..d6e03fd 100644 --- a/client/bot/handlers/rule.go +++ b/client/bot/handlers/rule.go @@ -10,6 +10,8 @@ import ( "github.com/charmbracelet/log" "github.com/duke-git/lancet/v2/slice" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/common/utils/strutil" "github.com/krau/SaveAny-Bot/database" "github.com/krau/SaveAny-Bot/pkg/rule" @@ -22,7 +24,7 @@ func handleRuleCmd(ctx *ext.Context, update *ext.Update) error { user, err := database.GetUserByChatID(ctx, userChatID) if err != nil { logger.Errorf("Failed to get user rules: %s", err) - ctx.Reply(update, ext.ReplyTextString("获取用户规则失败"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgRuleErrorGetUserRulesFailed, nil)), nil) return dispatcher.EndGroups } if len(args) < 2 { @@ -35,10 +37,14 @@ func handleRuleCmd(ctx *ext.Context, update *ext.Update) error { applyRule := !user.ApplyRule if err := database.UpdateUserApplyRule(ctx, user.ChatID, applyRule); err != nil { logger.Errorf("更新用户失败: %s", err) - ctx.Reply(update, ext.ReplyTextString("更新用户失败"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgRuleErrorUpdateUserFailed, nil)), nil) return dispatcher.EndGroups } - ctx.Reply(update, ext.ReplyTextString(fmt.Sprintf("已%s规则模式", map[bool]string{true: "启用", false: "禁用"}[applyRule])), nil) + if applyRule { + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgRuleInfoRuleModeEnabled, nil)), nil) + } else { + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgRuleInfoRuleModeDisabled, nil)), nil) + } case "add": // /rule add if len(args) < 6 { @@ -55,7 +61,10 @@ func handleRuleCmd(ctx *ext.Context, update *ext.Update) error { return rule.RuleType(""), fmt.Errorf("无效的规则类型: %s\n可用: %v", ruleTypeArg, slice.Join(rule.Values(), ", ")) }() if err != nil { - ctx.Reply(update, ext.ReplyTextString(err.Error()), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgRuleErrorInvalidRuleType, map[string]any{ + "Type": ruleTypeArg, + "Available": slice.Join(rule.Values(), ", "), + })), nil) return dispatcher.EndGroups } @@ -72,28 +81,28 @@ func handleRuleCmd(ctx *ext.Context, update *ext.Update) error { } if err := database.CreateRule(ctx, rd); err != nil { logger.Errorf("创建规则失败: %s", err) - ctx.Reply(update, ext.ReplyTextString("创建规则失败"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgRuleErrorCreateRuleFailed, nil)), nil) return dispatcher.EndGroups } - ctx.Reply(update, ext.ReplyTextString("创建规则成功"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgRuleInfoCreateRuleSuccess, nil)), nil) case "del": // /rule del if len(args) < 3 { - ctx.Reply(update, ext.ReplyTextString("请提供规则ID"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgRulePromptProvideRuleId, nil)), nil) return dispatcher.EndGroups } ruleID := args[2] id, err := strconv.Atoi(ruleID) if err != nil { - ctx.Reply(update, ext.ReplyTextString("无效的规则ID"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgRuleErrorInvalidRuleId, nil)), nil) return dispatcher.EndGroups } if err := database.DeleteRule(ctx, uint(id)); err != nil { logger.Errorf("删除规则失败: %s", err) - ctx.Reply(update, ext.ReplyTextString("删除规则失败"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgRuleErrorDeleteRuleFailed, nil)), nil) return dispatcher.EndGroups } - ctx.Reply(update, ext.ReplyTextString("删除规则成功"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgRuleInfoDeleteRuleSuccess, nil)), nil) default: ctx.Reply(update, ext.ReplyTextStyledTextArray(msgelem.BuildRuleHelpStyling(user.ApplyRule, user.Rules)), nil) return dispatcher.EndGroups diff --git a/client/bot/handlers/silent.go b/client/bot/handlers/silent.go index ef63320..fd01058 100644 --- a/client/bot/handlers/silent.go +++ b/client/bot/handlers/silent.go @@ -1,7 +1,6 @@ package handlers import ( - "fmt" "strings" "github.com/celestix/gotgproto/dispatcher" @@ -9,6 +8,8 @@ import ( "github.com/gotd/td/tg" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem" "github.com/krau/SaveAny-Bot/common/cache" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/database" "github.com/krau/SaveAny-Bot/pkg/tcbdata" "github.com/krau/SaveAny-Bot/storage" @@ -17,20 +18,27 @@ import ( func handleSilentCmd(ctx *ext.Context, update *ext.Update) error { user, err := database.GetUserByChatID(ctx, update.GetUserChat().GetID()) if err != nil { - ctx.Reply(update, ext.ReplyTextString("获取用户信息失败: "+err.Error()), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgCommonErrorGetUserInfoFailed, map[string]any{ + "Error": err.Error(), + })), nil) return nil } if !user.Silent && user.DefaultStorage == "" { - ctx.Reply(update, ext.ReplyTextString("请先使用 /storage 设置默认存储位置"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgCommonErrorDefaultStorageNotSet, nil)), nil) return nil } user.Silent = !user.Silent if err := database.UpdateUser(ctx, user); err != nil { - ctx.Reply(update, ext.ReplyTextString("更新用户信息失败: "+err.Error()), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgCommonErrorUpdateUserInfoFailed, map[string]any{ + "Error": err.Error(), + })), nil) return nil } - responseText := "已" + map[bool]string{true: "开启", false: "关闭"}[user.Silent] + "静默模式" - ctx.Reply(update, ext.ReplyTextString(responseText), nil) + if user.Silent { + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgCommonInfoSilentModeOn, nil)), nil) + } else { + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgCommonInfoSilentModeOff, nil)), nil) + } return dispatcher.EndGroups } @@ -49,18 +57,22 @@ func handleSetDefaultCallback(ctx *ext.Context, update *ext.Update) error { } if !ok { - return failedAnswer("数据已过期") + return failedAnswer(i18n.T(i18nk.BotMsgCommonErrorDataExpired, nil)) } userID := update.CallbackQuery.GetUserID() storageName := data.StorageName selectedStorage, err := storage.GetStorageByUserIDAndName(ctx, userID, storageName) if err != nil { - return failedAnswer("存储获取失败: " + err.Error()) + return failedAnswer(i18n.T(i18nk.BotMsgCommonErrorGetStorageFailed, map[string]any{ + "Error": err.Error(), + })) } user, err := database.GetUserByChatID(ctx, userID) if err != nil { - return failedAnswer("获取用户信息失败: " + err.Error()) + return failedAnswer(i18n.T(i18nk.BotMsgCommonErrorGetUserInfoFailed, map[string]any{ + "Error": err.Error(), + })) } var dir *database.Dir if data.DirID != 0 { @@ -68,24 +80,28 @@ func handleSetDefaultCallback(ctx *ext.Context, update *ext.Update) error { var err error dir, err = database.GetDirByID(ctx, data.DirID) if err != nil { - return failedAnswer("获取文件夹信息失败: " + err.Error()) + return failedAnswer(i18n.T(i18nk.BotMsgDirErrorGetUserDirsFailed, nil)) } user.DefaultDir = dir.ID } else { // 检查是否有可用的文件夹 dirs, err := database.GetDirsByUserIDAndStorageName(ctx, user.ID, storageName) if err != nil { - return failedAnswer("获取目录失败: " + err.Error()) + return failedAnswer(i18n.T(i18nk.BotMsgCommonErrorGetDirFailed, map[string]any{ + "Error": err.Error(), + })) } if len(dirs) > 0 { // 要求选择文件夹 markup, err := msgelem.BuildSetDefaultDirMarkup(ctx, storageName, dirs) if err != nil { - return failedAnswer("构建目录选择失败: " + err.Error()) + return failedAnswer(i18n.T(i18nk.BotMsgCommonErrorBuildDirSelectKeyboardFailed, map[string]any{ + "Error": err.Error(), + })) } ctx.EditMessage(userID, &tg.MessagesEditMessageRequest{ ID: update.CallbackQuery.GetMsgID(), - Message: "请选择要保存到的默认文件夹", + Message: i18n.T(i18nk.BotMsgCommonPromptSelectDefaultDir, nil), ReplyMarkup: markup, }) return dispatcher.EndGroups @@ -93,11 +109,18 @@ func handleSetDefaultCallback(ctx *ext.Context, update *ext.Update) error { } user.DefaultStorage = selectedStorage.Name() if err := database.UpdateUser(ctx, user); err != nil { - return failedAnswer("更新用户信息失败: " + err.Error()) + return failedAnswer(i18n.T(i18nk.BotMsgCommonErrorUpdateUserInfoFailed, map[string]any{ + "Error": err.Error(), + })) } - msg := fmt.Sprintf("已将默认存储位置设为: %s", selectedStorage.Name()) + msg := i18n.T(i18nk.BotMsgCommonInfoDefaultStorageSet, map[string]any{ + "Name": selectedStorage.Name(), + }) if dir != nil { - msg += fmt.Sprintf(":/%s", strings.TrimPrefix(dir.Path, "/")) + msg = i18n.T(i18nk.BotMsgCommonInfoDefaultStorageWithDirSet, map[string]any{ + "Name": selectedStorage.Name(), + "Dir": strings.TrimPrefix(dir.Path, "/"), + }) } ctx.EditMessage(userID, &tg.MessagesEditMessageRequest{ ID: update.CallbackQuery.GetMsgID(), @@ -110,15 +133,17 @@ func handleStorageCmd(ctx *ext.Context, update *ext.Update) error { userID := update.GetUserChat().GetID() storages := storage.GetUserStorages(ctx, userID) if len(storages) == 0 { - ctx.Reply(update, ext.ReplyTextString("无可用的存储"), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgCommonErrorNoAvailableStorage, nil)), nil) return nil } markup, err := msgelem.BuildSetDefaultStorageMarkup(ctx, storages) if err != nil { - ctx.Reply(update, ext.ReplyTextString("获取存储失败: "+err.Error()), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgCommonErrorGetStorageFailed, map[string]any{ + "Error": err.Error(), + })), nil) return nil } - ctx.Reply(update, ext.ReplyTextString("请选择要设为默认的存储位置"), &ext.ReplyOpts{ + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgCommonPromptSelectDefaultStorage, nil)), &ext.ReplyOpts{ Markup: markup, }) return dispatcher.EndGroups diff --git a/client/bot/handlers/telegraph.go b/client/bot/handlers/telegraph.go index 8f955f5..6f30600 100644 --- a/client/bot/handlers/telegraph.go +++ b/client/bot/handlers/telegraph.go @@ -13,6 +13,8 @@ import ( "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/dirutil" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/shortcut" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/pkg/enums/tasktype" "github.com/krau/SaveAny-Bot/pkg/tcbdata" "github.com/krau/SaveAny-Bot/storage" @@ -35,17 +37,19 @@ func handleTelegraphUrlMessage(ctx *ext.Context, update *ext.Update) error { }) if err != nil { logger.Errorf("Failed to build storage selection keyboard: %s", err) - ctx.Reply(update, ext.ReplyTextString("构建存储选择键盘失败: "+err.Error()), nil) + ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgTelegraphErrorBuildStorageSelectKeyboardFailed, map[string]any{ + "Error": err.Error(), + })), nil) return dispatcher.EndGroups } eb := entity.Builder{} if err := styling.Perform(&eb, - styling.Plain("标题: "), + styling.Plain(i18n.T(i18nk.BotMsgTelegraphInfoTitlePrefix, nil)), styling.Code(result.Page.Title), - styling.Plain("\n图片数量: "), + styling.Plain(i18n.T(i18nk.BotMsgTelegraphInfoPicCountPrefix, nil)), styling.Code(fmt.Sprintf("%d", len(result.Pics))), - styling.Plain("\n请选择存储位置"), + styling.Plain(i18n.T(i18nk.BotMsgTelegraphInfoPromptSelectStorage, nil)), ); err != nil { log.FromContext(ctx).Errorf("Failed to build entity: %s", err) return dispatcher.EndGroups diff --git a/client/bot/handlers/update.go b/client/bot/handlers/update.go index 34432b8..fae434a 100644 --- a/client/bot/handlers/update.go +++ b/client/bot/handlers/update.go @@ -2,7 +2,6 @@ package handlers import ( "errors" - "fmt" "regexp" "strings" @@ -11,6 +10,8 @@ import ( "github.com/celestix/gotgproto/ext" "github.com/gotd/td/telegram/message/html" "github.com/gotd/td/tg" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/config" "github.com/unvgo/ghselfupdate" ) @@ -18,24 +19,33 @@ import ( func handleUpdateCmd(ctx *ext.Context, u *ext.Update) error { currentV, err := semver.Parse(config.Version) if err != nil { - ctx.Reply(u, ext.ReplyTextString(fmt.Sprintf("You are in dev or the version var failed to inject: %v", err)), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgUpdateErrorVersionVarInvalid, map[string]any{ + "Error": err.Error(), + })), nil) return dispatcher.EndGroups } latest, ok, err := ghselfupdate.DetectLatest(config.GitRepo) if err != nil { - ctx.Reply(u, ext.ReplyTextString(fmt.Sprintf("检测最新版本失败: %v", err)), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgUpdateErrorCheckLatestFailed, map[string]any{ + "Error": err.Error(), + })), nil) return dispatcher.EndGroups } if !ok { - ctx.Reply(u, ext.ReplyTextString("没有找到版本信息"), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgUpdateErrorNoReleaseFound, nil)), nil) return dispatcher.EndGroups } if latest.Version.Major != currentV.Major { - ctx.Reply(u, ext.ReplyTextString(fmt.Sprintf("检测到大版本更新: %s -> %s , 请前往 GitHub 手动下载最新版本并查看迁移指南", currentV, latest.Version)), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgUpdateInfoMajorUpgradeRequired, map[string]any{ + "Current": currentV.String(), + "Latest": latest.Version.String(), + })), nil) return dispatcher.EndGroups } if latest.Version.LT(currentV) || latest.Version.Equals(currentV) { - ctx.Reply(u, ext.ReplyTextString(fmt.Sprintf("当前已经是最新版本: %s", config.Version)), nil) + ctx.Reply(u, ext.ReplyTextString(i18n.T(i18nk.BotMsgUpdateInfoAlreadyLatest, map[string]any{ + "Version": config.Version, + })), nil) return dispatcher.EndGroups } indocker := config.Docker == "true" @@ -55,32 +65,28 @@ func handleUpdateCmd(ctx *ext.Context, u *ext.Update) error { return `
` + md + `
` }())) if indocker { - text := fmt.Sprintf("发现新版本: %s\n当前版本: %s\n发布时间: %s\n由于您正在使用 Docker 部署, 请自行在部署平台上执行更新命令", - latest.Version, - config.Version, - latest.PublishedAt.Format("2006-01-02 15:04:05"), - ) + text := i18n.T(i18nk.BotMsgUpdateInfoNewVersionInDocker, map[string]any{ + "Latest": latest.Version.String(), + "Current": config.Version, + "PublishedAt": latest.PublishedAt.Format("2006-01-02 15:04:05"), + }) ctx.Reply(u, ext.ReplyTextString(text), nil) return dispatcher.EndGroups } - text := fmt.Sprintf(`发现新版本: %s -当前版本: %s - -文件大小: %.2f MB -下载链接: %s -发布时间: %s - -升级将重启 Bot , 是否升级?`, latest.Version, config.Version, - float64(latest.AssetByteSize)/(1024*1024), latest.AssetURL, - latest.PublishedAt.Format("2006-01-02 15:04:05"), - ) + text := i18n.T(i18nk.BotMsgUpdateInfoNewVersionPromptUpgrade, map[string]any{ + "Latest": latest.Version.String(), + "Current": config.Version, + "SizeMB": float64(latest.AssetByteSize) / (1024 * 1024), + "URL": latest.AssetURL, + "PublishedAt": latest.PublishedAt.Format("2006-01-02 15:04:05"), + }) ctx.Reply(u, ext.ReplyTextString(text), &ext.ReplyOpts{ Markup: &tg.ReplyInlineMarkup{ Rows: []tg.KeyboardButtonRow{ { Buttons: []tg.KeyboardButtonClass{ &tg.KeyboardButtonCallback{ - Text: "升级", + Text: i18n.T(i18nk.BotMsgUpdateButtonUpgrade, nil), Data: []byte("update"), }, }, @@ -98,19 +104,25 @@ func handleUpdateCallback(ctx *ext.Context, u *ext.Update) error { } ctx.EditMessage(u.GetUserChat().GetID(), &tg.MessagesEditMessageRequest{ ID: u.CallbackQuery.GetMsgID(), - Message: fmt.Sprintf("正在升级中, 当前版本: %s", config.Version), + Message: i18n.T(i18nk.BotMsgUpdateInfoUpgradingWithVersion, map[string]any{ + "Current": config.Version, + }), }) latest, err := ghselfupdate.UpdateSelf(currentV, config.GitRepo) if err != nil { ctx.EditMessage(u.GetUserChat().GetID(), &tg.MessagesEditMessageRequest{ ID: u.CallbackQuery.GetMsgID(), - Message: fmt.Sprintf("升级失败: %v", err), + Message: i18n.T(i18nk.BotMsgUpdateErrorUpgradeFailed, map[string]any{ + "Error": err.Error(), + }), }) return dispatcher.EndGroups } ctx.EditMessage(u.GetUserChat().GetID(), &tg.MessagesEditMessageRequest{ ID: u.CallbackQuery.GetMsgID(), - Message: fmt.Sprintf("已升级至版本 %s\n若 Bot 未自动重启请手动启动", latest.Version), + Message: i18n.T(i18nk.BotMsgUpdateInfoUpgradeSuccess, map[string]any{ + "Version": latest.Version.String(), + }), }) return errors.New("SAVEANTBOT-RESTART") } diff --git a/client/bot/handlers/utils/msgelem/dir.go b/client/bot/handlers/utils/msgelem/dir.go index 1482742..ea50fba 100644 --- a/client/bot/handlers/utils/msgelem/dir.go +++ b/client/bot/handlers/utils/msgelem/dir.go @@ -5,22 +5,24 @@ import ( "strings" "github.com/gotd/td/telegram/message/styling" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/database" ) func BuildDirHelpStyling(dirs []database.Dir) []styling.StyledTextOption { return []styling.StyledTextOption{ - styling.Bold("使用方法: /dir <操作> <参数...>"), - styling.Plain("\n\n可用操作:\n"), + styling.Bold(i18n.T(i18nk.BotMsgDirHelpUsage, nil)), + styling.Plain(i18n.T(i18nk.BotMsgDirHelpAvailableOps, nil)), styling.Code("add"), - styling.Plain(" <存储名> <路径> - 添加路径\n"), + styling.Plain(i18n.T(i18nk.BotMsgDirHelpAddSuffix, nil)), styling.Code("del"), - styling.Plain(" <路径ID> - 删除路径\n"), - styling.Plain("\n添加路径示例:\n"), - styling.Code("/dir add local1 path/to/dir"), - styling.Plain("\n\n删除路径示例:\n"), - styling.Code("/dir del 3"), - styling.Plain("\n\n当前已添加的路径:\n"), + styling.Plain(i18n.T(i18nk.BotMsgDirHelpDelSuffix, nil)), + styling.Plain(i18n.T(i18nk.BotMsgDirHelpAddExamplePrefix, nil)), + styling.Code(i18n.T(i18nk.BotMsgDirHelpAddExampleCmd, nil)), + styling.Plain(i18n.T(i18nk.BotMsgDirHelpDelExamplePrefix, nil)), + styling.Code(i18n.T(i18nk.BotMsgDirHelpDelExampleCmd, nil)), + styling.Plain(i18n.T(i18nk.BotMsgDirHelpExistingDirsPrefix, nil)), styling.Blockquote(func() string { var sb strings.Builder for _, dir := range dirs { diff --git a/client/bot/handlers/utils/msgelem/parse.go b/client/bot/handlers/utils/msgelem/parse.go index 0ad058a..a5adc88 100644 --- a/client/bot/handlers/utils/msgelem/parse.go +++ b/client/bot/handlers/utils/msgelem/parse.go @@ -7,6 +7,8 @@ import ( "github.com/gotd/td/telegram/message/entity" "github.com/gotd/td/telegram/message/styling" "github.com/gotd/td/tg" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/pkg/parser" ) @@ -14,15 +16,15 @@ func BuildParsedTextEntity(item parser.Item) (string, []tg.MessageEntityClass, e eb := entity.Builder{} if err := styling.Perform(&eb, styling.Bold(fmt.Sprintf("[%s]%s", item.Site, item.Title)), - styling.Plain("\n链接: "), + styling.Plain(i18n.T(i18nk.BotMsgParseInfoLinkPrefix, nil)), styling.Code(item.URL), - styling.Plain("\n作者: "), + styling.Plain(i18n.T(i18nk.BotMsgParseInfoAuthorPrefix, nil)), styling.Code(item.Author), - styling.Plain("\n描述: "), + styling.Plain(i18n.T(i18nk.BotMsgParseInfoDescriptionPrefix, nil)), styling.Code(strutil.Ellipsis(item.Description, 233)), - styling.Plain("\n文件数量: "), + styling.Plain(i18n.T(i18nk.BotMsgParseInfoFileCountPrefix, nil)), styling.Code(fmt.Sprintf("%d", len(item.Resources))), - styling.Plain("\n预计总大小: "), + styling.Plain(i18n.T(i18nk.BotMsgParseInfoTotalSizePrefix, nil)), styling.Code(fmt.Sprintf("%.2f MB", func() float64 { var totalSize int64 for _, res := range item.Resources { @@ -30,9 +32,9 @@ func BuildParsedTextEntity(item parser.Item) (string, []tg.MessageEntityClass, e } return float64(totalSize) / 1024 / 1024 }())), - styling.Plain("\n请选择存储位置"), + styling.Plain(i18n.T(i18nk.BotMsgParseInfoPromptSelectStorage, nil)), ); err != nil { - return "", nil, fmt.Errorf("构建消息失败: %w", err) + return "", nil, fmt.Errorf("failed to build parsed text entity: %w", err) } text, entities := eb.Complete() return text, entities, nil diff --git a/client/bot/handlers/utils/msgelem/rule.go b/client/bot/handlers/utils/msgelem/rule.go index a708038..6fa9b63 100644 --- a/client/bot/handlers/utils/msgelem/rule.go +++ b/client/bot/handlers/utils/msgelem/rule.go @@ -5,21 +5,28 @@ import ( "strings" "github.com/gotd/td/telegram/message/styling" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/database" ) func BuildRuleHelpStyling(enabled bool, rules []database.Rule) []styling.StyledTextOption { return []styling.StyledTextOption{ - styling.Bold("使用方法: /rule <操作> <参数...>"), - styling.Bold(fmt.Sprintf("\n当前已%s规则模式", map[bool]string{true: "启用", false: "禁用"}[enabled])), - styling.Plain("\n\n可用操作:\n"), + styling.Bold(i18n.T(i18nk.BotMsgRuleHelpUsage, nil)), + styling.Bold(func() string { + if enabled { + return i18n.T(i18nk.BotMsgRuleHelpCurrentModeEnabled, nil) + } + return i18n.T(i18nk.BotMsgRuleHelpCurrentModeDisabled, nil) + }()), + styling.Plain(i18n.T(i18nk.BotMsgRuleHelpAvailableOps, nil)), styling.Code("switch"), - styling.Plain(" - 开关规则模式\n"), + styling.Plain(i18n.T(i18nk.BotMsgRuleHelpSwitchSuffix, nil)), styling.Code("add"), - styling.Plain(" <类型> <数据> <存储名> <路径> - 添加规则\n"), + styling.Plain(i18n.T(i18nk.BotMsgRuleHelpAddSuffix, nil)), styling.Code("del"), - styling.Plain(" <规则ID> - 删除规则\n"), - styling.Plain("\n当前已添加的规则:\n"), + styling.Plain(i18n.T(i18nk.BotMsgRuleHelpDelSuffix, nil)), + styling.Plain(i18n.T(i18nk.BotMsgRuleHelpExistingRulesPrefix, nil)), styling.Blockquote(func() string { var sb strings.Builder for _, rule := range rules { diff --git a/client/bot/handlers/utils/msgelem/storage.go b/client/bot/handlers/utils/msgelem/storage.go index 36421c2..c037fc4 100644 --- a/client/bot/handlers/utils/msgelem/storage.go +++ b/client/bot/handlers/utils/msgelem/storage.go @@ -9,6 +9,8 @@ import ( "github.com/gotd/td/telegram/message/styling" "github.com/gotd/td/tg" "github.com/krau/SaveAny-Bot/common/cache" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/database" "github.com/krau/SaveAny-Bot/pkg/enums/tasktype" "github.com/krau/SaveAny-Bot/pkg/tcbdata" @@ -70,11 +72,14 @@ func BuildAddSelectStorageKeyboard(stors []storage.Storage, adddata tcbdata.Add) func BuildAddOneSelectStorageMessage(ctx context.Context, stors []storage.Storage, file tfile.TGFileMessage, msgId int) (*tg.MessagesEditMessageRequest, error) { eb := entity.Builder{} var entities []tg.MessageEntityClass - text := fmt.Sprintf("文件名: %s\n请选择存储位置", file.Name()) + text := i18n.T(i18nk.BotMsgTasksInfoAddedToQueueFull, map[string]any{ + "Filename": file.Name(), + "QueueLength": 0, + }) if err := styling.Perform(&eb, - styling.Plain("文件名: "), + styling.Plain(i18n.T(i18nk.BotMsgStorageInfoFilenamePrefix, nil)), styling.Code(file.Name()), - styling.Plain("\n请选择存储位置"), + styling.Plain(i18n.T(i18nk.BotMsgStorageInfoPromptSelectStorage, nil)), ); err != nil { log.FromContext(ctx).Errorf("Failed to build entity: %s", err) } else { @@ -185,7 +190,7 @@ func BuildSetDirMarkupForAdd(dirs []database.Dir, dataid string) (*tg.ReplyInlin return nil, fmt.Errorf("failed to set default directory data in cache: %w", err) } buttons = append(buttons, &tg.KeyboardButtonCallback{ - Text: "默认", + Text: i18n.T(i18nk.BotMsgDirButtonDefault, nil), Data: fmt.Appendf(nil, "%s %s", tcbdata.TypeAdd, dirDefaultDataId), }) markup := &tg.ReplyInlineMarkup{} diff --git a/client/bot/handlers/utils/msgelem/task.go b/client/bot/handlers/utils/msgelem/task.go index 9026be3..0ffb312 100644 --- a/client/bot/handlers/utils/msgelem/task.go +++ b/client/bot/handlers/utils/msgelem/task.go @@ -2,13 +2,14 @@ package msgelem import ( "context" - "fmt" "strconv" "github.com/charmbracelet/log" "github.com/gotd/td/telegram/message/entity" "github.com/gotd/td/telegram/message/styling" "github.com/gotd/td/tg" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" ) func BuildTaskAddedEntities( @@ -18,11 +19,15 @@ func BuildTaskAddedEntities( ) (string, []tg.MessageEntityClass) { entityBuilder := entity.Builder{} var entities []tg.MessageEntityClass - text := fmt.Sprintf("已添加到任务队列\n文件名: %s\n当前排队任务数: %d", filename, queueLength) + text := i18n.T(i18nk.BotMsgTasksInfoAddedToQueueFull, map[string]any{ + "Filename": filename, + "QueueLength": queueLength, + }) if err := styling.Perform(&entityBuilder, - styling.Plain("已添加到任务队列\n文件名: "), + styling.Plain(i18n.T(i18nk.BotMsgTasksInfoAddedToQueuePrefix, nil)), + styling.Plain(i18n.T(i18nk.BotMsgTasksInfoFilenamePrefix, nil)), styling.Code(filename), - styling.Plain("\n当前排队任务数: "), + styling.Plain(i18n.T(i18nk.BotMsgTasksInfoQueueLengthPrefix, nil)), styling.Bold(strconv.Itoa(queueLength)), ); err != nil { log.FromContext(ctx).Errorf("Failed to build entity: %s", err) diff --git a/client/bot/handlers/utils/shortcut/directlinks.go b/client/bot/handlers/utils/shortcut/directlinks.go index 00140b8..a4cf06d 100644 --- a/client/bot/handlers/utils/shortcut/directlinks.go +++ b/client/bot/handlers/utils/shortcut/directlinks.go @@ -5,6 +5,8 @@ import ( "github.com/celestix/gotgproto/ext" "github.com/charmbracelet/log" "github.com/gotd/td/tg" + "github.com/krau/SaveAny-Bot/common/i18n" + "github.com/krau/SaveAny-Bot/common/i18n/i18nk" "github.com/krau/SaveAny-Bot/common/utils/tgutil" "github.com/krau/SaveAny-Bot/core" "github.com/krau/SaveAny-Bot/core/tasks/directlinks" @@ -18,13 +20,15 @@ func CreateAndAddDirectTaskWithEdit(ctx *ext.Context, stor storage.Storage, dirP if err := core.AddTask(injectCtx, task); err != nil { log.FromContext(ctx).Errorf("Failed to add task: %s", err) ctx.EditMessage(userID, &tg.MessagesEditMessageRequest{ - ID: msgID, - Message: "任务添加失败: " + err.Error(), + ID: msgID, + Message: i18n.T(i18nk.BotMsgCommonErrorTaskAddFailed, map[string]any{ + "Error": err.Error(), + }), }) return dispatcher.EndGroups } ctx.EditMessage(userID, &tg.MessagesEditMessageRequest{ - Message: "任务已添加", + Message: i18n.T(i18nk.BotMsgCommonInfoTaskAdded, nil), }) return dispatcher.EndGroups } diff --git a/common/i18n/i18nk/keys.go b/common/i18n/i18nk/keys.go index 31d7d74..961fa89 100644 --- a/common/i18n/i18nk/keys.go +++ b/common/i18n/i18nk/keys.go @@ -8,6 +8,7 @@ const ( BotMsgCancelInfoCancelRequested Key = "bot.msg.cancel.info_cancel_requested" BotMsgCancelInfoCancellingTask Key = "bot.msg.cancel.info_cancelling_task" BotMsgCancelUsage Key = "bot.msg.cancel.usage" + BotMsgCommonErrorBuildDirSelectKeyboardFailed Key = "bot.msg.common.error_build_dir_select_keyboard_failed" BotMsgCommonErrorBuildStorageSelectKeyboardFailed Key = "bot.msg.common.error_build_storage_select_keyboard_failed" BotMsgCommonErrorBuildStorageSelectMessageFailed Key = "bot.msg.common.error_build_storage_select_message_failed" BotMsgCommonErrorDataExpired Key = "bot.msg.common.error_data_expired" @@ -26,6 +27,7 @@ const ( BotMsgCommonErrorNoAvailableStorage Key = "bot.msg.common.error_no_available_storage" BotMsgCommonErrorNoImagesInTelegraphPage Key = "bot.msg.common.error_no_images_in_telegraph_page" BotMsgCommonErrorNoMessagesInRange Key = "bot.msg.common.error_no_messages_in_range" + BotMsgCommonErrorNoPermission Key = "bot.msg.common.error_no_permission" BotMsgCommonErrorNoSavableFilesFound Key = "bot.msg.common.error_no_savable_files_found" BotMsgCommonErrorNoSavableMessagesInRange Key = "bot.msg.common.error_no_savable_messages_in_range" BotMsgCommonErrorParseTelegraphPathFailed Key = "bot.msg.common.error_parse_telegraph_path_failed" @@ -49,18 +51,32 @@ const ( BotMsgConfigErrorInvalidCallbackData Key = "bot.msg.config.error_invalid_callback_data" BotMsgConfigErrorInvalidTemplate Key = "bot.msg.config.error_invalid_template" BotMsgConfigFnametmplHelp Key = "bot.msg.config.fnametmpl_help" + BotMsgConfigInfoCurrentTemplatePrefix Key = "bot.msg.config.info_current_template_prefix" BotMsgConfigInfoFilenameStrategySet Key = "bot.msg.config.info_filename_strategy_set" BotMsgConfigInfoTemplateUpdated Key = "bot.msg.config.info_template_updated" BotMsgConfigPromptSelectFilenameStrategy Key = "bot.msg.config.prompt_select_filename_strategy" BotMsgConfigPromptSelectOption Key = "bot.msg.config.prompt_select_option" + BotMsgDirButtonDefault Key = "bot.msg.dir.button_default" BotMsgDirErrorCreateDirFailed Key = "bot.msg.dir.error_create_dir_failed" BotMsgDirErrorDeleteDirFailed Key = "bot.msg.dir.error_delete_dir_failed" BotMsgDirErrorGetUserDirsFailed Key = "bot.msg.dir.error_get_user_dirs_failed" BotMsgDirErrorGetUserFailed Key = "bot.msg.dir.error_get_user_failed" BotMsgDirErrorInvalidDirId Key = "bot.msg.dir.error_invalid_dir_id" BotMsgDirErrorUnknownOperation Key = "bot.msg.dir.error_unknown_operation" + BotMsgDirHelpAddExampleCmd Key = "bot.msg.dir.help_add_example_cmd" + BotMsgDirHelpAddExamplePrefix Key = "bot.msg.dir.help_add_example_prefix" + BotMsgDirHelpAddSuffix Key = "bot.msg.dir.help_add_suffix" + BotMsgDirHelpAvailableOps Key = "bot.msg.dir.help_available_ops" + BotMsgDirHelpDelExampleCmd Key = "bot.msg.dir.help_del_example_cmd" + BotMsgDirHelpDelExamplePrefix Key = "bot.msg.dir.help_del_example_prefix" + BotMsgDirHelpDelSuffix Key = "bot.msg.dir.help_del_suffix" + BotMsgDirHelpExistingDirsPrefix Key = "bot.msg.dir.help_existing_dirs_prefix" + BotMsgDirHelpUsage Key = "bot.msg.dir.help_usage" BotMsgDirInfoCreateDirSuccess Key = "bot.msg.dir.info_create_dir_success" BotMsgDirInfoDeleteDirSuccess Key = "bot.msg.dir.info_delete_dir_success" + BotMsgDlErrorNoValidLinks Key = "bot.msg.dl.error_no_valid_links" + BotMsgDlInfoFilesSelectStorage Key = "bot.msg.dl.info_files_select_storage" + BotMsgDlUsage Key = "bot.msg.dl.usage" BotMsgHelpTextFmt Key = "bot.msg.help_text_fmt" BotMsgMediaGroupErrorBuildStorageSelectKeyboardFailed Key = "bot.msg.media_group.error_build_storage_select_keyboard_failed" BotMsgMediaGroupInfoGroupFoundFilesSelectStorage Key = "bot.msg.media_group.info_group_found_files_select_storage" @@ -68,7 +84,13 @@ const ( BotMsgParseErrorBuildParsedTextEntityFailed Key = "bot.msg.parse.error_build_parsed_text_entity_failed" BotMsgParseErrorBuildStorageSelectKeyboardFailed Key = "bot.msg.parse.error_build_storage_select_keyboard_failed" BotMsgParseErrorParseTextFailed Key = "bot.msg.parse.error_parse_text_failed" + BotMsgParseInfoAuthorPrefix Key = "bot.msg.parse.info_author_prefix" + BotMsgParseInfoDescriptionPrefix Key = "bot.msg.parse.info_description_prefix" + BotMsgParseInfoFileCountPrefix Key = "bot.msg.parse.info_file_count_prefix" + BotMsgParseInfoLinkPrefix Key = "bot.msg.parse.info_link_prefix" BotMsgParseInfoParsing Key = "bot.msg.parse.info_parsing" + BotMsgParseInfoPromptSelectStorage Key = "bot.msg.parse.info_prompt_select_storage" + BotMsgParseInfoTotalSizePrefix Key = "bot.msg.parse.info_total_size_prefix" BotMsgParserErrorDownloadFileFailed Key = "bot.msg.parser.error_download_file_failed" BotMsgParserErrorFileTooLarge Key = "bot.msg.parser.error_file_too_large" BotMsgParserErrorGetFilenameFailed Key = "bot.msg.parser.error_get_filename_failed" @@ -86,6 +108,14 @@ const ( BotMsgRuleErrorInvalidRuleId Key = "bot.msg.rule.error_invalid_rule_id" BotMsgRuleErrorInvalidRuleType Key = "bot.msg.rule.error_invalid_rule_type" BotMsgRuleErrorUpdateUserFailed Key = "bot.msg.rule.error_update_user_failed" + BotMsgRuleHelpAddSuffix Key = "bot.msg.rule.help_add_suffix" + BotMsgRuleHelpAvailableOps Key = "bot.msg.rule.help_available_ops" + BotMsgRuleHelpCurrentModeDisabled Key = "bot.msg.rule.help_current_mode_disabled" + BotMsgRuleHelpCurrentModeEnabled Key = "bot.msg.rule.help_current_mode_enabled" + BotMsgRuleHelpDelSuffix Key = "bot.msg.rule.help_del_suffix" + BotMsgRuleHelpExistingRulesPrefix Key = "bot.msg.rule.help_existing_rules_prefix" + BotMsgRuleHelpSwitchSuffix Key = "bot.msg.rule.help_switch_suffix" + BotMsgRuleHelpUsage Key = "bot.msg.rule.help_usage" BotMsgRuleInfoCreateRuleSuccess Key = "bot.msg.rule.info_create_rule_success" BotMsgRuleInfoDeleteRuleSuccess Key = "bot.msg.rule.info_delete_rule_success" BotMsgRuleInfoRuleModeDisabled Key = "bot.msg.rule.info_rule_mode_disabled" @@ -93,12 +123,18 @@ const ( BotMsgRulePromptProvideRuleId Key = "bot.msg.rule.prompt_provide_rule_id" BotMsgSaveErrorInvalidIdOrUsername Key = "bot.msg.save.error_invalid_id_or_username" BotMsgSaveHelpText Key = "bot.msg.save_help_text" + BotMsgStorageInfoFilenamePrefix Key = "bot.msg.storage.info_filename_prefix" + BotMsgStorageInfoPromptSelectStorage Key = "bot.msg.storage.info_prompt_select_storage" BotMsgTasksCancelFailed Key = "bot.msg.tasks.cancel_failed" BotMsgTasksCancelRequestedPrefix Key = "bot.msg.tasks.cancel_requested_prefix" BotMsgTasksFieldCreated Key = "bot.msg.tasks.field_created" BotMsgTasksFieldId Key = "bot.msg.tasks.field_id" BotMsgTasksFieldStatus Key = "bot.msg.tasks.field_status" BotMsgTasksFieldTitle Key = "bot.msg.tasks.field_title" + BotMsgTasksInfoAddedToQueueFull Key = "bot.msg.tasks.info_added_to_queue_full" + BotMsgTasksInfoAddedToQueuePrefix Key = "bot.msg.tasks.info_added_to_queue_prefix" + BotMsgTasksInfoFilenamePrefix Key = "bot.msg.tasks.info_filename_prefix" + BotMsgTasksInfoQueueLengthPrefix Key = "bot.msg.tasks.info_queue_length_prefix" BotMsgTasksQueuedEmpty Key = "bot.msg.tasks.queued_empty" BotMsgTasksQueuedTitle Key = "bot.msg.tasks.queued_title" BotMsgTasksRunningEmpty Key = "bot.msg.tasks.running_empty" diff --git a/common/i18n/locale/zh-Hans.yaml b/common/i18n/locale/zh-Hans.yaml index 627659f..b61e889 100644 --- a/common/i18n/locale/zh-Hans.yaml +++ b/common/i18n/locale/zh-Hans.yaml @@ -103,6 +103,10 @@ bot: info_fetching_telegraph_page: "正在获取 telegraph 页面..." error_get_telegraph_page_failed: "获取 telegraph 页面失败: {{.Error}}" error_no_images_in_telegraph_page: "在 telegraph 页面中未找到图片" + error_build_dir_select_keyboard_failed: "构建目录选择键盘失败: {{.Error}}" + error_no_permission: | + 您不在白名单中, 无法使用此 Bot. + 您可以部署自己的实例: https://github.com/krau/SaveAny-Bot save: error_invalid_id_or_username: "无效的ID或用户名: {{.Error}}" watch: @@ -135,6 +139,10 @@ bot: queued_empty: "当前没有排队中的任务" queued_title: "当前排队中的任务:" truncated_note: "...\n只显示前 10 个任务, 共 {{.Count}} 个任务" + info_added_to_queue_full: "已添加到任务队列\n文件名: {{.Filename}}\n当前排队任务数: {{.QueueLength}}" + info_added_to_queue_prefix: "已添加到任务队列\n" + info_filename_prefix: "文件名: " + info_queue_length_prefix: "\n当前排队任务数: " rule: error_get_user_rules_failed: "获取用户规则失败" error_update_user_failed: "更新用户失败" @@ -147,6 +155,14 @@ bot: error_invalid_rule_id: "无效的规则ID" error_delete_rule_failed: "删除规则失败" info_delete_rule_success: "删除规则成功" + help_usage: "使用方法: /rule <操作> <参数...>" + help_current_mode_enabled: "\n当前已启用规则模式" + help_current_mode_disabled: "\n当前已禁用规则模式" + help_available_ops: "\n\n可用操作:\n" + help_switch_suffix: " - 开关规则模式\n" + help_add_suffix: " <类型> <数据> <存储名> <路径> - 添加规则\n" + help_del_suffix: " <规则ID> - 删除规则\n" + help_existing_rules_prefix: "\n当前已添加的规则:\n" dir: error_get_user_dirs_failed: "获取用户文件夹失败" error_get_user_failed: "获取用户失败" @@ -156,6 +172,16 @@ bot: error_delete_dir_failed: "删除文件夹失败" info_delete_dir_success: "文件夹删除成功" error_unknown_operation: "未知操作" + help_usage: "使用方法: /dir <操作> <参数...>" + help_available_ops: "\n\n可用操作:\n" + help_add_suffix: " <存储名> <路径> - 添加路径\n" + help_del_suffix: " <路径ID> - 删除路径\n" + help_add_example_prefix: "\n添加路径示例:\n" + help_add_example_cmd: "/dir add local1 path/to/dir" + help_del_example_prefix: "\n\n删除路径示例:\n" + help_del_example_cmd: "/dir del 3" + help_existing_dirs_prefix: "\n\n当前已添加的路径:\n" + button_default: "默认" parser: help_text: | 用法: @@ -176,6 +202,12 @@ bot: error_parse_text_failed: "Failed to parse text: {{.Error}}" error_build_storage_select_keyboard_failed: "Failed to build storage selection keyboard: {{.Error}}" error_build_parsed_text_entity_failed: "Failed to build parsed text entity: {{.Error}}" + info_link_prefix: "\n链接: " + info_author_prefix: "\n作者: " + info_description_prefix: "\n描述: " + info_file_count_prefix: "\n文件数量: " + info_total_size_prefix: "\n预计总大小: " + info_prompt_select_storage: "\n请选择存储位置" telegraph: error_build_storage_select_keyboard_failed: "构建存储选择键盘失败: {{.Error}}" info_title_prefix: "标题: " @@ -199,7 +231,7 @@ bot: 文件大小: {{.SizeMB}} MB 下载链接: {{.URL}} 发布时间: {{.PublishedAt}} - + 升级将重启 Bot , 是否升级? info_upgrading_with_version: "正在升级中, 当前版本: {{.Current}}" error_upgrade_failed: "升级失败: {{.Error}}" @@ -226,6 +258,11 @@ bot: 模板仅在文件名策略设置为 '自定义模板' 时生效, 且模板解析错误时会回退到默认文件名 error_invalid_template: "无效的模板, 请检查语法\n{{.Error}}" info_template_updated: "已更新文件名模板" + info_current_template_prefix: "当前模板: {{.Template}}" + dl: + usage: "用法: /dl <链接1> <链接2> ..." + error_no_valid_links: "没有有效的链接可供下载" + info_files_select_storage: "共 {{.Count}} 个文件, 请选择存储位置" cancel: usage: "用法: /cancel " error_cancel_failed: "取消任务失败: {{.Error}}" @@ -235,3 +272,6 @@ bot: info_saving_files: "正在保存文件..." error_build_storage_select_keyboard_failed: "构建存储选择键盘失败: {{.Error}}" info_group_found_files_select_storage: "共 {{.Count}} 个文件, 请选择存储位置" + storage: + info_filename_prefix: "文件名: " + info_prompt_select_storage: "\n请选择存储位置"