From 95da5b0a321da2f88629e0df07704321fa678324 Mon Sep 17 00:00:00 2001 From: Wu Zhuoran Date: Thu, 11 Apr 2024 00:02:43 -0700 Subject: [PATCH] Fix: I18n issues with missing dialog translation. And Add Chinese Translaton Support (#21) --- AnimalSitter/AnimalSitter.cs | 115 +++++++++++++++++++++++++++---- AnimalSitter/AnimalSitter.csproj | 2 +- AnimalSitter/i18n/zh.json | 112 ++++++++++++++++++++++++++++++ AnimalSitter/manifest.json | 2 +- README.md | 5 +- 5 files changed, 218 insertions(+), 18 deletions(-) create mode 100644 AnimalSitter/i18n/zh.json diff --git a/AnimalSitter/AnimalSitter.cs b/AnimalSitter/AnimalSitter.cs index e43bbb9..21e4f0c 100644 --- a/AnimalSitter/AnimalSitter.cs +++ b/AnimalSitter/AnimalSitter.cs @@ -12,6 +12,7 @@ using Object = StardewValley.Object; using AnimalSitter.Integrations.GenericModConfigMenu; using Microsoft.Xna.Framework.Input; +using System.Reflection; namespace AnimalSitter { @@ -65,10 +66,12 @@ public class AnimalSitter : Mod private ModConfig Config; - private DialogueManager DialogueManager; + // private DialogueManager DialogueManager; private ChestManager ChestManager; + private readonly Random RandomDialogue = new Random(); + /********* ** Public methods @@ -78,7 +81,7 @@ public class AnimalSitter : Mod public override void Entry(IModHelper helper) { this.Config = this.Helper.ReadConfig(); - this.DialogueManager = new DialogueManager(this.Config, helper.ModContent, this.Monitor); + // this.DialogueManager = new DialogueManager(this.Config, helper.ModContent, this.Monitor); this.ChestManager = new ChestManager(this.Monitor); I18n.Init(helper.Translation); @@ -202,7 +205,7 @@ private void OnSaveLoaded(object sender, SaveLoadedEventArgs e) this.ChestManager.SetDefault(this.ChestCoords); // Read in dialogue - this.DialogueManager.ReadInMessages(); + // this.DialogueManager.ReadInMessages(); this.Monitor.Log(I18n.Log_ChestCoords(x: this.ChestCoords.X, y: this.ChestCoords.Y), LogLevel.Trace); } @@ -551,16 +554,20 @@ private void ShowMessage(int numActions, int totalCost, bool doesPlayerHaveEnoug { if (Game1.player.isMarriedOrRoommates()) { - message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(1, "Xdialog"), stats, this.Config); + string spouse = Game1.player.isMarriedOrRoommates() ? Game1.player.getSpouse().getName() : this.Checker; + // message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(1, "Xdialog"), stats, this.Config); + message += I18n.Dialog_Xdialog1(spouse: spouse); } else { - message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(2, "Xdialog"), stats, this.Config); + // message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(2, "Xdialog"), stats, this.Config); + message += I18n.Dialog_Xdialog2(num_actions: stats.NumActions); } if (totalCost > 0 && this.CostPerAnimal > 0) { - message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(3, "Xdialog"), stats, this.Config); + // message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(3, "Xdialog"), stats, this.Config); + message += I18n.Dialog_Xdialog3(total_cost: stats.TotalCost); } HUDMessage msg = new HUDMessage(message); @@ -568,11 +575,13 @@ private void ShowMessage(int numActions, int totalCost, bool doesPlayerHaveEnoug } else if (gatheringOnly) { - message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(4, "Xdialog"), stats, this.Config); + // message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(4, "Xdialog"), stats, this.Config); + message += I18n.Dialog_Xdialog4(checker: this.Checker); if (totalCost > 0 && this.CostPerAnimal > 0) { - message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(3, "Xdialog"), stats, this.Config); + // message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(3, "Xdialog"), stats, this.Config); + message += I18n.Dialog_Xdialog3(total_cost: stats.TotalCost); } HUDMessage msg = new HUDMessage(message); @@ -590,18 +599,22 @@ private void ShowMessage(int numActions, int totalCost, bool doesPlayerHaveEnoug portrait = "$8"; } - message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetRandomMessage("greeting"), stats, this.Config); - message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(5, "Xdialog"), stats, this.Config); + // message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetRandomMessage("greeting"), stats, this.Config); + // message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(5, "Xdialog"), stats, this.Config); + message += I18n.Dialog_Greeting1(name: Game1.player.Name); + message += I18n.Dialog_Xdialog5(); if (this.CostPerAnimal > 0) { if (doesPlayerHaveEnoughCash) { - message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(6, "Xdialog"), stats, this.Config); + // message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(6, "Xdialog"), stats, this.Config); + message += I18n.Dialog_Xdialog6(total_cost: stats.TotalCost); } else { - message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetRandomMessage("unfinishedmoney"), stats, this.Config); + // message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetRandomMessage("unfinishedmoney"), stats, this.Config); + message += this.GetRandomMessage(messageStoreName: "unfinishedmoney", low: 1, high: 8); } } else @@ -610,7 +623,8 @@ private void ShowMessage(int numActions, int totalCost, bool doesPlayerHaveEnoug //message += portrait + "#$e#"; } - message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetRandomMessage("smalltalk"), stats, this.Config); + // message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetRandomMessage("smalltalk"), stats, this.Config); + message += this.GetRandomMessage(messageStoreName: "smalltalk", low: 1, high: 14); message += portrait + "#$e#"; character.CurrentDialogue.Push(new Dialogue(character, message)); @@ -619,7 +633,8 @@ private void ShowMessage(int numActions, int totalCost, bool doesPlayerHaveEnoug else { //message += checker + " has performed " + numActions + " for your animals."; - message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(7, "Xdialog"), stats, this.Config); + // message += this.DialogueManager.PerformReplacement(this.DialogueManager.GetMessageAt(7, "Xdialog"), stats, this.Config); + message += I18n.Dialog_Xdialog7(checker: this.Checker, num_actions: stats.NumActions); HUDMessage msg = new HUDMessage(message); Game1.addHUDMessage(msg); } @@ -639,5 +654,77 @@ private List GetAnimals() return animals; } + private string GetRandomMessage(string messageStoreName, int low=1, int high=4) + { + var rand = RandomDialogue.Next(low, high + 1); + + if (messageStoreName == "greeting") + { + return rand switch + { + 1 => I18n.Dialog_Greeting1(name: Game1.player.Name), + 2 => I18n.Dialog_Greeting2(name: Game1.player.Name), + 3 => I18n.Dialog_Greeting3(name: Game1.player.Name), + 4 => I18n.Dialog_Greeting4(name: Game1.player.Name), + 5 => I18n.Dialog_Greeting5(name: Game1.player.Name), + 6 => I18n.Dialog_Greeting6(name: Game1.player.Name), + 7 => I18n.Dialog_Greeting7(name: Game1.player.Name), + _ => I18n.Dialog_Greeting1(name: Game1.player.Name), + }; + } + else if (messageStoreName == "unfinishedmoney") + { + return rand switch + { + 1 => I18n.Dialog_Unfinishedmoney1(), + 2 => I18n.Dialog_Unfinishedmoney2(), + 3 => I18n.Dialog_Unfinishedmoney3(), + 4 => I18n.Dialog_Unfinishedmoney4(), + 5 => I18n.Dialog_Unfinishedmoney5(), + 6 => I18n.Dialog_Unfinishedmoney6(), + 7 => I18n.Dialog_Unfinishedmoney7(), + 8 => I18n.Dialog_Unfinishedmoney8(), + _ => I18n.Dialog_Unfinishedmoney1(), + }; + } + else if (messageStoreName == "unfinishedinventory") + { + return rand switch + { + 1 => I18n.Dialog_Unfinishedinventory1(), + 2 => I18n.Dialog_Unfinishedinventory2(), + 3 => I18n.Dialog_Unfinishedinventory3(), + 4 => I18n.Dialog_Unfinishedinventory4(), + _ => I18n.Dialog_Unfinishedinventory1(), + }; + } + else if (messageStoreName == "smalltalk") + { + return rand switch + { + 1 => I18n.Dialog_Smalltalk1(), + 2 => I18n.Dialog_Smalltalk2(), + 3 => I18n.Dialog_Smalltalk3(), + 4 => I18n.Dialog_Smalltalk4(), + 5 => I18n.Dialog_Smalltalk5(), + 6 => I18n.Dialog_Smalltalk6(), + 7 => I18n.Dialog_Smalltalk7(), + 8 => I18n.Dialog_Smalltalk8(), + 9 => I18n.Dialog_Smalltalk9(), + 10 => I18n.Dialog_Smalltalk10(), + 11 => I18n.Dialog_Smalltalk11(), + 12 => I18n.Dialog_Smalltalk12(), + 13 => I18n.Dialog_Smalltalk13(), + 14 => I18n.Dialog_Smalltalk14(), + _ => I18n.Dialog_Smalltalk1(), + }; + } + else + { + return "...$h#$e#"; + } + + } + } } diff --git a/AnimalSitter/AnimalSitter.csproj b/AnimalSitter/AnimalSitter.csproj index 8a4ec47..1f3a260 100644 --- a/AnimalSitter/AnimalSitter.csproj +++ b/AnimalSitter/AnimalSitter.csproj @@ -3,7 +3,7 @@ AnimalSitter AnimalSitter - 2.2.0 + 2.2.2 net6.0 AnyCPU AnyCPU diff --git a/AnimalSitter/i18n/zh.json b/AnimalSitter/i18n/zh.json new file mode 100644 index 0000000..89c47ee --- /dev/null +++ b/AnimalSitter/i18n/zh.json @@ -0,0 +1,112 @@ +{ + "config.KeyBind": "快捷键", + "config.KeyBind.description": "默认'O'键,按下后助手开始工作。", + + "config.GrowUpEnabled": "立即成长开关", + "config.GrowUpEnabled.description": "开启后助手会使用神秘力量使你的动物立即长大,并产出产品。默认为关闭。", + + "config.MaxHappinessEnabled": "最大快乐值开关", + "config.MaxHappinessEnabled.description": "开启后,无论何时何地,助手会一直照料动物到最大快乐值后才停止工作。默认为关闭。", + + "config.MaxFullnessEnabled": "喂养开关", + "config.MaxFullnessEnabled.description": "开启后助手会喂养动物,动物吃饱后会多产。默认为关闭。", + + "config.HarvestEnabled": "收获开关", + "config.HarvestEnabled.description": "助手会收集动物产品。如果想自己动手,则设置为关闭。", + + "config.PettingEnabled": "抚摸开关", + "config.PettingEnabled.description": "助手会抚摸动物。默认开启。如果想自己动手,则设置为关闭。", + + "config.MaxFriendshipEnabled": "好感度开关", + "config.MaxFriendshipEnabled.description": "助手照料动物后,动物好感度是否增长。默认为否。", + + "config.CostPerAction": "雇佣金", + "config.CostPerAction.description": "给助手照料每只动物的雇佣金,默认为25金币。", + + "config.WhoChecks": "雇员", + "config.WhoChecks.description": "决定谁受雇来照料你的动物,默认为配偶即'spouse'。你可以设置为你的宠物,但不会有太多反馈;也可以设置为其他角色,这样会启动相关对话;还可以设置成别的名字,这个名字会在消息中显示。", + + + "config.EnableMessages": "信息显示开关", + "config.EnableMessages.description": "是否在游戏中开启动物照料的信息提醒。默认为是。", + + "config.TakeTrufflesFromPigs": "修复松露开关", + "config.TakeTrufflesFromPigs.description": "助手会捡拾松露。解决松露变杂草的BUG。", + + "config.BypassInventory": "产品入箱开关", + "config.BypassInventory.description": "产品被收集后,是否不进入背包,而是存放在你指定的箱子中,默认为否。", + + "config.ChestCoords": "指定箱子位置", + "config.ChestCoords.description": "背包不够,产品溢出时,存放溢出物的箱子位置坐标。默认为(73,14)。", + + "config.ChestDefs": "ChestDefs", + "config.ChestDefs.description": "This is a bar-separated list of chest locations that you have defined for specific items. It defaults to blank, but here is an example: '430,70,14|340,7,4,FarmHouse' You can see there are 2 options.", + + "dialog.comment_1": "Indexes in this file that are prefixed with an X rely on specific ordering for the in game dialog to make sense. Other ones are randomly selected, so order doesn't matter. Indexes also need to be in the format group_id, with a single underscore.", + "dialog.Xdialog_1": " {{spouse}} 已经照料完动物了。", + "dialog.Xdialog_2": "你的助手完成了 {{num_actions}} 任务。", + "dialog.Xdialog_3": "花费了 {{total_cost}}金币。", + "dialog.Xdialog_4": " {{checker}} 已经收集完了动物产品。", + "dialog.Xdialog_5": "我今天照料完动物了。", + "dialog.Xdialog_6": "我从卡里刷走了 {{total_cost}} 金币。", + "dialog.Xdialog_7": " {{checker}} 完成了给动物 {{num_actions}} 的工作。", + "dialog.greeting_1": "你好啊, {{name}} 。", + "dialog.greeting_2": "早上好, {{name}} 。", + "dialog.greeting_3": "嘿 {{name}} !", + "dialog.greeting_4": "完成了 {{name}} 。", + "dialog.greeting_5": "嘿嘿 {{name}} ,抓到你了。", + "dialog.greeting_6": " {{name}} ,还好嘛?", + "dialog.greeting_7": "农夫 {{name}} !", + "dialog.unfinishedmoney_1": " 因为……嗯……我们聊过的一些金钱上的问题,我没能干完所有活。", + "dialog.unfinishedmoney_2": " 为了你的预算不至于超额,我不得不略过一些工作。", + "dialog.unfinishedmoney_3": " 我没干完所有活。如果你想再找我过来,给我打电话。", + "dialog.unfinishedmoney_4": " 动物数量太多了,你已经负担不起饲养成本了。或许你可以去乔家看看有没有工作机会。", + "dialog.unfinishedmoney_5": " 你没给钱,所以今天我不干了。", + "dialog.unfinishedmoney_6": " 我知道情况,手头不方便了是么。如果你拿出足够的照料其它动物的酬劳,可以再找我。", + "dialog.unfinishedmoney_7": " 除非有人给你邮寄一些现金,并且它们就躺在邮箱里等你。否则你可能得自己照料一些动物了。", + "dialog.unfinishedmoney_8": " 我愿意降一些佣金,但我不想像你一样破产……只是开玩笑。", + "dialog.unfinishedinventory_1": " 看起来你没有足够的地方来存放这些产品。", + "dialog.unfinishedinventory_2": " 你可能得腾出更多的空间了,或者买一个更大的箱子。", + "dialog.unfinishedinventory_3": " 当你有足够空间放剩下的东西时,叫我一声。", + "dialog.unfinishedinventory_4": " 你的包和箱子都没有足够的空间放东西了,你腾出了地方后叫我一声。", + "dialog.smalltalk_1": " 跟你干活特别愉快!", + "dialog.smalltalk_2": " 你提供的这个工作让我挣到了更多钱,起到了很大的作用。", + "dialog.smalltalk_3": " 如果你的农场里还有什么别的工作,记得找我,我会很乐意过来的。", + "dialog.smalltalk_4": " 所以之前生活是怎样对待你的?", + "dialog.smalltalk_5": " 你能决定搬来星露谷,我真的特别高兴。", + "dialog.smalltalk_6": " 现在是一年当中动物产品质量最好的时候。", + "dialog.smalltalk_7": " 你的庄稼长的怎么样啦?", + "dialog.smalltalk_8": " 你最近和你的父母联系了么?", + "dialog.smalltalk_9": " 自从雇我以来,空出的这些时间你都做了什么?", + "dialog.smalltalk_10": " 我特别想问,你对周围流传的那些谣言怎么看?", + "dialog.smalltalk_11": " 对了,我真的挺喜欢你对这个农场的改造的。", + "dialog.smalltalk_12": " 你需要发票收据么?", + "dialog.smalltalk_13": " 我并不是贪婪,但兜里揣着一大堆现金的感觉真的好,不是么?", + "dialog.smalltalk_14": " 我明天一定要休假,你确定明天不自己去看看你的瓶瓶罐罐么?", + "dialog.Shane_1": " 我确定在这比在乔家工作时要好,那个班上的太糟了。", + "dialog.Shane_2": " 我今天走回家,介意我拿一个冰镇的么?", + "dialog.Haley_1": " 这个工作一开始很有趣,但我不确定我能习惯这个味道。", + "dialog.Haley_2": " 如果你觉得无礼,那么我提前说声抱歉。请雇别人来做这个,我感觉我快要死了。$a", + "dialog.Alex_1": " 你有没有考虑过做一些肉类的买卖?我不得不克制自己不去咬你的动物一口!", + "dialog.Leah_1": " 你介意我给你的动物画幅画么?", + "dialog.Marnie_1": " 你照料动物很拿手,难怪它们的产品品质这么好!", + + "log.chestCoords": "箱子坐标: {{x}}, {{y}}", + "log.error_parsing_key_bingding": "快捷键绑定错误; 默认为{{default_value}}", + "log.doing_free": "我可以无偿做这个,但我不会付给你钱来照料你的恶臭的动物!", + "log.set_cost_to_0": "将雇佣金设置为0。", + "log.exception_onkeyreleased": "快捷键设为: {{ex}}", + "log.petting_animal": "抚摸了 {{animal_name}} ", + "log.aging_animal": "使 {{animal_name}} 生长到成熟", + "log.feeding_animal": "喂养了 {{animal_name}} ", + "log.max_happiness_animal": " {{animal_name}} 快乐值满了", + "log.max_friendship_animal": " {{animal_name}} 亲密度满了", + "log.has_produce": " {{animal_name}} 生产了 {{animal_currentProduce}} ", + "log.total_cost": "助手完成了 {{actions}} 工作。总计花费: {{total_cost}} 金币", + "log.nothing_to_do": "现在没有能做的。", + "log.inventory_full": "空间满了,无法拾取动物产品。", + "log.found_coop_object": "Found coop object: {{obj_name}} / {{obj_category}}/{{obj_isAnimalProduct}}", + "log.meow": "喵……", + "log.woof": "汪……", + "log.imaginary_pet_take_care": "你幻想的宠物已经照料完了你的动物。" +} \ No newline at end of file diff --git a/AnimalSitter/manifest.json b/AnimalSitter/manifest.json index 8bff33a..a44579e 100644 --- a/AnimalSitter/manifest.json +++ b/AnimalSitter/manifest.json @@ -1,7 +1,7 @@ { "Name": "Animal Sitter LTS", "Author": "oliver", - "Version": "2.2.1", + "Version": "2.2.2", "Description": "Long Term Support Mod Version for Animal Sitter Mod. Let someone else pet all those pesky animals!", "UniqueID": "oliver.AnimalSitterLTS", "EntryDll": "AnimalSitter.dll", diff --git a/README.md b/README.md index 0a78c6e..b9682bb 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ The first specifies the item ID and the chest coordinates, this knows to check f ### Customization -The `dialog.xnb` file will allow you to customize the dialog to your liking. I've also included the dialog.yaml source file, but the mod will read it from the XNB file. If you don't know how to do it, google "how to unpack and repack stardew valley mods". +The `dialog.xnb` file will allow you to customize the dialog to your liking. I've also included the dialog.yaml source file, but the mod will read it from the XNB file. If you don't know how to do it, google "how to unpack and repack stardew valley mods". The dialogue elements are arranged in a name_index format. If the name starts with a capital 'X', that means those messages need to stay roughly in that order and in the same format for the dialog to make sense. The number is important. @@ -86,7 +86,7 @@ All other elements can be added to, and modified because they are used randomly Also you'll see that I added a few names down at the bottom,"Shane_1", "Shane_2", "Leah_1", for example. You can add any other Stardew characters dialog to the file in that same format. Those dialogues will be merged in with the "smalltalk" group if your "whoChecks" is set to one of the characters. Most of the notation that existing SDV dialogs use will work(for example @ is replaced by the name of the farmer). There's also notation added to use values from this mod in the dialog, they are (along with a description) - + **%%animalsPet%%** - The number of animals that were petted. **%%trufflesHarvested%%** - The number of truffles that were harvested. **%%productsHarvested%%** - The number of other animal products that were harvested (I promise to allow more granular tracking in the future). @@ -111,6 +111,7 @@ The dialog groups in the file, and a quick explanation of when each are used: * Original [Mod](https://www.nexusmods.com/stardewvalley/mods/581) and [Code](https://github.com/jdusbabek/stardewvalley) from [John Dusbabek](https://github.com/jdusbabek) * Unofficial Fix [Mod](http://forums.stardewvalley.net/threads/unofficial-mod-updates.2096/post-22271) +* Chinese Translation: [codeyz](https://www.nexusmods.com/stardewvalley/users/51596836) with its original translation [mod](https://www.nexusmods.com/stardewvalley/mods/22210) ## Contribution