Changes

update for unique string IDs and {{ModId}}
Line 15: Line 15:  
|-
 
|-
 
| <samp>ID</samp>
 
| <samp>ID</samp>
| A unique identifier for your language. This isn't shown in-game. The recommended format is <code>&lt;your name&gt;.&lt;mod name&gt;</code>, with no spaces or special characters.
+
| A [[Modding:Common data field types#Unique string ID|unique string ID]] for your language. This isn't shown in-game.
 
|-
 
|-
 
| <samp>LanguageCode</samp>
 
| <samp>LanguageCode</samp>
Line 43: Line 43:  
* <code>[DAY_OF_WEEK]</code>: the abbreviated day of week as returned by <code>Game1.shortDayDisplayNameFromDayOfSeason</code> (like <samp>Mon</samp> for Monday).
 
* <code>[DAY_OF_WEEK]</code>: the abbreviated day of week as returned by <code>Game1.shortDayDisplayNameFromDayOfSeason</code> (like <samp>Mon</samp> for Monday).
 
* <code>[DAY_OF_MONTH]</code>: the numerical day of the month.
 
* <code>[DAY_OF_MONTH]</code>: the numerical day of the month.
|-
  −
| <samp>UseLatinFont</samp>
  −
| Whether the language uses the game's default fonts. If set to <samp>false</samp>, you must set the <samp>FontFile</samp> field.
  −
|-
  −
| <samp>FontFile</samp>
  −
| ''(optional)'' The asset name for the font file to use (if <samp>UseLatinFont</samp> is <samp>false</samp>). See [[#Custom font|''custom font'']] below.
  −
|-
  −
| <samp>FontPixelZoom</samp>
  −
| ''(optional)'' A factor by while to multiply the font size.
   
|-
 
|-
 
| <samp>FontApplyYOffset</samp>
 
| <samp>FontApplyYOffset</samp>
| ''(optional)'' Whether to shift the font up by four pixels (multiplied by the <samp>FontPixelZoom</samp>), to better align languages with larger characters like Chinese and Japanese.
+
| ''(optional)'' Whether to shift the font up by four pixels (multiplied by the <samp>FontPixelZoom</samp>), to better align languages with larger characters like Chinese and Japanese. Default false.
 
|-
 
|-
 
| <samp>NumberComma</samp>
 
| <samp>NumberComma</samp>
| ''(optional)'' The string to use as the thousands separator (e.g. <code>","</code> for <code>5,000,000</code>). Defaults to a comma.
+
| ''(optional)'' The string to use as the thousands separator (like <code>","</code> for <code>5,000,000</code>). Defaults to a comma.
 
|-
 
|-
 
| <samp>SmallFontLineSpacing</samp>
 
| <samp>SmallFontLineSpacing</samp>
Line 66: Line 57:     
Specifically, this affects the <samp>Strings\StringsFromCSFiles:SocialPage.cs.11635</samp> translation ("''(Single)''"). When enabled, it can contain male and female translations separated by <code>/</code>, like the vanilla Portuguese translation: "''(solteiro)/(solteira)''".
 
Specifically, this affects the <samp>Strings\StringsFromCSFiles:SocialPage.cs.11635</samp> translation ("''(Single)''"). When enabled, it can contain male and female translations separated by <code>/</code>, like the vanilla Portuguese translation: "''(solteiro)/(solteira)''".
 +
|-
 +
| ''custom font fields''
 +
| See ''[[#Add a custom font|add a custom font]]'' below.
 
|}
 
|}
    
===Example===
 
===Example===
This Content Patcher pack would add Esperanto to the game. '''You should change <samp>Pathoschild.Esperanto</samp> to your mod's actual ID.'''
+
This Content Patcher pack would add Esperanto to the game. (<code><nowiki>{{ModId}}</nowiki></code> is a token, which will be replaced with your mod ID automatically.)
 
{{#tag:syntaxhighlight|
 
{{#tag:syntaxhighlight|
 
{
 
{
     "Format": "{{Content Patcher version}}",
+
     "Format": "{{Content Patcher version}}",<nowiki>
 
     "Changes": [
 
     "Changes": [
 
         // define language
 
         // define language
Line 79: Line 73:  
             "Target": "Data/AdditionalLanguages",
 
             "Target": "Data/AdditionalLanguages",
 
             "Entries": {
 
             "Entries": {
                 "Pathoschild.Esperanto": { // for technical reasons, you need to specify the ID here *and* in the "ID" field
+
                 "{{ModId}}_Esperanto": { // for technical reasons, you need to specify the ID here *and* in the "ID" field
                     "ID": "Pathoschild.Esperanto",
+
                     "ID": "{{ModId}}_Esperanto",
 
                     "LanguageCode": "eo",
 
                     "LanguageCode": "eo",
                     "ButtonTexture": "Mods/Pathoschild.Esperanto/Button",
+
                     "ButtonTexture": "Mods/{{ModId}}/Button",
 
                     "UseLatinFont": true,
 
                     "UseLatinFont": true,
 
                     "TimeFormat": "[HOURS_24_00]:[MINUTES]",
 
                     "TimeFormat": "[HOURS_24_00]:[MINUTES]",
Line 94: Line 88:  
         {
 
         {
 
             "Action": "Load",
 
             "Action": "Load",
             "Target": "Mods/Pathoschild.Esperanto/Button",
+
             "Target": "Mods/{{ModId}}/Button",
 
             "FromFile": "assets/button.png"
 
             "FromFile": "assets/button.png"
 
         }
 
         }
 
     ]
 
     ]
}|lang=javascript}}
+
}</nowiki>|lang=javascript}}
    
Once the language is defined, you can add translations to the game by patching game assets like usual, and use the language code you specified above. For example:
 
Once the language is defined, you can add translations to the game by patching game assets like usual, and use the language code you specified above. For example:
Line 116: Line 110:  
</syntaxhighlight>
 
</syntaxhighlight>
   −
==Custom font==
+
==Add a custom font==
If you set <samp>UseLatinFont: false</samp> in the language data, you can provide your own Bitmap font with the <samp>FontFile</samp> field. This lets you map arbitrary Unicode characters to sprites in your font texture. You can [[Modding:Editing XNB files#Unpack game files|unpack your game's <samp>Content</samp> folder]] and look at the Chinese, Japanese, Korean, and Russian fonts in the <samp>Fonts</samp> folder for some examples.
+
You can provide your own Bitmap font for your custom language, which maps arbitrary Unicode characters to sprites in your font texture. You can [[Modding:Editing XNB files#Unpack game files|unpack your game's <samp>Content</samp> folder]] and look at the Chinese, Japanese, Korean, and Russian fonts in the <samp>Fonts</samp> folder for examples of how this looks in practice.
 +
 
 +
===Data format===
 +
To enable a custom font, add these three extra fields to [[#Add a custom language|your <samp>Data/AdditionalLanguages</samp> entry]]:
 +
 
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! description
 +
|-
 +
| <samp>UseLatinFont</samp>
 +
| Whether the language uses the game's default fonts. '''Set to <samp>false</samp>''' to enable a custom font.
 +
|-
 +
| <samp>FontFile</samp>
 +
| The asset name for your <samp>.fnt</samp> font data file (see [[#Font files|''font files'']] below). This must be the asset's name in the game's <samp>Content</samp> folder, not the file path in your content pack; see [[#Example 2|the example below]].
 +
|-
 +
| <samp>FontPixelZoom</samp>
 +
| A factor by which to multiply the font size. The recommended baseline is 1.5, but you can adjust it to make your text smaller or bigger in-game.
 +
|}
 +
 
 +
===Font files===
 +
Note: if your language has a TrueType font available, you can use the [https://www.angelcode.com/products/bmfont/ Bitmap font generator] to generate these files from it.
 +
 
 +
; Font data
 +
: Each font must have a text (XML) file with the <samp>.fnt</samp> extension which describes the font.
   −
For example, here's the <samp>Content/Fonts/Japanese.fnt</samp> file (with most of the characters stripped out for brevity):
+
: For example, here's the <samp>Content/Fonts/Japanese.fnt</samp> file (with most of the characters stripped out for brevity):
   −
<syntaxhighlight lang="xml">
+
: <syntaxhighlight lang="xml">
 
<?xml version="1.0"?>
 
<?xml version="1.0"?>
 
<font>
 
<font>
Line 138: Line 156:  
</syntaxhighlight>
 
</syntaxhighlight>
   −
See the [https://www.angelcode.com/products/bmfont/doc/file_format.html official format documentation] to understand all the options, but at a high level:
+
: See the [https://www.angelcode.com/products/bmfont/doc/file_format.html official format documentation] to understand all the options, but at a high level:
   −
{| class="wikitable"
+
: {| class="wikitable"
 
|-
 
|-
 
! field
 
! field
Line 157: Line 175:  
| Maps each Unicode character you'll use in-game to the sprite font. The example above defines one character with these <samp>char</samp> fields:
 
| Maps each Unicode character you'll use in-game to the sprite font. The example above defines one character with these <samp>char</samp> fields:
   −
{| class="wikitable"
+
: {| class="wikitable"
 
|-
 
|-
 
! char attribute
 
! char attribute
Line 163: Line 181:  
|-
 
|-
 
| <samp>id</samp>
 
| <samp>id</samp>
| The decimal Unicode ID for the character (e.g. 37347 in the example above is 釣). You can search characters in [https://www.unicodepedia.com/unicode/cjk-unified-ideographs/91e3/cjk-unified-ideograph-91e3/ Unicodepedia] to find their Unicode IDs.
+
| The decimal Unicode ID for the character (''e.g.,'' 37347 in the example above is 釣). You can search characters in [https://www.unicodepedia.com/unicode/cjk-unified-ideographs/91e3/cjk-unified-ideograph-91e3/ Unicodepedia] to find their Unicode IDs.
 
|-
 
|-
 
| <samp>x</samp><br /><samp>y</samp><br /><samp>width</samp><br /><samp>height</samp>
 
| <samp>x</samp><br /><samp>y</samp><br /><samp>width</samp><br /><samp>height</samp>
Line 181: Line 199:  
|}
 
|}
 
|}
 
|}
 +
 +
; Font images
 +
: Each font also needs one or more images which contain the character sprites (white on a transparent background). The file names and sprite positions are defined in the above font data file.
 +
 +
: For example, here's the <samp>Content/Fonts/Japanese_0</samp> file (with a black background so the sprites are visible):
 +
: <div style="display: inline-block; background:#000;">[[File:Modding - example font texture.png|300px]]</div>
 +
 +
===Example===
 +
If you're using [[Modding:Content Patcher|Content Patcher]], your content pack should look something like this with the files described above:
 +
<pre>
 +
📁 Your Mod Name/
 +
  🗎 content.json
 +
  🗎 manifest.json
 +
  📁 assets/
 +
    🗎 YourLanguage.fnt
 +
    🗎 YourLanguage_0.png
 +
</pre>
 +
 +
Now you just need to make them available through the game's <samp>Content/Fonts</samp> folder. Make sure the target for the <samp>.fnt</samp> file matches what you specified via <samp>FontFile</samp> in the [[#Add a custom language|language data]], and the target for the image matches what you specified via <samp>pages</samp> in the [[#Font files|font data]].
 +
 +
For example, here's the previous Esperanto example with a custom font (note the <samp>UseLatinFont</samp> and <samp>FontFile</samp> fields in the language data, and the two new patches at the bottom):
 +
{{#tag:syntaxhighlight|
 +
{
 +
    "Format": "{{Content Patcher version}}",<nowiki>
 +
    "Changes": [
 +
        // define language
 +
        {
 +
            "Action": "EditData",
 +
            "Target": "Data/AdditionalLanguages",
 +
            "Entries": {
 +
                "{{ModId}}_Esperanto": { // for technical reasons, you need to specify the ID here *and* in the "ID" field
 +
                    "ID": "{{ModId}}_Esperanto",
 +
                    "LanguageCode": "eo",
 +
                    "ButtonTexture": "Mods/{{ModId}}/Button",
 +
                    "UseLatinFont": false,
 +
                    "FontFile": "Fonts/{{ModId}}/Esperanto",
 +
                    "TimeFormat": "[HOURS_24_00]:[MINUTES]",
 +
                    "ClockTimeFormat": "[HOURS_24_00]:[MINUTES]",
 +
                    "ClockDateFormat": "[DAY_OF_WEEK] [DAY_OF_MONTH]"
 +
                }
 +
            }
 +
        },
 +
 +
        // load button texture
 +
        {
 +
            "Action": "Load",
 +
            "Target": "Mods/{{ModId}}/Button",
 +
            "FromFile": "assets/button.png"
 +
        }
 +
 +
        // load font files
 +
        {
 +
            "Action": "Load",
 +
            "Target": "Fonts/{{ModId}}/Esperanto",
 +
            "FromFile": "assets/Esperanto.fnt"
 +
        },
 +
        {
 +
            "Action": "Load",
 +
            "Target": "Fonts/{{ModId}}/Esperanto_0",
 +
            "FromFile": "assets/Esperanto_0.png"
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
 +
 +
==Limitations==
 +
Custom languages must be available very early in the game startup, and won't be handled correctly if they're added later. That means:
 +
* For Content Patcher packs, they must be added without <samp>When</samp> conditions (or only using immutable conditions like config or <samp>HasMod</samp>).
 +
* For C# mods, they should be added in [[Modding:Modder Guide/APIs/Events#Game loop|<samp>GameLaunched</samp>]] or earlier.
    
==See also==
 
==See also==
translators
8,404

edits