Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
324 changes: 324 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,324 @@
# Localization Kit
v1.1.1
by: standardcombo

With the Localization Kit players are able to choose the language they
prefer to play in, and the game adapts all texts to match that choice.
Supports a flexible number of languages of your choosing and includes tools
that solve many of the workflow challenges associated with the process of
translating a Core game.

Core has a global player base. Localization is a high return, low cost
investment to your game that increases player retention and engagement.
While English is a commonly known language, most players worldwide prefer
to play in their local language and many don't know a foreign language
at all.

This package is open source and available at:
https://github.com/ManticoreGamesInc/LocalizationCC


Setup
=====

1. For an existing game, use the `Locale Text Scanner` to extract the
game's texts into a spreadsheet. See instructions below.
2. Use the external `Loc Import Tool` to import game texts from a
spreadsheet. See instructions below.
3. Connect the library of texts to the Locale API. See instructions below.
4. Add a copy of the `Locale Manager` template to the hierarchy.
5. Add a copy of `Language Selection Popup` to the hierarchy.


Locale Text Scanner
===================

This is a tool designed to help extract texts from a game that is already
developed and prep them for translation. Follow these steps:

1. Add a copy of the `Locale Text Scanner` template into the hierarchy.
2. Run your game in preview (single player or multiplayer).
3. Act out normal gameplay actions to explore the different content in the
game. While you are doing those actions, the Scanner is saving all texts
that appear in UI or in 3D.
4. Spend at least 1 second on each piece of dynamic content. E.g. If your
game has a shop or collection system, look through all possible items.
For static UI that is always in the hierarchy, the Scanner will gather
from those immediately, without the need to "look" at them.
5. When you are ready, press LShift + T to dump all the game's texts into
the Event Log.
6. Go to the Event Log window.
7. Take note of the number of texts found by the Scanner.
8. Continue with the "Spreadsheet" instructions below...

Delete the Text Scanner from the hierarchy when done.


The Spreadsheet
===============

An external spreadsheet program is used during the translation step of the
process in order to convert the texts to all languages. This setup uses
Google Sheets, but another spreadsheet, such as Excel, can also work.

Setup:
1. Navigate to
https://docs.google.com/spreadsheets/d/1oDcC5-Mm4yIFmmWd38CdOqQpX8kZCKgZqRUZdkQ-P5o
2. File > Make a Copy
3. Name your spreadsheet according to your game.

If using `Locale Text Scanner`:
1. Scroll to the bottom of the spreadsheet, where it says:
"Add [1000] more rows".
2. Enter the amount for how many texts were generated by the Scanner.
3. In Core, in the Event Log view, select all the lines of text that
begin with "tid_" and are followed by the game text.
4. Copy the texts (Ctrl + C).
5. In your spreadsheet, select the first blank cell that was added.
6. Paste the texts copied over from the Scanner. If done correctly, the
"TIDs" and "enUS" columns should be filled up with your game's texts.

Translation:
1. Add and remove texts as needed by editing the spreadsheet.
2. The spreadsheet comes with a row that says "tid_hello_world". This row
demonstrates how to use the Google Translate formula to translate texts.
3. "TID" stands for "Text ID" and is an industry standard for localization.
You can name the TIDs anything, as long as they begin with "tid_" and each
one is unique.
4. If possible, send the spreadsheet to be professionally translated.

Other:
1. Look for texts that are very similar and procedurally generated.
E.g. If your game has a health bar, you may see many variations of
"Health 95/100". Texts such as these are dynamic and imply they should
be a single text with parameters. See the "Dynamic Texts" section below.
2. To disable translation of a specific text, add <disable> in front of it.
That text will appear with the default language instead.
3. The "Max Glyphs" column serves as instruction for translators. Specifying
a maximum number of glyphs helps some texts fit correctly in the UI.
4. The "Explanation" column tells translators about the context of a text.
Many texts don't need an explanation or it is easy to infer. However,
it's very common that game-specific terms need to be consistent across
the whole work and should be explained. Other cases where explanation is
needed include: Abiguity, gender, plurality, etc. If a translator asks for
clarification about a text, add an explanation.


Loc Import Tool
===============

Once the spreadsheet is translated (by people or by use of the Google formula),
it's time to bring those texts back into your game. The Loc Import Tool is
external to Core. It works by taking the contents of your spreadsheet as input
and auto-generating Lua files-- one per language.

The Import tool is also open source and part of the same git location as
this whole package.

Setup:
1. Download the tool from:
standardcombo.com/Loc_import_tool.zip
2. Extract the .zip
3. Run the executable `Loc Import Tool.exe`. Depending on your anti-virus
software it may be necessary to add an exception.

Importing:
1. If doing this for the first time, exit your Core project.
2. Go to your spreadsheet.
3. Select all content in the spreadsheet and copy it (Ctrl + A, Ctrl + C).
4. Return to the `Loc Import Tool`.
5. Press the button "Import from clipboard".
6. Navigate to the script folder in your Core project.
7. Name it "LocaleLibrary.lua" and press "Save".

For each language column that was copied, the tool will generate a
corresponding Library script, plus one additional script, that serves as an
index for the others.

Options:
- Columns to ignore: This option allows you to specify which columns will be
skipped during the import process. The default value of "b, c" corresponds
to the "Max Glyphs" and "Explanation" columns.
- Generate .pbt files: For scripts to appear in your Core project, they must
each have a .pbt file. This option creates the .pbts if they don't exist.
This option also connects the library scripts to each other, through
custom properties.

As the library of texts is auto-generated, it's not recommended to edit those
Lua files after they are generated. To make changes to game texts, instead
edit the spreadsheet and re-import it.


Connect the Library
===================

This is a one-time step that connects your library of generated texts with
the Localization system. After this is done, you can keep re-importing the
library whenever there are text changes, without the need to re-connect it.

1. In Project Content, select the script `APILocale`.
2. Locate the script `LocaleLibrary` that was generated by the import tool.
3. Drag the `LocaleLibrary` asset into the Properties view, to
create a custom property on `APILocale`.


Locale Manager (template)
==============

This is the main component that should be placed in the hierarchy. It
provides access to the Locale API on both client and server, encapsulating
the underlying mechanisms.

Text Detector:
The Manager template contains a client script called
`LocaleTextDetectorClient`. See below.

Player storage:
When a player selects their preferred language, the script
`LocaleManagerServer` handles saving of that choice, for the next time
that player joins your game.

Event:
When the player changes their language, the Manager broadcasts an event
with id "LocaleChanged". The callback function should expect one
parameter with the new Locale Key (e.g. enUS). For an example of this
event, add the `Example Dynamic Text` template to the hierarchy.


Text Detector
=============

The Text Detector comes as a sub-script of the `Locale Manager` template.
Its purpose is to automatically replace text in UI elements. It looks for
texts corresponding to entries in the library and replaces them based on
the player's language choice.

Object types supported:
- UIText
- UIButton
- WorldText

To disable this script simply delete it from the hierarchy.

To see the Text Detector in action, add the `Example Localized UI` template
to the hierarchy. This example has no scripts and is localized solely by
action of the Text Detector.

To prevent individual text elements from being modified by the Text
Detector, add a "AutoLocalize" custom property to the UI element, of type
Bool. For an example of this feature see the `Example Dynamic Text`
template, which contains a `UI Text Box` with auto-localize disabled.

A text's TID can be used instead of default text in UI elements and they
will be replaced just the same. For example, a UIText can say
"tid_button_play" instead of "Play". At runtime the Text Detector will
swap it for the correct value. This is advantageous if you expect the
English version of the text to be modified. This prevents human error from
breaking the localization.


Language Selection Popup (template)
========================

The Language Selection Popup is a UI template that gives players the choice
of language to play in.

Setup:
1. Add a copy of the template to the hierarchy.
2. Customize the style to match your game's look/feel.

The template contains a script called `ShowLanguageSelectionPopup`. All
this script does is to broadcast the event "Show_LanguageSelectionPopup"
if the player has never selected a language before. Your game may desire
a custom UI flow for when to display the language choice. In that case,
delete the script `ShowLanguageSelectionPopup` and broadcast the event
"Show_LanguageSelectionPopup" at the right moment. This event can also
be used if your game contains a settings screen that allows the player
to change their language at any time.


Dynamic Texts
=============

For an example of dynamic text replacement see the
`Example Dynamic Text` template.

It's often the case where placeholder symbols are used in texts, for
the purpose of replacing them at runtime.

E.g.
"Hello {player}, welcome to Core!"
becomes:
"Hello standardcombo, welcome to Core!"

In the above example, instead of using the string:
"Hello {player}, welcome to Core!"

You could imagine using two strings with concatenation, such as:
"Hello " .. player.name .. ", welcome to Core!"

While in English this is fine, in other languages the position of
subject/verb and other gramatical structures varies wildly. The strategy
of replacing tokens at runtime is a way to give to the translators the
power to customize the gramar, without having to understand relationships
between two different texts in the spreadsheet.


Testing & Bugfixing
===================

It's important to test your game in the different languages to see if
everything appears ok.

Common localization issues:

1. Some texts may not have been captured with the `Locale Text Scanner`.
It's not important to run the scanner for all text, as new texts or
texts that were missed can be entered manually into the spreadsheet.

2. Texts in an established game may be in a default context or networked.
Localization only makes sense in a client context, because each player
will select their own language. Components such as the Text Detector
will ignore Text objects that are not in a client context.

3. Texts in some languages may not fit into the UI layout. In those cases,
you can specify a glyph limit in the spreadsheet's second column and
ask the translators to see if they can come up with shorter versions.
In some cases it may be better to modify the UI elements to behave in
a more dynamic fashion, in a way that is flexible to the content size.

4. Sometimes special alphabets, such as Cyrillic, can be missing some of
the glyphs in one of the fonts. If that happens, report the issue to
Manticore and try to find an alternative translation that works. If
needed, you can disable the translation of a text in a specific
language by prefixing that text in the spreadsheet with "<disable>".


Adding a Language
=================

Let's say your game is fully translated and working. At some point you
may want to add another language. Here's how:

1. In the spreadsheet, add a column to the right-most side.
2. Change the header to set the locale key for the new language.
3. Send the file to a translator or use the Google Translate formula to
fill up the rows for each text.
4. Import the texts using the `Loc Import Tool` (see above).
5. Select the `LocaleLibrary` script and ensure it has your new language
script as one of its custom properties. If not, add it.
6. Edit the Language Selection Popup to include the new language choice:
a) Enable visibility on the panel so you can see it during edit.
b) Duplicate one of the language buttons and adjust the layout.
c) Select the new button. In the Properties view, change the `Text`
property to say the name of the language. At the bottom, in the
Custom properties, modify the LocaleKey to match the header in the
spreadsheet.
d) Revert visibility on the panel back to its original value.
7. Open the script `LanguageSelectionClient`.
8. Look at the function `UpdateTitleAndButton()` to see if it already
accounts for the new language. If not, add it to the if-else block.


Questions? Problems? Head to the forum:
<TODO>