Sponsored By

Localization as a Unity Developer

Localization is something that never seems to happen at the right time. Given that Unity allows you to run scripts to analyze your assets, and I created an open source framework to make it easier to localize regardless of where you are in development.

Alex Sink, Blogger

May 7, 2014

6 Min Read

Localization as a Unity Developer

As a game developer, often times localization is something that never seems to happen at the right time. Either we put it in from the beginning, because we think that's the right way to do it, and then the game flops. Or the game does well, and we have to try frantically to figure out how to put it in later. I've been more comfortable putting this problem into the latter classification of a "rich man" problem-set: if it's a problem you have, then it's one that you can afford to throw money at.

I recently came off a project with funding for localization, and the task was much more daunting than it should have been. There had to be a simple way, but with no good suggestions, the task was shelved. I had access to the entire asset pipeline with unity and it's still no easier to get the game translated. I still have to go through my source, assets, and all the scenes searching for text and then re-engineer all of them to reference some utility to get translations based on the current language. I knew that things could be done better. Right?

I was introduced to Jani at Transfluent, who had a similar vision of a tool to make it easier to get a game translated by leveraging unity’s asset pipeline. He had done a first pass at getting a basic in-editor translation tool up and running. It had encountered many second- and third-tier issues, so that first pass was a useful jumping-off point. However, like many unity gui editor windows, use of immediate mode leaked into code structure in ways that tended to create multi-thousand-line files. So it was a great starting point to start learning some lessons.

Obsticles to localization:

  1. Extract text and put it into a data store to be translated

  2. Remove any simple references to text –in scenes and prefabs– and replace with pure script- controlled text

  3. Replace any string concatenation ("hello "+ "world") and dynamic text (such as text from the user "hello there"+username) with strings in some format.

  4. Re-integrate text stored in the data store into your UI solution of choice

  5. Find a way to work with translators to get your data – this often involves going into the blue room (i.e., not making a game)

  6. Check that your game has translated everything – using a "foreign" language that you understand but still can use to navigate to various desired options. See: Facebook’s “English (Pirate)” https://www.facebook.com/settings?section=language 

  7. Get new translations when a phrase is found un-translated

What went right:

  1. Wrapping all of unity's OnGUI and GUILayout functionality. Seemed crazy at the time, but this ended up creating a pretty simple way to get an OnGUI-heavy game with lots of static text into a translated form as quickly as possible. There may be some functions that are somewhat ambiguous, like whether the input should be auto-translated, but as long as those are exceptions, this makes it easy to translate your game.

  2. Asset scanning for textmeshes, scenes and prefabs alike. It will find your text and get it translated. I think the blacklsiting mechanism in GameSpecificMigration can be improved.

  3. Simple storage format. Initially, I had tied the data format to a proprietary format, thinking it would make my life easier. ScriptableObjects are wonderful things that are basically gameobjects that don't live in the scene. They get the same optimizations at runtime and the merge-friendly of YAML when collaborating with folks. Keeping the interface to a simple dictionary allowed a lot of flexibility in how to handle a variety of simple tasks later on, too.

  4. "Backwards" language – an easy way to check your game to make sure you have translated most of your decisions. 

  5. "Capture mode" – being able to simply run through your game as a way of finding source translations instead of copy-pasting text from code to a translation database seems far less error-prone and easier to update. You can still do that if you want, but this helps.

  6. Editor window logic/view separation. Split out “view” logic like displaying text from “application” logic, such as uploading, ordering translations. I had grown used to this with strangeioc’s mediation pattern http://en.wikipedia.org/wiki/Mediator_pattern. Want to upload new translations you did yourself in the inspector? Sure. How about in the editor window? Ok too.

  7. Testing - Tests prevented me from getting hung up on silly things like being offline and planned outages. And they helped me verify design and data formats as I went along, because if I couldn’t test it independently of other things, then it was likely brittle. While I had previously used nunitlite, Unity’s test tools had just come out and were a nice improvement, and with Jenkins (l acostej.blogspot.com/2012/03/unity3d-from-commit-to-deployment-onto.html) I could automate the tests so that I immediately get feedback when code breaks something.

Unknown:  (i.e., the "Known unknowns")

  1. Runtime support with OnLocalize. Obviously there needs to be a way to notify clients that the language has changed, so I decided to go with the Unity way of broadcasting messages to clients. Not something I’d do normally, but it’s a pattern that I’ve seen successfully used by other similar middleware.

  2. Tokenization. I think this ended up in the positive realm, but only because the KISS principle won out over an effort to be clever that would have taken me out of my depth. The simplest solution was simply wrapping string. Format, and using strings in the format "Hello, {0}" seem like they may be the right way to go. And as it turns out, there are a *ton* of nuances to translation that would make a screenshot way more useful than a suggested part of speech (or worse yet, suggestion of plurality) as a token name in there.

Future work:

  1. Editor-support. Translate your editor tools – EditorGUILayout and EditorGUI seem to work. I think all that would be needed to have fully localized editor tools would be some way to connect the wrapped editorguilayout and editorgui with a specific TranslationUtilityInstance instead of the global one. I don't think this would be challenging at all, but the demand for such a thing seems to be uncertain.

  2. Making sure the text will "look" right and give the translators a better clue if their translations will work upfront. This could be as simple as sending screenshots while in capture mode as well. 

  3. Deeper integrations – support word wrapping and resizing (see: shrink to fit) on various frameworks

  4. Supporting more UI frameworks – they have different challenges involved with them.

  5. Middleware integration – integration into things like fungus and other toolchains meant to make it easier to create games. It would be cool to have tools like fungus, and other story/game building tools supported natively.

  6. More asset scanning. Create more supported auto-migrated text.  Think: localized playmaker text.  The Asset Scanner was set up to help solve some of the sticky bits of editor scripting and ICustomProcessors that just deal with the GameObjects to extend functionality to new types of scripts.

As more folks use the tool, the goal is to continue to make it better as new use-cases are identified. I hope to hear from you so we can start to solve some of these problems better, together. 

Come get it free on the asset store at https://www.assetstore.unity3d.com/en/#!/content/17648 !  

-Alex

Read more about:

Blogs

About the Author(s)

Daily news, dev blogs, and stories from Game Developer straight to your inbox

You May Also Like