Make remote localization startup non-blocking

This commit is contained in:
master
2026-03-11 10:07:30 +02:00
parent 7a1c090f2e
commit 5c874c8f64
8 changed files with 299 additions and 18 deletions

View File

@@ -44,28 +44,28 @@ public sealed class TranslationRegistry
// Ensure default locale is always loaded
allLocales.Add(_options.DefaultLocale);
// Load bundles in priority order (lower first, higher overwrites)
// Load bundles in priority order (lower first, higher overwrites).
// Locales within the same provider are independent, so load them concurrently
// and merge back in deterministic locale order.
foreach (var provider in ordered)
{
foreach (var locale in allLocales)
var loadTasks = allLocales
.OrderBy(locale => locale, StringComparer.OrdinalIgnoreCase)
.Select(locale => LoadProviderBundleAsync(provider, locale, ct))
.ToArray();
var results = await Task.WhenAll(loadTasks).ConfigureAwait(false);
foreach (var result in results)
{
try
if (result.Bundle.Count == 0)
{
var bundle = await provider.LoadAsync(locale, ct).ConfigureAwait(false);
if (bundle.Count > 0)
{
MergeBundles(locale, bundle);
_logger.LogDebug(
"Loaded {Count} translations for locale {Locale} from provider (priority {Priority})",
bundle.Count, locale, provider.Priority);
}
}
catch (Exception ex)
{
_logger.LogWarning(ex,
"Failed to load translations for locale {Locale} from provider (priority {Priority})",
locale, provider.Priority);
continue;
}
MergeBundles(result.Locale, result.Bundle);
_logger.LogDebug(
"Loaded {Count} translations for locale {Locale} from provider (priority {Priority})",
result.Bundle.Count, result.Locale, provider.Priority);
}
}
@@ -75,6 +75,27 @@ public sealed class TranslationRegistry
_store.Count, totalKeys);
}
private async Task<ProviderLocaleBundle> LoadProviderBundleAsync(
ITranslationBundleProvider provider,
string locale,
CancellationToken ct)
{
try
{
var bundle = await provider.LoadAsync(locale, ct).ConfigureAwait(false);
return new ProviderLocaleBundle(locale, bundle);
}
catch (Exception ex)
{
_logger.LogWarning(ex,
"Failed to load translations for locale {Locale} from provider (priority {Priority})",
locale, provider.Priority);
return new ProviderLocaleBundle(
locale,
new Dictionary<string, string>(StringComparer.Ordinal));
}
}
/// <summary>
/// Merges a bundle into the store. Higher-priority values overwrite lower.
/// </summary>
@@ -248,4 +269,6 @@ public sealed class TranslationRegistry
_ => value.ToString() ?? string.Empty
};
}
private sealed record ProviderLocaleBundle(string Locale, IReadOnlyDictionary<string, string> Bundle);
}