mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
* Load new localization before firing change event * Update texts in SettingsWindow when locale changes * Localize settings search * Update settings search input - Disable when Credits are scrolling, so Search Results aren't shown instead - Select all on single click, as usual for a search bar * Remove unused IsVisible property * Fix General tab being unselected on language change * Fix search results throwing, oops * Missed using LocRef in EnumSettingsEntry * Set CultureInfo before loading locs * Change it to LazyLoc instead So CheapLoc can export localizations...
212 lines
7.6 KiB
C#
212 lines
7.6 KiB
C#
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
|
|
using CheapLoc;
|
|
|
|
using Serilog;
|
|
|
|
namespace Dalamud;
|
|
|
|
/// <summary>
|
|
/// Class handling localization.
|
|
/// </summary>
|
|
[ServiceManager.ProvidedService]
|
|
public class Localization : IServiceType
|
|
{
|
|
/// <summary>
|
|
/// Array of language codes which have a valid translation in Dalamud.
|
|
/// </summary>
|
|
public static readonly string[] ApplicableLangCodes = { "de", "ja", "fr", "it", "es", "ko", "no", "ru", "zh", "tw" };
|
|
|
|
private const string FallbackLangCode = "en";
|
|
|
|
private readonly string locResourceDirectory;
|
|
private readonly string locResourcePrefix;
|
|
private readonly bool useEmbedded;
|
|
private readonly Assembly assembly;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="Localization"/> class.
|
|
/// </summary>
|
|
/// <param name="locResourceDirectory">The working directory to load language files from.</param>
|
|
/// <param name="locResourcePrefix">The prefix on the loc resource file name (e.g. dalamud_).</param>
|
|
/// <param name="useEmbedded">Use embedded loc resource files.</param>
|
|
public Localization(string locResourceDirectory, string locResourcePrefix = "", bool useEmbedded = false)
|
|
{
|
|
this.DalamudLanguageCultureInfo = CultureInfo.InvariantCulture;
|
|
this.locResourceDirectory = locResourceDirectory;
|
|
this.locResourcePrefix = locResourcePrefix;
|
|
this.useEmbedded = useEmbedded;
|
|
this.assembly = Assembly.GetCallingAssembly();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delegate for the <see cref="Localization.LocalizationChanged"/> event that occurs when the language is changed.
|
|
/// </summary>
|
|
/// <param name="langCode">The language code of the new language.</param>
|
|
public delegate void LocalizationChangedDelegate(string langCode);
|
|
|
|
/// <summary>
|
|
/// Event that occurs when the language is changed.
|
|
/// </summary>
|
|
public event LocalizationChangedDelegate? LocalizationChanged;
|
|
|
|
/// <summary>
|
|
/// Gets an instance of <see cref="CultureInfo"/> that corresponds to the language configured from Dalamud Settings.
|
|
/// </summary>
|
|
public CultureInfo DalamudLanguageCultureInfo { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Gets an instance of <see cref="CultureInfo"/> that corresponds to a Dalamud <paramref name="langCode"/>.
|
|
/// </summary>
|
|
/// <param name="langCode">The language code which should be in <see cref="ApplicableLangCodes"/>.</param>
|
|
/// <returns>The corresponding instance of <see cref="CultureInfo"/>.</returns>
|
|
public static CultureInfo GetCultureInfoFromLangCode(string langCode) =>
|
|
CultureInfo.GetCultureInfo(langCode switch
|
|
{
|
|
"tw" => "zh-hant",
|
|
"zh" => "zh-hans",
|
|
_ => langCode,
|
|
});
|
|
|
|
/// <summary>
|
|
/// Search the set-up localization data for the provided assembly for the given string key and return it.
|
|
/// If the key is not present, the fallback is shown.
|
|
/// The fallback is also required to create the string files to be localized.
|
|
/// </summary>
|
|
/// <param name="key">The string key to be returned.</param>
|
|
/// <param name="fallBack">The fallback string, usually your source language.</param>
|
|
/// <returns>The localized string, fallback or string key if not found.</returns>
|
|
// TODO: This breaks loc export, since it's being called without string args. Fix in CheapLoc.
|
|
public static string Localize(string key, string fallBack)
|
|
{
|
|
return Loc.Localize(key, fallBack, Assembly.GetCallingAssembly());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set up the UI language with the users' local UI culture.
|
|
/// </summary>
|
|
public void SetupWithUiCulture()
|
|
{
|
|
try
|
|
{
|
|
var currentUiLang = CultureInfo.CurrentUICulture;
|
|
Log.Information("Trying to set up Loc for culture {0}", currentUiLang.TwoLetterISOLanguageName);
|
|
|
|
if (ApplicableLangCodes.Any(langCode => currentUiLang.TwoLetterISOLanguageName == langCode))
|
|
{
|
|
this.SetupWithLangCode(currentUiLang.TwoLetterISOLanguageName);
|
|
}
|
|
else
|
|
{
|
|
this.SetupWithFallbacks();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex, "Could not get language information. Setting up fallbacks.");
|
|
this.SetupWithFallbacks();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set up the UI language with "fallbacks" (original English text).
|
|
/// </summary>
|
|
public void SetupWithFallbacks()
|
|
{
|
|
this.DalamudLanguageCultureInfo = CultureInfo.InvariantCulture;
|
|
|
|
Loc.SetupWithFallbacks(this.assembly);
|
|
|
|
foreach (var d in Delegate.EnumerateInvocationList(this.LocalizationChanged))
|
|
{
|
|
try
|
|
{
|
|
d(FallbackLangCode);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex, "Exception during raise of {handler}", d.Method);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set up the UI language with the provided language code.
|
|
/// </summary>
|
|
/// <param name="langCode">The language code to set up the UI language with.</param>
|
|
public void SetupWithLangCode(string langCode)
|
|
{
|
|
if (langCode.Equals(FallbackLangCode, StringComparison.InvariantCultureIgnoreCase))
|
|
{
|
|
this.SetupWithFallbacks();
|
|
return;
|
|
}
|
|
|
|
this.DalamudLanguageCultureInfo = GetCultureInfoFromLangCode(langCode);
|
|
|
|
try
|
|
{
|
|
Loc.Setup(this.ReadLocData(langCode), this.assembly);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex, "Could not load loc {0}. Setting up fallbacks.", langCode);
|
|
this.SetupWithFallbacks();
|
|
}
|
|
|
|
foreach (var d in Delegate.EnumerateInvocationList(this.LocalizationChanged))
|
|
{
|
|
try
|
|
{
|
|
d(langCode);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex, "Exception during raise of {handler}", d.Method);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Saves localizable JSON data in the current working directory for the provided assembly.
|
|
/// </summary>
|
|
/// <param name="ignoreInvalidFunctions">If set to true, this ignores malformed Localize functions instead of failing.</param>
|
|
public void ExportLocalizable(bool ignoreInvalidFunctions = false)
|
|
{
|
|
Loc.ExportLocalizableForAssembly(this.assembly, ignoreInvalidFunctions);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new instance of the <see cref="Localization"/> class.
|
|
/// </summary>
|
|
/// <param name="assetDirectory">Path to Dalamud assets.</param>
|
|
/// <param name="languageOverride">Optional language override.</param>
|
|
/// <returns>A new instance.</returns>
|
|
internal static Localization FromAssets(string assetDirectory, string? languageOverride)
|
|
{
|
|
var t = new Localization(Path.Combine(assetDirectory, "UIRes", "loc", "dalamud"), "dalamud_");
|
|
if (!string.IsNullOrEmpty(languageOverride))
|
|
t.SetupWithLangCode(languageOverride);
|
|
else
|
|
t.SetupWithUiCulture();
|
|
return t;
|
|
}
|
|
|
|
private string ReadLocData(string langCode)
|
|
{
|
|
if (this.useEmbedded)
|
|
{
|
|
var resourceStream = this.assembly.GetManifestResourceStream($"{this.locResourceDirectory}{this.locResourcePrefix}{langCode}.json");
|
|
if (resourceStream == null)
|
|
return null;
|
|
|
|
using var reader = new StreamReader(resourceStream);
|
|
return reader.ReadToEnd();
|
|
}
|
|
|
|
return File.ReadAllText(Path.Combine(this.locResourceDirectory, $"{this.locResourcePrefix}{langCode}.json"));
|
|
}
|
|
}
|