StreamingAssets in Android

I made the translation for the game as follows. In the folder Assets\StreamingAssets\Localization\en\text.json or Assets\StreamingAssets\Localization\uk\text.json was a translation in the form

{
“items": [
{ “key”: “localization”, ‘value’: “Localization” }
{ “key”: “start”, ‘value’: “Start Game” }
{ “key”: “setting”, ‘value’: “Setting” }
{ “key”: “continueGame”, ‘value’: “Continue” }
{ “key”: “exitGame”, ‘value’: “Exit” }
{ “key”: “bannerToggle”, ‘value’: “Banner toggle” }
]
}

I wrote the code to switch the language and everything works fine on the PC, but when I make an apk file, the code works very poorly on the phone. It doesn’t find any language, I choose one and it chooses another and so on, what’s wrong?

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.Networking; // Для UnityWebRequest

public class LanguageManager : MonoBehaviour
{
    public TMP_Dropdown languageDropdown;
    private Dictionary<string, string> translations;
    private const string LanguagePrefKey = "selectedLanguage";
    private string localizationFolderPath;

    // Словник для відображення мов на рідній мові
    private readonly Dictionary<string, string> languageNames = new Dictionary<string, string>
    {
        { "en", "English" },
        /*{ "es", "Español" },
        { "zh", "中文" },
        { "fr", "Français" },
        { "de", "Deutsch" },*/
        { "ru", "Русский" },
        /*{ "pt", "Português" },
        { "it", "Italiano" },
        { "ja", "日本語" },
        { "ko", "한국어" },
        { "ar", "العربية" },
        { "tr", "Türkçe" },
        { "nl", "Nederlands" },
        { "pl", "Polski" },
        { "sv", "Svenska" },
        { "da", "Dansk" },
        { "fi", "Suomi" },
        { "no", "Norsk" },
        { "cs", "Čeština" },
        { "he", "עברית" },*/
        { "uk", "Українська" } /*,
       { "th", "ไทย" },
        { "vi", "Tiếng Việt" },
        { "id", "Bahasa Indonesia" },
        { "ro", "Română" },
        { "hu", "Magyar" },
        { "el", "Ελληνικά" },
        { "ms", "Bahasa Melayu" }*/
    };

    void Start()
    {
        LoadAvailableLanguages();

        // Завантажуємо збережену мову або ставимо англійську за замовчуванням
        string savedLanguage = PlayerPrefs.GetString(LanguagePrefKey, "en");
        SetLanguage(savedLanguage);

        // Встановлюємо вибраний елемент у випадачці
        languageDropdown.value = languageDropdown.options.FindIndex(option => option.text == languageNames[savedLanguage]);
    }

    private void LoadAvailableLanguages()
    {
        languageDropdown.ClearOptions();

        // Додаємо назви доступних мов до випадачки
        List<string> options = languageNames.Values.ToList();
        languageDropdown.AddOptions(options);

        // Додаємо слухач для зміни мови
        languageDropdown.onValueChanged.AddListener(delegate {
            OnLanguageChanged(languageDropdown.options[languageDropdown.value].text);
        });
    }

    private void OnLanguageChanged(string newLanguage)
    {
        // Отримуємо код мови за назвою
        string languageCode = languageNames.FirstOrDefault(x => x.Value == newLanguage).Key;

        // Зберігаємо вибір користувача
        PlayerPrefs.SetString(LanguagePrefKey, languageCode);
        PlayerPrefs.Save();

        // Оновлюємо мову
        SetLanguage(languageCode);
    }

    private void SetLanguage(string languageCode)
    {
        // Оновлюємо весь текст у грі
        UpdateUI();
    }

    private void UpdateUI()
    {
        // Знаходимо всі об'єкти з `LocalizedText` і оновлюємо текст
        LocalizedText[] localizedTexts = FindObjectsOfType<LocalizedText>();
        foreach (LocalizedText localizedText in localizedTexts)
        {
            localizedText.UpdateText();
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using System.IO;
using TMPro;
using UnityEngine;
using UnityEngine.Networking;

[RequireComponent(typeof(TextMeshProUGUI))]
[ExecuteInEditMode] // Дозволяє працювати в режимі редагування
public class LocalizedText : MonoBehaviour
{
    public string phraseKey; // Ключ для перекладу
    private TextMeshProUGUI textComponent;
    private Dictionary<string, string> translations;

    void Awake()
    {
        textComponent = GetComponent<TextMeshProUGUI>();
    }

    void Start()
    {
        UpdateText();
    }

    public void UpdateText()
    {
        SetLanguage();

        if (textComponent != null)
        {
            string localizedText = GetTranslation(phraseKey);
            textComponent.text = localizedText;
        }
    }

    private void SetLanguage()
    {
        string currentLanguage = PlayerPrefs.GetString("selectedLanguage");
        string jsonPath = Path.Combine(Application.streamingAssetsPath, "Localization", currentLanguage, "text.json");

        if (Application.platform == RuntimePlatform.Android)
        {
            string androidPath = "jar:file://" + Application.dataPath + "!/assets/Localization/" + currentLanguage + "/text.json";
            StartCoroutine(LoadJsonFromAndroid(androidPath));
        }
        else
        {
            if (File.Exists(jsonPath))
            {
                string jsonContent = File.ReadAllText(jsonPath);
                ProcessJson(jsonContent);
            }
            else
            {
                Debug.LogError("JSON файл не знайдено: " + jsonPath);
            }
        }
    }

    private IEnumerator LoadJsonFromAndroid(string jsonPath)
    {
        using (UnityWebRequest www = UnityWebRequest.Get(jsonPath))
        {
            yield return www.SendWebRequest();

            if (www.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError("Помилка завантаження JSON: " + www.error);
            }
            else
            {
                ProcessJson(www.downloadHandler.text);
            }
        }
    }

    private void ProcessJson(string jsonContent)
    {
        translations = new Dictionary<string, string>();
        LocalizationData data = JsonUtility.FromJson<LocalizationData>(jsonContent);

        foreach (var item in data.items)
        {
            translations[item.key] = item.value;
        }
    }

    private string GetTranslation(string key)
    {
        if (translations != null && translations.ContainsKey(key))
        {
            return translations[key];
        }

        Debug.LogWarning("Переклад не знайдено для ключа: " + key);
        return key;
    }
}// Клас для десеріалізації JSON
[System.Serializable]
public class LocalizationData
{
    public LocalizationItem[] items;
}

[System.Serializable]
public class LocalizationItem
{
    public string key;
    public string value;
}

Sounds like you wrote a bug… and that means… time to start debugging!

By debugging you can find out exactly what your program is doing so you can fix it.

Use the above techniques to get the information you need in order to reason about what the problem is.

You can also use Debug.Log(...); statements to find out if any of your code is even running. Don’t assume any of the code above is actually running.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

Remember with Unity the code is only a tiny fraction of the problem space. Everything asset- and scene- wise must also be set up correctly to match the associated code and its assumptions.

Also, you have some inconsistencies: in one place you use LanguagePrefKey and in another you use "selectedLanguage"… why not make them the same? OR… centralize your playerprefs all in one static class, like this:

Alternately…

I have been using the Unity localization package for the past month… it does already work, and once you get used to the workflow it is pretty simple to use. It handles strings and also handles assets, such as localized textures or sprites.

https://docs.unity3d.com/Packages/com.unity.localization@1.0/manual/index.html