NPC Helper 2/Docs

Create an NPC

Localization

Translate NPC names, dialogue, schedules, marriage text, heart events, and festival lines, and ship translations as separate packs.

An NPC pack is the original version of the character. A locale folder is a small set of overrides for one game language. You do not need to copy every original file: add only the values you want to translate.

Start with one translated name#

If the NPC is called Rei, add a locale/th/Rei.toml file beside the original Rei.toml:

text
NPCs/Rei/
├── Rei.toml
└── locale/
    └── th/
        └── Rei.toml

Put this in the locale file:

toml
DisplayName = "เรย์"

That is a complete translation file. Keep the internal NPC name (Name = "Rei") unchanged; translate DisplayName, which is what players see. A locale file does not create another NPC.

Choosing the language folder#

The folder name is a language code, not a translated language name:

text
locale/th/       Thai
locale/es-ES/    Spanish (Spain)
locale/pt-BR/    Portuguese (Brazil)

Locale folders are layered. For es-ES, NPC Helper reads locale/es/ first and then locale/es-ES/ on top of it, so a regional folder only needs the texts that differ from its language folder. Base text comes underneath both. If no folder has a translation for a key, the original value remains.

Before 2.3.0 only the most specific folder was read, so a partial pt-BR folder hid the rest of pt. That is no longer the case.

English does not use a locale overlay. Folder matching is case-insensitive.

Which files go where?#

The locale folder mirrors the NPC's original files. Use the same filenames:

File What you can translate
Rei.toml DisplayName, and selected NPC data such as gift tastes
Dialogue.toml NPC dialogue
Schedule.toml A language-specific daily schedule, if you really need one
Marriage.toml Engagement dialogue, spouse dialogue, and wedding vows

For example:

text
NPCs/Rei/
├── Rei.toml
├── Dialogue.toml
├── Schedule.toml
├── Marriage.toml
└── locale/
    └── th/
        ├── Rei.toml
        ├── Dialogue.toml
        └── Marriage.toml

There is deliberately no Schedule.toml in this example: the original schedule is already suitable for Thai, so it does not need an override.

Translating dialogue#

Create locale/th/Dialogue.toml. Use the same keys as the original [Dialogue] table, and include only the lines you are translating:

toml
[Dialogue]
Introduction = "ไง... ฉันชื่อเรย์ เป็นผู้ช่วยหมออยู่ที่คลินิก ถ้าจะมาตรวจร่างกายก็ไม่ต้องเกร็งหรอกน่า || แต่ถ้าฉุกเฉิน ก็รีบพุ่งไปห้องฉุกเฉินนู่น... ให้ไวเลยนะ"
Mon2 = "เจอกันอีกแล้วนะ วันนี้พยายามอย่าหาเรื่องเจ็บตัวกลับมาล่ะ"
Rainy = "ฝนตกทีไรกลิ่นทุกอย่างดูสะอาดขึ้น... แต่บางทีก็เหม็นกว่าเดิม พกร่มมาด้วยล่ะ"

The keys above are examples from the example translation. Introduction, Mon2, and Rainy are keys, not labels to translate. The text to the right of = is the part players read. Any original dialogue key you leave out continues to use the original line.

Keep the game's dialogue tokens when translating a line. For example, @ is replaced with the player's name, $h is a dialogue mood token, and || separates alternative text. Do not remove or translate a token unless you intend to change its behavior.

Translating the NPC file and gift tastes#

You can change a display name without copying the rest of Rei.toml:

toml
DisplayName = "เรย์"

You can also override a complete gift-taste category. A category you include replaces that whole category; its list is not appended to the original list:

toml
[GiftTastes]
Love = ["Diamond", "Coffee", "Starfruit", "Peach"]

This example replaces Rei's entire Love list. If you only want to translate dialogue and the displayed name, leave [GiftTastes] out. Keep item names and other game data valid for the game; do not translate internal identifiers just because they appear in a TOML file.

Schedules: the important exception#

Most translated values override matching keys and leave all other original values alone. Schedules do not work that way. If a locale Schedule.toml contains at least one valid entry in [Schedule], that localized schedule replaces the original schedule. It does not add a Monday route to the original week's routes.

toml
[Schedule]
Mon = [
  "600 Hospital 1 18 1",
  "1100 Hospital 9 9 2",
]

This is a complete schedule override containing only the Monday route shown. Do not use a partial example like this if the NPC also needs their original Tuesday-to-Sunday routes: copy and provide all routes you want the NPC to keep. An empty [Schedule] table, or one without valid entries, does not replace the original schedule.

Usually, dialogue is what needs translation; leave Schedule.toml out of the locale folder unless the schedule itself should differ by language. The married schedule follows the same replacement rule and is the [Marriage] table in Schedule.toml.

Translating engagement, spouse dialogue, and vows#

These are all in locale/th/Marriage.toml, but each kind of text has its own table:

toml
[Engagement]
AcceptMermaidPendant = "นี่มัน... จี้นางเงือกใช่ไหม? @... เธอกำลังขอฉันแต่งงานเหรอ? ฉัน... ตอบตกลง"

[Dialogue]
Rei0 = "ฉันยังไม่ชินเลยว่าเราหมั้นกันแล้ว ฉันยังนึกถึงตอนนั้นซ้ำๆ อยู่เลย.$l"
Good_0 = "ชีวิตกับเธอยังเหมือนฝันอยู่เลย... ในทางที่ดีนะ.$l"

[Wedding]
Vows = [
  "หึ... ไม่นึกเลยว่าวันนี้จะเป็นฉันเองที่ต้องจับชีพจรตัวเอง มันเต้นแรงชะมัด$h",
  "ฉันเย็บแผลให้คนมานับไม่ถ้วน สั่งให้ทุกคนหายใจลึกๆ... แต่ไม่เคยบอกใครเลยว่า ฉันเป็นของเธอแล้วนะ @$l",
  "คำสัญญาของฉันง่ายๆ เธอล้มเมื่อไหร่ฉันจะรักษา ทำงานหนักเกินไปฉันจะดุ แล้วฉันก็จะอยู่ข้างๆ เธอตลอด... นี่แหละใบสั่งยาของฉัน$l",
]

[Engagement] and [Dialogue] override matching lines; spouse dialogue you do not include remains unchanged. A non-empty valid [Wedding] Vows list replaces the original vows as a list. For the married daily route, use [Marriage] in Schedule.toml instead; [Marriage] is not the schedule table to use in Marriage.toml.

Translating heart events and festival lines#

Events.toml and Festivals.toml in a locale folder translate heart events and festival lines.

For events, each [EventName] table has Texts: the translated lines in the order they are said, counting spoken lines and message steps. Where the characters stand and what they do stay those of the base file.

toml
[RainyClinic]
Texts = [
  "Entraste huyendo de la lluvia.$h",
  "...No le digas a la doctora jefa que dije eso.$9",
]

For festivals, the tables work as in the base file and replace Dialogue and SpouseDialogue.

A wrong number of lines, an event or festival the base pack does not have, or a table without Texts is reported. Lines left out keep the original words.

Distributing a translation separately#

A translation can be released independently from the NPC pack. Include only locale TOML files; they override the matching NPC's text and do not add another NPC. Use the same NPCs/<NPC name>/locale/<language>/ path in either distribution:

text
Translation Pack/
├── manifest.json
├── mod.toml                 optional: NPCs = [], Locales, Translates
└── NPCs/
    └── Rei/
        └── locale/
            └── th/
                ├── Rei.toml
                ├── Dialogue.toml
                └── Marriage.toml

Mod-manager archive#

Keep manifest.json, mod.toml and NPCs/ together in the translation pack folder, as shown above, with ContentPackFor set to Framework.Mod.NpcHelper. Install it as a separate mod with your mod manager. NPC Helper asks SMAPI for its content packs and checks only NPCs/<NPC name>/locale/<code>/ inside each; it does not scan the Mods folder, and it never loads NPC definitions from a translation pack. A translation mod that is not a content pack for NPC Helper is not found.

mod.toml takes optional settings that help NPC Helper report mistakes:

  • NPCs = [] states that the pack intentionally defines no NPCs.
  • Locales = ["th", "pt-BR"] lists the languages the pack provides. A listed language with no files is reported.
  • Translates = ["Rei"] lists the NPCs the pack translates. If none of them is loaded, NPC Helper says so at startup and suggests the NPC you probably meant.

npchelper new translation writes both lists for you.

The older "manual" form#

Before 2.1 a translation could be shipped as locale files placed inside the NPC mod's own folder, with a separate manifest-only folder for update checks. That form is only accepted for one existing translation pack and will be removed. A manifest-only pack with NPCs = [] under any other ID is reported as a pack that does nothing. Always make new translations as content packs, as shown above. npchelper new translation creates the correct form.

Updating and removing#

To update a translation, replace its folder with the new version. To remove it, delete its folder from Mods. Players should install only one copy of a translation.

A simple workflow#

  1. Copy the NPC folder's structure under locale/<language-code>/.
  2. Start with Rei.toml and Dialogue.toml; add only the lines you actually translate.
  3. Keep each translated key exactly aligned with the original key, and leave internal names and game identifiers unchanged.
  4. Add Marriage.toml only if you are translating marriage text. Add Schedule.toml only if you intend to replace the schedule.
  5. Launch the game with that language selected and check the NPC in-game. If a line is still in the original language, check the locale code, file path, filename, and key.

Common questions#

Do I need to copy every original dialogue line? No. Untranslated keys use the original text.

Does locale/es-ES/ combine with locale/es/? Yes. es/ is read first and es-ES/ overrides it, so keep shared Spanish text in es/ and only the regional differences in es-ES/.

What if two translation packs define the same key? The NPC's own locale folders are merged first, then matching translation packs in path order; the later pack wins.

What does npchelper validate check? Folder and file names the game would silently ignore (th_TH, Dialog.toml, a .txt file, translations placed directly in locale/) and translation folders whose NPC does not exist. npchelper pack refuses to zip a pack with these problems unless --force is given.

What happens when the language changes in game? NPC Helper rebuilds every file-based NPC from disk (base plus overlay) and refreshes the affected assets. If a rebuild fails, the previous version of that NPC is kept and a warning is logged.

Will changing DisplayName rename the NPC internally? No. Keep Name and the NPC folder name unchanged; translate DisplayName.

Can I translate images here? No. Sprites and portraits are not localized.

Why did my original schedule disappear? A valid localized schedule replaces it. Copy every route you intend to retain, or remove the locale Schedule.toml file.

What if two translation packs change the same line? The NPC's own locale files are applied first, followed by separate matching locale packs. If several packs override the same key, one wins based on the packs' path order. Avoid installing multiple translations for the same NPC and language.