diff --git a/pom.xml b/pom.xml index 746680a..030bb63 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.wdsj AdvancedSensitiveWords - Flame + Starry jar AdvancedSensitiveWords diff --git a/src/main/java/io/wdsj/asw/AdvancedSensitiveWords.java b/src/main/java/io/wdsj/asw/AdvancedSensitiveWords.java index 7910c5b..6633fe1 100644 --- a/src/main/java/io/wdsj/asw/AdvancedSensitiveWords.java +++ b/src/main/java/io/wdsj/asw/AdvancedSensitiveWords.java @@ -44,7 +44,6 @@ public final class AdvancedSensitiveWords extends JavaPlugin { public static boolean isInitialized = false; public static SensitiveWordBs sensitiveWordBs; private final File CONFIG_FILE = new File(getDataFolder(), "config.yml"); - private final File MESSAGE_FILE = new File(getDataFolder(), "messages.yml"); public static boolean isAuthMeAvailable; public static boolean isCslAvailable; public static SettingsManager settingsManager; @@ -66,8 +65,13 @@ public void onLoad() { .configurationData(PluginSettings.class) .useDefaultMigrationService() .create(); + File msgFile = new File(getDataFolder(), "messages_" + settingsManager.getProperty(PluginSettings.PLUGIN_LANGUAGE) + + ".yml"); + if (!msgFile.exists()) { + saveResource("messages_" + settingsManager.getProperty(PluginSettings.PLUGIN_LANGUAGE) + ".yml", false); + } messagesManager = SettingsManagerBuilder - .withYamlFile(MESSAGE_FILE) + .withYamlFile(msgFile) .configurationData(PluginMessages.class) .useDefaultMigrationService() .create(); diff --git a/src/main/java/io/wdsj/asw/setting/PluginSettings.java b/src/main/java/io/wdsj/asw/setting/PluginSettings.java index 0dd4d0b..24cfa06 100644 --- a/src/main/java/io/wdsj/asw/setting/PluginSettings.java +++ b/src/main/java/io/wdsj/asw/setting/PluginSettings.java @@ -11,118 +11,230 @@ import static ch.jalu.configme.properties.PropertyInitializer.newProperty; public class PluginSettings implements SettingsHolder { - @Comment("是否启用默认词库(6w+)(强烈建议开启)") + @Comment({"插件语言(zhcn/en)(重启服务器生效)", + "Plugin language: (zhcn/en)(Require a server restart)"}) + public static final Property PLUGIN_LANGUAGE = newProperty("Plugin.language", "zhcn"); + + @Comment({"是否启用默认词库(6w+)(强烈建议开启)", + "Whether to enable the default word library (60k+ words) (strongly recommended)"}) public static final Property ENABLE_DEFAULT_WORDS = newProperty("Plugin.enableDefaultWords", true); - @Comment("是否启用在线词库") + + @Comment({"是否启用在线词库", + "Whether to enable online word library"}) public static final Property ENABLE_ONLINE_WORDS = newProperty("Plugin.enableOnlineWords", false); - @Comment("在线词库地址") + + @Comment({"在线词库地址", + "Online word library URL"}) public static final Property ONLINE_WORDS_URL = newProperty("Plugin.onlineWordsUrl", "https://raw.githubusercontent.com/HaHaWTH/ASW-OnlineWordList/main/lists.txt"); - @Comment("在线文本字符编码(UTF-8/GBK)") + + @Comment({"在线文本字符编码(UTF-8/GBK)", + "Online words text encoding (UTF-8/GBK)"}) public static final Property ONLINE_WORDS_ENCODING = newProperty("Plugin.onlineWordsEncoding", "UTF-8"); - @Comment("是否记录违规消息(存储在violations.log中)") + + @Comment({"是否记录违规消息(存储在violations.log中)", + "Whether to log violations (stored in violations.log)"}) public static final Property LOG_VIOLATION = newProperty("Plugin.logViolation", true); - @Comment("是否在插件启动时自动清除旧的日志文件") + + @Comment({"是否在插件启动时自动清除旧的日志文件", + "Whether to automatically clear old log files on plugin startup"}) public static final Property PURGE_LOG_FILE = newProperty("Plugin.purgeLogFile", false); - @Comment("敏感词替换符号") + + @Comment({"敏感词替换符号", + "Replacement symbol for sensitive words"}) public static final Property REPLACEMENT = newProperty("Plugin.replacement", "*"); - @Comment("预定义替换(需要先加入blackList)(如包含相同敏感词,长的放前面)(用|来分隔敏感词和替换词)") + + @Comment({"预定义替换(需要先加入blackList)(如包含相同敏感词,长的放前面)(用|来分隔敏感词和替换词)", + "Predefined replacements (need to be added to blacklist first) (If there are identical sensitive words, place the longer one first) (Use '|' to separate sensitive words and their replacements)"}) public static final Property> DEFINED_REPLACEMENT = newListProperty("Plugin.definedReplacement", "失业|灵活就业"); - @Comment("*是否启用告示牌检测") + + @Comment({"*是否启用告示牌检测", + "*Whether to enable sign edit checks"}) public static final Property ENABLE_SIGN_EDIT_CHECK = newProperty("Plugin.enableSignEditCheck", true); - @Comment("*是否启用铁砧重命名检测") + + @Comment({"*是否启用铁砧重命名检测", + "*Whether to enable anvil edit checks"}) public static final Property ENABLE_ANVIL_EDIT_CHECK = newProperty("Plugin.enableAnvilEditCheck", true); - @Comment("*是否启用书检测") + + @Comment({"*是否启用书检测", + "*Whether to enable book checks"}) public static final Property ENABLE_BOOK_EDIT_CHECK = newProperty("Plugin.enableBookEditCheck", true); - @Comment("*是否启用玩家名称检测(推荐支持中文名的服务器开启)") + + @Comment({"*是否启用玩家名称检测(推荐支持中文名的服务器开启)", + "*Whether to enable player name checks (recommended for servers supporting Chinese names)"}) public static final Property ENABLE_PLAYER_NAME_CHECK = newProperty("Plugin.enablePlayerNameCheck", false); - @Comment("是否启用API接口(非必要请勿关闭)") + + @Comment({"是否启用API接口(非必要请勿关闭)", + "Whether to enable API (do not disable unless necessary)"}) public static final Property ENABLE_API = newProperty("Plugin.enableApi", true); - @Comment("是否启用AuthMe兼容(在玩家未登录时不进行检测, 避免误判)") + + @Comment({"是否启用AuthMe兼容(在玩家未登录时不进行检测, 避免误判)", + "Whether to enable AuthMe compatibility (no checks on players not logged in to avoid false positives)"}) public static final Property ENABLE_AUTHME_COMPATIBILITY = newProperty("Plugin.compatibility.authMe", false); - @Comment("是否启用CatSeedLogin兼容(在玩家未登录时不进行检测, 避免误判)") + + @Comment({"是否启用CatSeedLogin兼容(在玩家未登录时不进行检测, 避免误判)", + "Whether to enable CatSeedLogin compatibility (no checks on players not logged in to avoid false positives)"}) public static final Property ENABLE_CSL_COMPATIBILITY = newProperty("Plugin.compatibility.catSeedLogin", false); - @Comment("默认跳过字符") + + @Comment({"默认跳过字符", + "Default characters to ignore"}) public static final Property IGNORE_CHAR = newProperty("Plugin.ignoreChar", "`-—=~~!!@#$%^&*()_+[]{}\\|;:'\"“”,,.。、()<>??¥【】《》 "); - @Comment("检测大小写") + + @Comment({"检测大小写", + "Whether to ignore case"}) public static final Property IGNORE_CASE = newProperty("Plugin.ignoreCase", true); - @Comment("检测半角&全角字符") + + @Comment({"检测半角&全角字符", + "Whether to ignore width (half-width and full-width characters)"}) public static final Property IGNORE_WIDTH = newProperty("Plugin.ignoreWidth", true); - @Comment("检测变着花样发送的数字(例:1贰叁④)") + + @Comment({"检测变着花样发送的数字(例:1贰叁④)", + "Whether to ignore styled numbers (e.g., 1贰叁④)"}) public static final Property IGNORE_NUM_STYLE = newProperty("Plugin.ignoreNumStyle", true); - @Comment("检测变着花样发送的中文(简繁)") + + @Comment({"检测变着花样发送的中文(简繁)", + "Whether to ignore styled Chinese characters (Simplified and Traditional)"}) public static final Property IGNORE_CHINESE_STYLE = newProperty("Plugin.ignoreChineseStyle", true); - @Comment("检测变着花样发送的英文(例:Ⓕⓤc⒦)") + + @Comment({"检测变着花样发送的英文(例:Ⓕⓤc⒦)", + "Whether to ignore styled English characters (e.g., Ⓕⓤc⒦)"}) public static final Property IGNORE_ENGLISH_STYLE = newProperty("Plugin.ignoreEnglishStyle", true); + @Comment({"是否强制英文全词匹配", - "(例:屏蔽了av但又不想让have被屏蔽"}) + "(例:屏蔽了av但又不想让have被屏蔽)", + "Whether to force full-word matches for English", + "(e.g., to block 'av' without blocking 'have')"}) public static final Property FORCE_ENGLISH_FULL_MATCH = newProperty("Plugin.forceEnglishFullMatch", false); - @Comment("检测重复字符(例:SSSSSBBBBB)") + + @Comment({"检测重复字符(例:SSSSSBBBBB)", + "Whether to ignore repeated characters (e.g., SSSSSBBBBB)"}) public static final Property IGNORE_REPEAT = newProperty("Plugin.ignoreRepeat", true); - @Comment("启用连续数字检测(通常用于过滤群号&身份证号&手机号等)") + + @Comment({"启用连续数字检测(通常用于过滤群号&身份证号&手机号等)", + "Whether to enable consecutive number checks (commonly used for filtering group numbers, ID numbers, phone numbers, etc.)"}) public static final Property ENABLE_NUM_CHECK = newProperty("Plugin.enableNumCheck", true); - @Comment("判定为连续数字的长度") + + @Comment({"判定为连续数字的长度", + "Length considered as consecutive numbers"}) public static final Property NUM_CHECK_LEN = newProperty("Plugin.numCheckLen", 9); - @Comment("启用邮箱检测(xxx@xxx.xxx)") + + @Comment({"启用邮箱检测(xxx@xxx.xxx)", + "Whether to enable email address checks (xxx@xxx.xxx)"}) public static final Property ENABLE_EMAIL_CHECK = newProperty("Plugin.enableEmailCheck", false); - @Comment("启用网址检测(http://xxx.xxx)") + + @Comment({"启用网址检测(http://xxx.xxx)", + "Whether to enable URL checks (http://xxx.xxx)"}) public static final Property ENABLE_URL_CHECK = newProperty("Plugin.enableUrlCheck", true); - @Comment("启用敏感英文单词检测") + + @Comment({"启用敏感英文单词检测", + "Whether to enable sensitive English word checks"}) public static final Property ENABLE_WORD_CHECK = newProperty("Plugin.enableWordCheck", true); - @Comment("自定义敏感词列表") + + @Comment({"自定义敏感词列表", + "Custom sensitive word list"}) public static final Property> BLACK_LIST = newListProperty("Plugin.blackList", "失业"); - @Comment("敏感词白名单") + + @Comment({"敏感词白名单", + "Sensitive word whitelist"}) public static final Property> WHITE_LIST = newListProperty("Plugin.whiteList", "3p"); + @Comment({"是否关闭插件启动时的求赞助消息:(", - "赞助链接: https://afdian.net/a/114514woxiuyuan/"}) + "赞助链接: https://afdian.net/a/114514woxiuyuan/", "Whether to disable donation request messages on plugin startup", + "Donation link: https://afdian.net/a/114514woxiuyuan/"}) public static final Property DISABLE_DONATION = newProperty("Plugin.disableDonation", false); - @Comment("替换还是取消(replace/cancel)") + + @Comment({"替换还是取消(replace/cancel)", + "Replace or cancel (replace/cancel)"}) public static final Property CHAT_METHOD = newProperty("Chat.method", "replace"); + @Comment({"取消后是否发送假消息(仅取消模式可用)(支持PAPI)(Inspired by Bilibili Avalon System)", - "如果命令被取消则不会发送假消息. 避免隐私泄露" - }) + "如果命令被取消则不会发送假消息. 避免隐私泄露", + "Whether to send a fake message after cancellation (only available in cancel mode) (supports PAPI) (Inspired by Bilibili Avalon System)", + "If a command is cancelled, no fake message will be sent to avoid privacy leaks"}) public static final Property CHAT_FAKE_MESSAGE_ON_CANCEL = newProperty("Chat.fakeMessageOnCancel", false); - @Comment("是否发送消息提醒(和假消息冲突)") + + @Comment({"是否发送消息提醒(和假消息冲突)", + "Whether to send message alerts (conflicts with fake messages)"}) public static final Property CHAT_SEND_MESSAGE = newProperty("Chat.sendMessage", true); - @Comment("*是否启用服务器广播消息检测(仅提供取消和替换模式,配置跟随聊天检测)(不会触发API事件)") + + @Comment({"*是否启用服务器广播消息检测(仅提供取消和替换模式,配置跟随聊天检测)(不会触发API事件)", + "*Whether to enable server broadcast message checks (only offers cancel and replace modes, configuration follows chat checks) (does not trigger API events)"}) public static final Property CHAT_BROADCAST_CHECK = newProperty("Chat.broadcastCheck", true); - @Comment("是否开启聊天上下文检测(仅提供取消和假消息模式,配置跟随聊天检测)") + + @Comment({"是否开启聊天上下文检测(仅提供取消和假消息模式,配置跟随聊天检测)", + "Whether to enable chat context checks (only offers cancel and fake message modes, configuration follows chat checks)"}) public static final Property CHAT_CONTEXT_CHECK = newProperty("Chat.contextCheck", false); - @Comment("最大检测上下文大小") + + @Comment({"最大检测上下文大小", + "Maximum context size for checks"}) public static final Property CHAT_CONTEXT_MAX_SIZE = newProperty("Chat.contextMaxSize", 4); - @Comment("是否反转指令白名单为黑名单") + + @Comment({"是否反转指令白名单为黑名单", + "Whether to invert the command whitelist to a blacklist"}) public static final Property CHAT_INVERT_WHITELIST = newProperty("Chat.invertCommandWhiteList", false); - @Comment("指令白名单(白名单的指令如含敏感词不会被检测)") + + @Comment({"指令白名单(白名单的指令如含敏感词不会被检测)", + "Command whitelist (commands on the whitelist will not be checked for sensitive words)"}) public static final Property> CHAT_COMMAND_WHITE_LIST = newListProperty("Chat.commandWhiteList", "/asw", "/reload", "/help", "/ban", "/mute", "/unmute", "/kick", "/unban", "/res", "/sethome", "/home", "/l", "/tp", "/tpa", "/login", "/log", "/register", "/reg", "/lp"); - @Comment("替换还是取消(replace/cancel)") + + @Comment({"替换还是取消(replace/cancel)", + "Replace or cancel (replace/cancel)"}) public static final Property BOOK_METHOD = newProperty("Book.method", "replace"); - @Comment("是否跳过换行") + + @Comment({"是否跳过换行", + "Whether to skip newline characters"}) public static final Property BOOK_IGNORE_NEWLINE = newProperty("Book.ignoreNewLine", true); - @Comment("存在敏感词时是否发送消息提醒") + + @Comment({"存在敏感词时是否发送消息提醒", + "Whether to send a message alert when sensitive words are found"}) public static final Property BOOK_SEND_MESSAGE = newProperty("Book.sendMessage", true); - @Comment("是否启用书检测缓存(有助于优化性能)") + + @Comment({"是否启用书检测缓存(有助于优化性能)", + "Whether to enable book check caching (helps optimize performance)"}) public static final Property BOOK_CACHE = newProperty("Book.cache.enableCache", false); - @Comment("最大缓存数量(默认200)") + + @Comment({"最大缓存数量(默认200)", + "Maximum cache size (default is 200)"}) public static final Property BOOK_MAXIMUM_CACHE_SIZE = newProperty("Book.cache.maximumCacheSize", 200); - @Comment("重载时是否清空缓存") + + @Comment({"重载时是否清空缓存", + "Whether to clear cache on reload"}) public static final Property BOOK_CACHE_CLEAR_ON_RELOAD = newProperty("Book.cache.clearOnReload", false); - @Comment("替换还是取消(replace/cancel)") + + @Comment({"替换还是取消(replace/cancel)", + "Replace or cancel (replace/cancel)"}) public static final Property SIGN_METHOD = newProperty("Sign.method", "replace"); - @Comment("是否启用跨行检测") + + @Comment({"是否启用跨行检测", + "Whether to enable multi-line check"}) public static final Property SIGN_MULTI_LINE_CHECK = newProperty("Sign.multiLineCheck", true); - @Comment("存在敏感词时是否发送消息提醒") + + @Comment({"存在敏感词时是否发送消息提醒", + "Whether to send a message alert when sensitive words are found"}) public static final Property SIGN_SEND_MESSAGE = newProperty("Sign.sendMessage", true); - @Comment("替换还是取消(replace/cancel)") + + @Comment({"替换还是取消(replace/cancel)", + "Replace or cancel (replace/cancel)"}) public static final Property ANVIL_METHOD = newProperty("Anvil.method", "replace"); - @Comment("存在敏感词时是否发送消息提醒") + + @Comment({"存在敏感词时是否发送消息提醒", + "Whether to send a message alert when sensitive words are found"}) public static final Property ANVIL_SEND_MESSAGE = newProperty("Anvil.sendMessage", true); - @Comment("替换还是禁止登录(replace/cancel)") + + @Comment({"替换还是禁止登录(replace/cancel)", + "Replace or forbid login (replace/cancel)"}) public static final Property NAME_METHOD = newProperty("Name.method", "cancel"); - @Comment("存在敏感词时是否发送消息/踢出消息") + + @Comment({"存在敏感词时是否发送消息/踢出消息", + "Whether to send a message/kick message when sensitive words are found"}) public static final Property NAME_SEND_MESSAGE = newProperty("Name.sendMessage", true); - @Comment("是否跳过对基岩版玩家名称的检测(需要floodgate)") + + @Comment({"是否跳过对基岩版玩家名称的检测(需要floodgate)", + "Whether to skip checking player names for Bedrock Edition players (requires floodgate)"}) public static final Property NAME_IGNORE_BEDROCK = newProperty("Name.ignoreBedrock", false); - @Comment("是否启用NPC兼容(支持Leaves NPC)") + + @Comment({"是否启用NPC兼容(支持Leaves NPC)", + "Whether to enable NPC compatibility (supports Leaves NPC)"}) public static final Property NAME_IGNORE_NPC = newProperty("Name.ignoreNPC", true); @Override diff --git a/src/main/java/io/wdsj/asw/util/Utils.java b/src/main/java/io/wdsj/asw/util/Utils.java index c4784c1..96222c0 100644 --- a/src/main/java/io/wdsj/asw/util/Utils.java +++ b/src/main/java/io/wdsj/asw/util/Utils.java @@ -37,10 +37,6 @@ public static boolean isClassLoaded(String className) { } } - public static void playSounds(Player player, String soundName) { - if (soundName.equalsIgnoreCase("NONE")) return; - player.playSound(player.getLocation(), soundName, 1.0f, 0.0f); - } public static void logViolation(String playerName, String violationReason) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss"); diff --git a/src/main/resources/messages_en.yml b/src/main/resources/messages_en.yml new file mode 100644 index 0000000..e78ce50 --- /dev/null +++ b/src/main/resources/messages_en.yml @@ -0,0 +1,59 @@ +#AdvancedSensitiveWords Messages configuration +#Chat related messages +Chat: + #Fake messages(Only the player who send the message can see it) + #Internal placeholders: %integrated_player% %integrated_message% (PlaceHolderAPI supported) + fakeMessage: <%integrated_player%> %integrated_message% + #Messages on Chat + messageOnChat: '&cDo not send sensitive words in the chat.' +#Sign check related messages +Sign: + #Messages on Sign editing + messageOnSign: '&cDo not write sensitive vocabulary in the sign.' +#Anvil check related messages +Anvil: + #Messages on Anvil renaming + messageOnAnvilRename: '&cDo not write sensitive words in the Anvil.' +#Book check related messages +Book: + #Messages on Book editing + messageOnBook: '&cDo not write sensitive words in the book.' +#Player name check related messages +Name: + #Messages on Player name + messageOnName: '&cYour username contains sensitive words, please change your username or contact an administrator.' +#Plugin related messages +Plugin: + #Reload command + messageOnCommandReload: '&aAdvancedSensitiveWords has been reloaded.' + #Help command + messageOnCommandHelp: |- + &bAdvancedSensitiveWords&r---&b Help Menu + &7/asw reload&7: &areload filter dictionary and plug-in configuration + &7/asw status&7: &ashow plug-in status menu + &7/asw test : &arun sensitive word test + &7/asw help&7: &ashow help information + #Status command + messageOnCommandStatus: |- + &bAdvancedSensitiveWords&r---&b Plugin Status(%VERSION%)(MC %MC_VERSION%) + &7 System Information: &b%PLATFORM% %BIT% (Java %JAVA_VERSION% -- %JAVA_VENDOR%) + &7 Initialization: %INIT% + &7 API status: %API_STATUS% + &7 Current mode: %MODE% + &7 Number of filtered messages: &a%NUM% + &7 Average time spent on nearly 20 processes: %MS% + #Test command + commandTest: + #Return message when the test contains sensitive words + testResultTrue: |- + &7 Original message: &c%ORIGINAL_MSG% + &7 After filtering message: &a%PROCESSED_MSG% + &7 List of sensitive words: &b%CENSORED_LIST% + #No sensitive words in the test + testResultPass: '&aPending message has no sensitive words!' + #Not enough parameters + testArgNotEnough: '&cInsufficient parameters, use &7/asw test ' + #Plugin has not been initialized + testNotInit: '&cPlugin has not been initialized' + #No permission + noPermission: '&cYou do not have permission to execute the command.' diff --git a/src/main/resources/messages_zhcn.yml b/src/main/resources/messages_zhcn.yml new file mode 100644 index 0000000..4d13adc --- /dev/null +++ b/src/main/resources/messages_zhcn.yml @@ -0,0 +1,60 @@ +# AdvancedSensitiveWords 插件消息配置 +# 聊天检测消息 +Chat: + # 玩家发送敏感消息时候回复的假消息(只有玩家本人能看见) + # 内置变量%integrated_player% %integrated_message% (支持PlaceHolderAPI) + fakeMessage: <%integrated_player%> %integrated_message% + # 玩家发送敏感消息时候的提示 + messageOnChat: '&c请勿在聊天中发送敏感词汇.' +# 告示牌检测消息 +Sign: + # 玩家写入敏感消息时的提示 + messageOnSign: '&c请勿在告示牌中写入敏感词汇.' +# 铁砧重命名检测消息 +Anvil: + # 玩家在铁砧重命名时写入敏感消息的提示 + messageOnAnvilRename: '&c请勿在铁砧中写入敏感词汇.' +# 书检测消息 +Book: + # 玩家在书中写入敏感消息的提示 + messageOnBook: '&c请勿在书中写入敏感词汇.' +# 玩家名检测消息 +Name: + # 玩家名包含敏感词时的消息 + messageOnName: '&c您的用户名包含敏感词,请修改您的用户名或联系管理员.' +# 插件消息 +Plugin: + # 插件重载消息 + messageOnCommandReload: '&aAdvancedSensitiveWords has been reloaded.' + # 插件帮助菜单 + messageOnCommandHelp: |- + &bAdvancedSensitiveWords&r---&b帮助菜单 + &7/asw reload&7: &a重新加载过滤词库和插件配置 + &7/asw status&7: &a显示插件状态菜单 + &7/asw test <待测消息>: &a运行敏感词测试 + &7/asw help&7: &a显示帮助信息 + # 插件状态菜单 + messageOnCommandStatus: |- + &bAdvancedSensitiveWords&r---&b插件状态(%VERSION%)(MC %MC_VERSION%) + &7系统信息: &b%PLATFORM% %BIT% (Java %JAVA_VERSION% -- %JAVA_VENDOR%) + &7初始化: %INIT% + &7API状态: %API_STATUS% + &7当前模式: %MODE% + &7已过滤消息数: &a%NUM% + &7近20次处理平均耗时: %MS% + # 敏感词测试消息(不计入已过滤消息) + commandTest: + # 敏感词测试返回 + testResultTrue: |- + &b一眼丁真, 鉴定为敏感词(鉴定报告) + &7原消息: &c%ORIGINAL_MSG% + &7过滤后消息: &a%PROCESSED_MSG% + &7敏感词列表: &b%CENSORED_LIST% + # 敏感词测试通过 + testResultPass: '&a待测消息中没有敏感词喵~' + # 敏感词测试参数不足 + testArgNotEnough: '&c参数不足, 请使用 &7/asw test <待测消息>' + # 敏感词测试未初始化 + testNotInit: '&c插件还没有初始化完毕喵' + # 没有权限执行该指令 + noPermission: '&c你没有权限执行该指令.'