⟨/⟩ 40_Arch/Tech/Angular/ADR_UI_015_I18n.cs

163 строк · в начало

using System;
using Ban.Sdaid.Notation.Documents;
using Ban.Sdaid.Icd;

namespace Ban.Sdaid.Icd.Arch.Tech.Angular
{
    /// <summary>
    /// ADR-UI-015: Локализация и форматы. Единственный язык интерфейса — русский;
    /// единые форматы дат, времени и чисел; форматирование — через локаль и общие пайпы,
    /// без самодельных форматтеров в компонентах.
    /// </summary>
    public class ADR_UI_015_I18n : IAdrDocument, IFolder<ArchAngularFolder>
    {
        public string Name => "ADR-UI-015. Локализация и форматы";

        public string Description =>
            @"Целевая аудитория — российские библиотеки; весь интерфейс русский. Фиксируем: русский —
единственный язык (без i18n-инфраструктуры), единые форматы дат/времени/чисел по локали `ru` и единую
точку форматирования — встроенные пайпы Angular и общий пайп даты, без ручного форматирования в компонентах.";

        public string Version => "1.0";
        public string Status => "accepted";
        public string[] Comments => new[]
        {
            "2026-08-12. Принято при выводе даты в накопителе страницы «Ввод данных».",
        };

        public Type? Supersedes => null;

        public static string S1_Context = """
            ## Контекст и постановка задачи

            Система адресована российским библиотечным сетям — все тексты, а также форматы дат, времени и
            чисел должны быть русскими. Поддержка других языков сейчас не требуется.

            Нужно зафиксировать два решения, чтобы они не выбирались заново в каждой задаче:

            1. **Уровень локализации** — заводим ли мы i18n-инфраструктуру (словари переводов,
               `@angular/localize`) или обходимся одним языком напрямую.
            2. **Единая точка форматирования** — где и как форматируются даты и числа, чтобы вид был
               одинаков во всём приложении, а компоненты не форматировали значения «руками».

            Повод — вывод значения-даты (ISO `yyyy-mm-dd`) в человеко-читаемом виде.
            """;

        public static string S2_DecisionDrivers = """
            ## Драйверы решения

            1. **Соответствие спеке** — вся спецификация и все интерфейсные тексты на русском.
            2. **Минимум абстракций** — не тащить словари переводов и `@angular/localize` под единственный
               язык.
            3. **Единообразие форматов** — даты, время, числа выглядят одинаково на всех экранах.
            4. **Одна точка форматирования** — никаких локальных форматтеров, разъезжающихся по компонентам.
            """;

        public static string S3_ConsideredOptions = """
            ## Рассмотренные варианты

            - **A. Только русский, без i18n-инфраструктуры** — строки пишутся прямо на русском в шаблонах и
              коде; локаль `ru` задаётся один раз; форматирование — через локаль-зависимые пайпы.
            - **B. `@angular/localize` с единственной локалью `ru`** — заранее обернуть весь текст в `i18n`,
              «на будущее».
            - **C. Свой словарь переводов** (json + сервис) — то же, что B, но вручную.
            """;

        public static string S4_DecisionOutcome = """
            ## Решение

            Выбран **Вариант A**. Все строки UI — прямо на русском в шаблонах и коде, без `i18n`-обёрток и
            словарей. Мультиязычности нет.

            ### Регистрация локали (`app.config.ts`)

            Локаль `ru` регистрируется один раз и задаётся как `LOCALE_ID` — на неё опираются встроенные
            пайпы (`date`, `number`, `currency`) и наши форматтеры:

            ```ts
            import { registerLocaleData } from '@angular/common';
            import localeRu from '@angular/common/locales/ru';
            import { LOCALE_ID } from '@angular/core';

            registerLocaleData(localeRu);

            providers: [
              { provide: LOCALE_ID, useValue: 'ru' },
              // ...
            ]
            ```

            ### Фиксируемые форматы

            | Аспект                     | Значение                                             |
            | -------------------------- | ---------------------------------------------------- |
            | Язык интерфейса            | Русский (`ru`).                                      |
            | Формат даты                | `дд.мм.гггг` (`dd.MM.yyyy`).                          |
            | Формат даты-времени        | `дд.мм.гггг чч:мм` (`dd.MM.yyyy HH:mm`).              |
            | Десятичный разделитель     | запятая.                                             |
            | Разделитель тысяч          | неразрывный пробел.                                  |
            | Первый день недели         | понедельник.                                         |
            | Часовой пояс               | локальный, пользовательский.                         |
            | Валюта по умолчанию        | RUB (если появится вывод сумм).                      |

            ### Единая точка форматирования

            1. **Числа, суммы, «широкие» даты** — встроенные пайпы Angular (`number`, `currency`, `date`),
               работающие по `LOCALE_ID = 'ru'`.
            2. **Доменные значения-даты** приходят и хранятся как ISO-строка `yyyy-mm-dd` (машинный формат
               обмена с API). Для их показа — общий пайп **`icdDate`** (`ui/pipes`): режимы `date` /
               `datetime`, локаль `ru`. Пайп разбирает ISO-дату **как локальную** (полночь по месту),
               чтобы дата не «съезжала» на день при отрицательном смещении пояса.
            3. **Собственные компоненты набора** (`icd-date-picker` и др.) форматируют вывод и подписи
               календаря через `Intl` с локалью `ru`: понедельник — первый день недели, названия месяцев
               русские.
            4. **Компоненты не форматируют даты/числа вручную** (ни `padStart`-склейкой, ни локальными
               функциями) — только через пайпы/`Intl`-форматтеры выше.

            ### Тексты и ошибки

            - Тексты пишем на русском прямо в шаблонах и коде, без оборачивания.
            - Текст ошибок API формирует бэкенд (на русском); UI не переводит коды ошибок в строки.
            """;

        public static string S5_PositiveConsequences = """
            ## Положительные следствия

            - Нет лишнего слоя i18n в приложении на одном языке — меньше кода и зависимостей.
            - Тексты живут рядом с UI — проще читать и менять, чище diff.
            - Даты и числа выглядят одинаково везде: один `LOCALE_ID`, один пайп даты.
            """;

        public static string S6_NegativeConsequences = """
            ## Отрицательные следствия и компромиссы

            - При появлении требования мультиязычности тексты придётся извлекать вручную — решается
              миграцией на `@angular/localize` в тот момент (тогда же — отдельный ADR, этот получит
              статус `Superseded`).
            """;

        public static string S7_Validation = """
            ## Проверка

            - Даты в UI отображаются как `дд.мм.гггг` (дата-время — `дд.мм.гггг чч:мм`).
            - Календарь `icd-date-picker`: первый день недели — понедельник, месяцы по-русски.
            - В компонентах нет ручного форматирования дат/чисел — только пайпы/`Intl`.
            - ISO-дата `yyyy-mm-dd` показывается тем же днём независимо от часового пояса.
            """;

        public static string S8_OpenQuestions = """
            ## Открытые вопросы / отложено

            - **Вывод денежных сумм** — формат RUB зафиксирован, но появится вместе с первым экраном сумм.
            - **Мультиязычность** — отдельный ADR при появлении требования.
            """;

        public static string S99_Related = $"""
            ## Связанные артефакты

            - {nameof(Ban.Sdaid.Icd.Arch.Tech.Angular.ADR_UI_001_Stack)} — стек фронта (signals-first, набор `ui/`).
            - {nameof(Ban.Sdaid.Icd.Arch.Tech.Angular.ADR_UI_009_Forms)} — поле даты (`icd-date-picker`) как форм-контрол.
            """;
    }
}