Custom Package import - There is no active LocalizationSettings

Heyho

I have been packaging my code into a custom package. In my Code i use Localization Tables.
In the Runtime Assembly Folder i have a subfolder named “i18n” and in there is my Localization Settings.asset and in the subfolders the Locales and Tables assets.

When i import this custom package into a new Unity 3D Project, it imports the necessary Localization Package and my complete package.

As soon as i open then the scene in the package the following message appears
“There is no active LocalizationSettings”

I have such a settings file, but unity does not find it after import. Is there a way to tell unity to take mine when there is no other one?

Thanks for help

You need to set the active LocalizationSettings, You can click on the settings file and it will give you an option in the inspector or you can do it via script LocalizationEditorSettings.ActiveLocalizationSettings.

unfortunately i cannot find such a setting here…

Created now an editor Class with a static Initializer and it works like a charm. Now my Localization Settings file from the package will be taken. When i have already a localization, it does not touch it, but also include my tables from the package. Very neat :slight_smile:

Tell me please if it’s a problematic way to go like this.

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.Localization;
using UnityEngine;

[InitializeOnLoad]
public class LocalizationInitialization
{
    static LocalizationInitialization()
    {
        if (LocalizationEditorSettings.ActiveLocalizationSettings == null)
        {
            string[] foldersToSearch = { "Packages/zone.nonon.nononzonecontroller/Runtime/i18n/" };
            string[] guids = AssetDatabase.FindAssets("Localization Settings", foldersToSearch);
            string assetPath = AssetDatabase.GUIDToAssetPath(guids[0]);
            UnityEngine.Localization.Settings.LocalizationSettings settings = AssetDatabase.LoadAssetAtPath<UnityEngine.Localization.Settings.LocalizationSettings>(assetPath);
            LocalizationEditorSettings.ActiveLocalizationSettings = settings;

        }

    }
}

It has now an error with the locales that are double, but i can delete em in the package if they already exist.

Hey Karl. I extended now my script to set a new ActiveLocalization Setting and removing already existing locales when the package gets importet.

Now i still have a problem i cannot solve: At the new project where i imported the package, the info is displayed correctly in Unity Editor Play Mode. As soon as i Build the Standalone Player, the information is not displayed anymore. In the logs i have the following error:

System.Exception: Invalid path in TextDataProvider : 'C:/UnityProjects/Testimportli/Build/Testimportli_Data/StreamingAssets/aa/settings.json'.
RuntimeData is null.  Please ensure you have built the correct Player Content.
Addressables - Unable to load runtime data at location UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle`1[[UnityEngine.AddressableAssets.Initialization.ResourceManagerRuntimeData, Unity.Addressables, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].
OperationException : Addressables - Unable to load runtime data at location UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle`1[[UnityEngine.AddressableAssets.Initialization.ResourceManagerRuntimeData, Unity.Addressables, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].
UnityEngine.AddressableAssets.InvalidKeyException: Exception of type 'UnityEngine.AddressableAssets.InvalidKeyException' was thrown., Key=Locale, Type=UnityEngine.Localization.Locale
OperationException : ChainOperation failed because dependent operation failed
UnityEngine.AddressableAssets.InvalidKeyException: Exception of type 'UnityEngine.AddressableAssets.InvalidKeyException' was thrown., Key=Locale, Type=UnityEngine.Localization.Locale
No Locale could be selected:
No Locales were available. Did you build the Addressables?
The following (3) IStartupLocaleSelectors were used:
    UnityEngine.Localization.Settings.SpecificLocaleSelector
    UnityEngine.Localization.Settings.SystemLocaleSelector
    UnityEngine.Localization.Settings.CommandLineLocaleSelector
OperationException : SelectedLocale is null
OperationException : SelectedLocale is null
OperationException : SelectedLocale is null
OperationException : SelectedLocale is null
OperationException : SelectedLocale is null

Some more info. I found out, that when i do the “Build–>NewBuild–>Default Build Script” in the Adressable Groups Window it seems to work.

Tried to do this in my Editor Script in the static Constructor

AddressableAssetSettings.BuildPlayerContent();

But if i import this with my package the following error is thrown:

Calling NewScene from assembly reloading callbacks are not supported.

What version of Unity are you using? Did you build the Addressable assets?

I think BuildPlayerContent calls NewScene. Try using a callback to trigger the build so it happens after the reload. Maybe https://docs.unity3d.com/ScriptReference/EditorApplication-delayCall.html

Now it seems to work. I used

EditorApplication.delayCall += BuildPlayerContent;

is that correct?

Here the whole Localization Initializer Packet Script for Sharing:

using System.Collections.Generic;
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEditor.Localization;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;

namespace zone.nonon
{

    [InitializeOnLoad]
    public class LocalizationInitialization
    {
        public static string ASSET_GROUP_LOCALES = "Localization-";

        static LocalizationInitialization()
        {
            if (LocalizationEditorSettings.ActiveLocalizationSettings == null)
            {
                SetPackageActiveLocaleSettings();

            }
            else
            {
                DeleteDuplicateLocales();
            }

            SetAssetGroupBundleNamingMode();
        }

        /***
        * This Method is
        */
        static void SetAssetGroupBundleNamingMode()
        {
            AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings;
            List<AddressableAssetGroup> groups = settings.groups;
            foreach (AddressableAssetGroup grp in groups)
            {
                if (grp.Name.Contains(ASSET_GROUP_LOCALES))
                {
                    BundledAssetGroupSchema schema = grp.GetSchema<BundledAssetGroupSchema>();
                    if (!schema.BundleNaming.Equals(BundledAssetGroupSchema.BundleNamingStyle.AppendHash))
                    {
                        schema.BundleNaming = BundledAssetGroupSchema.BundleNamingStyle.AppendHash;
                        grp.SetDirty(AddressableAssetSettings.ModificationEvent.EntryModified, schema.BundleNaming, false, true);    
                        EditorApplication.delayCall += BuildPlayerContent;                           
                    }
                }
            }

        }

        static void BuildPlayerContent()
        {
            AddressableAssetSettings.BuildPlayerContent();           
        }


        static void SetPackageActiveLocaleSettings()
        {
            string[] foldersToSearch = { "Packages/zone.nonon.nononzonecontroller/Runtime/i18n/" };
            string[] guids = AssetDatabase.FindAssets("Localization Settings", foldersToSearch);
            string assetPath = AssetDatabase.GUIDToAssetPath(guids[0]);
            LocalizationSettings settings = AssetDatabase.LoadAssetAtPath<LocalizationSettings>(assetPath);

            LocalizationEditorSettings.ActiveLocalizationSettings = settings;
            ILocalesProvider locales = settings.GetAvailableLocales();
        }

        static void DeleteDuplicateLocales()
        {
            IReadOnlyCollection<Locale> existingLocales = LocalizationEditorSettings.GetLocales();

            List<Locale> locales2Delete = new List<Locale>();
            Dictionary<string, Locale> cache = new Dictionary<string, Locale>();

            foreach (Locale loc in existingLocales)
            {
                Locale value;
                if (cache.TryGetValue(loc.LocaleName, out value))
                {
                    locales2Delete.Add(loc);
                }
                else
                {
                    cache.Add(loc.LocaleName, loc);
                }
            }

            foreach (Locale loc in locales2Delete)
            {
                LocalizationEditorSettings.RemoveLocale(loc);
            }
        }
    }
}
1 Like