From 8a2ccb53c5adef4f72834abf3307728c63ef5ac1 Mon Sep 17 00:00:00 2001 From: Biang <62553265+BIANG-qilie@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:40:10 +0800 Subject: [PATCH 1/2] Feature/chinese i18n: Improve the international configuration of simplified Chinese (#1) * feat(i18n): update Chinese localization for Magic Storage mod * feat(i18n): enhance Chinese localization for Magic Storage mod with new translations and updates * fix(i18n): correct formatting in Chinese localization for Magic Storage mod --------- Co-authored-by: biang --- Localization/zh-Hans.hjson | 664 +++++++++++++++++++------------------ 1 file changed, 333 insertions(+), 331 deletions(-) diff --git a/Localization/zh-Hans.hjson b/Localization/zh-Hans.hjson index 5bf35ba2..d3cbf476 100644 --- a/Localization/zh-Hans.hjson +++ b/Localization/zh-Hans.hjson @@ -13,7 +13,7 @@ Mods: { 制作时算作处于水、熔岩、蜂蜜、雪原环境、灵雾、恶魔/猩红祭坛旁 放在物品栏或制作存储单元的制作站槽位内即可生效 放在物品栏时,不需要处在篝火旁即可将棒棒棉花糖烤熟 - 可在制作界面直接用棉花糖制作熟棉花糖 + 可在制作单元直接用棉花糖制作熟棉花糖 丢出去之后会像沙滩球一样弹弹弹 ''' } @@ -25,11 +25,11 @@ Mods: { CreativeStorageUnit: { DisplayName: 创造单元 - /* Tooltip: + Tooltip: + ''' + 可存储无限数量的每种物品类型 + 在存储系统中不计入存储限制 ''' - Stores an unlimited amount of every item type. - Does not count toward storage limits when in a storage system. - ''' */ } Locator: { @@ -332,7 +332,8 @@ Mods: { 存储核心以连接 暂未连接到任何核心 使用以访问相应存储核心 - 访问距离较小 + 连接的核心必须距离任何有效晶塔最多100个方块才能在每个晶塔上获得扩展范围 + 玩家必须距离连接的核心或晶塔最多1000个方块才能访问存储 ''' } @@ -343,7 +344,8 @@ Mods: { 存储核心以连接 暂未连接到任何核心 使用以访问相应存储核心 - 访问距离较小 + 连接的核心必须距离任何有效晶塔最多200个方块才能在每个晶塔上获得扩展范围 + 玩家必须距离连接的核心或晶塔最多3000个方块才能访问存储 ''' } @@ -368,32 +370,32 @@ Mods: { } PortableCraftingAccessPreHM: { - // DisplayName: Basic Portable Remote Crafting Access - /* Tooltip: + DisplayName: 基础便携远程制作装置 + Tooltip: + ''' + 制作单元以连接 + 暂未连接到任何单元 + 使用以访问相应制作单元 + 连接的制作单元必须距离任何有效晶塔最多100个方块才能在每个晶塔上获得扩展范围 + 玩家必须距离连接的制作单元或晶塔最多1000个方块才能访问制作功能 ''' - Crafting Interface to store location - Currently not set to any location - Use item to access your crafting - Linked Interface must be at most 100' from any valid pylon to gain extended reach on each pylon - Player must be at most 1000' away from the linked Interface or pylon to access crafting - ''' */ } PortableCraftingAccessHM: { - // DisplayName: Advanced Portable Remote Crafting Access - /* Tooltip: + DisplayName: 进阶便携远程制作装置 + Tooltip: + ''' + 制作单元以连接 + 暂未连接到任何单元 + 使用以访问相应制作单元 + 连接的制作单元必须距离任何有效晶塔最多200个方块才能在每个晶塔上获得扩展范围 + 玩家必须距离连接的制作单元或晶塔最多3000个方块才能访问制作功能 ''' - Crafting Interface to store location - Currently not set to any location - Use item to access your crafting - Linked Interface must be at most 200' from any valid pylon to gain extended reach on each pylon - Player must be at most 3000' away from the linked Interface or pylon to access crafting - ''' */ } DecraftingAccess: { - // DisplayName: Storage Aether Interface - // Tooltip: Enables shimmering with the items in a storage system + DisplayName: 存储以太单元 + Tooltip: 能够使用存储系统中的物品进行微光分解 } Shimmer_CoinLuck: { @@ -402,85 +404,85 @@ Mods: { } StorageCore: { - // DisplayName: Storage Core (Basic) - // Tooltip: "{$Mods.MagicStorage.Items.StorageCore.CommonTooltip}" - /* CommonTooltip: + DisplayName: 存储核心(基础) + Tooltip: "{$Mods.MagicStorage.Items.StorageCore.CommonTooltip}" + CommonTooltip: ''' - Stores the items that were in a Storage Unit - an Empty Storage Unit to insert it + 存储原本在存储单元中的物品 + 空存储单元以插入 - ''' */ - // ItemsStored: "[c/{0}:{1} / {2} items]" - // Hash: Data hash: {0:x08} - // BytesUsed: "[c/{0}:{1} bytes]" + ''' + ItemsStored: "[c/{0}:{1} / {2} 物品]" + Hash: 数据哈希: {0:x08} + BytesUsed: "[c/{0}:{1} 字节]" } - // StorageCoreBlueChlorophyte.DisplayName: Storage Core (Blue Chlorophyte) - // StorageCoreCrimtane.DisplayName: Storage Core (Crimtane) - // StorageCoreDemonite.DisplayName: Storage Core (Demonite) - // StorageCoreHallowed.DisplayName: Storage Core (Hallowed) - // StorageCoreHellstone.DisplayName: Storage Core (Hellstone) - // StorageCoreLuminite.DisplayName: Storage Core (Luminite) - // StorageCoreTerra.DisplayName: Storage Core (Terra) + StorageCoreBlueChlorophyte.DisplayName: 存储核心(蓝色叶绿) + StorageCoreCrimtane.DisplayName: 存储核心(猩红) + StorageCoreDemonite.DisplayName: 存储核心(魔金) + StorageCoreHallowed.DisplayName: 存储核心(神圣) + StorageCoreHellstone.DisplayName: 存储核心(狱岩) + StorageCoreLuminite.DisplayName: 存储核心(夜明) + StorageCoreTerra.DisplayName: 存储核心(泰拉) StorageExtractor: { - // DisplayName: Storage Core Wrench - // Tooltip: Can remove the Storage Core from a Storage Unit + DisplayName: 存储核心扳手 + Tooltip: 可以从存储单元中移除存储核心 } StorageUnitEmpty: { - // DisplayName: Empty Storage Unit - /* Tooltip: + DisplayName: 空存储单元 + Tooltip: + ''' + 用于在魔法存储系统中存储物品的组件 + 需要存储核心才能运作 + 手持存储核心时右键点击以插入 ''' - A component for storing items in a Magic Storage storage system - Needs a Storage Core to function - Right click while holding a Storage Core to insert it - ''' */ } StorageSecurity: { - // DisplayName: Storage Security Wand - /* Tooltip: + DisplayName: 存储安全魔杖 + Tooltip: + ''' + 存储核心以打开安全网络 + 连接到已分配给私有安全网络的存储核心的存储组件 + 在输入安全网络密码之前无法访问 + 但是,安全网络的创建者始终可以访问它 ''' - a Storage Heart to open the Security Network - Storage components connected to a Storage Heart assigned to a private Security Network - cannot be accessed until the password for the Security Network has been entered. - The creator of a Security Network will always have access to it, however. - ''' */ } ErrorItems: { - /* CommonTooltip: + CommonTooltip: ''' - ''' */ - // NameText: Name: {0}/{1} - // NameTextUnknown: - // PrefixText: Prefix: {0} - // PrefixTextModded: Prefix: {0}/{1} + ''' + NameText: 名称: {0}/{1} + NameTextUnknown: + PrefixText: 词缀: {0} + PrefixTextModded: 词缀: {0}/{1} } Error_ItemSlotRenderFail: { - // DisplayName: Error//ItemRender - // Message: "{$Mods.MagicStorage.HoverText.Errors.RenderFail}" + DisplayName: 错误//物品渲染 + Message: "{$Mods.MagicStorage.HoverText.Errors.RenderFail}" } Error_ItemNetReadFail: { - // DisplayName: Error//ItemClientRead - // Message: "{$Mods.MagicStorage.HoverText.Errors.NetFail}" + DisplayName: 错误//物品客户端读取 + Message: "{$Mods.MagicStorage.HoverText.Errors.NetFail}" } TagIOStressTest: { - // DisplayName: Debug//DataCompressionTest - // Tooltip: "" + DisplayName: 调试//数据压缩测试 + Tooltip: "" } Error_ItemNBTFail: { - // DisplayName: Error//NBTRead - // Message: "{$Mods.MagicStorage.HoverText.Errors.NBTFail}" + DisplayName: 错误//NBT读取 + Message: "{$Mods.MagicStorage.HoverText.Errors.NBTFail}" } } @@ -505,24 +507,24 @@ Mods: { LoveNPC: 附近的{NPCName}个体对本单元拥有一切操纵权. DislikeNPC: 本单元不屑于向{NPCName}提及蓝魔法。 HateNPC: "{NPCName}需要改变其试图将蓝魔法用于盈利的想法" - // LikeNPC_Princess: "{NPCName} is best friends with my creator." - // Princess_LovesNPC: "{NPCName} is such an interesting machine, how does it move?" + LikeNPC_Princess: "{NPCName}是我创造者最好的朋友。" + Princess_LovesNPC: "{NPCName}是一台如此有趣的机器,它是如何移动的?" } # Census support - // Census.SpawnCondition: '''"{$Mods.MagicStorage.Configs.MagicStorageServerConfig.allowAutomatonToMoveIn.Label}" config in the "{$Mods.MagicStorage.Configs.MagicStorageServerConfig.DisplayName}" set to On''' + Census.SpawnCondition: '''"{$Mods.MagicStorage.Configs.MagicStorageServerConfig.allowAutomatonToMoveIn.Label}" 配置在 "{$Mods.MagicStorage.Configs.MagicStorageServerConfig.DisplayName}" 中设置为开启''' } } EnvironmentModule: { UseInventoryModule: { DisplayName: 制作时采用物品栏内物品 - // DisabledTooltip: This module is currently disabled. + DisabledTooltip: 该模块已被禁用 } UseInventoryNoFavoritesModule: { DisplayName: 制作时采用物品栏内未收藏的物品 - // DisabledTooltip: This module is currently disabled. + DisabledTooltip: 该模块已被禁用 } JourneyInfiniteItems: { @@ -547,22 +549,22 @@ Mods: { CombinedStations3Tile.MapEntry: "{$Mods.MagicStorage.Items.CombinedStations3Item.DisplayName}" CombinedStations4Tile.MapEntry: "{$Mods.MagicStorage.Items.CombinedStations4Item.DisplayName}" EnvironmentAccess.MapEntry: "{$Mods.MagicStorage.Items.EnvironmentAccess.DisplayName}" - // EvilAltarTile.MapEntry: Evil Altar - // DecraftingAccess.MapEntry: "{$Mods.MagicStorage.Items.DecraftingAccess.DisplayName}" + EvilAltarTile.MapEntry: 邪恶祭坛 + DecraftingAccess.MapEntry: "{$Mods.MagicStorage.Items.DecraftingAccess.DisplayName}" } GameTips: { - // Automaton: The Automaton can teach you all there is to know about Magic Storage. - // ShadowDiamonds: Shadow Diamonds are dropped when a boss is defeated for the first time. They can be used as an alternative to Diamonds in Magic Storage recipes. - // RadiantJewel: The Moon Lord drops the Radiant Jewel, which can be used to craft Portable Remote Accesses with unlimited access range. - // StorageUpgrades: Running out of storage? Upgrade your Storage Units with Storage Upgrades! - // RemoteStorage: Access your storage at other locations in the world with a Remote Access after linking it to a Storage Heart with a Locator or Locator Disk. - // CombinedStations: Magic Storage provides Combined Crafting Stations to reduce the number of crafting stations you have to put in the Crafting Interface. - // EnvironmentAccess: The Storage Configuration Interface allows other mods to add "crafting modules" which can affect how the Crafting Interface functions. - // PortableAccess: Craft a Portable Remote Storage Access to access your storage while you're away from home. - // StorageCores: Use a Storage Core Wrench to remove the Storage Core from a Storage Unit, which can then be inserted into an Empty Storage Unit. - // DisableUnit: Use a Storage Unit Wand to disable a Storage Unit. A disabled Storage Unit cannot store items and will attempt to move its items to connected Storage Units. - // BiomeGlobe: The Biome Globe enables recipes for the Snow biome, Ecto Mist, the Campfire, Water, Lava, Honey and the Demon/Crimson Altars. + Automaton: 自动机可以教授你有关魔法存储的一切知识 + ShadowDiamonds: 暗影钻石在首次击败Boss时掉落。它们可以在魔法存储配方中用作钻石的替代品 + RadiantJewel: 月球领主掉落璀璨棱晶,可用于制作具有无限访问范围的便携远程存储装置 + StorageUpgrades: 存储空间不足?使用存储升级珠升级你的存储单元! + RemoteStorage: 使用定位器或定位器驱动将远程存储装置连接到存储核心后,可以在世界其他位置访问你的存储 + CombinedStations: 魔法存储提供组合制作站,以减少你需要放在制作单元中的制作站数量 + EnvironmentAccess: 存储网络配置单元允许其他模组添加"制作模块",这些模块可以影响制作单元的功能 + PortableAccess: 制作便携远程存储装置,以便在离家时访问你的存储 + StorageCores: 使用存储核心扳手从存储单元中移除存储核心,然后可以将其插入空存储单元 + DisableUnit: 使用存储单元魔杖禁用存储单元。被禁用的存储单元无法存储物品,并会尝试将其物品移动到连接的存储单元 + BiomeGlobe: 生态球可为雪地生物群系、灵雾、篝火、水、熔岩、蜂蜜以及恶魔/猩红祭坛启用配方 } Bestiary.Golem: @@ -688,13 +690,13 @@ Mods: { [i:MagicStorage/CombinedStations3Item] [i:MagicStorage/CombinedFurnitureStations2Item] [i:Autohammer] [i:LunarCraftingStation] [i:Fargowiltas/GoldenDippingVat] [i/s10:LavaBucket] [i/s10:HoneyBucket] @ 空手 = [i:MagicStorage/CombinedStations4Item] ''' Help18: 月球领主守护着璀璨棱晶,这颗宝石具有不可思议的力量。它的力量可以激发所有储存核心中蓝魔法的潜在潜力——无线存储。 - /* Help19: + Help19: ''' - The Configuration Interface allows other mods to add "crafting modules" which can affect how the [i:MagicStorage/CraftingAccess] functions. - These modules can be toggled on and off in the UI for the Configuration Interface. - By default, Magic Storage provides modules for reading from the player's inventory and Journey Mode duplication menu. + 存储网络配置单元允许其他模组添加"制作模块",这些模块可以影响 [i:MagicStorage/CraftingAccess] 的功能 + 这些模块可以在存储网络配置单元的UI中开启或关闭 + 默认情况下,魔法存储提供从玩家物品栏和旅途模式复制菜单读取的模块 [rg/s2:MagicStorage:AnyDiamond] [i/s50:DirtBlock] [i/s50:StoneBlock] [i/s50:MudBlock] [i/s50:SnowBlock] [i/s50:SandBlock] @ [rg:MagicStorage:AnyWorkBench] = [i:MagicStorage/EnvironmentAccess] - ''' */ + ''' Help20: ''' 尽管 [i:MagicStorage/RemoteAccess] 非常方便,但你要是离家远了可就不能方便地访问存储网络了 @@ -723,71 +725,71 @@ Mods: { [i:MagicStorage/StorageUnitBlueChlorophyte] + [i:MagicStorage/UpgradeLuminite] -> [i:MagicStorage/StorageUnitLuminite] [i:MagicStorage/StorageUnitLuminite] + [i:MagicStorage/UpgradeTerra] -> [i:MagicStorage/StorageUnitTerra] (2/2) ''' - /* Help22: + Help22: + ''' + 本单元已注意到你当前正在多人游戏世界中游玩。因此,[i:MagicStorage/StorageHeart] 中的某些功能被锁定在 [c/cccc00:服务器操作员] 状态之后 + 要成为 [c/cccc00:服务器操作员],你必须使用 [c/ff6a00:/msreqop] 命令。成功使用此命令将授予你 [c/cc0000:服务器管理员] 状态 + 一旦你拥有 [c/cc0000:服务器管理员] 状态,你可以使用 [c/ff6a00:/msop] 命令授予其他玩家 [c/cccc00:服务器操作员] 状态,或使用 [c/ff6a00:/msdeop] 移除它 + 任一状态将保持活动状态,直到你断开与服务器的连接 + [c/ffff00:魔法存储服务器配置] 有一个选项,启用时会强制主机成为 [c/cc0000:服务器管理员] ''' - This unit has noticed that you are currently playing in a multiplayer world. Hence, some features within the [i:MagicStorage/StorageHeart] are locked behind the [c/cccc00:Server Operator] status. - To become a [c/cccc00:Server Operator], you must use the [c/ff6a00:/msreqop] command. Using this command successfully will grant you the [c/cc0000:Server Admin] status. - Once you have the [c/cc0000:Server Admin] status, you can use the [c/ff6a00:/msop] command to grant other players the [c/cccc00:Server Operator] status or [c/ff6a00:/msdeop] to remove it. - Either status will stay active until you disconnect from the server. - The [c/ffff00:Magic Storage Server Config] has an option which forces the host to be a [c/cc0000:Server Admin] when enabled. - ''' */ - /* Help23: + Help23: ''' - Moving a storage system can be a hassle, especially if you have a lot of items stored. To make it easier, you can use the Storage Core Wrench to remove the Storage Core from a placed Storage Unit. + 移动存储系统可能很麻烦,特别是如果你存储了大量物品。为了简化操作,你可以使用存储核心扳手从已放置的存储单元中移除存储核心 [i:Wrench] + [i:MagicStorage/StorageComponent] + [i/s10:Wire] + [rg/s5:IronBar] @ [rg:MagicStorage:AnyPreHmAnvil] = [i:MagicStorage/StorageExtractor] - Removing the Storage Core will turn the Storage Unit into an [i:MagicStorage/StorageUnitEmpty], which can then be picked up and placed elsewhere. + 移除存储核心会将存储单元转换为 [i:MagicStorage/StorageUnitEmpty],然后可以拾取并放置在其他地方 (1/2) - ''' */ - /* Help24: - ''' - Dropping a [i:MagicStorage/CraftingAccess] into Shimmer will transform it into an Aether Interface, which can be used to shimmer items in a storage system. - All actions from shimmering are supported: decrafting items into their ingredients, transmuting items into other items, sacrificing coins for Coin Luck, and spawning NPCs from shimmering certain items. - ''' */ - /* Help25: - ''' - By default, all [i:MagicStorage/StorageHeart] (and their components) are accessible to everyone. - To make your storage more secure, consider creating a Storage Security Wand. While holding the tool, left click a [i:MagicStorage/StorageHeart] to open the Security system. - In this system's UI, you can create a Security Network which, when made private, will cause the [i:MagicStorage/StorageHeart] and its components to require a password to access. - Double-left click a Security Network to assign it to the [i:MagicStorage/StorageHeart] you used to access the Security system. - Recipe: [i/s3:GoldenKey] [i/s25:Wire] [rg/s5:IronBar] [i:MagicStorage/StorageComponent] [i/s6:Amber] @ [rg:MagicStorage:AnyPreHmAnvil] = [i:MagicStorage/StorageSecurity] - ''' */ - // Help26_Header: Are you finding the text prompts in the UIs cumbersome to use? Here are some helpful controls you can use to help with that: - /* Help26: + ''' + Help24: + ''' + 将 [i:MagicStorage/CraftingAccess] 丢入微光会将其转换为以太单元,可用于在存储系统中进行微光分解 + 支持所有微光操作:将物品分解为材料、将物品转换为其他物品、牺牲硬币获得幸运值,以及通过微光某些物品生成NPC + ''' + Help25: + ''' + 默认情况下,所有 [i:MagicStorage/StorageHeart](及其组件)对所有人都是可访问的 + 为了使你的存储更加安全,考虑创建一个存储安全魔杖。手持该工具时,左键点击 [i:MagicStorage/StorageHeart] 以打开安全系统 + 在此系统的UI中,你可以创建一个安全网络,当设置为私有时,将导致 [i:MagicStorage/StorageHeart] 及其组件需要密码才能访问 + 双击安全网络以将其分配给你用于访问安全系统的 [i:MagicStorage/StorageHeart] + 制作配方: [i/s3:GoldenKey] [i/s25:Wire] [rg/s5:IronBar] [i:MagicStorage/StorageComponent] [i/s6:Amber] @ [rg:MagicStorage:AnyPreHmAnvil] = [i:MagicStorage/StorageSecurity] + ''' + Help26_Header: 你是否觉得UI中的文本提示使用起来很麻烦?以下是一些有用的控制方式可以帮助你: + Help26: ''' {$Mods.MagicStorage.Dialogue.Golem.Help26_Header} - While the prompt is focused: - [c/cccc00:Ctrl + Z] to clear - [c/cccc00:Ctrl + X] or [c/cccc00:Shift + Delete] to copy to clipboard then clear - [c/cccc00:Ctrl + C] to copy to clipboard - [c/cccc00:Ctrl + V] or [c/cccc00:Shift + Insert] to paste from clipboard + 当提示框获得焦点时: + [c/cccc00:Ctrl + Z] 清除 + [c/cccc00:Ctrl + X] 或 [c/cccc00:Shift + Delete] 复制到剪贴板然后清除 + [c/cccc00:Ctrl + C] 复制到剪贴板 + [c/cccc00:Ctrl + V] 或 [c/cccc00:Shift + Insert] 从剪贴板粘贴 (1/3) - ''' */ - /* Help27: + ''' + Help27: ''' {$Mods.MagicStorage.Dialogue.Golem.Help26_Header} - While the prompt is focused: - [c/cccc00:Ctrl + Backspace] to delete the last space-separated word - [c/cccc00:Left Arrow] and [c/cccc00:Right Arrow] to move the cursor left and right by one character - [c/cccc00:Home] and [c/cccc00:End] to move the cursor to the start and end - [c/cccc00:Escape] or [c/cccc00:Right Click] the prompt to revert any changes made + 当提示框获得焦点时: + [c/cccc00:Ctrl + Backspace] 删除最后一个空格分隔的单词 + [c/cccc00:Left Arrow] 和 [c/cccc00:Right Arrow] 将光标左右移动一个字符 + [c/cccc00:Home] 和 [c/cccc00:End] 将光标移动到开头和结尾 + [c/cccc00:Escape] 或 [c/cccc00:Right Click] 提示框以撤销所做的任何更改 (2/3) - ''' */ - /* Help28: + ''' + Help28: ''' {$Mods.MagicStorage.Dialogue.Golem.Help26_Header} - While the prompt is not focused: - [c/cccc00:Right Click] the prompt to clear + 当提示框未获得焦点时: + [c/cccc00:Right Click] 提示框以清除 (3/3) - ''' */ - /* Help29: ''' - To insert a Storage Core back into the [i:MagicStorage/StorageUnitEmpty], simply right click it while holding the Storage Core. + Help29: + ''' + 要将存储核心重新插入 [i:MagicStorage/StorageUnitEmpty],只需在手持存储核心时右键点击它 [i:MagicStorage/StorageUnit] -> [i:MagicStorage/StorageCore] [i:MagicStorage/StorageUnitDemonite] -> [i:MagicStorage/StorageCoreDemonite] [i:MagicStorage/StorageUnitCrimtane] -> [i:MagicStorage/StorageCoreCrimtane] [i:MagicStorage/StorageUnitHellstone] -> [i:MagicStorage/StorageCoreHellstone] [i:MagicStorage/StorageUnitHallowed] -> [i:MagicStorage/StorageCoreHallowed] [i:MagicStorage/StorageUnitBlueChlorophyte] -> [i:MagicStorage/StorageCoreBlueChlorophyte] [i:MagicStorage/StorageUnitLuminite] -> [i:MagicStorage/StorageCoreLuminite] [i:MagicStorage/StorageUnitTerra] -> [i:MagicStorage/StorageCoreTerra] (2/2) - ''' */ + ''' } ChatOptions: { @@ -797,7 +799,7 @@ Mods: { } } - // NewHelpAvailable: The Automaton has new help tips available. + NewHelpAvailable: 自动机有新的帮助提示可用 } Active: 已启用 @@ -811,7 +813,7 @@ Mods: { RemoteAccessSuccess: 已成功连接远程存储装置! RemoteAccessHasLocator: 该远程存储装置已经定位到了一个存储核心,请挖掉并重新放置来重置定位点 RemoteAccessUnlocated: 当前定位器尚未设置定位点 - // RemoteAccessInvalidLocator: The locator is not connected to a Storage Heart + RemoteAccessInvalidLocator: 定位器未连接到存储核心 StorageUnitActivated: 该存储单元已被启用 StorageUnitDeactivated: 该存储单元已被禁用 FilterAllMods: 所有物品 @@ -829,12 +831,12 @@ Mods: { CraftTooltipOld: 左键单击以制作(按住Ctrl全部制作) Crafting: { - // Plus1: +1 - // Plus10: +10 - // Plus100: +100 - // Minus1: "-1" - // Minus10: "-10" - // Minus100: "-100" + Plus1: +1 + Plus10: +10 + Plus100: +100 + Minus1: "-1" + Minus10: "-10" + Minus100: "-100" MaxStack: 设为最大 Reset: 重置 Amount: 数量: {0} @@ -843,15 +845,15 @@ Mods: { Search: 搜索 SearchName: 以名称搜索 SearchMod: 以模组搜索 - // SortWaiting: Loading ... + SortWaiting: 加载中... SearchTips: { SearchName: 以名称搜索 SearchMod: @模组名 以模组搜索 SearchTooltip: "#物品介绍 以介绍搜索" SearchModAndTooltip: @模组名 #物品介绍 - // TipModAndTooltip: "[c/ffff00:@ModName] to search by mod, [c/ffff00:#Search Tooltip] to search by tooltip (can be combined in that order)" - // TipTooltipOnly: "[c/ffff00:#Search Tooltip] to search by tooltip" + TipModAndTooltip: "[c/ffff00:@模组名] 以模组搜索,[c/ffff00:#物品介绍] 以介绍搜索(可按该顺序组合)" + TipTooltipOnly: "[c/ffff00:#物品介绍] 以介绍搜索" } Recipes: 合成配方 @@ -871,21 +873,21 @@ Mods: { 无法打开魔法存储UI,因为游戏面板高度太小了,无法正常显示UI界面 请在设置中拉低UI缩放比例或在视频设置中提高游戏分辨率 ''' - /* ForcedLayoutChange: + ForcedLayoutChange: + ''' + 当前UI布局导致面板过短,无法正常显示UI元素。 + 强制将UI布局切换为"独立分页"以分配更多垂直空间。 ''' - Current UI layout resulted in a panel that was too short to properly display the UI elements. - Forcing the UI layout to "Modern Paged" to allocate more vertical space. - ''' */ Warnings: { StorageDefaultToAllItems: 当前筛选模式下搜索不到任何物品,即使存储中有相应物品。目前显示的是搜索所有物品的结果 StorageDefaultToAllMods: 当前筛选模式下搜索不到任何物品,即使存储中有相应物品。目前显示的是搜索所有物品的结果 CraftingNoBlacklist: 由于黑名单设置搜索不到任何配方。目前显示的是搜索所有配方的结果 CraftingDefaultToAllMods: 此模组中搜索不到任何配方。目前显示的是搜索所有配方的结果 - // DeleteItemsFailed: Deletion operation failed for unknown reasons. Please try again, or delete the items manually if necessary. - // DeleteDataFailed: Deletion operation failed for unknown reasons. Some items may still contain unloaded mod data. - // DecraftingNoBlacklist: No items displayed even though blacklisted items exist. Ignoring item blacklisting. - // DecraftingDefaultToAllMods: No items displayed even though items exist from other mods. Defaulting to "{$Mods.MagicStorage.FilterAllMods}" mod filter. + DeleteItemsFailed: 删除操作因未知原因失败。请重试,或必要时手动删除物品 + DeleteDataFailed: 删除操作因未知原因失败。某些物品可能仍包含未加载的模组数据 + DecraftingNoBlacklist: 即使存在黑名单物品,也未显示任何物品。忽略物品黑名单 + DecraftingDefaultToAllMods: 即使存在来自其他模组的物品,也未显示任何物品。默认使用 "{$Mods.MagicStorage.FilterAllMods}" 模组过滤器 } RecipeHidden: 隐藏物品 "{0}" 的制作配方 @@ -902,88 +904,88 @@ Mods: { DepositTooltipAlt: 快速堆叠 - Ctrl+左键 | 存放全部 - 左键 | 补货 - 右键 ServerOperator: { - // ConfigChangeDenied: Only users with the Server Operator status or higher can modify this config - // ControlRequirement: This control requires the Server Operator status. + ConfigChangeDenied: 只有拥有服务器操作员或更高状态的用户才能修改此配置 + ControlRequirement: 此控件需要服务器操作员状态 CommandInfo: { Descriptions: { - // reqop: Requests the Server Admin status (for Magic Storage) from the server - // op: Gives the Server Operator status (for Magic Storage) to client - // deop: Removes the Server Operator status (for Magic Storage) from client - // whois: Prints what each player's client index is - // whoami: Prints this client's player index + reqop: 向服务器请求服务器管理员状态(用于魔法存储) + op: 授予客户端 服务器操作员状态(用于魔法存储) + deop: 从客户端 移除服务器操作员状态(用于魔法存储) + whois: 打印每个玩家的客户端索引 + whoami: 打印此客户端的玩家索引 } - // NoArguments: Expected no arguments - // MultiplayerOnly: This command can only be used by multiplayer clients - // AlreadyAdmin: This player already has the Server Admin status - // OneIntArgument: Expected one integer argument - // ArgumentNotByte: Argument was not a positive integer between 0 and 255 - // MultiplayerAdminOnly: This command can only be used by multiplayer clients with the Server Admin status - // NotConnected: Client {0} is not connected to the server - // ClientAlreadyOp: Client {0} already has the Server Operator status - // ClientAlreadyDeop: Client {0} already lacks the Server Operator status - // MultiplayerOperatorOnly: This command can only be used by multiplayer clients with the Server Operator status - // Players: Players: - // YouAreClient: You are client {0} - /* ServerKeyText: + NoArguments: 预期没有参数 + MultiplayerOnly: 此命令只能由多人游戏客户端使用 + AlreadyAdmin: 此玩家已拥有服务器管理员状态 + OneIntArgument: 预期一个整数参数 + ArgumentNotByte: 参数不是0到255之间的正整数 + MultiplayerAdminOnly: 此命令只能由拥有服务器管理员状态的多人游戏客户端使用 + NotConnected: 客户端 {0} 未连接到服务器 + ClientAlreadyOp: 客户端 {0} 已拥有服务器操作员状态 + ClientAlreadyDeop: 客户端 {0} 已缺少服务器操作员状态 + MultiplayerOperatorOnly: 此命令只能由拥有服务器操作员状态的多人游戏客户端使用 + Players: 玩家: + YouAreClient: 你是客户端 {0} + ServerKeyText: ''' ===== - THIS MESSAGE WILL ONLY BE DISPLAYED ONCE! - Server Operator/Administrator Key: {0} + 此消息只会显示一次! + 服务器操作员/管理员密钥: {0} ===== - ''' */ - // ClientKeyText: === ENTER THE KEY PRINTED TO THE SERVER'S CONSOLE AND LOG FILE === - // ClientKeyResponseFailed: Inputted key did not match the key stored on the server. - // ClientKeyResponseSuccess: Magic Storage Server Operator and Administrator statuses have been successfully added. + ''' + ClientKeyText: === 输入打印到服务器控制台和日志文件的密钥 === + ClientKeyResponseFailed: 输入的密钥与服务器上存储的密钥不匹配 + ClientKeyResponseSuccess: 魔法存储服务器操作员和管理员状态已成功添加 } } AuditLogging: { CommandInfo: { Descriptions: { - /* msaudit: + msaudit: ''' - Translates the Magic Storage audit log for the world into a human-readable format - The name of the resulting file is derived from the world file's name and is placed in the Worlds folder - ''' */ - // msauditclear: Clears the Magic Storage audit log for the world + 将世界的魔法存储审计日志转换为人类可读格式 + 生成的文件名来自世界文件名,并放置在Worlds文件夹中 + ''' + msauditclear: 清除世界的魔法存储审计日志 } - // NoArguments: Expected no arguments - // MultiplayerOnly: This command can only be used by the server console - // NoLogFile: No Magic Storage audit log file found for this world - // LoggingDisabled: Magic Storage audit logging is disabled in the config, please enable it first - // AdminOnly: This command can only be used by by the server console or multiplayer clients with the Server Administrator status + NoArguments: 预期没有参数 + MultiplayerOnly: 此命令只能由服务器控制台使用 + NoLogFile: 未找到此世界的魔法存储审计日志文件 + LoggingDisabled: 魔法存储审计日志记录在配置中已禁用,请先启用 + AdminOnly: 此命令只能由服务器控制台或拥有服务器管理员状态的多人游戏客户端使用 } Errors: { Client: { - // NoBuffers: Translation audit file couldn't be written due to missing buffers - // IncompleteBuffers: Translation audit file couldn't be written due to some sections not being received - // MismatchedBufferCount: Translation audit file couldn't be written due to the amount of received sections ({0}) not matching the expected amount ({1}) + NoBuffers: 由于缺少缓冲区,无法写入翻译审计文件 + IncompleteBuffers: 由于某些部分未接收,无法写入翻译审计文件 + MismatchedBufferCount: 由于接收的部分数量 ({0}) 与预期数量 ({1}) 不匹配,无法写入翻译审计文件 } - // LoadFailed: Failed to load audit file - // SaveFailed: Failed to save audit file - // TranslationFailed: Failed to write translated audit log to file - // TranslationAlreadyRunning: The Magic Storage audit log is already being translated, please wait for the action to finish - // ClearingAlreadyRunning: The Magic Storage audit log is already being cleared, please wait for the action to finish + LoadFailed: 加载审计文件失败 + SaveFailed: 保存审计文件失败 + TranslationFailed: 无法将翻译后的审计日志写入文件 + TranslationAlreadyRunning: 魔法存储审计日志正在翻译中,请等待操作完成 + ClearingAlreadyRunning: 魔法存储审计日志正在清除中,请等待操作完成 } Messages: { Client: { - // RequestSent: Command request sent to the server, check the server console or log for information - // TranslationSuccess: Translation success! Magic Storage audit log was translated to: + RequestSent: 命令请求已发送到服务器,请检查服务器控制台或日志以获取信息 + TranslationSuccess: 翻译成功!魔法存储审计日志已翻译到: } - // LoadSuccess: Magic Storage audit log was loaded from: {0} - // SaveSuccess: Magic Storage audit log was saved to: {0} - // TranslationFileNotLoaded: Magic Storage audit log was not loaded yet, forcing load before translation... - // TranslationStarted: Translating Magic Storage audit log to a human-readable format... - // TranslationSuccess: Magic Storage audit log was translated to: {0} - // ClearingStarted: Magic Storage audit log will be cleared... - // ClearingSuccess: Magic Storage audit log was cleared, serializing empty file is pending + LoadSuccess: 魔法存储审计日志已从以下位置加载: {0} + SaveSuccess: 魔法存储审计日志已保存到: {0} + TranslationFileNotLoaded: 魔法存储审计日志尚未加载,强制在翻译前加载... + TranslationStarted: 正在将魔法存储审计日志转换为人类可读格式... + TranslationSuccess: 魔法存储审计日志已翻译到: {0} + ClearingStarted: 魔法存储审计日志将被清除... + ClearingSuccess: 魔法存储审计日志已清除,序列化空文件待处理 } } @@ -996,72 +998,72 @@ Mods: { DepositSafe: 转移保险箱物品 DepositForge: 转移护卫熔炉物品 DepositVault: 转移虚空保险库物品 - // InitShowcaseButton: Initialize Showcase - // ResetShowcaseButton: Reset Showcase Items - // ClearItemsButton: Clear All Items - // FillWithGarbage: Fill With Random Items + InitShowcaseButton: 初始化展示柜 + ResetShowcaseButton: 重置展示柜物品 + ClearItemsButton: 清除所有物品 + FillWithGarbage: 填充随机物品 SellDuplicatesHeader: 出售同种物品 SellDuplicatesButton: 出售 - // SetAStorageName: Enter a name here... - // NameWasCleared: Name was cleared - // NameWasSetTo: Name was set to: {0} + SetAStorageName: 在此输入名称... + NameWasCleared: 名称已清除 + NameWasSetTo: 名称已设置为: {0} ItemDeletionMode: { - // Label: Item Deletion Mode - // Enabled: Item Deletion mode is now [c/00ff00:enabled]. Double click an item to delete it. - // Disabled: Item Deletion mode is now [c/ff0000:disabled]. + Label: 物品删除模式 + Enabled: 物品删除模式现已 [c/00ff00:启用]。双击物品以删除它。 + Disabled: 物品删除模式现已 [c/ff0000:禁用]。 } SellDuplicatesMenu: { - // Label: Item Selling Mode - // Enabled: Item Selling Mode is now [c/00ff00:enabled]. Click on items to mark them as items to sell. - // Disabled: Item Selling Mode is now [c/ff0000:disabled]. + Label: 物品出售模式 + Enabled: 物品出售模式现已 [c/00ff00:启用]。点击物品以标记为待出售。 + Disabled: 物品出售模式现已 [c/ff0000:禁用]。 NoPrefix: 出售所有同种无词缀物品 KeepMostValue: 保留最值钱的物品 KeepLeastValue: 保留最不值钱的物品 SoldItemsReport: { - // GotCoins: "{0}/{1} items were sold for {2}" - // NoCoins: "{0}/{1} items were sold, but none had any value" - // NoSell: No items were sold - // PacketTooLarge: The amount of item stacks to sell was too large to send in one packet. Please try again with fewer stacks. + GotCoins: "{0}/{1} 个物品已出售,获得 {2}" + NoCoins: "{0}/{1} 个物品已出售,但没有任何价值" + NoSell: 没有物品被出售 + PacketTooLarge: 要出售的物品堆叠数量太大,无法在一个数据包中发送。请减少堆叠数量后重试。 } } SellQuantityPopup: { - // Label: Quantity: - // HintText: "0" + Label: 数量: + HintText: "0" } ActiveNetwork: { - // None: Active security network: Unassigned - // Assigned: Active security network: {0} + None: 活动安全网络: 未分配 + Assigned: 活动安全网络: {0} } } CraftingGUI: { - // ShowAllIngredients: Show all possible ingredients + ShowAllIngredients: 显示所有可能的材料 RecursionErrors: { - // NoRecipe: "[c/ff0000:Simulation failed to find a valid recursion tree, defaulting to original recipe]" - // NoObjects: "[c/ff0000:Simulation failed to find a valid recursion tree, defaulting to original recipe's required objects]" - // NoIngredients: "[c/ff0000:Simulation failed to find a valid recursion tree, defaulting to original recipe's ingredients]" + NoRecipe: "[c/ff0000:模拟未能找到有效的递归树,使用原始配方]" + NoObjects: "[c/ff0000:模拟未能找到有效的递归树,使用原始配方所需的对象]" + NoIngredients: "[c/ff0000:模拟未能找到有效的递归树,使用原始配方的材料]" } } HoverText: { - // Reset: Reset panel position and size + Reset: 重置面板位置和大小 Errors: { - // RenderFail: This item could not be rendered due to an error. - // NetFail: This item failed to load on the current client. - // NBTFail: The NBT data on this item failed to deserialize. + RenderFail: 由于错误,此物品无法渲染 + NetFail: 此物品在当前客户端上加载失败 + NBTFail: 此物品的NBT数据反序列化失败 } TestItems: { - // NoTooltip: "" - // RenderFail: Error Test: Item Rendering - // NetFail: Error Test: Item Loading + NoTooltip: "" + RenderFail: 错误测试: 物品渲染 + NetFail: 错误测试: 物品加载 } } @@ -1075,24 +1077,24 @@ Mods: { } DecraftingGUI: { - // StoredResults: Stored Result Items - // ShimmeringReports: Shimmering Results - // ItemHidden: Item "{0}" was blacklisted. - // ItemRevealed: Item "{0}" was whitelisted. - // ItemHiddenGlobal: Item "{0}" was global blacklisted. - // ItemRevealedGlobal: Item "{0}" was global whitelisted. - // ShimmerButton: Shimmer - // ShimmerButtonTooltip: Left click to Shimmer item - // ShimmerButtonTooltipOld: Left click to Shimmer item (ctrl to shimmer max) - // ShimmerAmount: Shimmering: {0} + StoredResults: 存储的结果物品 + ShimmeringReports: 微光结果 + ItemHidden: 物品 "{0}" 已被加入黑名单 + ItemRevealed: 物品 "{0}" 已被加入白名单 + ItemHiddenGlobal: 物品 "{0}" 已被全局加入黑名单 + ItemRevealedGlobal: 物品 "{0}" 已被全局加入白名单 + ShimmerButton: 微光 + ShimmerButtonTooltip: 左键点击以微光分解物品 + ShimmerButtonTooltipOld: 左键点击以微光分解物品(按住Ctrl以最大数量分解) + ShimmerAmount: 微光分解: {0} ShimmerReports: { - // DoesNotShimmer: No shimmer results found - // CoinLuck: +{0}% Luck (+{1:0.##} value) + DoesNotShimmer: 未找到微光结果 + CoinLuck: +{0}% 幸运值(+{1:0.##} 价值) NPCSpawn: { - // DirectTransform: "{0}" - // IndirectTransform: "{0} (style #{1})" + DirectTransform: "{0}" + IndirectTransform: "{0}(样式 #{1})" } } } @@ -1121,10 +1123,10 @@ Mods: { NotFullyResearched.Tooltip: 未完全研究的物品 FullyResearched.Tooltip: 已完全研究的物品 Materials.Tooltip: 材料 - // ToolsAndFishing.Tooltip: Filter Tools And Fishing Items - // Fishing.Tooltip: Filter Fishing Items - // MiscGameplayItems.Tooltip: Filter Misc Gameplay Items - // SellingItems.Tooltip: Filter Items Being Sold + ToolsAndFishing.Tooltip: 筛选工具和钓鱼物品 + Fishing.Tooltip: 筛选钓鱼物品 + MiscGameplayItems.Tooltip: 筛选杂项游戏玩法物品 + SellingItems.Tooltip: 筛选正在出售的物品 } SortingOption: { @@ -1139,82 +1141,82 @@ Mods: { } SellingDuplicateFinders: { - // SellAllExceptLeastExpensiveFinder.Label: Sell All Except Least Expensive - // SellAllExceptMostExpensiveFinder.Label: Sell All Except Most Expensive - // SellAllItemsWithNoPrefixFinder.Label: Sell All Items with No Prefix + SellAllExceptLeastExpensiveFinder.Label: 出售除最便宜外的所有物品 + SellAllExceptMostExpensiveFinder.Label: 出售除最昂贵外的所有物品 + SellAllItemsWithNoPrefixFinder.Label: 出售所有无词缀物品 } - ButtonConfigGear: Open Configuration Panel + ButtonConfigGear: 打开配置面板 UIPages: { Sorting: 排序 Filtering: 筛选 Crafting: 合成 Storage: 存储 - // Shimmering: Shimmering + Shimmering: 微光 # StorageGUI page for the extra controls Controls: 控件 # EnvironmentGUI page for the modules Modules: 模块 History: 历史 - // Networks: Security Networks + Networks: 安全网络 } Security: { - // Creation.Success: "[c/00ff00:Successfully created a new network]" - // Join.Success: "[c/00ff00:Successfully joined the network]" - // Removal.Success: "[c/00ff00:Successfully deleted the network]" - // Modification.Success: "[c/00ff00:Successfully modified the network's settings]" - // Access.Success: "[c/00ff00:Successfully granted access to the network]" - // NetworkChange.Success: "[c/00ff00:Successfully updated the network for this Storage Heart]" - // NetworkNotFound: "[c/ff0000:No network with the given ID was found]" - // EmptyPassword: "[c/ff0000:Password cannot be empty for private networks]" - // EmptyName: "[c/ff0000:Display name cannot be empty]" - // InvalidPassword: "[c/ff0000:Invalid password]" - // InvalidPlayer: "[c/ff0000:Player instance did not refer to a valid player]" - // UnauthorizedAccess: "[c/ff0000:Player does not meet the requirements to access the network]" - // UnauthorizedModification: "[c/ff0000:Player does not meet the requirements to modify the network]" - // EntityNotFound: "[c/ff0000:Storage entity could not be found for the request]" - // EntityNotAccessible: "[c/ff0000:Player does not meet the requirements to access the storage entity]" + Creation.Success: "[c/00ff00:成功创建新网络]" + Join.Success: "[c/00ff00:成功加入网络]" + Removal.Success: "[c/00ff00:成功删除网络]" + Modification.Success: "[c/00ff00:成功修改网络设置]" + Access.Success: "[c/00ff00:成功授予网络访问权限]" + NetworkChange.Success: "[c/00ff00:成功更新此存储核心的网络]" + NetworkNotFound: "[c/ff0000:未找到指定ID的网络]" + EmptyPassword: "[c/ff0000:私有网络的密码不能为空]" + EmptyName: "[c/ff0000:显示名称不能为空]" + InvalidPassword: "[c/ff0000:密码错误]" + InvalidPlayer: "[c/ff0000:玩家实例未指向有效玩家]" + UnauthorizedAccess: "[c/ff0000:玩家不满足访问网络的要求]" + UnauthorizedModification: "[c/ff0000:玩家不满足修改网络的要求]" + EntityNotFound: "[c/ff0000:未找到请求的存储实体]" + EntityNotAccessible: "[c/ff0000:玩家不满足访问存储实体的要求]" UnauthorizedNetmodeContext: { - // Singleplayer: "[c/ff0000:Cannot perform this action in singleplayer]" - // MultiplayerClient: "[c/ff0000:Cannot perform this action as a client in multiplayer]" - // MultiplayerServer: "[c/ff0000:Cannot perform this action as a server in multiplayer]" + Singleplayer: "[c/ff0000:无法在单人游戏中执行此操作]" + MultiplayerClient: "[c/ff0000:无法在多人游戏中以客户端身份执行此操作]" + MultiplayerServer: "[c/ff0000:无法在多人游戏中以服务器身份执行此操作]" } UI: { - // NameHint: Enter a name for the network - // PasswordHint: Enter a password for the network - // Private: Private network - // Public: Public network - // SearchHint: Search for a network - // NetworkAccessQuestion: Private network? - // Create: Create a new network - // ServerWait: Waiting for server response... - // RequestingPassword: Enter password for: {0} - // AccessPasswordHint: Password... - // NoResponse: Security responses will be displayed here - // NoHeartAccessDenied: Access Denied - // NoHeartMustConnect1: Connect a [i:MagicStorage/StorageHeart] assigned to the security network - // NoHeartMustConnect2: with ID {0} to access. - // NetworkOwner: Owner: {0} - // NetworkID: ID: {0} + NameHint: 输入网络名称 + PasswordHint: 输入网络密码 + Private: 私有网络 + Public: 公共网络 + SearchHint: 搜索网络 + NetworkAccessQuestion: 私有网络? + Create: 创建新网络 + ServerWait: 等待服务器响应... + RequestingPassword: 输入密码: {0} + AccessPasswordHint: 密码... + NoResponse: 安全响应将显示在此处 + NoHeartAccessDenied: 访问被拒绝 + NoHeartMustConnect1: 连接一个分配给安全网络的 [i:MagicStorage/StorageHeart] + NoHeartMustConnect2: ID为 {0} 以访问 + NetworkOwner: 所有者: {0} + NetworkID: ID: {0} Modes: { Search: { - // All: All networks - // Restricted: Private networks - // Public: Public networks + All: 所有网络 + Restricted: 私有网络 + Public: 公共网络 } Sort: { - // Name: Name A-Z - // NameReverse: Name Z-A - // Creator: Owner A-Z - // CreatorReverse: Owner Z-A - // ID: ID Ascending - // IDReverse: ID Descending + Name: 名称 A-Z + NameReverse: 名称 Z-A + Creator: 所有者 A-Z + CreatorReverse: 所有者 Z-A + ID: ID 升序 + IDReverse: ID 降序 } } } @@ -1249,7 +1251,7 @@ Mods: { } } - // Keybinds.PrintItemData.DisplayName: Print Item Data + Keybinds.PrintItemData.DisplayName: 输出物品数据 Configs: { MagicStorageConfig: { @@ -1291,17 +1293,17 @@ Mods: { clearHistory: { Label: "[i:Book] 清除配方历史记录" - Tooltip: 在打开制作界面时自动清除配方历史记录 + Tooltip: 在打开制作单元时自动清除配方历史记录 } recursionCraftingDepth: { - // Label: Recipe Recursion Depth - /* Tooltip: + Label: 配方递归深度 + Tooltip: + ''' + 制作UI中制作配方的递归深度 + 设置为0以禁用此功能 + 设置为-1表示无限深度 ''' - How deep the recursion goes for crafting recipes in the Crafting UI. - Set to 0 to disable this feature. - Set to -1 for infinite depth - ''' */ } glowNewItems: { @@ -1321,7 +1323,7 @@ Mods: { uiFavorites: { Label: "[i:FallenStar] 收藏物品与配方" - Tooltip: 开启后,可在制作界面中收藏物品和配方 + Tooltip: 开启后,可在制作单元中收藏物品和配方 } extraFilterIcons: { @@ -1345,18 +1347,18 @@ Mods: { } automatonRemembers: { - // Label: Automaton remembers last help tip - // Tooltip: The Automaton will remember which help tip it last displayed to the user and display that help tip when interacted with. + Label: 自动机记住最后一条帮助提示 + Tooltip: 自动机会记住它最后向用户显示的帮助提示,并在交互时显示该帮助提示。 } globalShimmerItemBlacklist: { - // Label: Global Item Shimmering Blacklist - // Tooltip: Click with Left Ctrl + Left Shift to add/remove blacklist + Label: 全局物品微光黑名单 + Tooltip: 按住左 Ctrl + 左 Shift 点击以添加/移除黑名单 } useOldSlotFocus: { - // Label: use Old Slot Focus - // Tooltip: "" + Label: 使用旧版槽位焦点 + Tooltip: "" } } @@ -1420,18 +1422,18 @@ Mods: { } auditLog: { - // Label: Server Audit Log - // Tooltip: Enable to make client interactions with any storage system be reported to an audit log + Label: 服务器审计日志 + Tooltip: 启用后,客户端与任何存储系统的交互将被报告到审计日志 } localHostAdmin: { - // Label: Give Server Admin to Local Host - // Tooltip: Enable to force the local host to have the Server Administrator status when joining a server + Label: 给予本地主机服务器管理员权限 + Tooltip: 启用后,强制本地主机在加入服务器时拥有服务器管理员状态 } automatonHappiness: { - // Label: Automaton Happiness Affects Sell Prices - // Tooltip: Disable to prevent the Automaton from affecting the sell value of items sold via Item Selling Mode + Label: 自动机快乐度影响出售价格 + Tooltip: 禁用以防止自动机影响通过物品出售模式出售的物品的出售价值 } } From fd6db4755d80cc66fb9e0c261a3bb180042cff62 Mon Sep 17 00:00:00 2001 From: Biang <62553265+BIANG-qilie@users.noreply.github.com> Date: Wed, 17 Dec 2025 13:32:59 +0800 Subject: [PATCH 2/2] Feature/pinyin search: the retrieval of items through the pinyin input method (#2) * feat(pinyin): Add Pinyin search functionality for Chinese item names - Introduced a new configuration option to enable Pinyin search in `MagicStorageConfig.cs`. - Implemented Pinyin search logic in `StorageViewControls.cs`, allowing users to search item names using full Pinyin or initials. - Added a new utility class `PinyinHelper.cs` for handling Pinyin conversion and caching. - Updated project references to include `NPinyin.Core` for Pinyin processing. - Enhanced localization files to support new Pinyin search feature in both English and Simplified Chinese. - Documented the feature in a new markdown file for clarity on usage and implementation. * refactor(auditing, shimmering): Update Utils references to use Terraria.Utils - Changed references from Utils to Terraria.Utils for coin splitting and clamping in AuditEntry.cs and ShimmerResultReports.cs. - Improved code clarity and consistency by ensuring the correct namespace is used for utility functions. * feat(pinyin): Integrate NPinyin.Core for enhanced Pinyin search functionality - Added support for loading NPinyin.Core.dll as an embedded resource to enable Pinyin search capabilities. - Implemented logic to delay JIT compilation of the ConvertToPinyin method until NPinyin.Core is fully loaded. - Enhanced PinyinHelper to utilize reflection for method invocation, ensuring compatibility and avoiding direct dependencies. - Updated localization files to include options for enabling Pinyin search in multiple languages. - Introduced checks to ensure Pinyin search is only active in a Simplified Chinese environment. * refactor(pinyin): Simplify method retrieval and enhance error handling in PinyinHelper - Introduced GetMethodsSafely and FindMethod utility functions to streamline method retrieval and improve error handling. - Updated PinyinHelper to utilize these new methods, reducing code complexity and enhancing maintainability. - Added comments for clarity on the purpose and functionality of the new methods. * refactor(pinyin): Update comments and documentation for clarity in PinyinHelper and MagicStorageMod * refactor(pinyin): Remove debug logging for Pinyin search feature in MagicStorageMod * feat(pinyin): Remove Pinyin search documentation file --------- Co-authored-by: biang --- CheckModBuildVersionBeforeJIT.cs | 8 + Common/Systems/Auditing/AuditEntry.cs | 4 +- .../Shimmering/ShimmerResultReports.cs | 2 +- .../Refreshing/StorageViewControls.cs | 12 +- Common/Utils/PinyinHelper.cs | 405 ++++++++++++++++++ Localization/en-US.hjson | 5 + Localization/es-ES.hjson | 5 + Localization/fr-FR.hjson | 5 + Localization/pl-PL.hjson | 5 + Localization/pt-BR.hjson | 5 + Localization/ru-RU.hjson | 5 + Localization/zh-Hans.hjson | 5 + MagicStorage.csproj | 6 + MagicStorageConfig.cs | 6 + MagicStorageMod.cs | 45 ++ 15 files changed, 518 insertions(+), 5 deletions(-) create mode 100644 Common/Utils/PinyinHelper.cs diff --git a/CheckModBuildVersionBeforeJIT.cs b/CheckModBuildVersionBeforeJIT.cs index 7957b481..c463a3b2 100644 --- a/CheckModBuildVersionBeforeJIT.cs +++ b/CheckModBuildVersionBeforeJIT.cs @@ -7,6 +7,7 @@ internal class CheckModBuildVersionBeforeJIT : PreJITFilter { // The GetInstance singleton is only loaded after mod JITing was performed, hence the need for a variable public static MagicStorageMod Mod; public static bool versionChecked; + public static bool nPinyinLoaded; public override bool ShouldJIT(MemberInfo member) { if (!versionChecked) { @@ -14,6 +15,13 @@ public override bool ShouldJIT(MemberInfo member) { versionChecked = true; } + // 延迟 JIT ConvertToPinyin 方法,直到 NPinyin.Core.dll 加载完成 + if (member is MethodInfo method && + method.DeclaringType?.FullName == "MagicStorage.Common.Utils.PinyinHelper" && + method.Name == "ConvertToPinyin") { + return nPinyinLoaded; + } + return base.ShouldJIT(member); } diff --git a/Common/Systems/Auditing/AuditEntry.cs b/Common/Systems/Auditing/AuditEntry.cs index 466fe928..32411da2 100644 --- a/Common/Systems/Auditing/AuditEntry.cs +++ b/Common/Systems/Auditing/AuditEntry.cs @@ -543,14 +543,14 @@ public override void Serialize(BinaryWriter writer) { protected override void Stringify(AuditFile source, StringBuilder builder) { base.Stringify(source, builder); - int[] coins = Utils.CoinsSplit(TotalSellValue); + int[] coins = Terraria.Utils.CoinsSplit(TotalSellValue); builder.Append($" on {SoldItemCount} items at price {coins[3]}p {coins[2]}g {coins[1]}s {coins[0]}c"); } protected override void NetStringify(StringBuilder builder) { base.NetStringify(builder); - int[] coins = Utils.CoinsSplit(TotalSellValue); + int[] coins = Terraria.Utils.CoinsSplit(TotalSellValue); builder.Append($", count {SoldItemCount}, value {coins[3]}p {coins[2]}g {coins[1]}s {coins[0]}c"); } } diff --git a/Common/Systems/Shimmering/ShimmerResultReports.cs b/Common/Systems/Shimmering/ShimmerResultReports.cs index d0b77d86..b3e047ca 100644 --- a/Common/Systems/Shimmering/ShimmerResultReports.cs +++ b/Common/Systems/Shimmering/ShimmerResultReports.cs @@ -83,7 +83,7 @@ private readonly string GetCoinLuckAdjustment(LocalizedText text) { Player player = Main.LocalPlayer; float currentLuckValue = player.coinLuck; - float adjustedLuckValue = Utils.Clamp(player.coinLuck + coinValue, 0f, 1e6f); + float adjustedLuckValue = Terraria.Utils.Clamp(player.coinLuck + coinValue, 0f, 1e6f); float luck = player.CalculateCoinLuck(currentLuckValue); float adjustedLuck = player.CalculateCoinLuck(adjustedLuckValue); diff --git a/Common/Threading/Refreshing/StorageViewControls.cs b/Common/Threading/Refreshing/StorageViewControls.cs index 864e0ad3..7b49c37c 100644 --- a/Common/Threading/Refreshing/StorageViewControls.cs +++ b/Common/Threading/Refreshing/StorageViewControls.cs @@ -1,4 +1,5 @@ using MagicStorage.Common.Systems; +using MagicStorage.Common.Utils; using MagicStorage.CrossMod; using System; using System.Collections.Generic; @@ -327,8 +328,15 @@ public bool ItemPassesTextFilter(Item item) { } if (!string.IsNullOrEmpty(itemNameSearchText)) { - if (!item.Name.Contains(itemNameSearchText, StringComparison.OrdinalIgnoreCase)) - return false; + // 支持拼音搜索(仅在简体中文环境下启用) + if (PinyinHelper.ShouldEnablePinyinSearch()) { + if (!PinyinHelper.MatchesSearch(item, itemNameSearchText)) + return false; + } else { + // 原有逻辑:直接字符串匹配 + if (!item.Name.Contains(itemNameSearchText, StringComparison.OrdinalIgnoreCase)) + return false; + } } if (!string.IsNullOrEmpty(itemTooltipSearchText)) { diff --git a/Common/Utils/PinyinHelper.cs b/Common/Utils/PinyinHelper.cs new file mode 100644 index 00000000..195c6158 --- /dev/null +++ b/Common/Utils/PinyinHelper.cs @@ -0,0 +1,405 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.CompilerServices; +using Terraria; +using Terraria.Localization; + +namespace MagicStorage.Common.Utils { + /// + /// Utility class providing pinyin search functionality + /// + public static class PinyinHelper { + /// + /// Cache for pinyin information of item types to avoid redundant calculations + /// Uses ConcurrentDictionary to ensure thread safety + /// + private static readonly ConcurrentDictionary _pinyinCache = new(); + + /// + /// Cached NPinyin.Core assembly + /// + private static Assembly _nPinyinAssembly; + + /// + /// Flag indicating whether NPinyin is loaded (set via reflection to avoid circular dependencies) + /// + private static bool? _nPinyinLoaded; + + /// + /// Cached NPinyin.Pinyin type (obtained via reflection to avoid JIT-time type resolution) + /// + private static Type _pinyinType; + + /// + /// Cached GetPinyin method + /// + private static MethodInfo _getPinyinMethod; + + /// + /// Cached GetInitials method + /// + private static MethodInfo _getInitialsMethod; + + /// + /// Lock object for synchronizing initialization of NPinyin types and methods + /// + private static readonly object _pinyinInitLock = new object(); + + /// + /// Checks if the current game language is Simplified Chinese + /// + /// Returns true if Simplified Chinese, otherwise false + public static bool IsSimplifiedChinese() { + try { + // Check the current active language culture + var culture = Language.ActiveCulture; + return culture != null && culture.Name == "zh-Hans"; + } catch { + // If detection fails, default to false (don't enable pinyin search) + return false; + } + } + + /// + /// Checks whether pinyin search should be enabled + /// Only enabled in Simplified Chinese environment and when NPinyin library is loaded + /// + /// Whether pinyin search is enabled + public static bool ShouldEnablePinyinSearch() { + // Check configuration option, language setting, and whether NPinyin library is loaded + if (!MagicStorageConfig.EnablePinyinSearch || !IsSimplifiedChinese()) + return false; + + // Ensure NPinyin library is loaded + return IsNPinyinLoaded(); + } + + /// + /// Pinyin information for an item + /// + public class PinyinInfo { + /// + /// Full pinyin (lowercase, no spaces), e.g., "tiekuang" + /// + public string FullPinyin { get; set; } = string.Empty; + + /// + /// Pinyin initials (lowercase), e.g., "tk" + /// + public string FirstLetters { get; set; } = string.Empty; + } + + /// + /// Gets pinyin information for an item (with caching) + /// + /// Item instance + /// Pinyin information + public static PinyinInfo GetPinyinInfo(Item item) { + if (item?.IsAir != false) + return new PinyinInfo(); + + // Get item name outside lambda to avoid closure capturing item object + // For the same item.type, item.Name should be stable + string itemName = item.Name ?? string.Empty; + int itemType = item.type; + + // Use GetOrAdd to ensure thread safety and avoid redundant calculations + return _pinyinCache.GetOrAdd(itemType, _ => ConvertToPinyin(itemName)); + } + + /// + /// Checks if search text matches item name + /// Supports three matching methods: Chinese, full pinyin, and pinyin initials + /// + /// Item instance + /// Search text + /// Whether it matches + public static bool MatchesSearch(Item item, string searchText) { + if (item?.IsAir != false || string.IsNullOrEmpty(searchText)) + return false; + + // Get item name, use empty string if null + string itemName = item.Name ?? string.Empty; + searchText = searchText.Trim(); + + // If search text is empty (after Trim), return false directly + if (string.IsNullOrEmpty(searchText)) + return false; + + // 1. Direct Chinese matching (original functionality, maintained for compatibility) + // This is the fastest matching method, check first + // If Chinese matching succeeds, return directly to avoid unnecessary pinyin conversion + if (!string.IsNullOrEmpty(itemName) && + itemName.Contains(searchText, StringComparison.OrdinalIgnoreCase)) + return true; + + // 2. Pinyin matching (only executed when Chinese matching fails, to avoid unnecessary pinyin conversion) + var pinyinInfo = GetPinyinInfo(item); + + // 2.1 Full pinyin matching (case-insensitive) + if (!string.IsNullOrEmpty(pinyinInfo.FullPinyin) && + pinyinInfo.FullPinyin.Contains(searchText, StringComparison.OrdinalIgnoreCase)) + return true; + + // 2.2 Pinyin initials matching (case-insensitive) + if (!string.IsNullOrEmpty(pinyinInfo.FirstLetters) && + pinyinInfo.FirstLetters.Contains(searchText, StringComparison.OrdinalIgnoreCase)) + return true; + + return false; + } + + /// + /// Converts Chinese text to pinyin information + /// Uses reflection to call NPinyin library, avoiding type resolution at JIT time + /// + /// Chinese text + /// Pinyin information + [MethodImpl(MethodImplOptions.NoInlining)] + private static PinyinInfo ConvertToPinyin(string text) { + if (string.IsNullOrEmpty(text)) + return new PinyinInfo(); + + // If NPinyin is not loaded, return empty information directly + // Check via reflection to avoid circular dependencies + if (!IsNPinyinLoaded()) + return new PinyinInfo(); + + // Lazy initialization of NPinyin types and methods (using reflection to avoid JIT-time type resolution) + // Use double-checked locking pattern to ensure thread safety + if (_pinyinType == null || _getPinyinMethod == null || _getInitialsMethod == null) { + try { + lock (_pinyinInitLock) { + // Check again to avoid redundant initialization + if (_pinyinType == null || _getPinyinMethod == null || _getInitialsMethod == null) { + try { + // Use reflection to find loaded assembly, avoiding direct reference + Assembly assembly = FindNPinyinAssembly(); + if (assembly == null) + return new PinyinInfo(); + + // Get type from loaded assembly + // Add additional null check to prevent issues with assembly itself + Type pinyinType = null; + try { + pinyinType = assembly.GetType("NPinyin.Pinyin", throwOnError: false); + } catch { + // If GetType throws exception, pinyinType remains null + } + + if (pinyinType == null) + return new PinyinInfo(); + + // Get methods (completely avoid using GetMethod, only use GetMethods then manually filter) + // This completely avoids AmbiguousMatchException + MethodInfo[] allMethods = GetMethodsSafely(pinyinType); + if (allMethods == null || allMethods.Length == 0) + return new PinyinInfo(); + + // Find GetPinyin(string) and GetInitials(string) methods + MethodInfo getPinyinMethod = FindMethod(allMethods, "GetPinyin"); + MethodInfo getInitialsMethod = FindMethod(allMethods, "GetInitials"); + + if (getPinyinMethod == null || getInitialsMethod == null) + return new PinyinInfo(); + + // Only assign to static fields after all checks pass (atomic operation) + _nPinyinAssembly = assembly; + _pinyinType = pinyinType; + _getPinyinMethod = getPinyinMethod; + _getInitialsMethod = getInitialsMethod; + } catch (Exception) { + // If any exception occurs during initialization, return empty information + // Don't log exception to avoid log pollution + return new PinyinInfo(); + } + } + } + } catch (Exception) { + // If exception occurs outside lock, return empty information + return new PinyinInfo(); + } + } + + // Check again if methods are initialized (prevent being set to null outside lock) + // Use local variables to save references, avoiding modification by other threads between check and use + MethodInfo getPinyin = _getPinyinMethod; + MethodInfo getInitials = _getInitialsMethod; + if (getPinyin == null || getInitials == null) + return new PinyinInfo(); + + try { + // Use reflection to call GetPinyin method (use local variables to ensure thread safety) + object fullPinyinResult = getPinyin.Invoke(null, new object[] { text }); + string fullPinyin = fullPinyinResult?.ToString() ?? string.Empty; + // Remove spaces, convert to lowercase + fullPinyin = fullPinyin.Replace(" ", "").ToLowerInvariant(); + + // Use reflection to call GetInitials method (use local variables to ensure thread safety) + object initialsResult = getInitials.Invoke(null, new object[] { text }); + string firstLetters = initialsResult?.ToString() ?? string.Empty; + firstLetters = firstLetters.ToLowerInvariant(); + + return new PinyinInfo { + FullPinyin = fullPinyin, + FirstLetters = firstLetters + }; + } catch { + // If conversion fails, return empty information (doesn't affect original search functionality) + return new PinyinInfo(); + } + } + + /// + /// Safely gets all methods of a type (avoids AmbiguousMatchException) + /// + /// Type to find methods for + /// Method array, returns null if failed + private static MethodInfo[] GetMethodsSafely(Type type) { + if (type == null) + return null; + + // Method 1: Without FlattenHierarchy + try { + MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Static); + if (methods != null && methods.Length > 0) + return methods; + } catch (AmbiguousMatchException) { + // If failed, try method 2 + } catch { + // Other exceptions also try method 2 + } + + // Method 2: With FlattenHierarchy + try { + MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); + if (methods != null && methods.Length > 0) + return methods; + } catch { + // If still failed, return null + } + + return null; + } + + /// + /// Finds a method with specified name from method array (accepts string or object parameter) + /// + /// Method array + /// Method name + /// Found method, returns null if not found + private static MethodInfo FindMethod(MethodInfo[] methods, string methodName) { + if (methods == null || string.IsNullOrEmpty(methodName)) + return null; + + Type stringType = typeof(string); + + foreach (MethodInfo method in methods) { + if (method == null || !method.IsStatic) + continue; + + // method.Name usually doesn't throw exceptions, no need for additional try-catch + if (method.Name != methodName) + continue; + + try { + ParameterInfo[] parameters = method.GetParameters(); + if (parameters == null || parameters.Length != 1) + continue; + + ParameterInfo param = parameters[0]; + if (param == null) + continue; + + Type paramType = param.ParameterType; + if (paramType == null) + continue; + + // Support string or object type parameters + if (paramType == stringType || paramType == typeof(object)) + return method; + } catch { + // Ignore errors for individual methods, continue searching + continue; + } + } + + return null; + } + + /// + /// Checks if NPinyin is loaded (via reflection to avoid circular dependencies) + /// + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool IsNPinyinLoaded() { + if (_nPinyinLoaded.HasValue) + return _nPinyinLoaded.Value; + + try { + // Check CheckModBuildVersionBeforeJIT.nPinyinLoaded via reflection + // Use current assembly name to avoid hardcoding + Assembly currentAssembly = Assembly.GetExecutingAssembly(); + string assemblyName = currentAssembly.GetName().Name; + Type checkType = Type.GetType($"MagicStorage.CheckModBuildVersionBeforeJIT, {assemblyName}"); + if (checkType != null) { + FieldInfo field = checkType.GetField("nPinyinLoaded", BindingFlags.Public | BindingFlags.Static); + if (field != null) { + object value = field.GetValue(null); + if (value is bool loaded) { + _nPinyinLoaded = loaded; + return loaded; + } + } + } + } catch { + // If reflection fails, assume not loaded (safe strategy) + } + + // Default to false to ensure pinyin search is not enabled due to reflection failure + _nPinyinLoaded = false; + return false; + } + + /// + /// Gets the loaded NPinyin.Core assembly + /// Gets from MagicStorageMod to avoid triggering assembly resolution at JIT time + /// + [MethodImpl(MethodImplOptions.NoInlining)] + private static Assembly FindNPinyinAssembly() { + try { + // Get assembly reference from MagicStorageMod via reflection + Type modType = Type.GetType("MagicStorage.MagicStorageMod, MagicStorage"); + if (modType == null) + return null; + + PropertyInfo prop = modType.GetProperty("NPinyinAssembly", BindingFlags.Public | BindingFlags.Static); + if (prop == null) + return null; + + object assemblyObj = prop.GetValue(null); + if (assemblyObj == null) + return null; + + return assemblyObj as Assembly; + } catch (Exception) { + // If reflection fails, return null + return null; + } + } + + /// + /// Clears pinyin cache (for memory management) + /// + public static void ClearCache() { + _pinyinCache.Clear(); + } + + /// + /// Gets cache size (for debugging and monitoring) + /// + public static int CacheSize => _pinyinCache.Count; + } +} + diff --git a/Localization/en-US.hjson b/Localization/en-US.hjson index cfcbd289..db43910d 100644 --- a/Localization/en-US.hjson +++ b/Localization/en-US.hjson @@ -1347,6 +1347,11 @@ Mods: { Tooltip: The Automaton will remember which help tip it last displayed to the user and display that help tip when interacted with. } + enablePinyinSearch: { + Label: Enable Pinyin Search + Tooltip: Enable to search Chinese item names using pinyin (full pinyin or initials). This feature only works in Simplified Chinese (zh-Hans) language environment. + } + globalShimmerItemBlacklist: { Label: Global Item Shimmering Blacklist Tooltip: Click with Left Ctrl + Left Shift to add/remove blacklist diff --git a/Localization/es-ES.hjson b/Localization/es-ES.hjson index 5cb7b561..e7690251 100644 --- a/Localization/es-ES.hjson +++ b/Localization/es-ES.hjson @@ -1363,6 +1363,11 @@ Mods: { Tooltip: El Automatón recordará qué consejo de ayuda mostró por última vez al usuario y mostrará ese consejo de ayuda al interactuar con él. } + enablePinyinSearch: { + // Label: Enable Pinyin Search + // Tooltip: Enable to search Chinese item names using pinyin (full pinyin or initials). This feature only works in Simplified Chinese (zh-Hans) language environment. + } + globalShimmerItemBlacklist: { // Label: Global Item Shimmering Blacklist // Tooltip: Click with Left Ctrl + Left Shift to add/remove blacklist diff --git a/Localization/fr-FR.hjson b/Localization/fr-FR.hjson index aeba6547..aaae24c0 100644 --- a/Localization/fr-FR.hjson +++ b/Localization/fr-FR.hjson @@ -1343,6 +1343,11 @@ Mods: { // Tooltip: The Automaton will remember which help tip it last displayed to the user and display that help tip when interacted with. } + enablePinyinSearch: { + // Label: Enable Pinyin Search + // Tooltip: Enable to search Chinese item names using pinyin (full pinyin or initials). This feature only works in Simplified Chinese (zh-Hans) language environment. + } + globalShimmerItemBlacklist: { // Label: Global Item Shimmering Blacklist // Tooltip: Click with Left Ctrl + Left Shift to add/remove blacklist diff --git a/Localization/pl-PL.hjson b/Localization/pl-PL.hjson index 6f67f432..4d886ed9 100644 --- a/Localization/pl-PL.hjson +++ b/Localization/pl-PL.hjson @@ -1343,6 +1343,11 @@ Mods: { // Tooltip: The Automaton will remember which help tip it last displayed to the user and display that help tip when interacted with. } + enablePinyinSearch: { + // Label: Enable Pinyin Search + // Tooltip: Enable to search Chinese item names using pinyin (full pinyin or initials). This feature only works in Simplified Chinese (zh-Hans) language environment. + } + globalShimmerItemBlacklist: { // Label: Global Item Shimmering Blacklist // Tooltip: Click with Left Ctrl + Left Shift to add/remove blacklist diff --git a/Localization/pt-BR.hjson b/Localization/pt-BR.hjson index 16e34448..eccfde7e 100644 --- a/Localization/pt-BR.hjson +++ b/Localization/pt-BR.hjson @@ -1346,6 +1346,11 @@ Mods: { Tooltip: O Autômato lembrará qual dica de ajuda foi exibida pela última vez ao usuário e exibirá essa dica de ajuda quando interagir com ele. } + enablePinyinSearch: { + // Label: Enable Pinyin Search + // Tooltip: Enable to search Chinese item names using pinyin (full pinyin or initials). This feature only works in Simplified Chinese (zh-Hans) language environment. + } + globalShimmerItemBlacklist: { Label: Lista Negra Global De Itens Cintilantes Tooltip: Clique com Ctrl esquerdo + Shift esquerdo para adicionar/remover da lista negra. diff --git a/Localization/ru-RU.hjson b/Localization/ru-RU.hjson index 04bd5e41..22d304ec 100644 --- a/Localization/ru-RU.hjson +++ b/Localization/ru-RU.hjson @@ -1344,6 +1344,11 @@ Mods: { Tooltip: Робот запомнит, какую подсказку он в последний раз показывал пользователю, и отобразит эту подсказку при взаимодействии с ней. } + enablePinyinSearch: { + // Label: Enable Pinyin Search + // Tooltip: Enable to search Chinese item names using pinyin (full pinyin or initials). This feature only works in Simplified Chinese (zh-Hans) language environment. + } + globalShimmerItemBlacklist: { Label: Глобальный черный список Мерцания Tooltip: Нажмите левый Ctrl + левый Shift, чтобы добавить/удалить из черного списка diff --git a/Localization/zh-Hans.hjson b/Localization/zh-Hans.hjson index d3cbf476..3e4f4eb0 100644 --- a/Localization/zh-Hans.hjson +++ b/Localization/zh-Hans.hjson @@ -1351,6 +1351,11 @@ Mods: { Tooltip: 自动机会记住它最后向用户显示的帮助提示,并在交互时显示该帮助提示。 } + enablePinyinSearch: { + Label: 启用拼音搜索 + Tooltip: 启用后,可以通过拼音全拼或拼音首字母搜索中文物品名称 + } + globalShimmerItemBlacklist: { Label: 全局物品微光黑名单 Tooltip: 按住左 Ctrl + 左 Shift 点击以添加/移除黑名单 diff --git a/MagicStorage.csproj b/MagicStorage.csproj index cf91949a..d3a679bd 100644 --- a/MagicStorage.csproj +++ b/MagicStorage.csproj @@ -37,6 +37,9 @@ + + NPinyin.Core.dll + ..\references\SerousCommonLib.dll @@ -46,5 +49,8 @@ $(SerousCommonLibPath) + + ..\references\NPinyin.Core.dll + \ No newline at end of file diff --git a/MagicStorageConfig.cs b/MagicStorageConfig.cs index 3abfb1dd..b1c4952a 100644 --- a/MagicStorageConfig.cs +++ b/MagicStorageConfig.cs @@ -83,6 +83,9 @@ public class MagicStorageConfig : ModConfig [DefaultValue(true)] public bool automatonRemembers; + [DefaultValue(true)] + public bool enablePinyinSearch; // 新增:启用拼音搜索(仅在简体中文环境下生效) + public static MagicStorageConfig Instance => ModContent.GetInstance(); [JsonIgnore] @@ -148,6 +151,9 @@ public class MagicStorageConfig : ModConfig [JsonIgnore] public static bool DisplayLastSeenAutomatonTip => Instance.automatonRemembers; + [JsonIgnore] + public static bool EnablePinyinSearch => Instance.enablePinyinSearch; + public override ConfigScope Mode => ConfigScope.ClientSide; // TODO: remove custom json converter when tml fix ItemDefinition format error diff --git a/MagicStorageMod.cs b/MagicStorageMod.cs index 417ff018..2946f18b 100644 --- a/MagicStorageMod.cs +++ b/MagicStorageMod.cs @@ -3,7 +3,9 @@ using MagicStorage.CrossMod.Storage; using SerousCommonLib.API.Helpers; using SerousCommonLib.API.ModCall; +using System; using System.IO; +using System.Reflection; using Terraria; using Terraria.Localization; using Terraria.ModLoader; @@ -33,8 +35,12 @@ public override void Load() { UsingPrivateBeta = DisplayName.Contains("BETA"); + // Load localization first to ensure it's available LocalizationHelper.ForceLoadModHJsonLocalization(this); + // Load NPinyin.Core.dll from embedded resources (after localization) + LoadNPinyinAssembly(); + InterfaceHelper.Initialize(); //Sorting options @@ -44,6 +50,45 @@ public override void Load() FilteringOptionLoader.Load(); } + /// + /// Reference to the loaded NPinyin.Core assembly + /// + public static Assembly NPinyinAssembly { get; private set; } + + /// + /// Load NPinyin.Core.dll from embedded resources + /// + private void LoadNPinyinAssembly() { + try { + // Get the current assembly + Assembly assembly = Assembly.GetExecutingAssembly(); + string resourceName = "NPinyin.Core.dll"; + + // Read DLL from embedded resources + using (Stream stream = assembly.GetManifestResourceStream(resourceName)) { + if (stream == null) { + Logger.Warn($"Could not find embedded resource: {resourceName}. Pinyin search will be disabled."); + return; + } + + // Read DLL byte array + byte[] assemblyData = new byte[stream.Length]; + stream.Read(assemblyData, 0, assemblyData.Length); + + // Load assembly and save reference + NPinyinAssembly = Assembly.Load(assemblyData); + + // Mark NPinyin as loaded, allowing JIT compilation of ConvertToPinyin method + CheckModBuildVersionBeforeJIT.nPinyinLoaded = true; + + Logger.Info("Successfully loaded NPinyin.Core.dll from embedded resources."); + } + } catch (Exception ex) { + // If loading fails, log error but don't affect other mod functionality + Logger.Warn($"Failed to load NPinyin.Core.dll: {ex.Message}. Pinyin search will be disabled."); + } + } + public override void Unload() { StorageGUI.Unload();