// // /*===============================================================================
// // Copyright (C) 2024 PhantomsXR Ltd. All Rights Reserved.
// //
// // This file is part of the Phantom.XRMOD.Localization.Runtime.
// //
// // The Localization cannot be copied, distributed, or made available to
// // third-parties for commercial purposes without written permission of PhantomsXR Ltd.
// //
// // Contact nswell@phantomsxr.com for licensing requests.
// // ===============================================================================*/
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Phantom.XRMOD.XRMODPackageTools.Runtime;
using UnityEngine;
namespace Phantom.XRMOD.Localization.Runtime
{
public class LocalizationModule
{
///
/// All text component of ugui
///
private Dictionary> textComponents;
private Dictionary> imgComponents;
private Dictionary> audioComponents;
#if USE_AUDIO_MODULE
private Dictionary> audioModuleComponents;
#endif
///
/// The current language dictionary in use.
///
private Dictionary> localizationTable;
///
/// Current language in use.
///
private string currentLanguage;
///
/// Current localization work space
///
private LocalizationScope localizationScope;
///
/// Current project name
///
private string projectName;
///
/// Create a new localizationModule
///
/// The language dictionary database
/// First language
/// Workspace
public LocalizationModule(string _projectName, byte[] _localizationTable, string _language,
LocalizationScope _place)
{
projectName = _projectName;
Init(_localizationTable, _language, _place);
}
///
/// Init current localization module
///
/// The language dictionary database
/// First language
/// Workspace
protected void Init(byte[] _localizationTable, string _language, LocalizationScope _place)
{
currentLanguage = _language;
localizationScope = _place;
textComponents = new();
localizationTable = new();
imgComponents = new();
audioComponents = new();
#if USE_AUDIO_MODULE
audioModuleComponents = new();
#endif
LoadLanguageDb(_localizationTable);
Refresh(localizationScope);
}
///
/// Get the localized string via a key.
///
/// The key for localized.
/// The localized string.
public string GetLocalizedString(string _key)
{
if (localizationTable == null)
{
return GetErrorFormat("The default language not exist!");
}
if (!localizationTable.ContainsKey(currentLanguage))
{
Debug.LogError($"{currentLanguage} not exist!");
return GetErrorFormat($"{currentLanguage} not exist!");
}
if (localizationTable[currentLanguage].TryGetValue(_key, out var tmp_Value))
return tmp_Value;
Debug.LogError($"{currentLanguage}->{_key} not exist!");
return GetErrorFormat($"{currentLanguage}->{_key} not exist!");
}
///
/// Change current localized language to other language
///
/// The language database(Dictionary)
/// Target language
/// Workspace
public void ChangeLanguage(byte[] _localizationTable, string _language, LocalizationScope _place)
{
textComponents.Clear();
var tmp_AllLocalizedTextComps =
Object.FindObjectsByType(FindObjectsInactive.Include,
FindObjectsSortMode.None);
var tmp_FilteredLocalizedTextComps =
tmp_AllLocalizedTextComps.Where(_comp => _comp.GetLocalizationScope == _place)
.ToList();
// Add or update
if (!textComponents.TryAdd(_place, tmp_FilteredLocalizedTextComps))
{
textComponents[_place] = tmp_FilteredLocalizedTextComps;
}
if (localizationTable == null) return;
if (textComponents.Count == 0) return;
currentLanguage = _language;
Init(_localizationTable, _language, _place);
foreach (var tmp_Text in textComponents[_place])
{
tmp_Text.UpdateContent(GetLocalizedString(tmp_Text.GetKey()));
}
}
///
/// Manually add the text component to the localization
///
/// The unity ugui component(Request:LocalizedTextMeshProUGUI/LocalizedText/LocalizedTextMeshPro)
/// Workspace
public void AddText(BaseLocalizedTextComponent _contentComponent, LocalizationScope _place)
{
if (textComponents.TryGetValue(_place, out var tmp_Text))
{
tmp_Text.Add(_contentComponent);
_contentComponent.UpdateContent(GetLocalizedString(_contentComponent.GetKey()));
}
}
///
/// Manually add the text component to the localization
///
/// The unity ugui component(Request:LocalizedTextMeshProUGUI/LocalizedText/LocalizedTextMeshPro)
/// Workspace
public async void AddImage(BaseLocalizedImageComponent _contentComponent, LocalizationScope _place)
{
if (imgComponents.TryGetValue(_place, out var tmp_Img))
{
tmp_Img.Add(_contentComponent);
var tmp_Key = GetLocalizedString(_contentComponent.GetKey());
if (_place == LocalizationScope.InExperiences)
{
var tmp_Sprite = await BasePackageLoaderUtility.LoadAssetFromPackage(projectName, tmp_Key);
_contentComponent.UpdateContent(tmp_Sprite);
}
else
{
_contentComponent.UpdateContent(Resources.Load(tmp_Key));
}
}
}
///
/// Manually add the text component to the localization
///
/// The unity ugui component(Request:LocalizedTextMeshProUGUI/LocalizedText/LocalizedTextMeshPro)
/// Workspace
public async void AddAudio(LocalizationAudioComponent _contentComponent, LocalizationScope _place)
{
if (audioComponents.TryGetValue(_place, out var tmp_AudioComponents))
{
tmp_AudioComponents.Add(_contentComponent);
var tmp_Key = GetLocalizedString(_contentComponent.GetKey());
if (_place == LocalizationScope.InExperiences)
{
var tmp_AudioClip =
await BasePackageLoaderUtility.LoadAssetFromPackage(projectName, tmp_Key);
_contentComponent.UpdateContent(tmp_AudioClip);
}
else
{
_contentComponent.UpdateContent(Resources.Load(tmp_Key));
}
}
}
#if USE_AUDIO_MODULE
///
/// Manually add the text component to the localization
///
/// The unity ugui component(Request:LocalizedTextMeshProUGUI/LocalizedText/LocalizedTextMeshPro)
/// Workspace
public async void AddAudioModule(LocalizationAudioModuleComponent _contentComponent, LocalizationScope _place)
{
if (audioModuleComponents.TryGetValue(_place, out var tmp_AudioComponents))
{
tmp_AudioComponents.Add(_contentComponent);
var tmp_Key = GetLocalizedString(_contentComponent.GetKey());
if (_place == LocalizationScope.InExperiences)
{
var tmp_AudioClipData =
await BasePackageLoaderUtility
.LoadAssetFromPackage(projectName,
tmp_Key);
_contentComponent.UpdateContent(tmp_AudioClipData);
}
else
{
_contentComponent.UpdateContent(
Resources.Load(tmp_Key));
}
}
}
#endif
///
/// Refresh all text component
///
internal void Refresh(LocalizationScope _place)
{
RefreshTextComps(_place);
RefreshImageComps(_place);
RefreshAudioComps(_place);
RefreshAudioModuleComps(_place);
}
private async void RefreshAudioModuleComps(LocalizationScope _place)
{
#if USE_AUDIO_MODULE
if (audioModuleComponents.TryGetValue(_place, out var tmp_AudioComponents))
{
tmp_AudioComponents.Clear();
}
var tmp_AllLocalizedAudioModuleComps =
Object.FindObjectsByType(FindObjectsInactive.Include,
FindObjectsSortMode.None);
var tmp_FilteredLocalizedAudioModuleComps =
tmp_AllLocalizedAudioModuleComps.Where(_comp => _comp.GetLocalizationScope == _place)
.ToList();
// Add or update
if (!audioModuleComponents.TryAdd(_place, tmp_FilteredLocalizedAudioModuleComps))
{
audioModuleComponents[_place] = tmp_FilteredLocalizedAudioModuleComps;
}
foreach (var tmp_AudioModule in audioModuleComponents[_place])
{
var tmp_Key = GetLocalizedString(tmp_AudioModule.GetKey());
if (_place == LocalizationScope.InExperiences)
{
var tmp_AudioClipData =
await BasePackageLoaderUtility
.LoadAssetFromPackage(projectName,
tmp_Key);
tmp_AudioModule.UpdateContent(tmp_AudioClipData);
}
else
{
tmp_AudioModule.UpdateContent(
Resources.Load(tmp_Key));
}
}
#endif
}
private async void RefreshAudioComps(LocalizationScope _place)
{
if (audioComponents.TryGetValue(_place, out var tmp_AudioComponents))
{
tmp_AudioComponents.Clear();
}
var tmp_AllLocalizedAudioComps =
Object.FindObjectsByType(FindObjectsInactive.Include,
FindObjectsSortMode.None);
var tmp_FilteredLocalizedAudioComps =
tmp_AllLocalizedAudioComps.Where(_comp => _comp.GetLocalizationScope == _place)
.ToList();
// Add or update
if (!audioComponents.TryAdd(_place, tmp_FilteredLocalizedAudioComps))
{
audioComponents[_place] = tmp_FilteredLocalizedAudioComps;
}
foreach (var tmp_AudioComponent in audioComponents[_place])
{
var tmp_Key = GetLocalizedString(tmp_AudioComponent.GetKey());
if (_place == LocalizationScope.InExperiences)
{
var tmp_AudioClip =
await BasePackageLoaderUtility.LoadAssetFromPackage(projectName, tmp_Key);
tmp_AudioComponent.UpdateContent(tmp_AudioClip);
}
else
{
tmp_AudioComponent.UpdateContent(Resources.Load(tmp_Key));
}
}
}
private async void RefreshImageComps(LocalizationScope _place)
{
if (imgComponents.TryGetValue(_place, out var tmp_ImageComponents))
{
tmp_ImageComponents.Clear();
}
var tmp_AllLocalizedImgComps =
Object.FindObjectsByType(FindObjectsInactive.Include,
FindObjectsSortMode.None);
var tmp_FilteredLocalizedImgComps =
tmp_AllLocalizedImgComps.Where(_comp => _comp.GetLocalizationScope == _place)
.ToList();
// Add or update
if (!imgComponents.TryAdd(_place, tmp_FilteredLocalizedImgComps))
{
imgComponents[_place] = tmp_FilteredLocalizedImgComps;
}
foreach (var tmp_Img in imgComponents[_place])
{
var tmp_ImgKey = GetLocalizedString(tmp_Img.GetKey());
if (_place == LocalizationScope.InExperiences)
{
var tmp_Sprite =
await BasePackageLoaderUtility.LoadAssetFromPackage(projectName, tmp_ImgKey);
tmp_Img.UpdateContent(tmp_Sprite);
}
else
{
tmp_Img.UpdateContent(Resources.Load(tmp_ImgKey));
}
}
}
private void RefreshTextComps(LocalizationScope _place)
{
if (textComponents.TryGetValue(_place, out var tmp_TextComponents))
{
tmp_TextComponents.Clear();
}
var tmp_AllLocalizedTextComps =
Object.FindObjectsByType(FindObjectsInactive.Include,
FindObjectsSortMode.None);
var tmp_FilteredLocalizedTextComps =
tmp_AllLocalizedTextComps.Where(_comp => _comp.GetLocalizationScope == _place)
.ToList();
// Add or update
if (!textComponents.TryAdd(_place, tmp_FilteredLocalizedTextComps))
{
textComponents[_place] = tmp_FilteredLocalizedTextComps;
}
foreach (var tmp_Text in textComponents[_place])
{
tmp_Text.UpdateContent(GetLocalizedString(tmp_Text.GetKey()));
}
}
///
/// Load the language db(Parsing from csv file)
///
///
private void LoadLanguageDb(byte[] _localizationTable)
{
List tmp_AllRows = new List(0);
MemoryStream tmp_Stream = new MemoryStream(_localizationTable);
StreamReader tmp_Sr = new StreamReader(tmp_Stream, Encoding.UTF8);
while (tmp_Sr.ReadLine() is { } tmp_Line)
{
tmp_AllRows.Add(tmp_Line);
}
tmp_Sr.Close();
string tmp_Pattern = @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))";
var tmp_Header = Regex.Split(tmp_AllRows[0], tmp_Pattern);
for (int tmp_Idx = 1; tmp_Idx < tmp_Header.Length; tmp_Idx++)
{
string tmp_Lang = GetExactValue(tmp_Header[tmp_Idx].Trim('"'));
if (tmp_Lang != currentLanguage) continue;
Dictionary tmp_Value = new Dictionary();
for (int tmp_J = 1; tmp_J < tmp_AllRows.Count; tmp_J++)
{
string tmp_Row = tmp_AllRows[tmp_J];
var tmp_Cells = Regex.Split(tmp_Row, tmp_Pattern);
tmp_Value.Add(GetExactValue(tmp_Cells[0]), GetExactValue(tmp_Cells[tmp_Idx]));
}
localizationTable.Add(tmp_Lang, tmp_Value);
}
}
///
/// Get the value string from the cvs file
///
///
///
private string GetExactValue(string _val)
{
if (_val[0] == '"' && _val[^1] == '"')
{
_val = _val.Substring(1, _val.Length - 2);
}
const char tmp_const_P = '"';
string tmp_Pattern = tmp_const_P + tmp_const_P.ToString();
string tmp_P2 = tmp_const_P + "";
_val = _val.Replace(tmp_Pattern, tmp_P2);
return _val;
}
///
/// The error key tips
///
///
///
private string GetErrorFormat(string _error)
{
return $"{_error}";
}
}
}