Hi,
I was wondering how text translation works with UI TK.
Do we have to go through an external tool and then modify each text via code or is there a system provided for this purpose?
Hi,
I was wondering how text translation works with UI TK.
Do we have to go through an external tool and then modify each text via code or is there a system provided for this purpose?
If you want to integrate with UXML then you will need to make a child class but if you are ok with C# then you can use a special function like this:
public static void SetLocalizedLabel(this TextField textField, string localeKey)
{
var p = localeKey.IndexOf('/');
var localizedString = new LocalizedString();
if (p > 0 && p != (localeKey.Length - 1) && localeKey.Length > 2)
{
localizedString.TableReference = localeKey.Substring(0, p);
localizedString.TableEntryReference = localeKey.Substring(p + 1);
}
var locale = LocalizationSettings.SelectedLocale;
if (locale != null)
{
updateLabel(locale);
}
LocalizationSettings.SelectedLocaleChanged += updateLabel;
void updateLabel(Locale locale)
{
if (!localizedString.IsEmpty)
{
var localizedTextHandle = localizedString.GetLocalizedStringAsync(locale);
localizedTextHandle.Completed += (handle) =>
{
textField.label = handle.Result;
};
}
}
}
with:
myTextField.SetLocalizedLabel("LocalizationTableName/lbKey");
Thank you for your answer.
I don’t understand how I can link this code with the UI Toolkit system. Is this valid with any translation system?
I am using I2 Languages in my project.
That could be an extention class you create on your own project, using that approach you will need to set the localized version by code at the start.
As suggested above by @dlorre but with the added static class:
public static class TextFieldExtention
{
public static void SetLocalizedLabel(this TextField textField, string localeKey)
{
var p = localeKey.IndexOf('/');
var localizedString = new LocalizedString();
if (p > 0 && p != (localeKey.Length - 1) && localeKey.Length > 2)
{
localizedString.TableReference = localeKey.Substring(0, p);
localizedString.TableEntryReference = localeKey.Substring(p + 1);
}
var locale = LocalizationSettings.SelectedLocale;
if (locale != null)
{
updateLabel(locale);
}
LocalizationSettings.SelectedLocaleChanged += updateLabel;
void updateLabel(Locale locale)
{
if (!localizedString.IsEmpty)
{
var localizedTextHandle = localizedString.GetLocalizedStringAsync(locale);
localizedTextHandle.Completed += (handle) =>
{
textField.label = handle.Result;
};
}
}
}
}
The other solution he mentioned is making a visual element that is a child of TextField that on Start it calls internally the I2 library passing the current text as the translation key.
I will need to implement the same thing due and I will use a mixed approach, where the text is static I will use the child of the TextField. When instead the text is dynamic I will use the extended method at runtime.
I hope this clarify a bit ![]()
It works with the localization package: About Localization | Localization | 1.0.5
And yes, @PaoloAm has shown a good way to use it. I have made a LocalizedLabel class but I find the static method more simple.
@dlorre how do you extend the exposed properties of the parent in the UI Builder? In the builder I can’t fill the text of the Label and this would means I need to programmatically do it for static string as well. Thanks!
public class TranslatedLabel : Label
{
#region UXML
[Preserve]
public new class UxmlFactory : UxmlFactory<TranslatedLabel, UxmlTraits> { }
[Preserve]
public new class UxmlTraits : VisualElement.UxmlTraits { }
#endregion
public TranslatedLabel()
{
TranslateContent(base.text);
}
public TranslatedLabel(string text) : base(text)
{
TranslateContent(text);
}
public void SetText(string newContent)
{
TranslateContent(newContent);
}
private void TranslateContent(string newContent)
{
if (!string.IsNullOrEmpty(newContent))
{
base.text = LocalisationUtils.GetLocalization(newContent);
}
}
}
EDIT:
One solution I have found is to take the traits directly from the parent element but this prevent me for creating child properties (not that I need them at the moment but it’s a good to know)
public new class UxmlFactory : UxmlFactory<TranslatedLabel, Label.UxmlTraits> { }
If I try to extend it in the UxmlTraits class directly they don’t get displayed sadly
I did not make it inherit from Label but I rather copied the source of Label and then made the changes:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using UnityEngine.Localization.Tables;
using UnityEngine.UIElements;
namespace UnityEngine.UIElements
{
class LocalizedLabel : TextElement
{
public new class UxmlFactory : UxmlFactory<LocalizedLabel, UxmlTraits> { }
public new class UxmlTraits : TextElement.UxmlTraits
{
UxmlStringAttributeDescription m_LocaleKey = new UxmlStringAttributeDescription { name = "locale-key" };
public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription
{
get { yield break; }
}
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
{
base.Init(ve, bag, cc);
var ll = ve as LocalizedLabel;
ll.localeKey = m_LocaleKey.GetValueFromBag(bag, cc);
ll.initLabel();
}
}
public string localeKey { get; set; }
private LocalizedString localizedString;
public new static readonly string ussClassName = "localized-label";
public LocalizedLabel() : this(String.Empty) { }
public LocalizedLabel(string localeKey)
{
AddToClassList(ussClassName);
this.localeKey = localeKey;
}
private void updateLabel(Locale locale)
{
if (!localizedString.IsEmpty)
{
var localizedTextHandle = localizedString.GetLocalizedStringAsync(locale);
localizedTextHandle.Completed += (handle) =>
{
text = handle.Result;
};
}
}
private void initLabel()
{
var p = localeKey.IndexOf('/');
localizedString = new LocalizedString();
if (p > 0 && p != (localeKey.Length - 1) && localeKey.Length > 2)
{
localizedString = new LocalizedString();
localizedString.TableReference = localeKey.Substring(0, p);
localizedString.TableEntryReference = localeKey.Substring(p + 1);
}
var locale = LocalizationSettings.SelectedLocale;
if (locale != null)
{
updateLabel(locale);
}
LocalizationSettings.SelectedLocaleChanged += updateLabel;
}
}
}
Thanks for the tip, it solve my issue I was having that they was changed everytime even when not running.
So what I did is update your version to use the library I am using (I2).
Here the working code, it can be used when you have a static string you don’t change, otherwise just use a normal label and change it programmatically
using System;
using System.Collections.Generic;
using I2.Loc;
using UnityEngine.UIElements;
namespace ui.Generics
{
class LocalizedLabel : Label
{
public new class UxmlFactory : UxmlFactory<LocalizedLabel, UxmlTraits> { }
public new class UxmlTraits : Label.UxmlTraits
{
UxmlStringAttributeDescription _mLocaleKey = new UxmlStringAttributeDescription { name = "locale-key" };
public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription
{
get { yield break; }
}
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
{
base.Init(ve, bag, cc);
var ll = ve as LocalizedLabel;
ll.LocaleKey = _mLocaleKey.GetValueFromBag(bag, cc);
ll.InitLabel();
}
}
public string LocaleKey { get; set; }
private new static readonly string ussClassName = "localized-label";
public LocalizedLabel() : this(String.Empty) { }
public LocalizedLabel(string localeKey)
{
AddToClassList(ussClassName);
this.LocaleKey = localeKey;
}
private void UpdateLabel()
{
if (!string.IsNullOrEmpty(LocaleKey))
{
base.text = LocalizationManager.GetTranslation(LocaleKey);
}
}
private void InitLabel()
{
if (!string.IsNullOrEmpty(LocaleKey))
{
UpdateLabel();
}
LocalizationManager.OnLocalizeEvent += UpdateLabel;
}
}
}
Thank you for your answers ! This will help me with my issue too!