Translations import/exports in XLIFF, JSON, simple CSV or something ?

Announcements, support questions, and discussion for the Dialogue System.
NotVeryProfessional
Posts: 150
Joined: Mon Nov 23, 2020 6:35 am

Translations import/exports in XLIFF, JSON, simple CSV or something ?

Post by NotVeryProfessional »

I'm trying to integrate Weblate for community translations.

Found out that while Unity Localization works really well, the Dialogue System export doesn't. It is well-suited for using a spreadsheet to translate, but it's not a standard file format.

Would it be possible to get an export and import to a more standard file format? (link to the ones Weblate supports: https://docs.weblate.org/en/latest/formats.html)

I've manually massaged them to work now, but it'll be quite a bit of manual work to re-import them.

If not, I might sit myself down and try to write that, but obviously official support would be a lot better.

---

Alternatively: Maybe Dialogue System uses a file format that can be converted back and forth? If so, where can I find a converter?
User avatar
Tony Li
Posts: 22093
Joined: Thu Jul 18, 2013 1:27 pm

Re: Translations import/exports in XLIFF, JSON, simple CSV or something ?

Post by Tony Li »

Hi,

Have you tried using the Dialogue System's Localization Export/Import? It exports to simple CSV spreadsheets.

I do have a task to also support xliff in the future, but it's way down on the task list because csv works fine.
NotVeryProfessional
Posts: 150
Joined: Mon Nov 23, 2020 6:35 am

Re: Translations import/exports in XLIFF, JSON, simple CSV or something ?

Post by NotVeryProfessional »

Yes, the CSV export is what I'm talking about.

It exports to a spreadsheet. As far I can tell, that is in no format anything else supports. Weblate, for example, expects one line per term (key, translation). The Dialogue System exports a CSV that is great for editing in a spreadsheet (e.g. Excel) because it has all the context in one line, but that can be several translation terms.

Essentially, just like the Actors_*.csv files.

If that's planned for the near future, I'm happy to wait. Otherwise I would probably cook up a few quick scripts to convert the files.
User avatar
Tony Li
Posts: 22093
Joined: Thu Jul 18, 2013 1:27 pm

Re: Translations import/exports in XLIFF, JSON, simple CSV or something ?

Post by Tony Li »

It'll be a while before I get to xliff. Your best bet is to write a script to change it to the format you want, or maybe use the i2 Localization integration or Unity Localization Package integration.
NotVeryProfessional
Posts: 150
Joined: Mon Nov 23, 2020 6:35 am

Re: Translations import/exports in XLIFF, JSON, simple CSV or something ?

Post by NotVeryProfessional »

I'll do that and post the scripts here.

I tried the Unity Localization integration a long time ago, but it made me unhappy. Don't remember why. I might try again in light of this because at least export works, I'm still fiddling with the re-import.
User avatar
Tony Li
Posts: 22093
Joined: Thu Jul 18, 2013 1:27 pm

Re: Translations import/exports in XLIFF, JSON, simple CSV or something ?

Post by Tony Li »

Unity's Localization Package is overly complex. But if you do use it, please import the Localization Package Support unitypackage from DS 2.2.49 or higher. The integration was updated in DS 2.2.49.
NotVeryProfessional
Posts: 150
Joined: Mon Nov 23, 2020 6:35 am

Re: Translations import/exports in XLIFF, JSON, simple CSV or something ?

Post by NotVeryProfessional »

Updated and tried it out.

Do I see right in DialogueToLocalizationTableWindow.cs that it doesn't export localizations that I made in Dialogue System using the localized fields (e.g. "DisplayName de")?

The code indicates it imports them, but it doesn't export them.

I'll try to add that myself if that's the case.
User avatar
Tony Li
Posts: 22093
Joined: Thu Jul 18, 2013 1:27 pm

Re: Translations import/exports in XLIFF, JSON, simple CSV or something ?

Post by Tony Li »

Yes, that's the case. The idea is that the Localization Package's data will be the authoritative source.
NotVeryProfessional
Posts: 150
Joined: Mon Nov 23, 2020 6:35 am

Re: Translations import/exports in XLIFF, JSON, simple CSV or something ?

Post by NotVeryProfessional »

Probably the right approach except in my case where I've already translated stuff inside Dialogue System and now want to transition over.

Here is a modified CopyStringTableToTextTables.cs that appears to work. It has a 3rd button to export with translations for actors, quests and conversation entries (forum doesn't allow to attach .cs files).

Code: Select all

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using UnityEditor.Localization;
using UnityEditorInternal;

namespace PixelCrushers.DialogueSystem.LocalizationPackageSupport
{

    /// <summary>
    /// Custom editor window to populate Localization Package string table with
    /// actor names and dialogue entry text. At runtime, DialogueSystemLocalizationPackageBridge
    /// will read localized values from string table.
    /// </summary>
    public class DialogueToLocalizationTableWindow : EditorWindow
    {

        [MenuItem("Tools/Pixel Crushers/Dialogue System/Third Party/Localization/Dialogue To Localization Table", false, 3)]
        public static void Init()
        {
            var window = EditorWindow.GetWindow(typeof(DialogueToLocalizationTableWindow), false, "DS To Loc") as DialogueToLocalizationTableWindow;
            window.minSize = new Vector2(300, 280);
        }

        private const string PrefsKey = "DialogueSystem.DSToLTPrefs";

        [Serializable]
        public class Prefs
        {
            public List<string> databaseGuids = new List<string>();
            public List<string> textTableGuids = new List<string>();
            public string localizationSettingsGuid;
            public string stringTableCollectionGuid;
            public string defaultLocaleGuid;
            public string guidFieldTitle = "Guid";
        }

        private Prefs prefs;
        private LocalizationSettings localizationSettings;
        private StringTableCollection stringTableCollection;
        private Locale defaultLocale;
        private List<DialogueDatabase> databases = new List<DialogueDatabase>();
        private List<TextTable> textTables = new List<TextTable>();
        private ReorderableList databasesList;
        private ReorderableList textTablesList;
        private Vector2 scrollPosition = Vector2.zero;

        private void OnEnable()
        {
            if (EditorPrefs.HasKey(PrefsKey))
            {
                prefs = JsonUtility.FromJson<Prefs>(EditorPrefs.GetString(PrefsKey));
            }
            if (prefs == null) prefs = new Prefs();

            databases.Clear();
            foreach (var databaseGuid in prefs.databaseGuids)
            {
                if (!string.IsNullOrEmpty(databaseGuid))
                {
                    var database = AssetDatabase.LoadAssetAtPath<DialogueDatabase>(AssetDatabase.GUIDToAssetPath(databaseGuid));
                    if (database != null)
                    {
                        databases.Add(database);
                    }
                }
            }
            textTables.Clear();
            foreach (var textTableGuid in prefs.textTableGuids)
            {
                if (!string.IsNullOrEmpty(textTableGuid))
                {
                    var textTable = AssetDatabase.LoadAssetAtPath<TextTable>(AssetDatabase.GUIDToAssetPath(textTableGuid));
                    if (textTable != null)
                    {
                        textTables.Add(textTable);
                    }
                }
            }
            localizationSettings = AssetDatabase.LoadAssetAtPath<LocalizationSettings>(AssetDatabase.GUIDToAssetPath(prefs.localizationSettingsGuid));
            stringTableCollection = AssetDatabase.LoadAssetAtPath<StringTableCollection>(AssetDatabase.GUIDToAssetPath(prefs.stringTableCollectionGuid));
            defaultLocale = AssetDatabase.LoadAssetAtPath<Locale>(AssetDatabase.GUIDToAssetPath(prefs.defaultLocaleGuid));
        }

        private void OnDisable()
        {
            prefs.databaseGuids.Clear();
            foreach (var database in databases)
            {
                prefs.databaseGuids.Add((database != null) ? AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(database)) : string.Empty);
            }
            prefs.textTableGuids.Clear();
            foreach (var textTable in textTables)
            {
                prefs.textTableGuids.Add((textTable != null) ? AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(textTable)) : string.Empty);
            }
            prefs.localizationSettingsGuid = (localizationSettings != null) ? AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(localizationSettings)) : string.Empty;
            prefs.stringTableCollectionGuid = (stringTableCollection != null) ? AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(stringTableCollection)) : string.Empty;
            prefs.defaultLocaleGuid = (defaultLocale != null) ? AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(defaultLocale)) : string.Empty;
            EditorPrefs.SetString(PrefsKey, JsonUtility.ToJson(prefs));
        }

        private void OnGUI()
        {
            try
            {
                scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
                if (databasesList == null)
                {
                    databasesList = new ReorderableList(databases, typeof(DialogueDatabase), true, true, true, true);
                    databasesList.drawHeaderCallback += OnDrawDatabasesListHeader;
                    databasesList.drawElementCallback += OnDrawDatabasesListElement;
                    databasesList.onAddCallback += OnAddDatabase;
                }
                databasesList.DoLayoutList();
                if (textTablesList == null)
                {
                    textTablesList = new ReorderableList(textTables, typeof(TextTable), true, true, true, true);
                    textTablesList.drawHeaderCallback += OnDrawTextTablesListHeader;
                    textTablesList.drawElementCallback += OnDrawTextTablesListElement;
                    textTablesList.onAddCallback += OnAddTextTable;
                }
                textTablesList.DoLayoutList();
                prefs.guidFieldTitle = EditorGUILayout.TextField(new GUIContent("Unique Field Title", "Field title to use/create in dialogue database to uniquely and persistently identify each Key in string table."), prefs.guidFieldTitle);
                localizationSettings = EditorGUILayout.ObjectField("Localization Settings", localizationSettings, typeof(LocalizationSettings), false) as LocalizationSettings;
                stringTableCollection = EditorGUILayout.ObjectField("String Table", stringTableCollection, typeof(StringTableCollection), false) as StringTableCollection;
                defaultLocale = EditorGUILayout.ObjectField("Default Locale", defaultLocale, typeof(Locale), false) as Locale;
                EditorGUI.BeginDisabledGroup(!HasAnyDatabases() || stringTableCollection == null || defaultLocale == null || string.IsNullOrEmpty(prefs.guidFieldTitle));
                if (GUILayout.Button("Dialogue System To String Table"))
                {
	                CopyDialogueSystemToStringTable(false);
                }
	            if (GUILayout.Button("Dialogue System To String Table (with translations)"))
	            {
		            CopyDialogueSystemToStringTable(true);
	            }
	            if (GUILayout.Button("String Table To Dialogue System"))
                {
                    CopyStringTableToDialogueSystem();
                }
                EditorGUI.EndDisabledGroup();
            }
            finally
            {
                EditorGUILayout.EndScrollView();
            }
        }

        private bool HasAnyDatabases()
        {
            return databases.Find(x => x != null) != null;
        }

        private void OnDrawDatabasesListHeader(Rect rect)
        {
            EditorGUI.LabelField(rect, "Databases");
        }

        private void OnDrawDatabasesListElement(Rect rect, int index, bool isActive, bool isFocused)
        {
            if (!(0 <= index && index < databases.Count)) return;
            databases[index] = EditorGUI.ObjectField(rect, databases[index], typeof(DialogueDatabase), true) as DialogueDatabase;
        }

        private void OnAddDatabase(ReorderableList list)
        {
            databases.Add(null);
        }

        private void OnDrawTextTablesListHeader(Rect rect)
        {
            EditorGUI.LabelField(rect, "Text Tables");
        }

        private void OnDrawTextTablesListElement(Rect rect, int index, bool isActive, bool isFocused)
        {
            if (!(0 <= index && index < textTables.Count)) return;
            textTables[index] = EditorGUI.ObjectField(rect, textTables[index], typeof(TextTable), true) as TextTable;
        }

        private void OnAddTextTable(ReorderableList list)
        {
            textTables.Add(null);
        }

        private void SaveStringTables()
        {
            EditorUtility.SetDirty(stringTableCollection);
            for (int i = 0; i < stringTableCollection.StringTables.Count; i++)
            {
                EditorUtility.SetDirty(stringTableCollection.StringTables[i]);
            }
            AssetDatabase.SaveAssets();
        }

	    private void CopyDialogueSystemToStringTable(bool withTranslations)
        {
	        CopyDialogueDatabasesToStringTable(withTranslations);
            CopyTextTablesToStringTable();
            SaveStringTables();
        }

        private void CopyStringTableToDialogueSystem()
        {
            CopyStringTableToDialogueDatabases();
            CopyStringTableToTextTables();
        }

	    private void CopyDialogueDatabasesToStringTable(bool withTranslations)
        {
            try
            {

                Undo.RecordObjects(new UnityEngine.Object[] { stringTableCollection.SharedData, stringTableCollection }, "Modified table");

                var table = stringTableCollection.StringTables.First(x => x.LocaleIdentifier == defaultLocale.Identifier);
                if (table == null)
                {
                    Debug.LogError("Can't find string table for locale " + defaultLocale.Identifier.Code);
                    return;
                }

                var hasRecordedDatabaseUndo = false;
                float total = 0;
                foreach (var database in databases)
                {
                    if (database == null) continue;
                    total += database.actors.Count + database.conversations.Count;
                    var quests = database.items.FindAll(x => !x.IsItem);
                    total += quests.Count;
                }
                int progress = 0;

                // Actor display names:
                foreach (var database in databases)
                {
                    if (database == null) continue;
                    foreach (var actor in database.actors)
                    {
                        progress++;
                        if (EditorUtility.DisplayCancelableProgressBar("Dialogue To String Table", actor.Name, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }

                        // Get actor guid:
                        var field = Field.Lookup(actor.fields, prefs.guidFieldTitle);
                        if (field == null)
                        {
                            if (!hasRecordedDatabaseUndo)
                            {
                                hasRecordedDatabaseUndo = true;
                                Undo.RecordObject(database, "Modify database");
                            }
                            field = new Field(prefs.guidFieldTitle, Guid.NewGuid().ToString(), FieldType.Text);
                            actor.fields.Add(field);
                        }
                        else if (string.IsNullOrEmpty(field.value))
                        {
                            field.value = Guid.NewGuid().ToString();
                        }

                        var actorDisplayName = actor.FieldExists("Display Name") ? actor.LookupValue("Display Name") : actor.Name;
	                    table.AddEntry(field.value, actorDisplayName);

	                    // export existing translations
	                    if (withTranslations) foreach (var localeTable in stringTableCollection.StringTables) {
		                    if (localeTable.LocaleIdentifier != defaultLocale.Identifier) {
		                    	string fieldName = "Display Name "+localeTable.LocaleIdentifier.Code;
		                    	if (actor.FieldExists(fieldName)) {
		                    		string fieldContent = actor.LookupValue(fieldName);
		                    		if (!string.IsNullOrEmpty(fieldContent)) {
			                    		localeTable.AddEntry(field.value, fieldContent);
		                    		}
		                    	}
		                    }
	                    }
   
                    }
                }

                // Quests:
                foreach (var database in databases)
                {
                    if (database == null) continue;
                    foreach (var quest in database.items)
                    {
                        if (quest.IsItem) continue;
                        progress++;
                        if (EditorUtility.DisplayCancelableProgressBar("Dialogue To String Table", quest.Name, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }

                        // Get quest guid:
                        var field = Field.Lookup(quest.fields, prefs.guidFieldTitle);
                        if (field == null)
                        {
                            if (!hasRecordedDatabaseUndo)
                            {
                                hasRecordedDatabaseUndo = true;
                                Undo.RecordObject(database, "Modify database");
                            }
                            field = new Field(prefs.guidFieldTitle, Guid.NewGuid().ToString(), FieldType.Text);
                            quest.fields.Add(field);
                        }
                        else if (string.IsNullOrEmpty(field.value))
                        {
                            field.value = Guid.NewGuid().ToString();
                        }

                        var questDisplayName = quest.FieldExists("Display Name") ? quest.LookupValue("Display Name") : quest.Name;
                        table.AddEntry(field.value, questDisplayName);

                        var description = quest.LookupValue("Description");
                        table.AddEntry(field.value + "_Description", description);
                        var successDescription = quest.LookupValue("Success Description");
                        if (!string.IsNullOrEmpty(successDescription)) table.AddEntry(field.value + "_SuccessDescription", successDescription);
                        var failureDescription = quest.LookupValue("Failure Description");
	                    if (!string.IsNullOrEmpty(failureDescription)) table.AddEntry(field.value + "_FailureDescription", failureDescription);
	                    /* FIXME: this duplicates the group name across all quests
	                    var groupName = quest.LookupValue("Group");
	                    if (!string.IsNullOrEmpty(groupName)) table.AddEntry(field.value + "_Group", groupName);
	                    */

	                    // export existing translations
	                    if (withTranslations) foreach (var localeTable in stringTableCollection.StringTables) {
	                    	string fieldName = "";
	                    	string fieldContent = "";

		                    if (localeTable.LocaleIdentifier != defaultLocale.Identifier) {
		                    	fieldName = "Display Name "+localeTable.LocaleIdentifier.Code;
		                    	if (quest.FieldExists(fieldName)) {
		                    		fieldContent = quest.LookupValue(fieldName);
		                    		if (!string.IsNullOrEmpty(fieldContent)) {
			                    		localeTable.AddEntry(field.value, fieldContent);
		                    		}
		                    	}
		                    	fieldName = "Description "+localeTable.LocaleIdentifier.Code;
	                    		fieldContent = quest.LookupValue(fieldName);
			                    if (!string.IsNullOrEmpty(fieldContent)) {
			                    	localeTable.AddEntry(field.value + "_Description", fieldContent);
		                    	}
		                    	fieldName = "Success Description "+localeTable.LocaleIdentifier.Code;
	                    		fieldContent = quest.LookupValue(fieldName);
			                    if (!string.IsNullOrEmpty(fieldContent)) {
			                    	localeTable.AddEntry(field.value + "_SuccessDescription", fieldContent);
		                    	}
		                    	fieldName = "Failure Description "+localeTable.LocaleIdentifier.Code;
	                    		fieldContent = quest.LookupValue(fieldName);
			                    if (!string.IsNullOrEmpty(fieldContent)) {
			                    	localeTable.AddEntry(field.value + "_FailureDescription", fieldContent);
		                    	}
			                    /* FIXME: this duplicates the group name across all quests
		                    	fieldName = "Group "+localeTable.LocaleIdentifier.Code;
	                    		fieldContent = quest.LookupValue(fieldName);
			                    if (!string.IsNullOrEmpty(fieldContent)) {
			                    	localeTable.AddEntry(field.value + "_Group", fieldContent);
		                    	}
		                    	*/
		                    }
	                    }


                        var entryCount = quest.LookupInt("Entry Count");
                        for (int i = 1; i <= entryCount; i++)
                        {
                            table.AddEntry(field.value + "_Entry_" + i, quest.LookupValue("Entry " + i));
	                        // export existing translations
	                        if (withTranslations) foreach (var localeTable in stringTableCollection.StringTables) {
		                        if (localeTable.LocaleIdentifier != defaultLocale.Identifier) {
			                        string fieldName = "Entry " + i + " "+localeTable.LocaleIdentifier.Code;
			                        string fieldContent = quest.LookupValue(fieldName);
			                        if (!string.IsNullOrEmpty(fieldContent)) {
				                        localeTable.AddEntry(field.value + "_Entry_" + i, fieldContent);
			                        }
		                        }
	                        }
                        }
                    }
                }

                // Conversations:
                foreach (var database in databases)
                {
                    if (database == null) continue;
                    foreach (var conversation in database.conversations)
                    {
                        progress++;
                        if (EditorUtility.DisplayCancelableProgressBar("Dialogue To String Table", conversation.Title, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }

                        foreach (var entry in conversation.dialogueEntries)
                        {
                            // Get dialogue entry guid:
                            var field = Field.Lookup(entry.fields, prefs.guidFieldTitle);
                            if (field == null)
                            {
                                if (!hasRecordedDatabaseUndo)
                                {
                                    hasRecordedDatabaseUndo = true;
                                    Undo.RecordObject(database, "Modify database");
                                }
                                field = new Field(prefs.guidFieldTitle, Guid.NewGuid().ToString(), FieldType.Text);
                                entry.fields.Add(field);
                            }
                            else if (string.IsNullOrEmpty(field.value))
                            {
                                field.value = Guid.NewGuid().ToString();
                            }

                            // Add localized entries:
                            table.AddEntry(field.value, entry.DialogueText);
                            if (!string.IsNullOrEmpty(entry.MenuText))
                            {
                                table.AddEntry(field.value + "_MenuText", entry.MenuText);
                            }

	                        // export existing translations
	                        if (withTranslations) foreach (var localeTable in stringTableCollection.StringTables) {
		                        if (localeTable.LocaleIdentifier != defaultLocale.Identifier) {
			                        string fieldName = localeTable.LocaleIdentifier.Code;
			                        string fieldContent = Field.LookupValue(entry.fields, fieldName);
			                        if (!string.IsNullOrEmpty(fieldContent)) {
				                        localeTable.AddEntry(field.value, fieldContent);
			                        }
			                        fieldName = "Menu Text " + localeTable.LocaleIdentifier.Code;
			                        fieldContent = Field.LookupValue(entry.fields, fieldName);
			                        if (!string.IsNullOrEmpty(fieldContent)) {
				                        localeTable.AddEntry(field.value + "_MenuText", fieldContent);
			                        }
		                        }
	                        }

                        }
                    }
                }

                Debug.Log("Populated Localization Package string table " + stringTableCollection.name + " with dialogue database fields.", stringTableCollection);
            }
            finally
            {
                EditorUtility.ClearProgressBar();
            }
        }

        private void CopyStringTableToDialogueDatabases()
        {
            try
            {
                float total = databases.Count;
                int progress = 0;
                foreach (var database in databases)
                {
                    if (database == null) continue;
                    Undo.RecordObject(database, "Localization to Database");
                    progress++;

                    // Actor display names:
                    foreach (var actor in database.actors)
                    {
                        if (EditorUtility.DisplayCancelableProgressBar("String Table To Dialogue", actor.Name, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }

                        // Get actor guid:
                        var field = Field.Lookup(actor.fields, prefs.guidFieldTitle);
                        if (field == null || string.IsNullOrEmpty(field.value)) continue;
                        foreach (var stringTable in stringTableCollection.StringTables)
                        {
                            var stringTableEntry = stringTable.GetEntry(field.value);
                            if (stringTableEntry == null) continue;
                            var displayNameFieldTitle = "Display Name";
                            if (stringTable.LocaleIdentifier != defaultLocale.Identifier)
                            {
                                displayNameFieldTitle += $" {stringTable.LocaleIdentifier.Code}";
                            }
                            Field.SetValue(actor.fields, displayNameFieldTitle, stringTableEntry.LocalizedValue, FieldType.Localization);
                        }
                    }

                    // Quests:
                    foreach (var quest in database.items)
                    {
                        if (quest.IsItem) continue;
                        if (EditorUtility.DisplayCancelableProgressBar("String Table To Dialogue", quest.Name, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }

                        // Get quest guid:
                        var field = Field.Lookup(quest.fields, prefs.guidFieldTitle);
                        if (field == null || string.IsNullOrEmpty(field.value)) continue;
                        foreach (var stringTable in stringTableCollection.StringTables)
                        {
                            CopyStringTableEntryToField(stringTable, field.value, quest.fields, "Display Name");
                            CopyStringTableEntryToField(stringTable, field.value + "_Description", quest.fields, "Description");
                            CopyStringTableEntryToField(stringTable, field.value + "_SuccessDescription", quest.fields, "Success Description");
                            CopyStringTableEntryToField(stringTable, field.value + "_FailureDescription", quest.fields, "Failure Description");
	                        /* FIXME: this duplicates the group name across all quests
	                        CopyStringTableEntryToField(stringTable, field.value + "_Group", quest.fields, "Group");
	                        */
	                        var entryCount = quest.LookupInt("Entry Count");
                            for (int i = 1; i <= entryCount; i++)
                            {
                                CopyStringTableEntryToField(stringTable, field.value + "_Entry_" + i, quest.fields, "Entry " + i);
                            }
                        }
                    }

                    // Conversations:
                    if (database == null) continue;
                    foreach (var conversation in database.conversations)
                    {
                        if (EditorUtility.DisplayCancelableProgressBar("String Table To Dialogue", conversation.Title, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }

                        foreach (var entry in conversation.dialogueEntries)
                        {
                            // Get dialogue entry guid:
                            var field = Field.Lookup(entry.fields, prefs.guidFieldTitle);
                            if (field == null || string.IsNullOrEmpty(field.value)) continue;
                            // Add localized entries:
                            foreach (var stringTable in stringTableCollection.StringTables)
                            {
                                if (stringTable == null) continue;
                                var stringTableEntry = stringTable.GetEntry(field.value);
                                if (stringTableEntry != null)
                                {
                                    if (stringTable.LocaleIdentifier == defaultLocale.Identifier)
                                    {
                                        Field.SetValue(entry.fields, "Dialogue Text", stringTableEntry.LocalizedValue);
                                    }
                                    else
                                    {
                                        Field.SetValue(entry.fields, stringTable.LocaleIdentifier.Code, stringTableEntry.LocalizedValue, FieldType.Localization);
                                    }
                                }
                                stringTableEntry = stringTable.GetEntry(field.value + "_MenuText");
                                if (stringTableEntry != null)
                                {
                                    if (stringTable.LocaleIdentifier == defaultLocale.Identifier)
                                    {
                                        Field.SetValue(entry.fields, "Menu Text", stringTableEntry.LocalizedValue);
                                    }
                                    else
                                    {
                                        Field.SetValue(entry.fields, "Menu Text " + stringTable.LocaleIdentifier.Code, stringTableEntry.LocalizedValue, FieldType.Localization);
                                    }
                                }
                            }
                        }
                    }
                    EditorUtility.SetDirty(database);
                }
                Debug.Log("Copied Localization Package string table " + stringTableCollection.name + " values back to dialogue database.", stringTableCollection);
            }
            finally
            {
                EditorUtility.ClearProgressBar();
            }
        }

        private void CopyStringTableEntryToField(UnityEngine.Localization.Tables.StringTable stringTable, string entryKey, List<Field> fields, string fieldTitle)
        {
            var stringTableEntry = stringTable.GetEntry(entryKey);
            if (stringTableEntry == null) return;
            if (stringTable.LocaleIdentifier != defaultLocale.Identifier)
            {
                fieldTitle += $" {stringTable.LocaleIdentifier.Code}";
            }
            Field.SetValue(fields, fieldTitle, stringTableEntry.LocalizedValue, FieldType.Localization);
        }

        private void CopyTextTablesToStringTable()
        {
            try
            {

                var table = stringTableCollection.StringTables.First(x => x.LocaleIdentifier == defaultLocale.Identifier);
                if (table == null)
                {
                    Debug.LogError("Can't find string table for locale " + defaultLocale.Identifier.Code);
                    return;
                }

                float total = 0;
                foreach (var textTable in textTables)
                {
                    if (textTable == null) continue;
                    total += textTable.fields.Count;
                }

                int progress = 0;
                foreach (var textTable in textTables)
                {
                    if (textTable == null) continue;
                    foreach (var field in textTable.fields.Values)
                    {
                        progress++;
                        if (string.IsNullOrEmpty(field.fieldName) || field.texts == null || field.texts.Count == 0) continue;
                        if (EditorUtility.DisplayCancelableProgressBar("Text Table To String Table", field.fieldName, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }
                        table.AddEntry(field.fieldName, field.texts[0]);
                    }
                }

                Debug.Log("Populated Localization Package string table " + stringTableCollection.name + " with text table fields.", stringTableCollection);
            }
            finally
            {
                EditorUtility.ClearProgressBar();
            }
        }

        private void CopyStringTableToTextTables()
        {
            try
            {

                var table = stringTableCollection.StringTables.First(x => x.LocaleIdentifier == defaultLocale.Identifier);
                if (table == null)
                {
                    Debug.LogError("Can't find string table for locale " + defaultLocale.Identifier.Code);
                    return;
                }

                float total = 0;
                foreach (var textTable in textTables)
                {
                    if (textTable == null) continue;
                    total += textTable.fields.Count;
                }

                int progress = 0;
                foreach (var textTable in textTables)
                {
                    if (textTable == null) continue;

                    var languageCodeToTextTableID = new Dictionary<string, int>();
                    foreach (var kvp in textTable.languages)
                    {
                        languageCodeToTextTableID[kvp.Key] = kvp.Value;
                        if (kvp.Key == "Default" && defaultLocale != null)
                        {
                            languageCodeToTextTableID[defaultLocale.Identifier.Code] = kvp.Value;
                        }
                    }
                    foreach (var field in textTable.fields.Values)
                    {
                        progress++;
                        if (string.IsNullOrEmpty(field.fieldName) || field.texts == null || field.texts.Count == 0) continue;
                        if (EditorUtility.DisplayCancelableProgressBar("String Table To Text Table", field.fieldName, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }
                        foreach (var stringTable in stringTableCollection.StringTables)
                        {
                            var stringTableEntry = stringTable.GetEntry(field.fieldName);
                            if (stringTableEntry == null) continue;
                            int languageID;
                            if (languageCodeToTextTableID.TryGetValue(stringTable.LocaleIdentifier.Code, out languageID))
                            {
                                textTable.SetFieldTextForLanguage(field.fieldName, languageID, stringTableEntry.LocalizedValue);
                            }
                        }
                    }
                    EditorUtility.SetDirty(textTable);
                }

                Debug.Log("Copied Localization Package string table " + stringTableCollection.name + " back to text table fields.", stringTableCollection);
            }
            finally
            {
                EditorUtility.ClearProgressBar();
            }
        }

    }
}


Last edited by NotVeryProfessional on Sat Nov 09, 2024 11:50 am, edited 1 time in total.
NotVeryProfessional
Posts: 150
Joined: Mon Nov 23, 2020 6:35 am

Re: Translations import/exports in XLIFF, JSON, simple CSV or something ?

Post by NotVeryProfessional »

I'm not sure how to handle group names here. If I add it as a field, I get the group name duplicated for each quest in the group, which is not what it should be.
Post Reply