Changes

Jump to navigation Jump to search
added See Also section to include link to Pathoschild script on formatting events for translations
Line 4: Line 4:     
==Overview==
 
==Overview==
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 <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.
+
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.
    
==i18n folder==
 
==i18n folder==
 
===File structure===
 
===File structure===
SMAPI reads translations from JSON files in an <tt>i18n</tt> subfolder in your mod folder:
+
SMAPI reads translations from JSON files in an <samp>i18n</samp> subfolder in your mod folder:
 
<pre>
 
<pre>
 
YourMod/
 
YourMod/
Line 19: Line 19:  
</pre>
 
</pre>
   −
The <tt>default.json</tt> 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:
+
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:
    
{| class="wikitable"
 
{| class="wikitable"
Line 27: 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>
 +
|-
 +
| Turkish
 +
| <samp>tr.json</samp>
 
|}
 
|}
 +
 +
For a [[Modding:Custom languages|custom language]], use its <samp>LanguageCode</samp> value in the filename.
    
===File format===
 
===File format===
Each <tt>.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:
+
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:
<source lang="javascript">
+
<syntaxhighlight lang="javascript">
 
{
 
{
 
     // example translations
 
     // example translations
Line 53: Line 70:  
     "item-type.fruit-tree": "{{fruitName}} tree",
 
     "item-type.fruit-tree": "{{fruitName}} tree",
 
}
 
}
</source>
+
</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).
 
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).
Line 62: Line 79:     
==Reading translations==
 
==Reading translations==
 +
===Built-in API===
 
Once your i18n files are set up, you can read translations for the current locale:
 
Once your i18n files are set up, you can read translations for the current locale:
<source lang="c#">
+
<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 69: 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.
   −
If your code has a lot of translation calls, you can make it less verbose by aliasing the translation helper:
+
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:
<source lang="c#">
+
<syntaxhighlight lang="c#">
var i18n = helper.Translation;
+
string label = I18n.ItemType_Label();
 +
string text = I18n.ItemType_FruitTree(fruitName: "apple");
 +
</syntaxhighlight>
   −
i18n.Get("item-type.fruit-tree", new { fruitName = i18n.Get("apple") });
+
If a translation breaks, you'll know immediately since it won't compile.
</source>
     −
{{modding guide footer
+
==See also==
|prev = [[Modding:Modder Guide/APIs|SMAPI reference]]
+
[https://gist.github.com/Pathoschild/4e0af42158583983a4206d4d734bfc0b LINQ script] to format an event for translations
|next =
  −
}}
 
94

edits

Navigation menu