Modding:Custom languages

From Stardew Valley Wiki
Jump to navigation Jump to search

Index

The following describes the upcoming SMAPI 3.13.0, and may change before release.

This page explains how to create custom languages in Stardew Valley 1.5.5+. This is an advanced guide for modders.

To translate text into an existing language, see Modding:Translations instead.

Add a custom language

Data format

You can add custom languages by editing the Data/AdditionalLanguages asset. Each entry consists of an object with these fields:

field description
ID A unique identifier for your language. This isn't shown in-game. The recommended format is <your name>.<mod name>, with no spaces or special characters.
LanguageCode The language code for this localization. This should ideally be an ISO 639-1 code, with only letters and hyphens. You should avoid commas for compatibility with Content Patcher packs checking the {{Language}} token.
ButtonTexture The asset name for a 174x78 pixel texture containing the button of the language for language selection menu. The top half of the sprite is the default state, while the bottom half is the hover state.
TimeFormat A string which describes the in-game time format, with tokens replaced by in-game values. For example, [HOURS_12]:[MINUTES] [AM_PM] would show 12:00 PM at noon.

The valid tokens are:

  • [HOURS_12]: hours in 12-hour format, where midnight and noon are both "12".
  • [HOURS_12_0]: hours in 12-hour format, where midnight and noon are both "0".
  • [HOURS_24]: hours in 24-hour format, where midnight is "0" and noon is "12".
  • [HOURS_24_00]: hours in 24-hour format with zero-padding, where midnight is "00" and noon is "12".
  • [MINUTES]: minutes with zero-padding.
  • [AM_PM]: the localized text for "am" or "pm" (taken from Strings\\StringsFromCSFiles:DayTimeMoneyBox.cs.10370 and DayTimeMoneyBox.cs.10371 respectively). The game shows "pm" between noon and 11:59pm inclusively; it shows "am" otherwise.
ClockTimeFormat A string which describes the in-game time format. Equivalent to TimeFormat, but used for the in-game clock.
ClockDateFormat A string which describes the in-game date format as shown in the in-game clock, with tokens replaced by in-game values. For example, [DAY_OF_WEEK]. [DAY_OF_MONTH] would show Mon. 1.

The valid tokens are:

  • [DAY_OF_WEEK]: the abbreviated day of week as returned by Game1.shortDayDisplayNameFromDayOfSeason (like Mon for Monday).
  • [DAY_OF_MONTH]: the numerical day of the month.
FontApplyYOffset (optional) Whether to shift the font up by four pixels (multiplied by the FontPixelZoom), to better align languages with larger characters like Chinese and Japanese. Default false.
NumberComma (optional) The string to use as the thousands separator (like "," for 5,000,000). Defaults to a comma.
SmallFontLineSpacing (optional) The line spacing value used by smallFont. Defaults to 26.
UseGenderedCharacterTranslations (optional) Whether the social tab and gift log will use gender-specific translations (like the vanilla Portuguese language). Defaults to false.

Specifically, this affects the Strings\StringsFromCSFiles:SocialPage.cs.11635 translation ("(Single)"). When enabled, it can contain male and female translations separated by /, like the vanilla Portuguese translation: "(solteiro)/(solteira)".

custom font fields See add a custom font below.

Example

This Content Patcher pack would add Esperanto to the game. You should change Pathoschild.Esperanto to your mod's actual ID.

{
    "Format": "1.23.0",
    "Changes": [
        // define language
        {
            "Action": "EditData",
            "Target": "Data/AdditionalLanguages",
            "Entries": {
                "Pathoschild.Esperanto": { // for technical reasons, you need to specify the ID here *and* in the "ID" field
                    "ID": "Pathoschild.Esperanto",
                    "LanguageCode": "eo",
                    "ButtonTexture": "Mods/Pathoschild.Esperanto/Button",
                    "UseLatinFont": true,
                    "TimeFormat": "[HOURS_24_00]:[MINUTES]",
                    "ClockTimeFormat": "[HOURS_24_00]:[MINUTES]",
                    "ClockDateFormat": "[DAY_OF_WEEK] [DAY_OF_MONTH]"
                }
            }
        },

        // load button texture
        {
            "Action": "Load",
            "Target": "Mods/Pathoschild.Esperanto/Button",
            "FromFile": "assets/button.png"
        }
    ]
}

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:

{
    "Action": "EditData",
    "Target": "Strings/StringsFromCSFiles",
    "Entries": {
        "Game1.cs.3043": "Lundo",
        "Game1.cs.3044": "Mardo",
        ...
    },
    "When": {
        "Language": "eo"
    }
}

Add a custom font

You can provide your own Bitmap font for your custom language, which maps arbitrary Unicode characters to sprites in your font texture. You can unpack your game's Content folder and look at the Chinese, Japanese, Korean, and Russian fonts in the Fonts folder for examples of how this looks in practice.

Data format

To enable a custom font, add these three extra fields to your Data/AdditionalLanguages entry:

field description
UseLatinFont Whether the language uses the game's default fonts. Set to false to enable a custom font.
FontFile The asset name for your .fnt font data file (see font files below). This must be the asset's name in the game's Content folder, not the file path in your content pack; see the example below.
FontPixelZoom 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 Bitmap font generator to generate these files from it.

Font data
Each font must have a text (XML) file with the .fnt extension which describes the font.
For example, here's the Content/Fonts/Japanese.fnt file (with most of the characters stripped out for brevity):
<?xml version="1.0"?>
<font>
  <info face="SetoFont-SP" size="24" bold="0" italic="0" charset="" unicode="1" stretchH="100" smooth="1" aa="1" padding="0,0,0,0" spacing="1,1" outline="0"/>
  <common lineHeight="24" base="21" scaleW="1024" scaleH="1024" pages="2" packed="0" alphaChnl="0" redChnl="4" greenChnl="4" blueChnl="4"/>
  <pages>
    <page id="0" file="Japanese_0" />
    <page id="1" file="Japanese_1" />
  </pages>
  <chars count="2514">
    ...
    <char id="37347" x="100" y="265" width="24" height="22" xoffset="0" yoffset="1" xadvance="24" page="0" chnl="15" />
    ...
  </chars>
</font>
See the official format documentation to understand all the options, but at a high level:
field description
info Describes the font itself: the name, TrueType size, padding and spacing, etc.
common Provides common info which applies to all of the characters, like the line height.
pages Lists the sprite textures that are part of the font. In the above example, the Japanese character sprites are split into two images: Japanese_0.png and Japanese_1.png. Each character in chars specifies which page it's on.
chars Maps each Unicode character you'll use in-game to the sprite font. The example above defines one character with these char fields:
char attribute explanation
id The decimal Unicode ID for the character (e.g., 37347 in the example above is 釣). You can search characters in Unicodepedia to find their Unicode IDs.
x
y
width
height
The top-left position and size of the character sprite in the page image, measured in pixels.
xoffset
yoffset
A pixel offset to apply to the character when it's drawn to the screen.
xadvance When drawing multiple characters to the screen, how many pixels drawing this character should advance the cursor.
page The ID of the page image which contains the sprite, as defined in the pages field.
chnl The color channel for which the sprite has data. (This is always 15 for all channels in Stardew Valley's current fonts.)
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 Content/Fonts/Japanese_0 file (with a black background so the sprites are visible):
Modding - example font texture.png

Example

If you're using Content Patcher, your content pack should look something like this with the files described above:

📁 Your Mod Name/
  🗎 content.json
  🗎 manifest.json
  📁 assets/
    🗎 YourLanguage.fnt
    🗎 YourLanguage_0.png

Now you just need to make them available through the game's Content/Fonts folder. Make sure the target for the .fnt file matches what you specified via FontFile in the language data, and the target for the image matches what you specified via pages in the font data.

For example, here's the previous Esperanto example with a custom font (note the UseLatinFont and FontFile fields in the language data, and the two new patches at the bottom):

{
    "Format": "1.23.0",
    "Changes": [
        // define language
        {
            "Action": "EditData",
            "Target": "Data/AdditionalLanguages",
            "Entries": {
                "Pathoschild.Esperanto": { // for technical reasons, you need to specify the ID here *and* in the "ID" field
                    "ID": "Pathoschild.Esperanto",
                    "LanguageCode": "eo",
                    "ButtonTexture": "Mods/Pathoschild.Esperanto/Button",
                    "UseLatinFont": false,
                    "FontFile": "Fonts/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/Pathoschild.Esperanto/Button",
            "FromFile": "assets/button.png"
        }

        // load font files
        {
            "Action": "Load",
            "Target": "Fonts/Esperanto",
            "FromFile": "assets/Esperanto.fnt"
        },
        {
            "Action": "Load",
            "Target": "Fonts/Esperanto_0",
            "FromFile": "assets/Esperanto_0.png"
        }
    ]
}

See also