Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How can I localize a TextAsset?

Discussion in 'Localization Tools' started by _eternal, Jan 29, 2021.

  1. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    258
    Sorry for the simple question, but the Localization library is still a bit confusing as of now (0.10.0), and the documentation is lacking in examples.

    I figured out how to use the LocalizeStringEvent component, but most of the dialogue in my game is stored in txt files and imported as a TextAsset. Currently, the txt files are all marked as Addressable, and they're loaded via AssetReferences.

    I can't find an example or explanation in the docs about how to deal with localized assets other than textures/sprites. I tried creating an Asset Table and adding a txt file to it, but I'm not sure how to load from these tables or how to switch between assets when the locale is changed. Has anyone done this yet?
     
  2. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    7,787
    You can create a new LocalizedAsset class like so

    Code (csharp):
    1.  
    2. using System;
    3. using UnityEngine;
    4. using UnityEngine.Localization;
    5.  
    6. [Serializable]
    7. public class LocalizedTextAsset : LocalizedAsset<TextAsset>{}
    8.  
    9. public class Example : MonoBehaviour
    10. {
    11.     public LocalizedTextAsset localizedTextAsset;
    12.  
    13.     void OnEnable()
    14.     {
    15.         localizedTextAsset.AssetChanged += LocalizedTextAsset_AssetChanged;
    16.     }
    17.  
    18.     private void LocalizedTextAsset_AssetChanged(TextAsset value)
    19.     {
    20.         Debug.Log(value.text);
    21.     }
    22. }
    The asset changed event will be called whenever the Locale is changed.

    You can also do this to get it to work the same way as the other components. The event will be called when the Locale is changed.

    Code (csharp):
    1.  
    2. using System;
    3. using UnityEngine;
    4. using UnityEngine.Events;
    5. using UnityEngine.Localization;
    6. using UnityEngine.Localization.Components;
    7.  
    8. [Serializable]
    9. public class LocalizedTextAsset : LocalizedAsset<TextAsset> { };
    10.  
    11. [Serializable]
    12. public class UnityEventTextAsset : UnityEvent<TextAsset> { }
    13.  
    14. [AddComponentMenu("Localization/Asset/Localize Text Asset")]
    15. public class LocalizeTextAssetEvent : LocalizedAssetEvent<TextAsset, LocalizedTextAsset, UnityEventTextAsset>
    16. {
    17. }
    If your translated text is all stored in text assets you would get more benefit from moving it into String Tables This could be automated with a script if you need to.
     
    _eternal likes this.
  3. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    258
    Thanks! I'll give this a try, and I'll drop a comment later if I'm still having trouble.
     
    karl_jones likes this.
  4. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    258
    Hi again - quick follow-up here.

    Well, I've got the general idea, and I can see how the LocalizeTextAssetEvent works. Now, the challenge is that my TextAssets are actually stored in a Dictionary<string, TextAsset>. I can't use a component just like the others, because we have to update every TextAsset in the Dict when the locale changes (as opposed to swapping out a specific string or asset).

    I tried a couple different solutions, but they didn't work, so now I'll just ask. What would be the proper way to do this?

    Also, maybe moving to String Tables would be easier, but I'm not sure. My DialogueManager is already set up to read from TextAssets, so I'd rather leave it that way unless there's a very good reason to switch.
     
  5. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    7,787
    You could have list of LocalizedTextAsset, then call GetAsset (LoadAssets1) for each of them or just bypass the LocalizedTextAsset and get them directly from the Localized Asset Database (LoadAssets2):

    Code (csharp):
    1.  
    2. public class Example : MonoBehaviour
    3. {
    4.     public List<LocalizedTextAsset> assets = new List<LocalizedTextAsset>();
    5.  
    6.     private void OnEnable()
    7.     {
    8.         LocalizationSettings.SelectedLocaleChanged += LocalizationSettings_SelectedLocaleChanged;
    9.     }
    10.  
    11.     private void LocalizationSettings_SelectedLocaleChanged(Locale obj)
    12.     {
    13.         StartCoroutine(LoadAssets1());
    14.     }
    15.  
    16.     IEnumerator LoadAssets1()
    17.     {
    18.         foreach(var asset in assets)
    19.         {
    20.             var operation = asset.LoadAssetAsync();
    21.             if (!operation.IsDone)
    22.                 yield return operation;
    23.  
    24.             // Update dictionary
    25.         }
    26.     }
    27.  
    28.     IEnumerator LoadAssets2()
    29.     {
    30.         foreach(var asset in assets)
    31.         {
    32.             var operation = LocalizationSettings.AssetDatabase.GetLocalizedAssetAsync<TextAsset>("My Table", "My Text Asset");
    33.             if (!operation.IsDone)
    34.                 yield return operation;
    35.  
    36.             // Update dictionary
    37.         }
    38.     }
    39. }
     
  6. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    258
    Ohh, okay. I'm getting closer. I tried something similar to LoadAssets1 before, but I couldn't figure out how to get the TextAsset from the LocalizedTextAsset. It's working now thanks to that load code.

    Only one problem remaining: I need to assign the LocalizedTextAsset[] array in the editor, but the Table Collection Name field won't stick. It seems to want a string - probably the name of the Asset Table that we're referencing, right? And the Key would be a string that matches the Key in the Asset Table. But, when I type something into the Table Collection Name, it gets reverted to a blank string.

     
  7. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    7,787
    It can be a key I'd or key name. If you do it through the editor it should use the I'd as that's safer.
     
  8. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    258
    Hang on, I still can't set Table Collection Name in the editor. This is what I mean. The string field gets cleared when I press enter or click away.

    I'm also not sure how to set it by script. I tried
    new UnityEngine.Localization.Tables.TableReference()
    , but TableCollectionName is defined as private set, so I can't change it.
     
  9. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    7,787
    Are you using a custom editor? It should have a property drawer. You are directly editing the data. There can only be a key Id or key, if you set one then the other will be ignored. So only set the Key and leave the Id field as 0.

    Table collection name should work. I think it's because the property drawer is not being used.
    If you enter the name of an actual table collection does it work?

    You don't need to assign to the table collection name property, just assign a string to the actual Table reference structure. It will convert it. E.g

    new LocalizedTextAsset{ TableReference = "Table name" }
     
    Last edited: Feb 1, 2021
    _eternal likes this.
  10. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    258
    Ahh, I see. I'm using Odin Inspector, so it's probably interfering with Unity's serialization somehow.

    Ultimately I couldn't figure out how to get Odin to work with this, but I was able to create the LocalizedTextAssets via code, which turned out to be easier anyway. As far as I can tell, everything's working now. Thanks a bunch!
     
    karl_jones likes this.
  11. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    258
    Wait a minute. This was working just yesterday, but when I try to change language now, I'm getting a InvalidKeyException.

    Code (CSharp):
    1. Exception encountered in operation CompletedOperation, status=Failed, result= : Exception of type 'UnityEngine.AddressableAssets.InvalidKeyException' was thrown., Key=61dd9ebd431fa8a4ba1e82667d98240a, Type=UnityEngine.Object
    2. UnityEngine.Localization.PreloadDatabaseOperation`2:LoadTableContents(AsyncOperationHandle`1)
    3. DelegateList`1:Invoke(AsyncOperationHandle`1) (at Library/PackageCache/com.unity.addressables@1.16.16/Runtime/ResourceManager/Util/DelegateList.cs:69)
    4. UnityEngine.ResourceManagement.ChainOperationTypelessDepedency`1:OnWrappedCompleted(AsyncOperationHandle`1)
    5. DelegateList`1:Invoke(AsyncOperationHandle`1) (at Library/PackageCache/com.unity.addressables@1.16.16/Runtime/ResourceManager/Util/DelegateList.cs:69)
    6. UnityEngine.ResourceManagement.ResourceManager:Update(Single)
    7. MonoBehaviourCallbackHooks:Update() (at Library/PackageCache/com.unity.addressables@1.16.16/Runtime/ResourceManager/Util/MonoBehaviourCallbackHooks.cs:26)
    Pretty sure the only thing I did in the meantime was shuffle some files around. I changed the hierarchy of my txt files. But, I'm looking at my Localization Tables, and all of the references are still there. I even tried rebuilding my Addressables in case that's relevant, but the result is the same.

    I should mention, I'm also seeing an editor bug in 0.10.0, and I don't know if that's related at all. When I click on Project Settings -> Localization, the menu doesn't appear, and I get this error: https://pastebin.com/xE2nce6R

    I can't reproduce the editor bug in a new project, though. I could make a new thread for that if you think it's relevant.
     
  12. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    7,787
    Looks like the Addressables have become corrupted. Can you open the Addressables group window and see if the String Tables and Locales are in it?
    When you moved the assets around did you delete the meta files they had? The Shared Table Data needs to keep the meta file or it may change its guid. It looks like the guid 61dd9ebd431fa8a4ba1e82667d98240a is not being found in Addressables at the moment.
    That could also be the guid of an Asset, so if you changed the Text files around the guid may have changed.

    If you are able to reproduce this could you please file a bug report? The callstack doesn't really give much away as to what the problem is.
     
  13. _eternal

    _eternal

    Joined:
    Nov 25, 2014
    Posts:
    258
    Ohhh, wait a minute. I think this happened because some of the .txt files weren't marked as Addressable. I just marked every txt file as Addressable (in addition to the Asset Tables themselves), and it appears to be working now. Your suggestions set me on the right track, so thanks again!
     
    karl_jones likes this.
  14. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    7,787
    Ah right. They should be automatically marked as addressable when you add them to an asset table however if you later unmarked them manually then it will break :confused:
    We are working on adding some safe guards against this in the future.
     
    protopop and _eternal like this.