Skip to main content
GameDev.net gamedev.net

PRO Tired of ads? Read GameDev.net ad-free and help keep the community independent with GameDev Pro — $3/month.

How We Made Unreal Engine Localization Easier Without Rebuilding Our Game

How We Made Unreal Engine Localization Easier Without Rebuilding Our Game

velutranslate
velutranslate's Blog · · 11 min read
191 0

When we first started working on localization for our Unreal Engine game, the first version of our plugin was pretty simple.

We had a few Blueprint functions. You'd get the VeluTranslate Subsystem, provide a translation key, and connect it to a TextBlock.

And it worked.

For a basic menu with a handful of buttons, that was enough.

But as the plugin grew, we started thinking more about how other developers would actually use it in their own projects.

We didn't just want to keep adding features. We wanted localization to fit naturally into the way people already build games in Unreal Engine.

That turned out to be a bigger task than we originally expected. :)

Why replace something Unreal Engine already has?

One of the things we gradually focused on was working with Unreal Engine's existing localization system.

Unreal already has String Tables.

A developer can create a perfectly normal Widget Blueprint, add a TextBlock, open its text properties, select a String Table, and choose the appropriate key.

And that's it.

You don't need to create a special widget derived from a VeluTranslate class or connect extra Blueprint nodes just to display localized text.

VeluTranslate works with that native String Table system.

Developers can keep building their UI the usual way, using Unreal Engine tools they're already familiar with.

This was important to us.

We didn't want someone to have to rebuild their existing menus just because they wanted to manage translations online or add more languages.

We wanted VeluTranslate to extend Unreal's existing localization workflow rather than replace it.

What about text that changes during gameplay?

Of course, not every piece of UI text stays the same while the game is running.

Take a simple sound toggle button.

When sound is enabled, the button might say "Turn Sound Off".

When it's disabled, it changes to "Turn Sound On".

Both texts can have their own keys in a String Table.

For static text, selecting the appropriate String Table entry directly in Unreal Editor is usually enough.

But when you need to change that text after a button click or some gameplay event, that's where VeluTranslate's Blueprint functions come in.

A developer can select another localization key at runtime and update the text displayed by that particular UI element.

There's no need to create two separate TextBlocks and switch their visibility depending on the game's state.

The String Table still holds the translation keys, while the Blueprint logic decides which text should be displayed at that moment.

So we weren't trying to get rid of Blueprint functions entirely.

We wanted to use them where they actually make sense, instead of requiring them for every ordinary label.

More features, but what about simplicity?

As we kept developing the plugin, more functionality started appearing.

Language selection, offline translations, language file updates, automatic detection of the player's preferred language, tools for existing projects, and quite a few other features.

Naturally, that also meant more Blueprint nodes and configuration options.

Eventually, we reached a point where we knew exactly how everything worked, but started wondering whether it would be equally obvious to someone opening the plugin for the first time.

Not exactly ideal for a developer tool.

We didn't want someone to spend an entire afternoon figuring out what belonged in GameMode, what needed to go into a Widget Blueprint, and which functions had to run when the language changed.

So we started building simpler solutions for common situations.

Not by removing the advanced options, but by making them unnecessary when a developer doesn't actually need them.

A language selector without writing your own Blueprint logic

Language selection is a good example.

If you're building your own language selector, you normally need to handle loading available languages, populating the list, displaying names and images, handling button clicks, and switching the selected language.

It's all perfectly doable.

But why write the same logic again for every game?

So we created a setup built around two widgets.

The first is the main language selection window.

A developer creates their own Widget Blueprint, derives it from the prepared VeluTranslate class, and designs it however they want.

The second widget represents an individual language entry.

It might contain a button, the language name, a flag, or some other image.

The developer designs that widget too, then connects it to the main selector.

The main widget uses those individual entries to display the languages available in the game.

And here's the important part.

For the standard setup, developers don't really need to write their own Blueprint logic.

They just need to name and bind the required buttons, text elements, and images according to the plugin's conventions.

The prepared widget classes take care of the language selection behavior.

The developer still controls the appearance.

It can be a simple list, a dropdown-style menu, or perhaps a grid of languages with flags.

The selector can display native language names such as English, Deutsch, Français, or Slovenčina, use translated names based on the currently selected language, or combine names with images.

Custom graphics are possible too.

We mainly wanted developers to focus on what their language selection UI should look like, instead of having to rebuild the same localization logic in every project.

What if the player speaks a language the game doesn't have yet?

This was another situation we wanted to simplify.

Imagine a player launching a game that doesn't currently support their preferred language.

A developer might want to show a message explaining that the language isn't available yet.

And if automatic AI translation is enabled and the developer has enough credits, VeluTranslate can prepare that language in the background.

But we didn't want every developer to have to build their own preferred-language detection, availability checks, and notification system.

So we added dedicated widget classes for these situations.

The developer creates a Widget Blueprint for the missing-language notification.

They can then create a second widget for when that language becomes available.

Both widget classes are selected directly in the VeluTranslate plugin settings.

There's no need to manually trigger them through GameMode or GameInstance, or build the entire detection workflow with Blueprint nodes.

The plugin handles checking the player's preferred language and showing the appropriate configured widget.

If automatic translation is running, the player can continue using one of the available languages.

Once the requested language is ready, the game can display the second widget and offer the player a choice: switch to the new language or stay with the current one.

Again, the developer controls how both windows look.

The underlying workflow can run without additional manual setup.

And if someone needs custom behavior, the more advanced Blueprint functions are still available.

What about developers who already use String Tables?

This was another thing we had to think about.

Not everyone starts a new game from scratch.

Many developers already have their UI built, their String Tables organized, and hundreds or even thousands of localization keys.

We didn't want VeluTranslate to force them to recreate all of that.

If a project already uses Unreal Engine String Tables, those tables can stay exactly where they are.

There's no need to replace existing TextBlocks or rebuild all the references to individual keys.

The developer just needs to connect Unreal Editor to VeluTranslate.

For that, we built a pairing system.

In their VeluTranslate profile, the developer generates a pairing token valid for 15 minutes.

They use that token in the editor-side part of the plugin to connect their account and project.

This pairing mechanism belongs to the Unreal Editor integration. It isn't included in the packaged game.

Once connected, the developer can use the import tools to bring their existing String Tables, keys, and source-language texts into VeluTranslate.

And this is one of the parts we particularly like.

There's no need to create another String Table for every additional language.

Developers can keep their existing String Table references and manage the additional languages through VeluTranslate.

Translations for those languages are stored in language JSON files, which the runtime integration uses to make the appropriate localized text available for the selected language.

From the developer's perspective, the references to the original String Table remain in place, but the game can display different language versions.

So if a main menu already uses English String Table entries, the developer doesn't need to create a separate collection of String Tables for Slovak, German, French, and every other language they decide to add.

They can manage those languages and translations through VeluTranslate instead.

And you don't even have to leave Unreal Editor

This is another part of the integration we've spent time expanding.

Once the project is paired, developers don't have to keep switching between Unreal Engine and the VeluTranslate website.

A lot of localization work can be done directly inside the editor.

Our editor tools allow developers to manage localization keys, add languages, edit texts, and send content for translation.

So if you're working on a menu and suddenly need another string, you don't have to leave Unreal Engine.

Open the VeluTranslate editor tool, create the key, enter the text, and continue working.

One detail was especially important to us.

New keys should be available immediately while working in the editor, even if synchronization or translation hasn't finished on the server yet.

Let's say a developer adds a new key that still needs translating into several languages.

They can already see and use that key in the editor while the translation process is still running.

There's no need to wait for the entire translation pipeline to finish or for the updated language files to be published to the game's runtime delivery system.

Of course, that doesn't automatically mean the new translation is already available to players in a packaged game.

Editor workflows and runtime distribution are two different things.

And we think keeping those processes separate makes sense.

When someone is actively developing a game, we don't want every server-side operation to interrupt their work.

The VeluTranslate web interface remains available for developers who prefer managing their translations through a browser.

We wanted both workflows to be possible.

We didn't forget about C++

Not everything in our game is built with Blueprints.

A large part of our gameplay systems is written in C++, and some localization keys are used directly in that code.

So we didn't want VeluTranslate to be limited to Widget Blueprints and visual scripting.

The plugin can also be used from C++.

That can be useful for developers building custom gameplay systems, C++ components, or other Unreal Engine plugins.

It's a more advanced integration method, and someone who just wants to translate a few menu buttons probably won't need it.

But if a developer already has a large part of their game implemented in C++, it's useful to handle localization directly there.

There's no reason to route everything through Blueprints just to retrieve a translated string.

We actually use all these approaches in the same game

One of the things we like most is that we didn't have to choose between these approaches.

We actually combine them in our own Unreal Engine game.

Some gameplay systems are written in C++, with localization keys referenced directly in the code.

For regular UI labels, we use Unreal Engine's native String Tables.

When a text needs to change dynamically during gameplay, we use VeluTranslate Blueprint functions.

And for language selection or notifications about newly available languages, we use the prepared widget classes.

All of these approaches work together in the same project.

That's important to us.

We didn't have to rebuild our entire game's architecture around a single localization method.

Instead, we use whatever makes the most sense for each part of the project.

If something is easiest with a String Table, we use a String Table.

If we need additional logic, we use Blueprints.

If the gameplay system is already written in C++, we handle localization there.

And if a prepared widget saves us from repeating the same setup, there's no reason to build that functionality again from scratch.

We think a localization plugin should fit the way developers build their games, rather than forcing developers to rebuild their games around the plugin.

Existing projects are different. We definitely haven't covered everything.

We've already added tools for several ways of importing and migrating localization data from existing Unreal Engine projects.

But it would be strange to claim we've solved every possible integration scenario.

Every developer organizes their projects a little differently.

Some use String Tables, others rely on their own localization files, and some combine multiple tools.

There are almost certainly workflows we haven't encountered yet.

And that's exactly where we'd appreciate feedback.

If you have an Unreal Engine project with an existing localization setup that our integration tools don't currently support, we'd genuinely like to hear about it.

What localization files do you use? How do you organize your keys? What would make importing or synchronizing translations easier?

That kind of feedback could help us decide what additional integration options to include in our development roadmap.

We don't want to build migration tools based only on how we imagine other developers work.

We'd rather hear how they actually work.

Still plenty to improve

The VeluTranslate Unreal Engine plugin has changed quite a bit since those first few Blueprint functions.

And the more it grows, the more we realize that adding features isn't enough.

Making those features understandable and comfortable to use matters just as much.

We're still working on the editor tools, integration workflows, prepared widgets, and other parts of the plugin.

Some of these approaches have worked well in our own game, but we'd like to see how they hold up in other developers' projects.

That's one of the reasons we've opened the VeluTranslate Pilot Program.

We're looking for developers who'd like to try the platform in their own game or application and tell us what works, what feels awkward, and what's missing.

Selected projects can receive 60 days of free access to the platform. AI translation is optional, and AI credits are billed separately if used.

You can find more information here:

VeluTranslate – Pilot Program

How do you handle localization in Unreal Engine?

I'm curious how other developers approach localization in their own projects.

Do you use native String Tables, Blueprint functions, C++, custom widgets, or some combination of these?

And if you've ever moved existing localization data between different systems, what caused the biggest headaches?

We'd especially like to hear about workflows that are difficult to migrate or integrate with other tools.

Maybe you're using something we haven't even thought about while developing VeluTranslate.

We'd be interested to hear your experiences. Maybe we can learn something from each other.

Discussion

Loading comments...