Changes

Jump to navigation Jump to search
no edit summary
Line 1: Line 1:  
{{../../header}}
 
{{../../header}}
   −
===Translation===
+
The translation API lets you translate your mod, and include all languages in one release package for SMAPI to use automatically based on the game language.
The translation API lets you translate your mod into the player's current language, accounting for locale fallback automatically (e.g. if a translation isn't available in <tt>pt-BR.json</tt>, SMAPI will check <tt>pt.json</tt> and <tt>default.json</tt>). Translations can be a simple string, or they can include tokens to inject values into the translation.
     −
<dl>
+
==Overview==
<dt>File structure</dt>
+
SMAPI reads translations from files in your mod folder. When you request a translation, it will automatically handle locale fallback (''e.g.,'' if a translation isn't available in <samp>pt-BR.json</samp>, SMAPI will check <samp>pt.json</samp> and <samp>default.json</samp>). Translations can be a simple string, or they can include tokens to inject values into the translation.
<dd>SMAPI reads translations from JSON files in a structure like this:
+
 
 +
==i18n folder==
 +
===File structure===
 +
SMAPI reads translations from JSON files in an <samp>i18n</samp> subfolder in your mod folder:
 
<pre>
 
<pre>
 
YourMod/
 
YourMod/
Line 17: Line 19:  
</pre>
 
</pre>
   −
The <tt>default.json</tt> file should contain a flat key→value lookup with your default text. Each key is case-insensitive, and can contain alphanumeric, underscore, hyphen, and dot characters. Feel free to add JavaScript comments to organise or document your translations. For example:
+
The <samp>default.json</samp> file includes the default text that will be shown if a more specific translation isn't available, and you create a separate file for each language. Each translation file should have one of these file names:
<source lang="javascript">
  −
{
  −
    // example translations
  −
    "item-type.label": "Item type",
  −
    "item-type.fruit-tree": "{{fruitName}} tree",
  −
}
  −
</source>
  −
 
  −
You can then add translation files for each language you want to support, by copying the <tt>default.json</tt> file and translating its values. Each translation file should have one of these file names:
      
{| class="wikitable"
 
{| class="wikitable"
Line 34: Line 27:  
|-
 
|-
 
| Chinese
 
| Chinese
| <tt>zh.json</tt>
+
| <samp>zh.json</samp>
 +
|-
 +
| French
 +
| <samp>fr.json</samp>
 
|-
 
|-
 
| German
 
| German
| <tt>de.json</tt>
+
| <samp>de.json</samp>
 +
|-
 +
| Hungarian
 +
| <samp>hu.json</samp>
 +
|-
 +
| Italian
 +
| <samp>it.json</samp>
 
|-
 
|-
 
| Japanese
 
| Japanese
| <tt>ja.json</tt>
+
| <samp>ja.json</samp>
 +
|-
 +
| Korean
 +
| <samp>ko.json</samp>
 
|-
 
|-
 
| Portuguese
 
| Portuguese
| <tt>pt.json</tt>
+
| <samp>pt.json</samp>
 
|-
 
|-
 
| Russian
 
| Russian
| <tt>ru.json</tt>
+
| <samp>ru.json</samp>
 
|-
 
|-
 
| Spanish
 
| Spanish
| <tt>es.json</tt>
+
| <samp>es.json</samp>
|}</dd>
+
|-
 +
| Turkish
 +
| <samp>tr.json</samp>
 +
|}
   −
<dt>Reading translations</dt>
+
For a [[Modding:Custom languages|custom language]], use its <samp>LanguageCode</samp> value in the filename.
<dd>Once your i18n files are set up, you can read translations for the current locale:
+
 
<source lang="c#">
+
===File format===
 +
Each <samp>.json</samp> file should contain a flat key→value lookup with your default text. Each key is case-insensitive, and can contain alphanumeric, underscore, hyphen, and dot characters. Feel free to add JavaScript comments to organise or document your translations. For example:
 +
<syntaxhighlight lang="javascript">
 +
{
 +
    // example translations
 +
    "item-type.label": "Item type",
 +
    "item-type.fruit-tree": "{{fruitName}} tree",
 +
}
 +
</syntaxhighlight>
 +
 
 +
The <code><nowiki>{{fruitName}}</nowiki></code> in the above example is a token. You can add any tokens you want (each having only letters in the name), and replace them with a different value in code (see [[#Reading translations|''reading translations'']] below).
 +
 
 +
===Tips for translators===
 +
* Save i18n files with UTF-8 encoding to avoid broken symbols in-game.
 +
* Type <code>reload_i18n</code> into the SMAPI console and hit enter to reload translations without exiting the game. (If a mod internally cached a translation, it may not be updated.)
 +
 
 +
==Reading translations==
 +
===Built-in API===
 +
Once your i18n files are set up, you can read translations for the current locale:
 +
<syntaxhighlight lang="c#">
 
// read a simple translation
 
// read a simple translation
 
string label = helper.Translation.Get("item-type.label");
 
string label = helper.Translation.Get("item-type.label");
Line 60: Line 87:  
// read a translation which uses tokens (accepts an anonymous object, dictionary, or model)
 
// read a translation which uses tokens (accepts an anonymous object, dictionary, or model)
 
string text = helper.Translation.Get("item-type.fruit-tree", new { fruitName = "apple" });
 
string text = helper.Translation.Get("item-type.fruit-tree", new { fruitName = "apple" });
</source>
+
</syntaxhighlight>
   −
The <tt>helper.Translate(…)</tt> method returns a fluent interface — you can keep calling methods on its return value to customise the translation. (See IntelliSense for a description of the available methods.) To get the text, simply assign it to a string:
+
The <samp>helper.Translate(…)</samp> method returns a fluent interface — you can keep calling methods on its return value to customise the translation. (See IntelliSense for a description of the available methods.) To get the text, just assign it to a string:
<source lang="c#">
+
<syntaxhighlight lang="c#">
 
// use fluent chain
 
// use fluent chain
string text = helper.Translate(key).Tokens(tokens).Tokens(moreTokens).Assert();
+
string text = helper.Translation.Get(key).Tokens(tokens).Tokens(moreTokens).Default("missing translation?");
</source>
+
</syntaxhighlight>
 +
 
 +
===Strongly-typed API===
 +
The built-in API doesn't have build-time validation. For example, if you set a <code>fruitName</code> argument but the translation actually uses <code><nowiki>{{fruit}}</nowiki></code>, you won't know until you test each translation in-game and see the broken message. That's fine for most mods, but can be an issue with larger mods that have hundreds of translations across many different UI flows.
 +
 
 +
The optional [https://github.com/Pathoschild/SMAPI-ModTranslationClassBuilder#readme SMAPI mod translation class builder] package lets you generate a strongly-typed class to read translations like this instead:
 +
<syntaxhighlight lang="c#">
 +
string label = I18n.ItemType_Label();
 +
string text = I18n.ItemType_FruitTree(fruitName: "apple");
 +
</syntaxhighlight>
   −
If your code has a lot of translation calls, you can make it less verbose by aliasing the translation helper:
+
If a translation breaks, you'll know immediately since it won't compile.
<source lang="c#">
  −
var i18n = helper.Translation;
     −
i18n.Get("item-type.fruit-tree", new { fruitName = i18n.Get("apple") });
+
==See also==
</source></dd>
+
[https://gist.github.com/Pathoschild/4e0af42158583983a4206d4d734bfc0b LINQ script] to format an event for translations
   −
<dt>Tips for translators</dt>
+
[[zh:模组:制作指南/APIs/Translation]]
<dd>
  −
* Save i18n files with UTF-8 encoding to avoid broken symbols in-game.
  −
* Type <code>reload_i18n</code> into the SMAPI console and hit enter to reload translations without exiting the game. (If a mod internally cached a translation, it may not be updated.)
  −
</dd>
  −
</dl>
 
105,906

edits

Navigation menu