using System;
using System.Collections.Generic;
using System.Reflection;
namespace PKHeX.Core;
///
/// Localization utility for changing all properties of a static type.
///
public static class LocalizationUtil
{
private const string TranslationSplitter = " = ";
private const char TranslationFirst = ' '; // perf; no properties contain spaces.
///
/// Gets the names of the properties defined in the given input
///
/// Enumerable of translation definitions in the form "Property = Value".
private static string[] GetProperties(ReadOnlySpan input)
{
var result = new string[input.Length];
for (int i = 0; i < input.Length; i++)
{
var l = input[i];
var split = l.IndexOf(TranslationFirst);
result[i] = l[..split];
}
return result;
}
private static string[] DumpStrings(Type t)
{
var ti = t.GetTypeInfo();
var props = (PropertyInfo[])ti.DeclaredProperties;
var result = new string[props.Length];
for (int i = 0; i < props.Length; i++)
{
var p = props[i];
var value = p.GetValue(null);
result[i] = $"{p.Name}{TranslationSplitter}{value}";
}
return result;
}
///
/// Gets the current localization in a static class containing language-specific strings
///
///
public static string[] GetLocalization(Type t) => DumpStrings(t);
///
/// Gets the current localization in a static class containing language-specific strings
///
///
/// Existing localization lines (if provided)
public static string[] GetLocalization(Type t, ReadOnlySpan existingLines)
{
var currentLines = GetLocalization(t);
var existing = GetProperties(existingLines);
var current = GetProperties(currentLines);
var result = new string[currentLines.Length];
for (int i = 0; i < current.Length; i++)
{
int index = Array.IndexOf(existing, current[i]);
result[i] = index < 0 ? currentLines[i] : existingLines[index];
}
return result;
}
///
/// Applies localization to a static class containing language-specific strings.
///
/// Type of the static class containing the desired strings.
/// Lines containing the localized strings
private static void SetLocalization(Type t, ReadOnlySpan lines)
{
if (lines.Length == 0)
return;
var translatable = new Dictionary(lines.Length);
foreach (var line in lines)
{
var index = line.IndexOf(TranslationFirst);
if (index < 0)
continue;
var prop = line[..index];
translatable[prop] = line[(index + TranslationSplitter.Length)..];
}
var ti = t.GetTypeInfo();
var props = (PropertyInfo[])ti.DeclaredProperties;
foreach (var p in props)
{
if (translatable.TryGetValue(p.Name, out var value))
p.SetValue(null, value);
}
}
///
/// Applies localization to a static class containing language-specific strings.
///
/// Type of the static class containing the desired strings.
/// Prefix of the language file to use. Example: if the target is legality_en.txt, should be "legality".
/// Culture information
private static void SetLocalization(Type t, string languageFilePrefix, string currentCultureCode)
{
var lines = Util.GetStringList($"{languageFilePrefix}_{currentCultureCode}");
SetLocalization(t, lines);
}
///
/// Applies localization to a static class containing language-specific strings.
///
/// Type of the static class containing the desired strings.
/// The values used to translate the given static class are retrieved from [TypeName]_[CurrentLangCode2].txt in the resource manager of PKHeX.Core.
/// Culture information
public static void SetLocalization(Type t, string currentCultureCode)
{
SetLocalization(t, t.Name, currentCultureCode);
}
}