0
votes

I've made an app in Unity which has been on the Google Play Store for over a year. Today I wanted to deployt it on Apple App Market but the translations don't work there.

I use the following code to load my app translations

public bool LoadLocalizedText(SystemLanguage language)
{
    localizedText = new Dictionary<string, string>();
    string filePath = Path.Combine(Application.streamingAssetsPath, "localizedText_" + language + ".json");

    WWW reader = new WWW(filePath);
    if (reader.text == null || reader.text == "") return false;
    while (!reader.isDone) { }
    string dataAsJson;
    dataAsJson = reader.text;
    LocalizationData loadedData = JsonUtility.FromJson<LocalizationData>(dataAsJson);



     for (int i = 0; i < loadedData.items.Length; i++)
     {
         localizedText.Add(loadedData.items[i].key, loadedData.items[i].value);
     }


    Debug.Log("Data loaded, dictionary contains: " + localizedText.Count + " entries");
    if (localizedText.Count == 0) return false;
    else
    {
        isReady = true;
        return true;
    }
}

Yet somehow, all text fields display "Localized Text Not Found" because it cannot find my Assets... what could this be?

Is this because the StreamingAssets folder isn't copied to xCode? Is it because the location is different on iOS? Something else?

This is my folder structure Folder structure

3
Does this work on Android? Can you show screenshot of where you put the json file? - Programmer
@Programmer yes it does work on Android. I've included a screenshot now with the folder structure. inside StreamingAssets are the json files - Wouter Vandenputte

3 Answers

4
votes

The WWW or UnityWebRequest API is used to read files on the StreamingAssets on Android. For iOS, The any API from the System.IO namespace such as System.IO.File.ReadAllText should be used.

Something like this:

IEnumerator ReadFromStreamingAssets()
{
    string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "MyFile");
    string result = "";
    if (filePath.Contains("://"))
    {
        UnityEngine.Networking.UnityWebRequest www = UnityEngine.Networking.UnityWebRequest.Get(filePath);
        yield return www.SendWebRequest();
        result = www.downloadHandler.text;
    }
    else
        result = System.IO.File.ReadAllText(filePath);
}

Also, the WWW API is made to be used in a coroutine function so that you can wait or yield it until the download is complete. Your while (!reader.isDone) { } can freeze Unity. That should be while (!reader.isDone) yield return null; which waits every frame until download is finished. The LoadLocalizedText function must also be a coroutine function so the return type should be IEnumerator instead of bool. To make it return bool too, use Action<bool> as parameter.

After fixing both issues, below is what the new code should look like:

public IEnumerator LoadLocalizedText(SystemLanguage language, Action<bool> success)
{
    localizedText = new Dictionary<string, string>();
    string filePath = Path.Combine(Application.streamingAssetsPath, "localizedText_" + language + ".json");

    string dataAsJson;

    //Android
    if (filePath.Contains("://"))
    {

        WWW reader = new WWW(filePath);

        //Wait(Non blocking until download is done)
        while (!reader.isDone)
        {
            yield return null;
        }

        if (reader.text == null || reader.text == "")
        {
            success(false);

            //Just like return false
            yield break;
        }

        dataAsJson = reader.text;
    }

    //iOS
    else
    {
        dataAsJson = System.IO.File.ReadAllText(filePath);
    }


    LocalizationData loadedData = JsonUtility.FromJson<LocalizationData>(dataAsJson);



    for (int i = 0; i < loadedData.items.Length; i++)
    {
        localizedText.Add(loadedData.items[i].key, loadedData.items[i].value);
    }


    Debug.Log("Data loaded, dictionary contains: " + localizedText.Count + " entries");
    if (localizedText.Count == 0)
        success(false);
    else
    {
        isReady = true;
        success(true);
    }
}

And used like this:

StartCoroutine(LoadLocalizedText(languageInstance, (status) =>
{
    if (status)
    {
        //Success
    }
}));
1
votes

JsonUtility has a problem with iOS so it doesn't work and if you test in local use File.OpenRead(path) works in iOS filePath = Application.streamingAssetsPath

StreamReader streamReader = new StreamReader(File.OpenRead(string.Format("{0}/{1}.txt", filePath, fileName)));

and streamingAssets read only if you want to write the file in iOS use this path -> Application.persistentDataPath

1
votes

Actually the problem is that Application.streamingAssetsPath is not fully correct for iOS device. You need to add "file://" manually to the path as well. Please note that it should be done outside of Path.Combine() method because for some reason, Combine() method strips it =) I wasted couple of hours trying to understand what is going wrong and I hope my post will save someone's time. Proper way to do is: filePath = "file://" System.IO.Path.Combine(Application.streamingAssetsPath, "MyFile"); The rest of the code is the same (this is true for AssetBundles as well)