reckfellENGINE

Localization with CSV

UTF-8 tables, contexts, Russian plural forms and Label refresh.

On this page

A CSV table stores message keys in its first column and locales in the header. Reckfell imports one .translation resource per language. Register these resources as described in translation setup.

A table that imports correctly

Save Locale/ui.csv as UTF-8. These examples use commas and no byte order mark. Export the actual CSV file from your spreadsheet, not an XLSX file renamed to .csv.

Text
keys,en,ru,_note
PLAY,Play,Играть,Main menu
ONLY_EN,English fallback,,Intentionally missing in ru
QUOTE,"He said ""Hello, friend"".","Он сказал «Привет, друг».",CSV quoting
LINES,Line one\nLine two,Строка один\nСтрока два,Escaped newline
  • The first header cell is only a label. en and ru identify locale columns; keep identifiers exact and do not add surrounding spaces.
  • A header starting with an underscore, such as _note, marks an ignored comment column.
  • Keys are case-sensitive. Keep each key/context pair unique. Do not rely on duplicate rows overriding each other.
  • Enclose fields containing delimiters, quotes or literal newlines in double quotes. Represent an embedded double quote as two quotes.
  • An empty translation cell is skipped; lookup can use the fallback language.

The QUOTE row preserves both the comma and embedded quotes. With default settings, LINES contains a real newline after import.

Import options

Select the CSV in Content Browser, change its Import settings and apply Reimport.

SettingValues and effect
delimiter0: comma; 1: semicolon; 2: tab. Must match the file
compress0: Disabled; 1: Auto. Auto optimizes simple tables; actual use of contexts or plural forms keeps an ordinary Translation resource
unescape_keysfalse by default: preserve backslash sequences in keys
unescape_translationstrue by default: interpret sequences such as \n. Disable when a backslash must remain literal

Changing an option does not change the source CSV. Reimport applies it and regenerates the language resources. Treat .translation files generated from CSV as output: edit the CSV, not those resources.

Distinguish the same word by context

Add a ?context column. This is a complete separate table:

Text
keys,?context,en,ru
Open,verb,Open,Открыть
Open,state,Open,Открыто

Inside a method, TranslationServer.Translate("Open", "state").ToString() returns Открыто with locale ru. Context is part of the lookup identity: an unknown context does not match an arbitrary context row. For an automatic Control translation, use its TranslationContext property; for computed text pass the context explicitly.

Select plural forms before formatting

Save this complete table as Locale/forms.csv and register both generated resources alongside ui resources:

Text
keys,?plural,?context,en,ru
Open,,verb,Open,Открыть
Open,,state,Open,Открыто
ITEM,ITEMS,,{0} item,{0} предмет
,,,{0} items,{0} предмета
,,,,{0} предметов

The first plural row supplies the singular key and the plural source key. Continuation rows leave keys, ?plural and ?context empty. Supply forms in the locale's rule order: English has two; Russian has three. Do not duplicate English into a third cell merely to fill the table.

TranslatePlural("ITEM", "ITEMS", n) selects a form. It does not substitute n. With ru, n=1 selects {0} предмет, 2 selects {0} предмета, 5 and 11 select {0} предметов, and 21 selects {0} предмет. Format the selected string afterward. The {0} placeholder must remain valid in every translation.

For a deliberate custom rule, a ?pluralrule row can set that language's nplurals/plural expression. The built-in ru/en rules suffice here; prefer them to an unnecessary override.

A Label that updates when the language changes

Attach this complete LocaleDemo.cs to a Label. It requires forms.en.translation and forms.ru.translation in the project's translations array. Call SetGameLocale("ru") or SetGameLocale("en") from your language selector. After changing ItemCount, call RefreshText.

C#
using Reckfell;

public partial class LocaleDemo : Label
{
    public int ItemCount { get; set; } = 5;

    public override void _Ready()
    {
        AutoTranslateMode = AutoTranslateModeEnum.Disabled;
        RefreshText();
    }

    public override void _Notification(int what)
    {
        if (what == NotificationTranslationChanged && IsInsideTree())
            RefreshText();
    }

    public void RefreshText()
    {
        // TranslatePlural selects a form; it does not insert the number.
        string form = TranslationServer.TranslatePlural("ITEM", "ITEMS", ItemCount).ToString();
        Text = string.Format(form, ItemCount);
    }

    public void SetGameLocale(string locale)
    {
        TranslationServer.SetLocale(locale);
    }
}

Automatic translation is disabled here because Text already contains the calculated result. The script uses TranslationServer explicitly. Label.Language controls text shaping; it is not the global game locale. SetGameLocale therefore calls TranslationServer.SetLocale instead.

Diagnose an import

SymptomAction
No language resourcesCheck UTF-8, locale headers, delimiter and importer messages
Entire row appears as one fieldSelect the delimiter actually used by the file and reimport
Literal \n or an unexpected newlineCheck unescape_translations; do not confuse CSV quoting with backslash escaping
Wrong plural form or missing formCheck continuation rows, locale, form order and preserved placeholders
Runtime still shows a keyRegister generated resources; verify case, context and fallback

Native tests cover import, quoting, Unicode, escapes, semicolon configuration, compression behavior, contexts, ru/en plural selection and the exact C# example. UI interaction, tab-delimited input, custom CSV plural-rule overrides, rendered typography and exports are not covered by these tests.

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.