Localizing Strings in Daggerfall Unity – Part 6

Localizing Strings in Daggerfall Unity – Part 1
Localizing Strings in Daggerfall Unity – Part 2
Localizing Strings in Daggerfall Unity – Part 3
Localizing Strings in Daggerfall Unity – Part 4
Localizing Strings in Daggerfall Unity – Part 5
Localizing Strings in Daggerfall Unity – Part 6

Custom Fonts

Note: Before progressing to this tutorial, please update source project to Daggerfall Unity 0.11.3 or later. This version has fixes required to complete this part in series.

In Part 3 of this series, we noted the Korean (ko) locale would print out question mark characters (?? ???) instead of proper glyphs.

This happens because Daggerfall Unity does not yet have an appropriate font asset to render these characters. The default fonts have a full complement of Latin characters but non-Latin languages require a new font to display their unique alphabet.

This tutorial will demonstrate how to add a custom Korean font with a Hangul alphabet to Daggerfall Unity, but the same process can be used to add Cyrillic fonts, Kanji fonts, or even just a custom default font.

The font we’ll be using is Noto Serif KR from Google Fonts. Click Download family on that page to download the font used in this tutorial, or substitute with another TTF/OTF font for your language.

Once downloaded, unzip the whole font family and locate NotoSerifKR-Regular.otf. This is the specific font we’ll be using. To start with, we’ll add this font to our Unity project.

  1. In Project view, navigate to our DemoTranslationMod/Resources folder.
  2. Drag and drop the NotoSerifKR-Regular.otf font into this folder with other resources. Unity will import this like below.

Create TextMeshPro Font

Daggerfall Unity uses TextMeshPro (TMP) fonts. Before we can see this font in game, we need to create a TMP font asset.

  1. Click Window menu > TextMeshPro > Font Asset Creator
  2. Set NotoSerifKR-Regular in Source Font File by clicking the circle selector on right-hand side then selecting font

Now we need to determine which character codes our TMP font will support. This will vary based on many factors unique to the target language, but the core concept is that we want to inform Font Asset Creator which character codes from your alphabet to compile into your TMP font. Any characters not added to TMP font asset will continue to display as question marks in game.

There are multiple ways to describe which characters to use. You can select from a basic list of settings, use decimal/hex ranges, import from another TMP font, import from a file, etc. Whatever method you use, keep track of the settings so you can add to it later if any characters are found missing.

In this example, we’re going to use a subset of Hangul alphabet by directly entering the characters required. It’s better to start with a subset of characters for the region/dialect you’re targeting rather than just trying to include everything. Some languages have thousands of characters which can result in an unusable TMP atlas without enough fidelity.

  1. In Font Asset Creator, drop down Character Set selector and choose Custom Characters
  2. Copy and paste the following custom characters into the Custom Character List text box. Note the very first character is a space character.

The above characters are enough for this tutorial, but will need to be expanded for full language support. This is how it looks in Font Asset Creator. We’re also adding the basic English alphabet to have a well-rounded font that can still display any untranslated English text.

Click Generate Font Atlas to render all the specified characters into a TMP atlas. Once you’ve created the atlas, you’ll see all the characters packed like below. Click for full size.

TextMeshPro renders glyphs using signed distance fields (SDF). How this works is outside the scope of this tutorial, but to summarise it’s a way of representing fonts using mathematical values that can maintain smooth shapes at any resolution.

In the output field, take note of the Missing characters, Excluded characters, and “characters missing from font file”. This will display any character codes you requested but could not be found in the provided TTF/OTF font. If your source font is missing any important characters, then it’s necessary to locate another TTF/OTF font containing those characters.

Depending on your font requirements, you might want to increase Atlas Resolution, e.g. to 4096×4096 or higher to support more characters with good fidelity. You can also adjust packing method, sample size, etc. for your specific font needs.

For this tutorial, the atlas generated above is good enough. Click the Save button and save your new TMP font to DemoTranslationMod/Resources. We’ll use the default name in a moment, please don’t change it. This creates a new TMP font asset like below with the name “NotoSerifKR-Regular SDF”.

This new SDF asset contains the atlas and other information required to render the TMP font in Daggerfall Unity. You can come back and recreate the font later with different properties or more characters if needed.

Associate Font With Locale

There’s one more step before can see this font in game. We need to associate our custom font with the correct locale so that Daggerfall Unity knows to use it. This is done using the StartupScript.cs code we created previously.

Open StartupScript.cs in your code editor and replace the entire contents with below. Don’t forget to save your changes!

using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using DaggerfallWorkshop.Game;
using DaggerfallWorkshop.Game.Utility.ModSupport;
using DaggerfallWorkshop.Game.UserInterface;

namespace DemoTranslationMod
    public class StartupScript : MonoBehaviour
        // Define the names of translated string table collections
        const string runtimeInternalStrings = "Demo_Strings";
        const string runtimeRSCStrings = "Demo_RSC";

        public static Mod mod;

        [Invoke(StateManager.StateTypes.Start, 0)]
        public static void Init(InitParams initParams)
            mod = initParams.Mod;
            var go = new GameObject(mod.Title);

        private void Awake()
            // Set TextManager properties to use translated string table collections
            TextManager.Instance.RuntimeInternalStrings = runtimeInternalStrings;
            TextManager.Instance.RuntimeRSCStrings = runtimeRSCStrings;

            // Load KO font
            DaggerfallFont font_ko = new DaggerfallFont(DaggerfallFont.FontName.FONT0003);
            font_ko.LoadSDFFontAsset("NotoSerifKR-Regular SDF");

            // Assign KO font
            Locale ko = LocalizationSettings.AvailableLocales.GetLocale("ko");
            if (ko)
                TextManager.Instance.RegisterLocalizedFont(ko, DaggerfallFont.FontName.FONT0003, font_ko);

            Debug.Log("StartScript has completed.");

Let’s take a look at what changed. To start with, we added some new using statements. These import some extra functionality to the script.

using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using DaggerfallWorkshop.Game.UserInterface;

Then we added the following code to associate our custom font with the KO locale to Daggerfall’s FONT003. This is the default font used in most parts of the game.

// Load KO font
DaggerfallFont font_ko = new DaggerfallFont(DaggerfallFont.FontName.FONT0003);
font_ko.LoadSDFFontAsset("NotoSerifKR-Regular SDF");

// Assign KO font
Locale ko = LocalizationSettings.AvailableLocales.GetLocale("ko");
if (ko)
    TextManager.Instance.RegisterLocalizedFont(ko, DaggerfallFont.FontName.FONT0003, font_ko);

First, we create a custom DaggerfallFont called font_ko. By default we’re loading FONT003, but we’ll replace this in a moment with our custom font.

Second, we tell font_ko to load our custom font asset using LoadSDFFontAsset(). Any font created using the TextMeshPro Font Asset Creator should load OK. Reminder: you need to be on Daggerfall Unity 0.11.3 or later.

Finally, we try to get the “ko” locale and only continue if this locale is found. If the locale is found, we associate our custom DaggerfallFont with the “ko” locale using RegisterLocalizedFont().

When this code executes at startup, Daggerfall Unity now knows it should use a different font when rendering FONT003 within the Korean (ko) locale. You can associate the same SDF font with FONT001, FONT002, etc. but you might want to use different styles of typefaces to better match the desired look and feel in your translation.

Make sure your changes are saved, then we can try this font in game.

  1. Click Play to start the game and click through to title menu.
  2. Use the locale drop-down to select Korean (ko) in Game view.
  3. Click Start New Game in title menu. If everything works as expected, our custom font will be selected and used with our translated text example.

Click Play again to stop game.

To summarise, creating a custom font requires the following steps:

  1. Locate appropriate TTF/OTF source fonts for your language. These fonts must contain all the alphabet characters you need for your translation.
  2. Import the TTF/OTF font into Unity project.
  3. Use the Font Asset Creator to generate a custom TMP font asset with the required characters and resolution.
  4. Associate new font with your custom locale and related Daggerfall font in startup C# script.

You might need to recreate font several times when creating your translation mod, either to add new characters, change resolution, or just finetune the look and feel. If you change the asset name, don’t forget to update this in your startup script.

Now that we have a custom font, we can move on to packaging our localisation to standalone files. This will be covered in Localizing Strings in Daggerfall Unity – Part 7.

Daggerfall Unity Beta 0.11.3

Daggerfall Unity 0.11.3 is now available on Live Builds page. This is another general bug-fix release with some updates to mod system.

Starting from this release, I’m attaching zipped builds along with patch notes to Releases page on GitHub. This will eventually become a longer-term archive for older builds even after they’re cleaned up from Live Builds page. If there’s enough demand, I can work through attaching older builds to previous releases on this page.

Now that I’m finally caught up with code review, I’ll be able to get back into the localization tutorial series. This series was pending some fixes rolled out in 0.11.2 and 0.11.3, so please be sure to update before the next article in series is published.

Quest Debugger Input Changes

The quest debugger has a few changes to input settings. These changes are to prevent accidentally opening debugger during normal play, free up the Tab key for other uses, and to make shortcuts easier on non-US keyboards. For example, the square bracket keys [ and ] are not so easy to use on AZERTY keyboards.

If you are not a quest author or don’t care about quest debugger, you can ignore these changes.

  • Quest debugger is now disabled by default. Must edit EnableQuestDebugger=True in settings.ini to activate it again.
  • Ctrl+Shift+D now cycles through debugger display states off/partial/full
  • Ctrl+Shift+LeftArrow now opens previous active quest while debugger active
  • Ctrl+Shift+RightArrow now opens next active quest while debugger active
  • Ctrl+Shift+UpArrow now teleports to next dungeon quest marker while debugger active inside dungeon
  • Ctrl+Shift+DownArrow now teleports to previous dungeon quest marker while debugger active inside dungeon

Note: Some inputs might move character, e.g. Ctrl+Shift+D will also move character slightly to right when activating debugger. This is expected and not considered a breaking issue for a debug/development feature that is normally disabled.

General Fixes & Improvements


  • Potion maker: Fix issues tracking ingredient stack count between cauldron and player inventory
  • Conjured arrows: Don’t stack conjured arrows with different time-to-live
  • Conjured arrows: Always shoot conjured arrows first, priority to lowest time-to-live
  • Conjured arrows: Change colour of arrows to show if conjured or real in inventory and arrow counter on HUD
  • Conjured arrows: Prevent shooting a conjured arrow converting to a real arrow


  • World: Fix classic bug relating to %ef macro not using correct local race for building names


  • DaggerfallQuestJournalWindow: Change access permissions to allow overriding by mods
  • DaggerfallQuestJournalWindow: Allow events to be overridden by mods
  • DaggerfallLoot: Allow mods to add or modify loot items via FormulaHelper.ModifyFoundLootItems() override
  • Inventory UI: Right-click now works as described in Daggerfall manual to perform complement of equip/remove, appearance cycling moved to middle-mouse


  • DaggerfallInventoryWindow: Change access permissions to allow overriding by mods
  • Biographies: Fix issues parsing patched BIOG files
  • Biographies: Add ability to add custom biographies
  • FormulaHelper: Add hook to override CalculateCasterLevel
  • FormulaHelper: Add hooks to override spell costing formulas CalculateTotalEffectCosts, CalculateEffectCosts, ApplyTargetCostMultiplier
  • Magic: Fix spells with multiple effects ending too early


  • World: Fix incorrect nature billboards at climate borders


  • ActionDoor: Add support for MeshCollider
  • RuntimeMaterials: Fix bug where dungeon texture not applied if runtime material not attached to base object
  • MeshReplacement: Fix regressions of new scripts not added to mod-added models


  • TextBox: Do not draw defaultText if null


  • World: Extend town borders by 4096 units – increases distance at which flavour text is displayed, guards will chase player out of town, etc.
  • Magic: Fix player not receiving payload of Damage Fatigue effect
  • Formula: Fix randomness of levelup health roll so this is always different, even after a reload
  • Localization: Fix exception when determining size of new font atlas using deprecated fields
  • Engine: Update Addressables package to 1.17.17

Daggerfall Unity Beta 0.11.2

Daggerfall Unity 0.11.2 is now available on Live Builds page. This is a general bug-fix release with some updates to mod system.

New Features

Custom Mobile Units (TheLacus)

TheLacus has taken a big step towards support for replacing enemies with custom graphics, including 3D models. See gif below for an example of this in action using a humble cube.

If you don’t think a cube is that amazing, consider this a 3D model injected by a mod into an enemy mobile unit to alter it’s appearance. The same could be done with a fully animated 3D model. There are some limitations around this for now, notably that classic enemy attack triggers are linked to sprite animation frames. So for now a modder would also need to reimplement parts of combat to fully replace model. But this is something that can be refined over time as the community starts experimenting with this feature and sending their feedback.

Teleport To Any Dungeon Marker (Interkarma)

This is a very minor improvement to quest debugger that finally reimplements a test/cheat feature from classic. When quest debugger is open (default LeftShift+Tab) you can now use Shift+[ and Shift+] keys to cycle forwards and backwards through all markers in a dungeon. This doesn’t require a quest to be active in dungeon, only for the quest debugger to be open while player is in a dungeon. This is handy for situations like teleporting to Medora’s room in Direnni Tower, as she’s a permanent NPC without a specific quest marker.

The keybinds for quest debugger and cycling through markers can be changed in StreamingAssets/Text/DialogShortcuts.txt.

General Fixes & Improvements

Lots of bug fixes small and large from our awesome community of devs.


  • Fix dictionary access for non-existent world variant keys
  • Prevent “remote” Place quest selection from randomly selecting local Place
  • Don’t restrict shields by plate or chain to match classic
  • Move hardcoded info panel colour into DaggerfallUI
  • Allow non-member quests to have rep requirements – to fix non-joinable Witch Coven quest dispensing
  • Fix Oghma removal after use to function from everywhere including wagon


  • Change HotKeySequenceProcessed from Bool to Enum
  • Add forward thrust to click to attack – previously this move was never selected


  • Fix formatting of date lines in diary entries of quests


  • Fixed misnamed formula overrides for CalculateFatigueRecoveryRate and CalculateSpellPointsRecoveryRate
  • Fix torch burning ticks progressing while game is paused
  • Fix %hpw inconsistent with classic for Dunmer characters


  • Import mod settings and presets files after create or changes from editor window
  • Fix mod settings not accepting negative float values
  • Fix mod asset loading on Turkish culture
  • Fix RuntimeMaterials by ignoring climate when using dungeon table
  • Improve support of mod localization through CSV text tables


  • Toggle large HUD with F10 like classic
  • Fix interacting with HUD when cursor not active on Linux
  • Fix NullReferenceException
  • Horse now has constant jump height to clear hedges


  • Add joystick middle-click keybind and set joystick UI controls to protected
  • Prevent accidental axis button “presses” from binded movement and camera axes


  • Reduce delay filling Dungeon variable in PlayerEnterExit
  • Add detailed exception handling and logging to BookReader
  • Automap check CombineRDB state before resetting so it stays disabled if previously set in editor
  • Automap move mesh and material update to separate script and optimise automap creation times
  • Fix texture table in dungeon automap to match environment
  • RuntimeMaterials automap type differentiation for interior types and other models
  • Add support for the discovery state of OBJ models to be saved and loaded
  • Fix some editor warnings


  • Fix vampires not being offered vampire quests
  • Restore per-task click rearming
  • Update DaggerfallFont to use .atlasTexture instead of deprecated .atlas
  • Deprioritise System Locale Selector to prevent an error during localization development
  • S0000011: Fix needing to click Barenziah twice with Chapter 6 before quest ends
  • S0000011: Fix clicking Gortwog to hand in Chapter 6 with per-task click rearming
  • S0000011: Reordered gold reward so it doesn’t interupt Barenziah’s information at end of quest
  • N0B00Y16: Fix issue of clicking on merchant at wrong time stalling quest
  • S0000021: Fix King of Worms potentially spawning into Sentinel during quest
  • S0000021: Fix logic issues with click handling carried over from classic
  • S0000021: Fix success condition to correctly check player has killed lich
  • M0B21Y19: Fix victim default home being selected as local and stashing live version of dead NPC

Localizing Strings in Daggerfall Unity – Part 5

Localizing Strings in Daggerfall Unity – Part 1
Localizing Strings in Daggerfall Unity – Part 2
Localizing Strings in Daggerfall Unity – Part 3
Localizing Strings in Daggerfall Unity – Part 4
Localizing Strings in Daggerfall Unity – Part 5
Localizing Strings in Daggerfall Unity – Part 6

Create Mod Settings

We’ve now created new locales, string tables, imported text, translated text, and seen how to manually enable translated text in-game. We’ve also worked through concepts unique to Daggerfall Unity like character remapping, macros, and RSC markup. The next step is to create our mod settings.

  1. Click Daggerfall Tools menu > Mod Builder
  2. Click Create New Mod
  3. Navigate to path Assets/Game/Mods/DemoTranslationMod
  4. Set Filename to DemoTranslationMod
  5. Click Save
  6. Fill out some information about your mod, such as mod name, version, creator name and contact, etc.
  7. Select the platforms you want to build for. We’re just building for Windows in this tutorial.
  8. Click Save Mod Settings to File to save our settings. This should be done any time the settings are changed in Mod Builder.

You should now have something like below (click for full size).

Click Save Mod Settings to File and close the Mod Builder window.

Verify Mod Found

After completing Part 4, you should have the DaggerfallUnityStartup scene open. If not, please open this scene now from Assets/Scenes.

Daggerfall Unity will load any mod settings found as a virtual mod when starting from launcher scene. We’re going to check our new mod settings are found.

  1. Click editor Play button to start game
  2. Click Mods button in launcher
  3. Verify that Demo Translation Mod is listed under Mods Found and it is Enabled

Click editor Play button again to stop game.

Note: If you forget to stop Play from editor, your future changes will not be saved. Unity will revert editor changes when Play is stopped.

Create Mod Script

We’re now going to create a small C# script for our mod to coordinate everything at startup. To begin with, this script will simply set the translated text tables to Live String Tables, as we did manually in Part 3.

  1. In Project view, navigate to Assets/Game/Mods/DemoTranslationMod/Assets
  2. Right-click in empty space space inside this folder and click Create menu > Folder to create a new folder
  3. Name this folder Scripts

Now we can create our C# script.

  1. Navigate into Scripts folder above
  2. Right-click in empty space inside this folder and click Create menu > C# Script to create a new C# script
  3. Name this script StartupScript (Unity will automatically save with .cs extension)

Double-click StartupScript to open it in your configured code editor. Replace the full contents with below and save changes.

using UnityEngine;
using DaggerfallWorkshop.Game;
using DaggerfallWorkshop.Game.Utility.ModSupport;

namespace DemoTranslationMod
    public class StartupScript : MonoBehaviour
        // Define the names of translated string table collections
        const string runtimeInternalStrings = "Demo_Strings";
        const string runtimeRSCStrings = "Demo_RSC";

        public static Mod mod;

        [Invoke(StateManager.StateTypes.Start, 0)]
        public static void Init(InitParams initParams)
            mod = initParams.Mod;
            var go = new GameObject(mod.Title);

        private void Awake()
            // Set TextManager properties to use translated string table collections
            TextManager.Instance.RuntimeInternalStrings = runtimeInternalStrings;
            TextManager.Instance.RuntimeRSCStrings = runtimeRSCStrings;

            Debug.Log("StartScript has completed.");

Add Script To Mod

Now we have a script to set our string tables at start, we need to add this script to our mod’s list of assets.

  1. Click Daggerfall Tools menu > Mod Builder
  2. Select StartupScript in Project view
  3. Click Add Selected Assets in Mod Builder
  4. Expand Files in Mod Builder (click the little arrow next to Files to expand/contract)
  5. Confirm that StartupScript has been added to list of assets included in mod
  6. Click Save Mod Settings to File and close Mod Builder.

Now start the game with Play in Unity Editor. Click Play again on the launcher screen to start game as normal.

As the main game starts, you should see the following output to Console view. It will be near the end of output, but you might have to scroll up a little. The highlighted line below was emitted by our mod script, so we know it ran the Init() method.

If you don’t see the above, check that StartupScript is added to Mod Builder and you clicked Save Mod Settings to save changes. Be careful not to make editor changes while the game is playing.

Now script has executed, click on TextManager in Hierarchy view while game is running and confirm script has set correct names to Live String Tables in Inspector view. This live change by our script will only persist until game closes.

Now test translated strings are being used. We’ll test this by starting a new character as we did in Part 3.

  1. Select French (fr) locale from selector at top-right of Game view.
  2. Click Start New Game
  3. Confirm French language is shown

Click Play in editor to stop the game.

We now have a Daggerfall Unity mod including translated string tables and a C# script to coordinate settings. We will continue to build on this in Localizing Strings in Daggerfall Unity – Part 6.

Localizing Strings in Daggerfall Unity – Part 4

Localizing Strings in Daggerfall Unity – Part 1
Localizing Strings in Daggerfall Unity – Part 2
Localizing Strings in Daggerfall Unity – Part 3
Localizing Strings in Daggerfall Unity – Part 4
Localizing Strings in Daggerfall Unity – Part 5
Localizing Strings in Daggerfall Unity – Part 6

Understanding RSC Markup

Before configuring our mod for distribution, we’re going to look back at the Demo_RSC string table from Part 2. Here, you saw tags like [/center] and [/left] combined with plain text. This is called RSC markup. See screenshot below with some markup highlighted. To fully translate Daggerfall’s text will require an understanding of how to use this markup in RSC strings.

Strings imported from TEXT.RSC contain bytecode controlling how each line of text is to be formatted. Like TEXT.RSC itself, this bytecode is in a binary format and is not easily read or edited by humans. If this bytecode stream was to be translated directly into numbers with no other changes, it would look something like below.

STRENGTH[0xFD] Strength governs encumbrance, weapon damage[0xFC] and the ease of increasing strength-related skills.[0xFC] With your strength of %str, you are considered %ark[0xFC] [0xFB][0x14]%dam [0xFB](modifier is factored into your[0xFC] [0xFB](hand-to-hand / weapon damage.[0xFC] [0xFB][0x14]%enc [0xFB](kilograms is your maximum encumbrance.[0xFC][0xFE]

This is obviously not pleasant for humans to work with. To overcome this, Daggerfall Unity’s localization system converts raw RSC bytecode into neatly formatted RSC markup with plain-text codes standing in for raw numbers. Line breaks are added where appropriate to help make text more readable and simulate how it will format in-game. The end result seen in RSC string tables now looks like below.

 Strength governs encumbrance, weapon damage[/left]
 and the ease of increasing strength-related skills.[/left]
 With your strength of %str, you are considered %ark[/left]
 [/pos:x=20,y=0]%dam [/pos:x=40,y=0]modifier is factored into your[/left]
 [/pos:x=40,y=0]hand-to-hand / weapon damage.[/left]
 [/pos:x=20,y=0]%enc [/pos:x=40,y=0]kilograms is your maximum encumbrance.[/left]

At runtime, RSC markup text is converted back into a bytecode stream and printed to screen by Daggerfall’s UI based on these codes. It’s important not to translate markup codes. Anything contained inside of square brackets [ ] in an RSC-compatible string table will be treated as markup code.

Following is a summary of supported codes so far.

  • [/center] – Centre align this line and starts new line.
  • [/left] – Left align this line and starts a new line.
  • [/newline] – Starts a new line.
  • [/record] – Ends a sub-record for multi-record text (e.g. variants of answers or rumours in conversations).
  • [/input] – Requests a prompt from player (e.g. entering “yes” to open gates in Castel Daggerfall).
  • [/pos:x=0,y=0] – Position prefix for text aligned within UI (e.g. indented text under some other text). The X and Y values determine how far text is offset or indented from start position.
  • [/end] – End orecord. Each RSC record must contain [/end] once all data is completed. This tells the reader there are no more subrecords or data to read for this key.

As you work through the RSC strings, remember to never change anything between square brackets [ ] or the formatting will be broken. And as a general rule, any markup code at the end of a line will also start a new line, except for [/end] which terminates the record.

Understanding Macros

You might have noticed many strings contain a word prefixed with % character, e.g. %str in text above. In Daggerfall Unity, these are called macros, as they expand into some other text when printed out. For example, %str will be converted into the character’s actual STR value at time text is printed – e.g. 65 will be printed in-game in place of %str.

There are over a hundred different macros in Daggerfall, so they won’t be covered in detail here. Just keep in mind that like markup codes above between [ ], you should never translate a macro prefixed with %. This macro code has special meaning to the game and changing it will break the purpose of the text and result in an unhandled error.

Variants in Legacy Import

There are a few places where Daggerfall Unity doesn’t have the exact same string records as classic. The main example of this is TEXT.RSC record 9000 – questions and answers for class questionnaire.

In classic, this is one large record with dozens of entries terminated by a special separator character. This record is so large that it’s very difficult for humans to edit even with RSC markup, and the length of text breaks the Unity string editor UI.

To overcome this, Daggerfall Unity splits record 9000 into multiple new records not present in classic TEXT.RSC – 9000.1 through 9000.40. Each record represents a single question/answer block for class questionnaire and does away with special separator character.

If you import legacy TEXT.RSC translations as we did with French and German, you will note that IDs 9000.1 through 9000.40 are not populated.

It will be necessary to manually translate these 40 records again, following the formatting example shown in English. The other locales did not use a legacy TEXT.RSC file so imported with the default English language version of text.

Translate Some RSC

Earlier in this series, we mentioned it’s also possible to translate English strings. There are a few reasons you might want to create an English translation, such as to fix spelling and formatting, or to change the “flavour” of text to create a unique game experience in your mod.

For a bit of fun, we’ll translate the English record for STRENGTH info popup into pirate speak.

Please be sure to have completed Parts 1-3 and confirmed your translated string tables appear in game.

It helps if you have a save game to load here, as we’re going to view something on the Character Sheet which requires an actual character. If you don’t have a character available, quickly start a new game to put together a basic character, then save that game.

To translate your STRENGTH info popup.

  1. Click Window menu > Asset Management > Localization Tables
  2. Dropdown Selected Table Collection and select Demo_RSC (StringTable)
  3. Locate key 0 for STRENGTH text. It will be at top of string table
  4. If you need to, enlarge editor window and drag around column widths until you can comfortably edit the English (en) value
  5. Copy and paste the entire block of text below into the English (en) value field
 Ahoy matey! Strength governs yer encumbrance, weapon damage[/left]
 an' the ease o' increasin' strength-related skills.[/left]
 with yer strength o' %str, ye be considered %ark[/left]
 [/pos:x=20,y=0]%dam [/pos:x=40,y=0]modifier be factored into your[/left]
 [/pos:x=40,y=0]hand-to-hand / weapon damage.[/left]
 [/pos:x=20,y=0]%enc [/pos:x=40,y=0]kilograms be yer maximum encumbrance.[/left]

This should look like below.

You can now close the Localization Tables editor. To see your changes in-game:

  1. Click Play to start game
  2. Ensure English (en) is selected at the top-right of Game view
  3. Load a previously saved character
  4. Press F5 to open the Character Sheet UI (if you’ve changed this keybinding from default, use that key instead)
  5. Click on STR button to open the STRENGTH info popup

If everything has worked, it will look like below in-game.

Preparing to Distribute Mod

So far, we’ve done everything directly in the Unity Editor. This is fine for testing, but we eventually want to distribute translations so that others can use them. Getting ready for distribution will be the focus of next parts in this series.

Before we move on, we need to undo a couple of changes made in editor while testing. Moving forward, we’ll be preparing mod as if our translation work is completed and it’s time to ship the mod.

The first change to undo is the manual setting to use our string table collections.

  1. In DaggerfallUnityGame scene, click the TextManager object
  2. On the TextManager inspector, reset Live String Tables and other settings back to defaults as shown in below screenshot
  3. Save the scene using File menu > Save

We’re done with copying string tables, so empty those settings also.

Because we’re going to create a .dfmod for distribution, we need to ensure the DaggerfallUnityStartup scene is how we start the game. This scene is responsible for loading mods, and going direct to the game scene like we did for testing will skip this essential process.

Please open the DaggerfallUnityStartup scene now, and keep this scene open as you work through remainder of tutorial series.

Once you’ve opened DaggerfallUnityStartup scene, please check the settings for TextManager to ensure they’re still set to defaults as pictured above. We did not change startup scene’s TextManager, but please check it hasn’t been changed by mistake.

Now that we’ve reset TextManager properties and opened DaggerfallUnityStartup scene, we’re ready for Localizing Strings in Daggerfall Unity – Part 5.

Localizing Strings in Daggerfall Unity – Part 3

Localizing Strings in Daggerfall Unity – Part 1
Localizing Strings in Daggerfall Unity – Part 2
Localizing Strings in Daggerfall Unity – Part 3
Localizing Strings in Daggerfall Unity – Part 4
Localizing Strings in Daggerfall Unity – Part 5
Localizing Strings in Daggerfall Unity – Part 6

Editing Strings

In Part 1, we setup the string tables to receive our localized text. In Part 2, we imported strings to configure initial data for each locale with either English text or legacy translations from TEXT.RSC.

Before we edit a few strings into their respective language, we’re going to set all string tables to preload. This means their data is fully loaded sooner and region switching will be faster later in this tutorial. This is recommended when creating translation mods.

  1. Click Window menu > Asset Management > Localization Tables to open string editor.
  2. Drop-down Selected Table Collection and select Demo_Strings (StringTable).
  3. Click the metadata button above any of the string tables and put a tick in Preload All Tables. This will automatically select Preload Table for every locale.
  4. Repeat steps 2-3 for Demo-RSC (StringTable)

With that out of the way, let’s take a closer look at the string table and make our first edits.

The left-hand column of string table holds the unique key each for item. This key is how Daggerfall Unity looks up a string for any language. Never change the key value or this will break string lookup in-game.

Then for each language, there is a value field which contains data for that key. All languages share the same key, only the value needs to be translated.

Note: Daggerfall Unity will occasionally add new keys and values which must also be added to your translation mod. Syncing new keys to maintain your mod will be covered in a future tutorial in this series.

We’re now going to change the value of pleaseSelectYourHomeProvince for each locale. This is one of the first strings seen when starting a new character, and also near the top of list, so it’s a good place to start. Copy and paste the following text into each locale’s value field next to the pleaseSelectYourHomeProvince key.

Czech (ch) : Vyberte svou domovskou provincii…
French (fr) : Veuillez sélectionner votre province d’origine…
German (de) : Bitte wählen Sie Ihre Heimatprovinz…
Korean (ko) : 거주 지역을 선택하십시오…

Note: Translations were created using Google Translate.

Once this is completed, your string table should look like below (click for full size).

You can now close the Localization Tables editor.

Setting Play Mode Script

Before we take a look at these translations in-game, we’re going to check the Play Mode Script for addressables in Unity. We won’t go into this in detail, but we need to ensure the correct setting is selected before proceeding.

  1. Click Window menu > Asset Management > Addressables > Groups
  2. Click Play Mode Script and confirm Use Asset Database (fastest) is selected
  3. Close the Addressables Groups UI

The Play Mode Script is how Unity will load addressable assets like string tables during play. For simplicity and speed, we will only select Use Asset Database (fastest) in this tutorial. This is also the default setting.

Assign String Tables To TextManager

The final step to see our translations in-game is to tell Daggerfall Unity how to load our translated assets.

You should already have the DaggerfallGameScene open from Part 2. If not, locate this scene in Project view under Assets/Scenes and open it now.

Locate and select the TextManager component then look to the Inspector view. We must now change the Live String Tables to reference our custom translations instead of the default English language in core game. Make the highlighted edits in below screenshot.

The names Demo_Strings and Demo_RSC match the two string table collections we created back in Part 1. Changing these settings will redirect string lookups to our custom string tables.

To quickly summarise the purpose of each string table collection:

  • Internal Strings – Are all strings previously extracted from FALL.EXE and other hardcoded locations. Their key is in plain text and represents the text being translated.
  • RSC Strings – Are all strings extracted from TEXT.RSC. Their key is a numeric value matching an ID in TEXT.RSC.
  • BOK Strings – Will be all strings extracted from books in game data. This is under development and will be available in a future release of Daggerfall Unity.

Testing In-Game

To quickly recap everything we’ve done so far:

  1. Setup Unity 2019.4.10 and cloned the full Daggerfall Unity project
  2. Created empty string table collections Demo_Strings and Demo_RSC.
  3. Imported initial text to populate our two new string table collections, using legacy translations from French and German TEXT.RSC, and remapped back to correct character codes.
  4. Set all string tables to preload.
  5. Translated string values for “Please select your home province…” into multiple languages.
  6. Set the Play Mode Script to Use Asset Database (fastest).
  7. Opened the DaggerfallUnityGame scene.
  8. Assigned our string table collection to Live String Tables in TextManager inspector.

Click Play button to start the game. Because we have the DaggerfallUnityGame scene open, it will open straight to the title menu. Just click to dismiss any videos that play at startup.

Once game has started, take note of the language dropdown towards top-right of play window.

Note: Depending on your locale settings, you might have another language other than English (en) above.

Whatever your language is, use this dropdown and change the selected locale to French (fr). Then click Start New Game. If everything is working properly, you should see our translated text in French.

Note: There might be a short delay when Unity first preloads string data. You may need to click Start New Game twice after changing language.

Now press Escape key to return to title menu and change language to German (de). Click Start New Game again and the text should now be in German.

Finally, press Escape key back to title menu again, then change language to Korean (ko) and click Start New Game.

So what’s gone wrong here? Why are we seeing question marks? Everything looked OK when creating the translated string in the editor.

These question marks indicate Daggerfall Unity was unable to locate font characters matching one or more codes in source text. The default fonts in Daggerfall Unity have a full complement of Latin characters, but they do not have characters for non-Latin languages. When the game attempts to render these unknown characters, it will display question marks instead.

To fix this, we need to provide new fonts with locale-specific characters to Daggerfall Unity. Fonts will be covered in a future tutorial in this series.

We have a little more ground to cover first in Localizing Strings in Daggerfall Unity – Part 4.