Localize Font

Hello, i was trying out Localization Package and i do like it, however we did run into a problem where we want to have different fonts for different languages and i believe we do need Localize Font along side string,audio and textures, it would be really appreciated and useful!
For now i edited the script to support it for our game but would be simpler to have it by default , right.

Thanks, and keep the amazing work :slight_smile:

5 Likes

could you please share your solution ?

1 Like

Yes sure its quite simple nothing special, i created a script that registers to locale changes, then check if locale equals to certain language code, change font asset of this gameobejct. so basically whenever i add localize string component i also add a localize font script to the same component. and just reference your font assests however you like, im having them in a permanent script so i dont duplicate data. here is my code:

using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;

public class LocalizeFont : MonoBehaviour
{
    private TextMeshProUGUI text;

    protected virtual void OnEnable()
    {
        text = GetComponent<TextMeshProUGUI>();
        LocalizationSettings.SelectedLocaleChanged += ChangeHandler;
    }
    void OnDisable() => LocalizationSettings.SelectedLocaleChanged -= ChangeHandler;
    IEnumerator Start()
    {
        // Wait for the localization system to initialize, loading Locales, preloading etc.
        yield return LocalizationSettings.InitializationOperation;
        ChangeHandler(LocalizationSettings.SelectedLocale);
    }

    protected virtual void ChangeHandler(Locale value)
    {
        if(value.Identifier.Code.Equals("ar"))
            text.font = LocalizationScript.Instance.ArabicFont;
        else
            text.font = LocalizationScript.Instance.EnglishFont;
    }
}
6 Likes

Thank you Wardetta !

There’s an even easier solution to this. I made an Asset Table with my font assets per language(I’m using Text Mesh Pro font assets) and then made a Localized Font Class and Localized Font Event to add as a component to objects.

5969216–640454–LocalizedTMProFont.cs (263 Bytes)
5969216–640457–LocalizeTMProFontEvent.cs (770 Bytes)

3 Likes

I did this at first but the Asset Table object reverts back to null, i thought it did not support Text Mesh Pro Font as an asset and moved on, could have been a bug, mmmm.
Well either way we do add a component that we created so still same steps :smile: but thanks for letting me know that it worked for you! maybe i will try that again later if i added more languages

If it’s any help I’m on Unity 2019.4.1 (the LTS version) and on 0.7.1 for the localization package.

Oh so thats why, im still on the previous version 0.6, Thx :slight_smile:

2 Likes

Necro-ing an old thread to say that this helped me. The script can also be condensed down into one file as such:

using UnityEngine;
using UnityEngine.Events;
using System;
using Sirenix.OdinInspector;
using TMPro;
using UnityEngine.Localization;
using UnityEngine.Localization.Components;

[Serializable]
[DrawWithUnity]
public class LocalizedTMPFont : LocalizedAsset<TMP_FontAsset> { }

[Serializable]
public class UnityEventTMPFont : UnityEvent<TMP_FontAsset> { }

[AddComponentMenu("Localization/Asset/Localize TMP Font Event")]
public class LocalizeTMPFontEvent : LocalizedAssetEvent<TMP_FontAsset, LocalizedTMPFont, UnityEventTMPFont>
{ }

Localized Asset Event

Also if you are using Odin Inspector, the DrawWithUnity attribute fixes the issue of Odin overriding the LocalizedAsset drawer, allowing you to select your asset table key with the original dropdown as intended. Unfortunately there’s no way of adding the attribute to the existing Audio, Prefab, Sprite and Texture events without creating a similar custom component as we did here for the font :confused:

1 Like

Also would like to add few more things that the above solution need file name LocalizeTMPFontEvent.cs as per usual rule of MonoBehaviour, that one is the MonoBehaviour that serializes the above 2 mini classes.

And with TMP, switching font likely also need a new set of material as well to get those same outline style matching between different fonts. (In the case that you have many materials of the same font) So you make the same set of loc event for material except that it seems LocalizedMaterial is already provided in the package, so down to 2 classes.

    [Serializable]
    internal class UnityEventMaterial : UnityEvent<Material>
    {
    }

    internal class LocalizeFontMaterialEvent
        : LocalizedAssetEvent<Material, LocalizedMaterial, UnityEventMaterial>
    {
    }

Then target the event to dynamic fontSharedMaterial.

3 Likes

Hello!
I’m trying to add it to my TMP object, but it simply doesn’t appear on the inspector:
7589863--941137--upload_2021-10-21_7-3-0.png

I really just copied and pasted the code on a new cs script, what could be happening??

Thanks! After some time without any response to my previous message I came back here and found the answer just above my question :roll_eyes:

Just for someone in the future that my find the same problem I did, as 5argon said before, you need to name the file LocalizeTMPFontEvent.cs, otherwise it won’t work… :wink:

2 Likes

Hello everybody,

Again, just to help future people that like me, took a long time to find a solution to change fonts.

My problem was that I’m including languages like Chinese and Japanese in my game, and these don’t use the regular characters, so I needed a font specifically for them, not that I wanted to change the font because of the style, and well, there’s a much easier way of doing so, it’s the font Fallback, it is much easier and does the job just fine, here are the tutorial links Version 1.4.1-Preview 1 with Dynamic SDF for Unity 2018.3 now available! and
https://www.youtube.com/watch?v=slvRsAYS7zw
this is much easier than adding this script on every TMP object inside the game…

And this one can also be useful:

I had gone to this direction before and there are some problems when using fallback fonts as localization you may want to keep in mind.
https://gametorrahod.com/textmeshpro-anatomy#fallback-font-is-not-for-localization

In short,

  • Better switch TMP Font asset than having a master one that could fallback to all languages in the game because :
  • You are less in control of the baseline, padding, etc. because it tries to use the “best” one in your fallback chain. But some languages may or may not need higher line height, and may looks weird with line height that is too much (that the fallback languages forces on it)
  • Material that has effects dependent on amount of pixels in the texture like applying border will have thicker or thinner border for example when you use English (small 512x512 sheet?) then falling back to Japanese (huge 2048x2048 sheet), the Japanese font will appears to have thin border as the material is tuned for English texture size. Japanese game can sometimes need occasional English character, it is better the other way around and true to the meaning of “fallback”. (On English loc : Use English with no fallback. On Japanese loc : Use Japanese with fallback to English, not using English with fallback to Japanese and also attempt to use that with English also.) You can also fix this by coordinating fixed character size of all languages instead of fixed sheet size, but I think at this point using separate one is generally better. (Worse in space requirement, the “true” English and English for Japanese fallback is a different sheet.)
  • The most painful thing is to add loc component to ALL text in the game. Which can be fixed by using Prefab Workflow and never just create a text no matter how small it is. Always instantiate from a prefab or a variant of that.
5 Likes

Updated the above script to automatically add local TextMeshProUGUI.font dynamic event to OnUpdateAsset UnityEvent. File name should be LocalizeTMPFontEvent.cs

using UnityEngine;
using UnityEngine.Events;
using System;
using Sirenix.OdinInspector;
using TMPro;
using UnityEngine.Localization;
using UnityEngine.Localization.Components;
[Serializable]
[DrawWithUnity]
public class LocalizedTMPFont : LocalizedAsset<TMP_FontAsset> { }
[Serializable]
public class UnityEventTMPFont : UnityEvent<TMP_FontAsset> { }

[AddComponentMenu("Localization/Asset/Localize TMP Font Event")]
public class LocalizeTMPFontEvent : LocalizedAssetEvent<TMP_FontAsset, LocalizedTMPFont, UnityEventTMPFont>
{
    #if UNITY_EDITOR
    void OnValidate()
    {
        if(OnUpdateAsset.GetPersistentEventCount()>0) return;
        TextMeshProUGUI target = gameObject.GetComponent<TextMeshProUGUI>();
        var setStringMethod = target.GetType().GetProperty("font").GetSetMethod();
        var methodDelegate = Delegate.CreateDelegate(typeof(UnityAction<TMP_FontAsset>), target, setStringMethod) as UnityAction<TMP_FontAsset>;
        UnityEditor.Events.UnityEventTools.AddPersistentListener(OnUpdateAsset, methodDelegate);
    }
    #endif
}

[Serializable]
internal class UnityEventMaterial : UnityEvent<Material>
{
}
internal class LocalizeFontMaterialEvent
    : LocalizedAssetEvent<Material, LocalizedMaterial, UnityEventMaterial>
{
}

Everything seems to work fine in editor but my stand-alone builds act strange. It is like the asset or font is not applied initially and only after changing to a different language (with different font asset) and switching back does the text get updated properly. See attached video to explain better…

What version of the package are you using? Can you try 1.3.2? If you are using 1.3.2 and its still happening, do you have any errors in the log file?

It could also be due to the execution order. If the text updates before the font then this is likely to happen. If you change the script execution order so that the LocalizedTMPFont class comes earlier than default then this should fix it.https://docs.unity3d.com/Manual/class-MonoManager.html

I was still on 1.0.5 since that is what the package manager shows available so I updated it to 1.3.2 via manifest change. Works now with either script order applied, or not.

Thanks. I really need to watch the forum closer. Did not realize the package manager could let me fall behind in version number so far.

Yeah, the package manager often doesn’t show the latest version. It’s by design but I cant say I particularly agree with the decision. Its supposed to be showing the versions that have been verified with that version of Unity when it was released, but the way to verify a new version is convoluted and slow to update so you often miss new releases if you don’t update Unity. It’s supposed to improve in the future…

Heya, I’m using this script and its works wonderfully, so thank you very much!

I was wondering if there was a way I could have it auto-populate which entry in the asset table it defaults to when the script is added to a component?

I have many different localizedstring components that I need to place this script on and then select the font entry in the asset table, which is the same in 99% of cases (eg I always select “fonts/regular”) so that would save me a heap of time by just being able to add the component and then move on instead of selecting it from the dropdown.

Thanks!