So i’m new with the Localization Package (which is super useful by the way), added a dropdown to pick different languages, textmeshpro works like a charm with that… perfect.
The problem is that i have a ton of NPCs with different Scriptable Objects which contains the strings of dialog, how can i “Localize” them?
If you want to localize a string with the current language and don’t localize it when language change, you can do something like this:
I work with task to control the asynchronous function but you can work with coroutine. - If you want to localize a string with the current language and localize it when language change, it’s more complex… I advise you to use TMP_Text and don’t use string… I hope this answer your question! Best, Alexis
This is for a dialog system, so each npc has a scriptable object with a list of phrases (strings), i changed that to a list of LocalizedString, the problem comes when i’m reading the phrases to print them in the UI via TMP, i just want to get the current localization string from the LocalizedString key, but to change the TMP text depending on the dialog index:
TMP.text = phrases[1];
(presses next)
TMP.text = phrases[2];
(presses next)
TMP.text = phrases[3];
…
I can no longer do that cause “phrases” now contains LocalizedString instead of string.
Thanks Alexis, finally i came up with the solution:
UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle<string> localizedText = _conversacion[_indexConversacion].GetLocalizedString();
if (localizedText.IsDone)
this.dialogTextTMP.text = localizedText.Result;
The only problem is that “isDone” takes a bit of time so i have to re-call the method, i think i should use an IEnumerator to wait for the text to be ready but i’m not 100% sure how, i’m doing some testings… any ideas are welcome!
What do you mean it doesnt work?
I have had mixed results using Tasks. I find Coroutines to be more reliable
private IEnumerator PreloadConversation()
{
for (int i = 0; i < npcScriptableObject.localizedStringsConversation.Count; i++)
{
var localizedText = npcScriptableObject.localizedStringsConversation[i].GetLocalizedString();
yield return localizedText;
conversation.Add(localizedText.Result);
}
}
To make the above faster you could call GetLocalizedString on all strings and then yield on them. if you check the IsDone flag then this should also help as you wont need to yield an extra frame when the string is already loaded
Thanks or your reply, unfortunately i’m getting this:
ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
System.ThrowHelper.ThrowArgumentOutOfRangeException (System.ExceptionArgument argument, System.ExceptionResource resource) (at :0)
System.ThrowHelper.ThrowArgumentOutOfRangeException () (at :0)
System.Collections.Generic.List`1[T].get_Item (System.Int32 index) (at :0)
DialogManager_SC.MostrarFraseConversacion () (at Assets/Scripts…
When trying to retrieve the string from the list, in other words, is not preloading the strings.
So THIS works:
void Awake() {
if (npcScriptableObject != null)
PreloadConversation();
}
private async Task PreloadConversation() {
for (int i = 0; i < npcScriptableObject.localizedStringsConversation.Count; i++) {
UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle<string> localizedText = npcScriptableObject.localizedStringsConversation[i].GetLocalizedString();
while (!localizedText.IsDone)
await Task.Delay(10);
conversation.Add(localizedText.Result);
}
}
But this DOESN’T:
void Awake() {
if (npcScriptableObject != null)
StartCoroutine(PreloadConversation());
}
private IEnumerator PreloadConversation() {
for (int i = 0; i < npcScriptableObject.localizedStringsConversation.Count; i++) {
var localizedText = npcScriptableObject.localizedStringsConversation[i].GetLocalizedString();
yield return localizedText;
conversation.Add(localizedText.Result);
}
}
It’s a bit complex, it’s a dialog system, so the basics are:
Awake → Preload
On collision enter 2d → launch dialog, which starts on index 0
Hit interact button → show next index
With the “IEnumerator” method the list is empty, is not preloading anything, so when you try to access any of the indexes it throws that error.
I did a bit of debug:
private async Task PreloadConversation() {
for (int i = 0; i < npcScriptableObject.localizedStringsConversation.Count; i++) {
UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle<string> localizedText = npcScriptableObject.localizedStringsConversation[i].GetLocalizedString();
Debug.Log("Preloading = " + i);
while (!localizedText.IsDone)
await Task.Delay(10);
Debug.Log("Preloaded correctly = " + localizedText.Result);
conversation.Add(localizedText.Result);
}
}
And got in console:
Preloading = 0
Preloaded correctly = Hi my name is Mike…
Preloading = 1
Preloaded correctly = …
So it’s loading the strings as i already know because the NPC dialogs are working and beight shown.
But with this:
private IEnumerator PreloadConversation() {
for (int i = 0; i < npcScriptableObject.localizedStringsConversation.Count; i++) {
var localizedText = npcScriptableObject.localizedStringsConversation[i].GetLocalizedString();
Debug.Log("Preloading = " + i);
yield return localizedText;
conversation.Add(localizedText.Result);
Debug.Log("Preloaded correctly = " + localizedText.Result);
}
}
I only got:
Preloading = 0 (one per scriptable object).
I think it could be because it’s inside a loop? don’t know, but it never reaches the part in which i get the result.
What’s the code that sets up localizedStringsConversation look like?
There is no immediate preloading because we need to wait for the addressable asset system to load the asset bundles and this updates in LateUpdate so will be at least 1 frame.