← Назад к вопросам

Как организуешь работу с числительными при локализации?

2.2 Middle🔥 141 комментариев
#Другое

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Подход к локализации числительных в C# Backend

Локализация числительных — сложная задача, требующая учёта грамматических, морфологических и культурных особенностей языка. В C# экосистеме существует несколько уровней решения этой проблемы.

Основные аспекты локализации числительных

  1. Форматирование чисел (разделители, валюта)
  2. Склонение числительных по падежам
  3. Правильное согласование с существительными
  4. Особенности написания (прописью/цифрами)
  5. Культурные различия (например, миллиард/биллион в разных странах)

Стандартные средства .NET для базового форматирования

Для простого форматирования чисел .NET предоставляет встроенные механизмы:

// Базовое форматирование с учётом культуры
decimal value = 1234567.89m;

// Локализованное форматирование
string formattedUS = value.ToString("C", new CultureInfo("en-US")); // $1,234,567.89
string formattedRU = value.ToString("C", new CultureInfo("ru-RU")); // 1 234 567,89 ₽
string formattedDE = value.ToString("C", new CultureInfo("de-DE")); // 1.234.567,89 €

// Форматирование с разделителями
string numberRU = value.ToString("N2", new CultureInfo("ru-RU")); // 1 234 567,89
string numberUS = value.ToString("N2", new CultureInfo("en-US")); // 1,234,567.89

Библиотеки для продвинутой локализации числительных

Для сложных случаев рекомендую использовать специализированные библиотеки:

Humanizer — наиболее популярное решение

// Установка: Install-Package Humanizer.Core.ru

// Преобразование чисел в слова
1.ToWords(new CultureInfo("ru")); // "один"
2.ToWords(new CultureInfo("en")); // "two"
123.ToWords(new CultureInfo("ru")); // "сто двадцать три"

// Склонение числительных с существительными
1.ToWords(GrammaticalGender.Masculine); // "один"
1.ToWords(GrammaticalGender.Feminine); // "одна"
1.ToWords(GrammaticalGender.Neuter); // "одно"

// Форматирование с учётом контекста
"month".ToQuantity(5, new CultureInfo("ru")); // "5 месяцев"
"day".ToQuantity(21, new CultureInfo("ru")); // "21 день"

SmartFormat — для сложных шаблонов

var smart = Smart.CreateDefaultSmartFormat();
smart.AddExtensions(new ChooseFormatter());

var data = new { Count = 5, Item = "сообщение" };
string result = smart.Format("{Count} {Item:|сообщение|сообщения|сообщений}", data);
// Результат: "5 сообщений"

Кастомная реализация для полного контроля

В проектах с особыми требованиями создаю собственные провайдеры:

public interface INumeralLocalizer
{
    string FormatNumber(decimal number, string culture);
    string NumberToWords(long number, string culture, GrammaticalCase grammaticalCase);
    string QuantityWithNoun(long number, string noun, string culture);
}

public class RussianNumeralLocalizer : INumeralLocalizer
{
    private static readonly string[][] Units = 
    {
        new[] { "", "один", "два", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять" },
        new[] { "", "одна", "две", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять" }
    };
    
    public string NumberToWords(long number, string culture, GrammaticalCase grammaticalCase)
    {
        if (number == 0) return "ноль";
        
        var parts = new List<string>();
        var groups = SplitIntoGroups(Math.Abs(number));
        
        for (int i = 0; i < groups.Length; i++)
        {
            var groupValue = groups[i];
            if (groupValue > 0)
            {
                parts.Add(ProcessGroup(groupValue, i, groups.Length));
            }
        }
        
        return string.Join(" ", parts);
    }
    
    private long[] SplitIntoGroups(long number)
    {
        // Реализация разбиения на группы (тысячи, миллионы и т.д.)
        return new long[0]; // Упрощённая реализация
    }
}

Архитектурные рекомендации

  1. Слои абстракции: Создайте интерфейс INumeralLocalizationService для инверсии зависимостей
  2. Кэширование: Результаты преобразования чисел в слова часто кэшируются
  3. Фабричный метод: Для создания локализаторов по коду культуры
  4. Fallback-стратегия: При отсутствии локализации для конкретной культуры

Пример внедрения в ASP.NET Core

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<INumeralLocalizerFactory, NumeralLocalizerFactory>();
    services.AddScoped<INumeralLocalizationService>(provider =>
    {
        var factory = provider.GetRequiredService<INumeralLocalizerFactory>();
        var httpContext = provider.GetRequiredService<IHttpContextAccessor>().HttpContext;
        var culture = httpContext?.Request.GetCulture() ?? "ru-RU";
        return factory.Create(culture);
    });
}

// Использование в контроллере
public class ProductsController : Controller
{
    private readonly INumeralLocalizationService _localizer;
    
    public IActionResult GetProduct(int id)
    {
        var product = _productService.GetProduct(id);
        var viewModel = new ProductViewModel
        {
            Name = product.Name,
            PriceFormatted = _localizer.FormatCurrency(product.Price),
            ItemsInStockText = _localizer.QuantityWithNoun(
                product.StockQuantity, 
                "товар", 
                GrammaticalCase.Nominative
            )
        };
        
        return View(viewModel);
    }
}

Особые случаи и граничные условия

  1. Отрицательные числа: В некоторых языках отрицание выражается по-разному
  2. Дробные числа: Форматирование дробей (1/2, 0.5, ½)
  3. Диапазоны: "от 1 до 5" vs "1–5"
  4. Падежи после числительных: "5 товаров", "с 5 товарами", "о 5 товарах"
  5. Порядковые числительные: "1-й", "первый", "первая"

Тестирование локализации

[Theory]
[InlineData(1, "ru-RU", "один")]
[InlineData(2, "ru-RU", "два")]
[InlineData(21, "ru-RU", "двадцать один")]
[InlineData(101, "en-US", "one hundred one")]
public void NumberToWords_ValidInput_ReturnsCorrectString(
    long number, 
    string culture, 
    string expected)
{
    var localizer = _factory.Create(culture);
    var result = localizer.NumberToWords(number, culture);
    Assert.Equal(expected, result);
}

Ключевые выводы: Локализация числительных требует комплексного подхода. Начинайте со стандартных средств .NET для базового форматирования, используйте Humanizer для большинства стандартных задач и создавайте кастомные решения для специфических бизнес-требований. Всегда проектируйте систему с учётом расширяемости для поддержки новых языков и культурных особенностей.

Как организуешь работу с числительными при локализации? | PrepBro