< Summary

Information
Class: MyNet.Globalization.Localization.Translation.Translator
Assembly: MyNet.Globalization
File(s): https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Globalization/Localization/Translation/Translator.cs
Tag: 323_28699572109
Line coverage
94%
Covered lines: 35
Uncovered lines: 2
Coverable lines: 37
Total lines: 135
Line coverage: 94.5%
Branch coverage
91%
Covered branches: 22
Total branches: 24
Branch coverage: 91.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%22100%
.ctor(...)100%210%
Translate(...)100%11100%
Translate(...)100%11100%
TranslateInternal(...)100%1010100%
PostProcessing(...)83.33%66100%
TryTranslate(...)75%44100%
ApplyInflectionFallback(...)100%22100%

File(s)

https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Globalization/Localization/Translation/Translator.cs

#LineLine coverage
 1// -----------------------------------------------------------------------
 2// <copyright file="Translator.cs" company="Stéphane ANDRE">
 3// Copyright (c) Stéphane ANDRE. All rights reserved.
 4// </copyright>
 5// -----------------------------------------------------------------------
 6
 7using System.Globalization;
 8using System.Linq;
 9using MyNet.Globalization.Inflection;
 10using MyNet.Globalization.Localization.Policies;
 11using MyNet.Globalization.Localization.Translation.Catalog;
 12using MyNet.Globalization.Localization.Translation.KeyResolving;
 13using MyNet.Text.Templating;
 14
 15namespace MyNet.Globalization.Localization.Translation;
 16
 17/// <summary>
 18/// Pure, stateless implementation of <see cref="ITranslator"/> backed by an <see cref="ITranslationCatalog"/>.
 19/// This class has no dependency on any "current culture" context — the caller always provides the culture explicitly.
 20/// Culture fallback is applied according to the configured <see cref="ICultureFallbackPolicy"/>:
 21///   by default, walks up the hierarchy: requested culture → parent culture → invariant culture.
 22/// </summary>
 23public sealed class Translator(
 24    ITranslationCatalog catalog,
 25    ITranslationKeyResolver keyResolver,
 26    IPluralizationService pluralizationService,
 27    ICultureFallbackPolicy? fallbackPolicy = null) : ITranslator
 28{
 32829    private readonly ICultureFallbackPolicy _fallbackPolicy = fallbackPolicy ?? CultureFallbackPolicies.ParentCulture;
 30
 31    /// <summary>
 32    /// Initializes a new instance of the <see cref="Translator"/> class with default parent-culture fallback.
 33    /// </summary>
 34    public Translator(ITranslationCatalog catalog, ITranslationKeyResolver keyResolver, IPluralizationService pluralizat
 035        : this(catalog, keyResolver, pluralizationService, CultureFallbackPolicies.ParentCulture)
 36    {
 037    }
 38
 39    /// <inheritdoc />
 535840    public string Translate(string key, TranslationOptions options, CultureInfo culture) => TranslateInternal(key, optio
 41
 42    /// <inheritdoc />
 32443    public string Translate(string key, TranslationOptions options, CultureInfo culture, string resourceKey) => Translat
 44
 45    /// <summary>
 46    /// Internal translation method that performs the actual lookup and fallback logic.
 47    /// </summary>
 48    /// <param name="key">The translation key.</param>
 49    /// <param name="options">The translation options.</param>
 50    /// <param name="culture">The target culture.</param>
 51    /// <param name="resourceKey">The resource key to search in. If null or empty, all registered resources are searched
 52    /// <returns>The translated string if found; otherwise, an empty string.</returns>
 53    private string TranslateInternal(string key, TranslationOptions options, CultureInfo culture, string? resourceKey = 
 54    {
 568255        if (string.IsNullOrEmpty(key))
 356            return string.Empty;
 57
 567958        var effectiveCulture = culture;
 59
 127260        while (true)
 61        {
 695162            var candidateKeys = keyResolver.Resolve(key, options, effectiveCulture);
 2299863            foreach (var candidateKey in candidateKeys)
 64            {
 696365                var translation = TryTranslate(candidateKey.Key, effectiveCulture, resourceKey);
 66
 696367                if (!string.IsNullOrWhiteSpace(translation))
 68                {
 483069                    return PostProcessing(translation, candidateKey.Policy, options, effectiveCulture);
 70                }
 71            }
 72
 212173            var fallback = _fallbackPolicy.GetFallback(effectiveCulture);
 212174            if (fallback is null)
 75                break;
 76
 127277            effectiveCulture = fallback;
 78        }
 79
 84980        return options.UseKeyAsFallback ? key : string.Empty;
 483081    }
 82
 83    /// <summary>
 84    /// Performs post-processing on the translated value, such as formatting the count if applicable. If the translation
 85    /// </summary>
 86    /// <param name="value">The translation value.</param>
 87    /// <param name="policy">The translation fallback policy.</param>
 88    /// <param name="options">The translation options.</param>
 89    /// <param name="culture">The culture to use for formatting.</param>
 90    /// <returns>The translation value with post-processing applied.</returns>
 91    private string PostProcessing(string value, TranslationFallbackPolicy policy, TranslationOptions options, CultureInf
 92    {
 483093        var translation = options.UseInflectionFallback && policy.AllowInflectionFallback && options.Quantity.HasValue
 483094            ? ApplyInflectionFallback(value, options.Quantity.Value, culture)
 483095            : value;
 96
 483097        return new TemplateTransform(new()
 483098        {
 483099            Quantity = options.Quantity,
 4830100            Arguments = options.Arguments,
 4830101            QuantityFormat = options.QuantityFormat,
 4830102            QuantityRenderingMode = options.QuantityRenderingMode,
 4830103            QuantitySeparator = options.QuantitySeparator
 4830104        }).Apply(translation, culture);
 105    }
 106
 107    /// <summary>
 108    /// Attempts to look up the translation for the given key and culture, optionally restricted to a specific resource.
 109    /// </summary>
 110    /// <param name="key">The translation key.</param>
 111    /// <param name="culture">The target culture.</param>
 112    /// <param name="resourceKey">The resource key to search in. If null or empty, all registered resources are searched
 113    /// <returns>The translated string if found; otherwise, null.</returns>
 114    private string? TryTranslate(string key, CultureInfo culture, string? resourceKey)
 6963115        => string.IsNullOrWhiteSpace(resourceKey)
 6963116            ? catalog.Resources.Values.Select(resource => resource.GetString(key, culture)).FirstOrDefault(value => !str
 6963117            : catalog.Resources.TryGetValue(resourceKey, out var rm)
 6963118                ? rm.GetString(key, culture)
 6963119                : null;
 120
 121    /// <summary>
 122    /// Applies inflection fallback to the given value based on the count and culture using the provided inflector.
 123    /// </summary>
 124    /// <param name="value">The value to apply inflection fallback to.</param>
 125    /// <param name="count">The count used to determine pluralization.</param>
 126    /// <param name="culture">The culture to use for inflection.</param>
 127    /// <returns>The value with inflection fallback applied.</returns>
 128    private string ApplyInflectionFallback(string value, decimal count, CultureInfo culture)
 129    {
 528130        var isPlural = pluralizationService.IsPlural(count, culture);
 131
 528132        return isPlural ? pluralizationService.Pluralize(value, culture) : pluralizationService.Singularize(value, cultu
 133    }
 134}
 135