Auto-create string table entries when Localize text components

UPD 01.11.2021
Thanks to @Misha_Kh and @karl_jones we know the right (and quite simple) way to add new entries to the table:

string key = "key";
string text = "text";
StringTable table = reference_to_table;

// actual code
table.AddEntry(key, text);
EditorUtility.SetDirty(table);
EditorUtility.SetDirty(table.SharedData);

Original post:
There is a pretty handy context menu option for setting up LocalizedStringEvent component:
6541057--739546--upload_2020-11-19_20-49-19.png

But I would like to go further and somehow create entries based on the existing content of the component.

For now, I need to:

  • click on Localize
  • unfold localized string property
  • select desired table (in most cases it’s the same table again and again)
  • click on “Add new entry”
  • copy content from text component
  • unfold desired locale
  • paste text into locale

For small games it’s ok, but I have something like a narrative novel so I have a lot of text and text components. And the past half of an hour I was doing these steps again and again (I already have a lot of content in the game). And I’m really tired of doing this :slight_smile: It would be really really cool if the newly created entry would have text from text component for default language.

Text components are only one part of the issue. I also have custom dialog nodes that also need to be localized. And there are tons of nodes and text. I really want to automize this process. Hope this makes sense.

So I’m wondering is there a way to add entries to tables from code?
I can’t find anything related in the documentation and this forum.

Yes we have lots of automation support.
Here is an example that adds the text from TextMeshPro

using TMPro;
using UnityEditor;
using UnityEditor.Localization;
using UnityEngine.Events;
using UnityEngine.Localization.Components;
using UnityEngine.Localization.Tables;

static class LocalizeMenuItem
{
    [MenuItem("CONTEXT/TextMeshProUGUI/Localize - Add Entry")]
    static void LocalizeTMProText(MenuCommand command)
    {
        var target = command.context as TextMeshProUGUI;
        SetupForLocalization(target);
    }

    public static void SetupForLocalization(TextMeshProUGUI target)
    {
        var comp = Undo.AddComponent(target.gameObject, typeof(LocalizeStringEvent)) as LocalizeStringEvent;
        var setStringMethod = target.GetType().GetProperty("text").GetSetMethod();
        var methodDelegate = System.Delegate.CreateDelegate(typeof(UnityAction<string>), target, setStringMethod) as UnityAction<string>;
        UnityEditor.Events.UnityEventTools.AddPersistentListener(comp.OnUpdateString, methodDelegate);

        var table = LocalizationEditorSettings.GetStringTableCollection("My Table");
        var stringTable = table.GetTable("en") as StringTable;

        var newKey = stringTable.SharedData.AddKey();
        stringTable.AddEntry(newKey.Id, target.text);

        EditorUtility.SetDirty(stringTable);
        EditorUtility.SetDirty(stringTable.SharedData);
    }
}
4 Likes

Thanks a lot! You don’t wanna see what I wrote trying to figure it out by myself XD

That’s working, but how can I force StringTable editor window and LocalizedString property drawer to update their editor representation?
For now, I need to switch to another table then go back, and only after that I can see changes in StringTable editor window.
Same for LocalizedString: I need to select another object and then select the desired object back, only after that changes are applied to the editor.

I figured it out!
After adding entry you need to raise some events to update editors:

LocalizationEditorSettings.EditorEvents.RaiseTableEntryAdded(stringTable, newKey);
LocalizationEditorSettings.EditorEvents.RaiseCollectionModified(null, stringTable);
1 Like

Oh yes. Nice :slight_smile:

Hi! Trying to add entries manually now, looks like I can’t invoke those events, because they are now became internal. Actually, what I’m trying to do, is to fill localisation table with entries from dictionary in memory. I’m using

SharedTableData.SharedTableEntry entry = _currentStringTable.SharedData.AddKey(key);

        var newEntry = _currentStringTable.AddEntry(entry.Id, text);

…where “text” is my text, and “key” is my key from dictionary. Then I’m testing the new value - have it returned correctly, like this:

return _currentStringTable[key].LocalizedValue;

But when I open the table editor, I see all entries generated - and empty :frowning: Am I missing something?

Did you mark the collection dirty? Changes wont be saved if you dont.

EditorUtility.SetDirty(_currentStringTable);
EditorUtility.SetDirty(_currentStringTable.SharedData);

Also you can just call AddEntry, it will add the key if it does not already exist.

1 Like

Thanks for replay! Yeah, I did after reading this thread - no luck for now…

So the values you add to the tables never show up in the editor?
What does your full code look like?

UPDATE

Sorry, it was my bad - just had to remove CurrentStringTable.OnAfterDeserialize(); - turns out, it breaks the things. I have read about adding it for correct work somewhere on forums. After removing all works fine!
Thanks for help!

I think, there is no problem with serialisation - I see newly added key in the table. But it’s empty - that’s the question. Here is my full code (have made this simplified version - with same result):

[CreateAssetMenu]
public class DebugLocalization : ScriptableObject
{
    [SerializeField]
    public StringTable CurrentStringTable;
 
    public void Add(string key, string text)
    {
        CurrentStringTable.AddEntry(key, text);
        Debug.Log("------------ Test: Key " + key + " Value " + CurrentStringTable[key].Value);

        //LocalizationEditorSettings.EditorEvents.RaiseTableEntryAdded(_currentStringTable, newEntry);
        //LocalizationEditorSettings.EditorEvents.RaiseCollectionModified(null, _currentStringTable);

        CurrentStringTable.OnAfterDeserialize();
    }
}

And custom editor for it:

[CustomEditor(typeof(DebugLocalization))]
public class DebugLocalizationEditor : Editor
{
    private DebugLocalization _target;

    private void OnEnable()
    {
        _target = target as DebugLocalization;
    }

    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();
        if (GUILayout.Button("Add"))
        {
            _target.Add("DebugKey3", "Debug value3");

            EditorUtility.SetDirty(_target.CurrentStringTable);
            EditorUtility.SetDirty(_target.CurrentStringTable.SharedData);
        }
    }
}

The result of pressing “Add” button:

  1. Choose assigned table in inspector → hit “edit table” → see key aded, but both languages values are empty
  2. See correct console output “Test: Key DebugKey3 Value Debug value3”
1 Like