SwiftlyS2
Development

Translations

SwiftlyS2 translation APIs let you localize plugin text by key and automatically resolve player-specific language.

Translation File Layout

Place translation files in your plugin under:

resources/translations/

Use .jsonc files named by language code (for example en.jsonc, fr.jsonc, pt-BR.jsonc, es-419.jsonc).

Custom language codes are supported for direct lookups through Core.Localizer, but they are not resolved by Core.Translation.GetPlayerLocalizer(player). Player localizers are limited to language codes provided by the player's game language.

Keep an en.jsonc baseline with all keys so unsupported or incomplete languages still have usable text.

Language Codes

Use the following language codes when naming your translation files:

LanguageCodeFile Name
Arabicarar.jsonc
Bulgarianbgbg.jsonc
Chinese (CN & TW)zh-CN / zh-TWzh-CN.jsonc / zh-TW.jsonc
Czechcscs.jsonc
Danishdada.jsonc
Dutchnlnl.jsonc
Englishenen.jsonc
Finnishfifi.jsonc
Frenchfrfr.jsonc
Germandede.jsonc
Greekelel.jsonc
Hungarianhuhu.jsonc
Indonesianidid.jsonc
Italianitit.jsonc
Japanesejaja.jsonc
Koreankoko.jsonc
Norwegiannono.jsonc
Polishplpl.jsonc
Portugueseptpt.jsonc
Portuguese (Brazilian)pt-BRpt-BR.jsonc
Romanianroro.jsonc
Russianruru.jsonc
Spanisheses.jsonc
Spanish (Latin America)es-419es-419.jsonc
Swedishsvsv.jsonc
Thaithth.jsonc
Turkishtrtr.jsonc
Ukrainianukuk.jsonc
Vietnamesevnvn.jsonc

Example Translation File

{
    // General
    "plugin.name": "My Plugin",
    "plugin.ready": "Plugin is ready.",

    // Command feedback
    "command.heal.success": "You have been healed.",
    "command.heal.other": "{0} healed {1}",
    "command.heal.no_permission": "You do not have permission.",

    // Errors
    "error.player_not_found": "Player '{0}' was not found."
}

Accessing Translation APIs

SwiftlyS2 exposes two useful entry points:

  • Core.Localizer (ILocalizer) for default/server-localized lookups
  • Core.Translation.GetPlayerLocalizer(IPlayer) for player-language lookups
public override void Load(bool hotReload)
{
    var serverLocalizer = Core.Localizer;
}

Server-Side Localization

Use Core.Localizer when the message is not player-specific.

string readyMessage = Core.Localizer["plugin.ready"];
string versionMessage = Core.Localizer["plugin.version", "1.2.0"];

Player-Specific Localization

Use Core.Translation.GetPlayerLocalizer(player) when output should match the player's language.

public async Task GreetAsync(IPlayer player)
{
    var localizer = Core.Translation.GetPlayerLocalizer(player);
    string message = localizer["welcome.message", player.PlayerName];

    await player.SendChatAsync(message);
}

IPlayer.PlayerLanguage can be used for diagnostics or conditional flows:

Core.Logger.LogInformation("Player language: {Language}", player.PlayerLanguage.ToString());

Placeholder Formatting

ILocalizer supports two indexer forms:

  • localizer["key"]
  • localizer["key", arg0, arg1, ...]

Keep placeholder order stable across languages:

{
    "round.win": "{0} won the round in {1} seconds"
}
string text = localizer["round.win", "CT", 42];

Key Design Best Practices

  • Use stable dot-separated keys (for example command.heal.success).
  • Keep the same key set across all language files.
  • Add JSONC comments for translator context when placeholders are involved.
  • Avoid string concatenation in code for translatable sentences.

Reference

See ITranslationService for translation service methods.

See ILocalizer for translation indexers.

See Language for supported language definitions.

On this page