Extracting Localization Phrases from our Unity projects
In our Unity projects, we handle localization using the No Such Localization component, as detailed in a previous post. Specifically, we use the phrases version, where phrases act as keys to retrieve strings from a comprehensive table. Switching languages is as simple as changing the table for text (for images, we use a different method).
We maintain a large database of strings and extract a subset tailored to each game’s specific requirements. To do this, we compile a list of all the phrases used by the localization components within a given game. Our process is straightforward: we open each scene in the Unity project, retrieve all localization components, and store their phrases.
The following code demonstrates our approach. We’ve integrated this functionality into a Unity editor menu option, automating the entire process of retrieving phrases and writing them into a text file.
public class IKIGamesEditorTools
{
private const string LocalizationMenuPath = "IKIGames/Localization/Extract All Phrases";
private const string LocalizationFileName = "localization_keys.txt";
[MenuItem(LocalizationMenuPath)]
private static void ExtractAllLocalizationPhrasesInAllScenes()
{
HashSet<string> phrases = new HashSet<string>();
List<string> scenePaths = GetScenePaths();
foreach (var scenePath in scenePaths)
{
ExtractPhrasesFromScene(scenePath, phrases);
}
WritePhrases(phrases, LocalizationFileName);
}
private static List<string> GetScenePaths()
{
List<string> scenePaths = new List<string>();
foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
{
scenePaths.Add(scene.path);
}
return scenePaths;
}
private static void ExtractPhrasesFromScene(string scenePath, HashSet<string> phrases)
{
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(scenePath, UnityEditor.SceneManagement.OpenSceneMode.Single);
ExtractPhrasesFromLocalizationComponentes(phrases);
// No need to close the new scene since OpenSceneMode.Single opens it as the only active scene
Debug.Log($"Processed: {scenePath}");
}
private static void ExtractPhrasesFromLocalizationComponentes(HashSet<string> phrases)
{
foreach (NoSuchStudio.Localization.Localizers.TMProTextLocalizer localizer in Resources.FindObjectsOfTypeAll<NoSuchStudio.Localization.Localizers.TMProTextLocalizer>())
{
if (!string.IsNullOrEmpty(localizer.phrase))
{
phrases.Add(localizer.phrase);
}
}
foreach (NoSuchStudio.Localization.Localizers.TextLocalizer localizer in Resources.FindObjectsOfTypeAll<NoSuchStudio.Localization.Localizers.TextLocalizer>())
{
if (!string.IsNullOrEmpty(localizer.phrase))
{
phrases.Add(localizer.phrase);
}
}
}
private static void WritePhrases(HashSet<string> hashSet, string filename)
{
string filePath = Path.Combine(Application.dataPath, filename);
try
{
using (StreamWriter writer = new StreamWriter(filePath))
{
foreach (string item in hashSet)
{
writer.WriteLine(item);
}
}
Debug.Log($"Phrases written successfully to: {filePath}");
}
catch (System.Exception ex)
{
Debug.LogError($"Failed to write phrases to file: {ex.Message}");
}
}
}