Appearance
Appearance
DANGER
WIP: The localization feature of Metaplay is still in development, and we're adding more content to this section as the segment develops. Currently, only the delivery of the localization content is supported, but the usage of the translations is the game's responsibility.
Metaplay contains a localization system that delivers appropriate translation files to the game. The system is only concerned with the delivery and management of translation data, and it's up to you to display the translations in-game. Currently, only string translations are supported. The localization system does not support other data formats or non-language-based localization (such as location-based).
You may inspect the localization system state with the built-in editor component of the MetaplaySDK
game object in the Unity editor:
Localization settings in the Metaplay SDK component.
The inspector shows the current MetaplaySDK.ActiveLanguage
, and the version of the language data. Below them, you can also see the state of all known languages. For each language, the inspector shows the LanguageId
and the localization sources:
builtin
for languages with a translation file baked into the application package. You should have at least one language baked in to allow the application to have a default localization on the first session.cdn
for language for which there is a translation file available in the CDN.cached
for languages with localization files downloaded from the CDN and cached into the app.update
if there is an updated version of the language available in the CDN.By clicking "Use”, the localization system switches over the language to the one selected. If the language was not found in the cache nor is it built into the client, it will be downloaded first. A language can be downloaded without switching to it by clicking "Fetch" which starts a background download for the language. You can only download languages that have both cdn
and update
flags.
Here's a quick guide on the steps necessary to integrate Metaplay's localization features:
In your MetaplayCoreOptions
, set MetaplayFeatureFlags.EnableLocalizations
to true:
public MetaplayCoreOptions Options { get; } = new MetaplayCoreOptions(
<snip>
featureFlags: new MetaplayFeatureFlags
{
EnableLocalizations = true // Set to true to enable localizations!
});
Translation files are spreadsheets with keys for every string that should be localized, followed by translations for every respective language.
TranslationId | en | fi | ... |
---|---|---|---|
hello.world | Hello, World! | Hei, maailma! | |
ui.appname | Idle WebDev | Loikoileva VerkkoKehitys | |
... |
The first row is exclusive for TranslationId
and the language tags. The following rows have the keys and translated strings themselves.
You must add localization information to your game configs to tell the SDK which languages your game supports.
LanguageId #key | DisplayName |
---|---|
en | English |
fi | Finnish |
... |
To do that, you can use the LanguageInfo
class the ships with the SDK. Since it implements an IGameConfigData
interface, you can add localization configs to your SharedGameConfig
to access them.
public class SharedGameConfig : SharedGameConfigBase
{
...
[GameConfigEntry("Languages")]
public GameConfigLibrary<LanguageId, LanguageInfo> Languages { get; private set; }
}
DANGER
You need to build the configs manually! The SDK's default config builder does not build localization archives automatically. Check out Building Localization Archives in the Advanced Guide section for information on how to do that.
You have now have Languages defined with theis LanguageId
s, but these IDs are just opaque strings and carry no inherent meaning. Next, you need to define how device languages map into these LanguageId's. By default, MetaplaySDK maps LanguageIDs by their ISO 639-1 (2-letter-names) language code such as 'en' for English and 'fi' for Finnish, but this may be customized by implementing a LanguageIdMapping
:
class MyLanguageIdMapping : LanguageIdMapping
{
public override LanguageId TryGetLanguageIdForDeviceLanguage(SystemLanguage systemLanguage)
{
// LanguageIDs are "<language>-<region>"
if (systemLanguage == SystemLanguage.English) return LanguageId.FromString("en-US");
if (systemLanguage == SystemLanguage.Finnish) return LanguageId.FromString("fi-FI");
return null;
}
}
Lastly, you can access the translated strings on the client:
MetaplaySDK.ActiveLanguage
to localize the game.MetaplaySDK.LocalizationManager.SetCurrentLanguage()
to change the active language of the game.To detect language changes to know when to refresh the translations in UI, a custom MetaplayLocalizationDelegate
needs to be supplied. In SDK init:
MetaplayClient.Initialize(new MetaplayClientOptions
{
<snip>
LocalizationDelegate = new GameLocalizationDelegate(),
});
where
class GameLocalizationDelegate : DefaultMetaplayLocalizationDelegate
{
public override void OnActiveLanguageChanged()
{
// TODO: Refresh translations in UI
}
}
Server-side code may access a player's currently active localization strings by calling PlayerActorBase.GetLocalizationLanguageAsync()
. This attempts to return the same version of the language the client is running. If that is not possible, the method returns the latest version of the player's language. As with client-side localization, the SDK currently only supports string translations.
There's no set step in the SDK for building the localization. However, here's how to do it:
Commonly, games will build localizations into a single ConfigArchive
. Each is composed of ConfigArchiveEntry
objects, in which the name of each entry is the language's code. You can create an entry by using LocalizationLanguage.ExportBinaryConfigArchiveEntry()
. Hence the archive could be generated as:
static async Task<ConfigArchive> BuildLocalizationsArchiveAsync(MetaTime timestamp)
{
// Fetch the 'Localizations' sheet that contains all the localizations (one column per language)
SpreadsheetContent content = GoogleSheetFetcher.FetchSheetAsync(GoogleSheetsCredentials, config.GoogleSheetId, sheetName, CancellationToken.None);
// Convert sheets to ConfigArchiveEntries with one entry per language
List<ConfigArchiveEntry> entries =
GameConfigHelper.SplitLanguageSheets(content, allowMissingTranslations: false)
.Select(sheet => ParseLocalizationLanguageSheet(sheet))
.ToList<ConfigArchiveEntry>();
// Create the final ConfigArchive
return new ConfigArchive(timestamp, entries);
}
static ConfigArchiveEntry ParseLocalizationLanguageSheet(SpreadsheetContent sheet)
{
// Parse sheet to LocalizationLanguage and export in binary-serialized format
LanguageId languageId = LanguageId.FromString(sheet.Name);
LocalizationLanguage language = LocalizationLanguage.FromSpreadsheetContent(languageId, sheet);
return language.ExportBinaryConfigArchiveEntry();
}
If you don’t have Google Sheets integrated into your configs workflow yet, you can also build your localization archives from local files:
string csvFilePath = "path/to/local/file";
byte[] csvBytes = await File.ReadAllAsync(csvFilePath);
SpreadsheetContent contents = GameConfigHelper.ParseCsvToSpreadsheet(Path.GetFileName(csvFilePath), csvBytes);
The server requires the localization data to be in the aforementioned config archive. So to use the created config, just upload/publish the config:
await GameConfigBuildUtil.PublishLocalizationArchiveToServerAsync("https://my-admin-host/api/", localizationsArchive, authorizationToke: null, confirmDialog: false);
The client expects the initial localization (the ones shipped with the game) to be in a one-file-per-language format in the StreamingAssets folder. You can arrange this as follows:
ConfigArchive.FolderEncoding.WriteToDirectory(localizationsArchive, "Assets/StreamingAssets/Localizations");
// Refresh AssetDatabase to make sure Unity sees changed files
AssetDatabase.Refresh();
Remember to delete existing localization files in the folder first!
Once you get your localizations going, you might want to start working on integrating Google Sheets into your game configs workflow. Google Sheets are a popular tool for managing configuration data and have the advantage of being free and familiar to most designers. Check out our Google Sheets Integration page for a step-by-step guide.