跳转至内容

[搬运][Windows][JSON-i18n]一款JSON文件快速本地化的翻译工具

妙妙工具
1 1 63 1
  • 项目地址:MonianHello/JSON-i18n: JSON文件快速本地化的翻译工具
    以下介绍为项目地址readme,因介绍已较为详细,故不另行编写
    本帖内不提供二次分发文件,请前往项目地址自行下载!


    JSON-i18n

    JSON文件快速本地化的翻译工具

    部分功能参考自CFPATools/Minecraft-Mods-Translator: Mods Translator for Minecraft 1.16+ (github.com)

    image-20230608112735258

    主要功能:

    程序提供五个快捷键:

    • Ctrl+F 跳转至搜索
    • Ctrl+H 跳转至替换
    • Ctrl+Shift+A 全选替换候选项
    • Ctrl+Up(方向键上) 跳转至审阅模式上一个键名
    • Ctrl+Down(方向键下) 跳转至审阅模式下一个键名

    详细说明:

    首次启动:

    首次启动后需要设置工作目录,设置完成后也可以在左上角 选项-首选项中修改

    注意:请避免通过直接修改config.ini的方式修改配置,由于不同设备的文本编辑器编码方式可能不同,错误的编码方式会导致程序异常。如果出现此类情况请删除config.ini以初始化程序

    外观设置:

    程序内支持修改全局字体及大小,在左上角 选项-首选项中修改。使用鼠标滚轮可以快速调整不同的字体及大小,方便预览。同时支持切换深色模式

    界面说明:

    程序左侧为文件浏览区域,可以快速选择需要打开的json文件

    程序右侧分别是查询栏和替换栏

    程序中间为操作区域,用来编辑json文件,在浏览模式下点击行号可以快速跳转到审阅模式

    菜单功能:

    上方菜单栏中有以下四个功能:

    • 首选项
    • 保存当前布局
    • 一键清空空格
    • 安全模式保存(在保存文件按钮失效时使用)

    左侧文件浏览区域中可以右键文件呼出菜单,有以下四个功能:

    • 在资源管理器中打开
    • 移动到回收站
    • 复制并重命名
    • 重命名

    翻译功能:

    翻译功能需要首先前往百度智能云-管理中心 (baidu.com)获取免费测试资源(500万字符/年),后续将陆续支持其他翻译api。

    使用前需要在配置文件中填入获取到的接口ak/sk,具体步骤见下文。

    测试成功后,可以点击左下角 翻译文件按钮,程序将自动对全文进行翻译。此时翻译并不会直接替换原文,需要用户进行进一步校对。如不需要,可以点击左下角 复制机翻按钮,一键替换译文与原文。完成后点击左下角 保存文件按钮即可保存更改。

    image-20230608115821872

    翻译接口领取步骤:

    1、登录百度账号,选择领取 文本翻译-通用版

    image-20230608115139348

    2、创建应用,接口选择 文本翻译-通用版,其他内容无要求

    image-20230608115356481

    3、复制ak与sk到程序中,测试成功后即可使用

    image-20230608115533624

    image-20230608115621227


相关推荐


  • [原创][数据包][持续更新]NuQuest模组中的对话框使用示例

    妙妙工具
    1
    0 赞同
    1 帖子
    133 浏览
    昨天没做东西,今天也没K
    很多人在催这玩意,但是也有人不知道这玩意怎么用,那我今天来教教大家吧。 数据包路径 关于数据包的路径存放 目前的路径是在nu_quest/dialog下的 完整路径就是data/nu_quest/dialog 代码会自动检测这个路径下的全部文件,包括子文件夹,所以大可放心整理问题。 编写数据包 那现在我们就来介绍如何写对话了 { "dialogueId": "intro", "dialogTexts": [ { "title": "dialog.nuquest.intro.title", "text": "dialog.nuquest.intro.text", "imageGroup": { "image": "foo:textures/gui/npc.png", "x": "0", "y": "(screenheight / 3 * 2) - 64", "width": 64, "height": 64, "uOffset": 0, "vOffset": 0, "uWidth": 64, "vHeight": 64, "textureWidth": 64, "textureHeight": 64 }, "soundGroup": { "sound": "minecraft:entity.villager.yes", "volume": 1.0, "pitch": 1.0 }, "textEffect": { "name": "typewriter" }, "params": { "speed": 2 } } ], "dialogActionDatas": [ { "message": "dialog.nuquest.intro.continue", "action": { "name": "dialog", "params": { "dialogId": "foo:intro_2" } } }, { "message": "dialog.nuquest.intro.exit", "action": { "name": "close" } } ] } 这是目前对话中可用的全部功能 在最外级的json元素中主要有三个,分别是dialogueId,dialogTexts,dialogActionDatas dialogueId定义了这个动画的id名,调用时也是通过id名来查找,而dialogTexts是一个列表,里面存放了对话的文本内容,dialogActionDatas是选项按钮,在对话文字全部播放完后则会出现。
  • [原创][Mod]通过特定格式文字进行查找结构

    妙妙工具 forge mixin
    1
    0 赞同
    1 帖子
    76 浏览
    昨天没做东西,今天也没K
    故事的起因是有帮twf写模组时,需要用到查找结构指令显示坐标给玩家,但是玩家不一定有权限或者ftbq发送并不会sendmessage给玩家,所以有了此代码。 我也将结构查找的功能写成了一个类,可以直接拿去用。 public class StructureLocator { private static final ResourceKey<Registry<ConfiguredStructureFeature<?, ?>>> STRUCTURE_REGISTRY_KEY = Registry.CONFIGURED_STRUCTURE_FEATURE_REGISTRY; /** * 根据单个结构 ResourceLocation(如 "minecraft:village" 或者自定义 mod:id)查找最近的那个点。 * * @param level 当前维度 * @param center 中心搜索点 * @param id 结构的 ResourceLocation * @param radius 搜索半径(方块数) * @param skipKnown 是否跳过已探索过的结构 * @return 如果找到,返回 Pair(结构坐标, Holder<该结构>); 找不到则 empty() */ public static Optional<Pair<BlockPos, Holder<ConfiguredStructureFeature<?, ?>>>> findNearest( ServerLevel level, BlockPos center, ResourceLocation id, int radius, boolean skipKnown ) { Registry<ConfiguredStructureFeature<?, ?>> registry = level.registryAccess().registryOrThrow(STRUCTURE_REGISTRY_KEY); ResourceKey<ConfiguredStructureFeature<?, ?>> key = ResourceKey.create(STRUCTURE_REGISTRY_KEY, id); Holder<ConfiguredStructureFeature<?, ?>> holder = registry.getHolder(key).orElse(null); if (holder == null) return Optional.empty(); HolderSet<ConfiguredStructureFeature<?, ?>> holderSet = HolderSet.direct(holder); Pair<BlockPos, Holder<ConfiguredStructureFeature<?, ?>>> result = level.getChunkSource() .getGenerator() .findNearestMapFeature(level, holderSet, center, radius, skipKnown); return Optional.ofNullable(result); } /** * 根据 TagKey(像 "#minecraft:village")来查找最近的结构。 * * @param level 当前维度 * @param center 中心搜索点 * @param tagKey 结构 TagKey(Registry.CONFIGURED_STRUCTURE_FEATURE_REGISTRY 下的 Tag) * @param radius 搜索半径 * @param skipKnown 是否跳过已探索结构 * @return 如果找到,返回 Pair(结构坐标, Holder<该结构>); 找不到则 empty() */ public static Optional<Pair<BlockPos, Holder<ConfiguredStructureFeature<?, ?>>>> findNearestByTag( ServerLevel level, BlockPos center, TagKey<ConfiguredStructureFeature<?, ?>> tagKey, int radius, boolean skipKnown ) { Registry<ConfiguredStructureFeature<?, ?>> registry = level.registryAccess().registryOrThrow(STRUCTURE_REGISTRY_KEY); HolderSet<ConfiguredStructureFeature<?, ?>> holderSet = registry.getOrCreateTag(tagKey); Pair<BlockPos, Holder<ConfiguredStructureFeature<?, ?>>> result = level.getChunkSource() .getGenerator() .findNearestMapFeature(level, holderSet, center, radius, skipKnown); return Optional.ofNullable(result); } /** * 把查到的结果格式化成一个聊天用的组件(绿色坐标 + 距离)。 * * @param structureName 你想显示的结构名称(如 "minecraft:village" 或 "#minecraft:village") * @param origin 搜索中心 * @param pair findNearest 返回的 Pair * @param translateKey 翻译 key,通常用 "commands.locate.success" */ public static Component formatLocateResult( String structureName, BlockPos origin, Pair<BlockPos, Holder<ConfiguredStructureFeature<?, ?>>> pair, String translateKey ) { BlockPos found = pair.getFirst(); int distance = Mth.floor( dist(origin.getX(), origin.getZ(), found.getX(), found.getZ()) ); MutableComponent coords = ComponentUtils.wrapInSquareBrackets( new TranslatableComponent("chat.coordinates", found.getX(), "~", found.getZ()) ); return new TranslatableComponent( translateKey, structureName, coords, distance ); } private static float dist(int x1, int z1, int x2, int z2) { int dx = x2 - x1, dz = z2 - z1; return Mth.sqrt((float) (dx * dx + dz * dz)); } } 这部分代码就是查找结构有关的类了,通过获取ConfiguredStructureFeature的注册表,然后再获取结构的Holder类,再给ChunkGenerator的findNearestMapFeature方法去获取到BlockPos。 @Mixin(ServerPlayer.class) public class ServerPlayerMixin { @ModifyArg(method = "sendMessage(Lnet/minecraft/network/chat/Component;Lnet/minecraft/network/chat/ChatType;Ljava/util/UUID;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/protocol/game/ClientboundChatPacket;<init>(Lnet/minecraft/network/chat/Component;Lnet/minecraft/network/chat/ChatType;Ljava/util/UUID;)V"), index = 0) public Component modifyMessage(Component component){ MutableComponent mutableComponent = component.copy(); String message = mutableComponent.getString(); ServerPlayer serverPlayer = (ServerPlayer) (Object) this; if (message.contains("<structure>") && message.contains("</structure>")) { String structure = message.replaceAll(".*<structure>(.*?)</structure>.*", "$1"); BlockPos center = serverPlayer.blockPosition(); Optional<Pair<BlockPos, Holder<ConfiguredStructureFeature<?, ?>>>> holderPair = StructureLocator.findNearest( serverPlayer.getLevel(), center, new ResourceLocation(structure), 100, false ); AtomicReference<String> replace = new AtomicReference<>(); holderPair.ifPresentOrElse(pair -> { Component component1 = StructureLocator.formatLocateResult(structure, center, pair, "commands.locate.success"); replace.set(component1.getString()); }, () -> { replace.set(new TranslatableComponent("commands.locate.failed", structure).getString()); }); Style style = component.getStyle(); mutableComponent = new TextComponent(message.replaceAll("<structure>(.*?)</structure>", "§a%s§r".formatted(replace.get()))).withStyle(style); } return mutableComponent; } } 这段mixin则是注入ServerPlayer的sendMessage方法,修改new ClientboundChatPacket(message, type, sender)的message参数,||因为我偷懒,所以没用MixinExtra||,用正则表达式进行匹配到对应的结构格式文字,然后修改原文字中的内容。 这差不多都就是本次代码的全部内容了。
  • 【发帖必读】妙妙工具版版规与发帖规范

    已固定 已锁定 妙妙工具
    1
    0 赞同
    1 帖子
    64 浏览
    不是椰浆
    总览第一章 板块定位第二章 发帖规范第三章 违规行为第四章 附则 第一章 板块定位 第一条 核心宗旨 妙妙工具板块致力于分享实用技术资源,包括但不限于: 原创或转载的程序、网页工具 KubeJS/CrT魔改脚本、工具集、配置集、Lib库 可复用的代码轮子、开发模板 其他可提升效率的技术解决方案 第二条 内容导向 鼓励发布完整度高、逻辑清晰、注释规范的作品,倡导技术交流与开源精神。 第二章 发帖规范 第三条 标题格式 一、基础格式 [原创/搬运][工具平台][工具英文名——工具译名] 其他说明与描述 说明: 原创/搬运:必填,标明内容性质(搬运需注明原出处); 工具平台:必填,标明工具类型或适用平台(如 Windows / Forge / KubeJS 6 / 在线工具 等); 工具名称: 有中英文名:格式为 英文名——中文译名; 无中文译名:可仅写英文名; 无英文名:可仅写中文名; 其他说明:选填,补充版本、功能亮点或短评(如 v3.2.1更新 / 便捷翻译工具)。 二、注意事项 标题中英文间用 短破折号 ——(非短横线 -); 标题中方括号使用英文字符[],而不使用中文字符【】 禁止添加夸张符号(如 !!! 【爆款】); 平台分类需简洁明确,避免模糊表述(如 [Minecraft] 应改为 [Minecraft 1.20.1-1.21.X])。 三、格式示例 [转载][Windows][JSON-i18n]一款JSON文件快速本地化的翻译工具 [转载][CrT 1.12.2][GrassUtils]基于CraftTweaker的便捷工具类集合 第四条 版权声明 原创内容:需在正文显著位置标注原创声明以及授权协议; 搬运内容: 一般情况下禁止二次转载(即“二转”),原搬运贴年久失修例外(超过三个大版本更新未同步内容); 若原作者注明转载需要授权,或原作品协议不允许转载,需在正文顶部展示授权协议截图/链接; 二次分发需要在协议允许的情况下进行,或获取原作者授权,需在正文顶部展示授权协议截图/链接; 衍生作品:若涉及二改、二次分发或反向工程,必须符合原始协议条款,否则视为剽窃。 第五条 安全警示 内容若包含以下操作,必须添加 unsafe 标签并在正文详细说明风险: 修改系统关键文件 静默执行的操作 涉及敏感权限 存在数据丢失/泄露风险的功能 (示例): 本脚本涉及对系统文件进行修改的操作! 第六条 质量管控 禁止发布以下低质量内容: 功能重复:与已有工具核心功能高度相似; 代码简陋:无异常处理、无注释、逻辑混乱的“玩具代码”; 可替代性强:可通过现有工具组合或简单命令实现同等效果; 描述模糊:未提供使用场景、参数说明或效果演示。 注:若承诺改进,需在标题添加 [持续更新] 并公示开发计划(如更新日志)。 第三章 违规行为 第七条 绝对禁止 剽窃:直接复制他人代码未标注来源,或篡改版权声明; 黑箱分发:对闭源工具进行逆向工程并违规传播; 恶意组件:植入后门、挖矿代码、数据爬虫等危害性内容; 虚假更新:标注 [持续更新] 但超30天无实质进展且未说明原因。 第八条 内容删除标准 未标注 [unsafe] 的高风险工具; 未提供授权证明的搬运内容; 被3名以上用户举报核实为低创作品。 第九条 违规处罚 违规类型 处理措施 未标注[unsafe] 警告+强制编辑 低创内容 删帖+禁止3日内发同类主题 剽窃/黑箱分发 永久封禁账号+全论坛置顶晒尸 第四章 附则 第十条 本规则自发布之日起生效,最终解释权归VariedMC管理组所有。