Skip to content

Localization

Learn how to add localization support to your Resonite mods using BepisLocaleLoader, enabling your mod to display text in multiple languages.

First, add the BepisLocaleLoader NuGet package to your project file (.csproj):

<ItemGroup>
<PackageReference Include="ResoniteModding.BepisLocaleLoader" Version="1.*" />
</ItemGroup>
<!-- Add the Resonite modding NuGet source -->
<PropertyGroup>
<RestoreAdditionalProjectSources>
https://nuget-modding.resonite.net/v3/index.json;
</RestoreAdditionalProjectSources>
</PropertyGroup>

Then, add BepisLocaleLoader as a dependency in your plugin:

using BepisLocaleLoader;
using BepInEx;
using BepInEx.Configuration;
using BepInExResoniteShim;
// PluginMetadata is automatically generated by ResonitePluginInfoProps
[ResonitePlugin(PluginMetadata.GUID, PluginMetadata.NAME, PluginMetadata.VERSION, PluginMetadata.AUTHORS, PluginMetadata.REPOSITORY_URL)]
[BepInDependency(BepInExResoniteShim.PluginMetadata.GUID, BepInDependency.DependencyFlags.HardDependency)]
[BepInDependency(BepisLocaleLoader.PluginMetadata.GUID, BepInDependency.DependencyFlags.HardDependency)]
public class MyPlugin : BasePlugin
{
// Your plugin code
}

When creating configuration entries, use ConfigLocale to provide localized descriptions:

public override void Load()
{
var myConfig = Config.Bind(
"General",
"EnableFeature",
true,
new ConfigDescription(
"Enable this feature",
null,
new ConfigLocale(
"Settings.dev.author.myPlugin.config.Key",
"Settings.dev.author.myPlugin.config.Description"
)
)
);
}

Create a Locale folder next to your plugin DLL with JSON files for each language:

MyPlugin/
├── MyPlugin.dll
└── Locale/
├── en.json
├── es.json
├── fr.json
└── ja.json

Each locale file should follow this structure:

{
"localeCode": "en-US",
"authors": ["YourName"],
"messages": {
"Settings.dev.author.myPlugin": "My Plugin",
"Settings.dev.author.myPlugin.Breadcrumb": "My Plugin Settings",
"Settings.dev.author.myPlugin.config.Key": "Enable Feature",
"Settings.dev.author.myPlugin.config.Description": "Enables the main feature of this plugin."
}
}

BepisLocaleLoader provides a convenient .T() extension method for string localization:

// Simple key lookup
var text = "Settings.MyPlugin.Welcome".T();

You can register localized strings directly in code:

LocaleLoader.AddLocaleString(
"Settings.MyPlugin.NewFeature",
"New Feature Text",
force: true, // Overwrite if exists
authors: "YourName"
);
  • force: false (default) - Safe for adding new keys without overwriting
  • force: true - Use when you need to override existing translations

Here’s a complete example based on the Optizoom mod:

using BepInEx;
using BepInEx.Configuration;
using BepisLocaleLoader;
using BepInExResoniteShim;
using Elements.Core;
// PluginMetadata is automatically generated by ResonitePluginInfoProps
[ResonitePlugin(PluginMetadata.GUID, PluginMetadata.NAME, PluginMetadata.VERSION, PluginMetadata.AUTHORS, PluginMetadata.REPOSITORY_URL)]
[BepInDependency(BepInExResoniteShim.PluginMetadata.GUID, BepInDependency.DependencyFlags.HardDependency)]
[BepInDependency(BepisLocaleLoader.PluginMetadata.GUID, BepInDependency.DependencyFlags.HardDependency)]
public class MyPlugin : BasePlugin
{
private static ConfigEntry<bool> enabled;
private static ConfigEntry<Key> hotkey;
private static ConfigEntry<float> intensity;
public override void Load()
{
// Basic toggle
enabled = Config.Bind(
"General",
"Enabled",
true,
new ConfigDescription(
"Enable the plugin",
null,
new ConfigLocale(
"Settings.dev.author.myPlugin.enabled.Key",
"Settings.dev.author.myPlugin.enabled.Description"
)
)
);
// Key binding
hotkey = Config.Bind(
"General",
"Hotkey",
Key.Tab,
new ConfigDescription(
"Activation hotkey",
null,
new ConfigLocale(
"Settings.dev.author.myPlugin.hotkey.Key",
"Settings.dev.author.myPlugin.hotkey.Description"
)
)
);
// Slider with range
intensity = Config.Bind(
"General",
"Intensity",
50f,
new ConfigDescription(
"Effect intensity",
new AcceptableValueRange<float>(0f, 100f),
new ConfigLocale(
"Settings.dev.author.myPlugin.intensity.Key",
"Settings.dev.author.myPlugin.intensity.Description"
)
)
);
}
}

Follow a consistent naming pattern for your locale keys:

Settings.dev.[author].[plugin].[category].[setting]

Example:

Settings.dev.lecloutpanda.optizoom.zoomSpeed.Key
Settings.dev.lecloutpanda.optizoom.zoomSpeed.Description
  1. Group related settings - Use consistent prefixes for related configuration options
  2. Provide clear descriptions - Help users understand what each setting does
  3. Include default languages - At minimum, provide English (en.json)
  4. Test all languages - Verify that text displays correctly in different languages

You can verify which plugins have loaded locales:

foreach (var plugin in LocaleLoader.PluginsWithLocales)
{
Log.LogInfo($"Plugin with locales: {plugin}");
}
  • Locales not loading: Ensure the Locale folder is next to your plugin DLL
  • JSON parsing errors: Check logs for detailed error messages
  • Keys not found: Verify the key names match exactly between code and JSON
  • Missing dependency: Ensure BepisLocaleLoader is installed and loaded before your plugin