Другое

AGA в Swift не работает в inline if-выражениях

Узнайте, почему автоматическое согласование грамматики (AGA) в Swift не работает в inline if-выражениях, и найдите правильные решения для условного согласования в iOS-разработке.

Почему автоматическое согласование грамматики (AGA) в Swift не работает в строковых выражениях с условным оператором if?

У меня возникла проблема: AGA работает корректно в обычном тексте, но не работает, когда используется внутри inline‑условного оператора.

Обычное поведение AGA

swift
Text("I have ^[\(dogCount) dogs](inflect: true).")

При dogCount = 2 выводится «I have 2 dogs.»
При dogCount = 1 выводится «I have 1 dog.»

Проблема с inline‑условным оператором

swift
Text(dogCount == 0 ? "No Dogs?!" : "I have ^[\(dogCount) dogs](inflect: true).")

Условный оператор работает правильно, но AGA внутри ветки else не склоняется.

Как правильно реализовать условное согласование грамматики в Swift, когда используется inline‑условный оператор?

Swift‑евая автоматическая согласованность грамматики (AGA) не работает в встроенных if‑выражениях, потому что параметр inflect: true требует специфической обработки строки, которая выполняется во время локализации, а это не происходит, когда строка является частью условного выражения. Синтаксис AGA ^[variable] (inflect: true) должен обрабатываться в контексте локализованного AttributedString, но встроенные условия обходят этот механизм локализации.


Содержание


Понимание ограничения AGA

Автоматическая согласованность грамматики в Swift опирается на параметр inflect: true внутри локализованных строк. Как описано в документации Apple по InflectionRule, эта функция работает через AttributedString, которые проходят морфологический анализ во время процесса локализации.

Синтаксис AGA ^[variable] (inflect: true) специально предназначен для локализованного контента, позволяя системе анализировать грамматический контекст и применять соответствующие правила склонения. Однако, когда вы помещаете этот синтаксис в встроенное условие, строка не проходит через обычный пайплайн локализации, который обеспечивает функциональность AGA.

Ключевой вывод: AGA требует обработки AttributedString с параметром localized: для корректной работы. Встроенные условия полностью обходят этот механизм.

Почему встроенные if‑выражения ломают AGA

Когда вы используете встроенные if‑выражения, например тернарный оператор, в вашем примере:

swift
Text(dogCount == 0 ? "No Dogs?!" : "I have ^[\(dogCount) dogs](inflect: true).")

Проблема возникает из‑за того, что:

  1. Время обработки строки: Синтаксис AGA должен обрабатываться во время локализации, но встроенные условия создают строку во время выполнения, обходя этот этап.
  2. Требование к AttributedString: Согласно форумам Apple, AGA требует AttributedString с корректным морфологическим анализом, чего нет в условных выражениях.
  3. Контекст локализации: Параметр inflect: true ожидает находиться внутри локализованной строки, но встроенные условия нарушают этот контекст.

Как отмечено в обсуждении на Stack Overflow, это известное ограничение, когда AGA просто не функционирует, когда встроена в условную логику.


Решения для условной согласованности грамматики

Решение 1: Использовать отдельные AttributedString

Самый надёжный подход — создать отдельные AttributedString для каждого условия и использовать правильную локализацию:

swift
Text(
    dogCount == 0
    ? AttributedString(localized: "No Dogs?!")
    : createInflectedAttributedString(count: dogCount)
)

private func createInflectedAttributedString(count: Int) -> AttributedString {
    let string = AttributedString(localized: "I have ^[\(count) dogs](inflect: true).")
    return string
}

Решение 2: Ручной контроль морфологии

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

swift
private func createConditionalAttributedString(count: Int) -> AttributedString {
    var morphology = Morphology()
    let number: Morphology.GrammaticalNumber = count == 0
        ? .zero
        : count == 1
        ? .singular
        : .plural

    morphology.number = number

    var string: AttributedString
    if count == 0 {
        string = AttributedString(localized: "No Dogs?!")
    } else {
        string = AttributedString(localized: "I have \(count) dogs.")
    }

    string.inflect = InflectionRule(morphology: morphology)
    return string.inflected()
}

Решение 3: Условное построение строки

Простой подход — построить строку отдельно:

swift
private func createDogCountMessage(count: Int) -> AttributedString {
    if count == 0 {
        return AttributedString(localized: "No Dogs?!")
    }

    return AttributedString(
        localized: "I have ^[\(count) dogs](inflect: true)."
    )
}

// Использование
Text(createDogCountMessage(count: dogCount))

Лучшие практики реализации AGA

1. Избегайте встроенных AGA в условиях

Никогда не встраивайте синтаксис AGA в условные выражения. Вместо этого разделяйте логику:

swift
// ❌ Не делайте так
Text(dogCount == 0 ? "No Dogs?!" : "I have ^[\(dogCount) dogs](inflect: true).")

// ✅ Делайте так
Text(getDogCountMessage(dogCount))

2. Используйте AttributedString последовательно

Как отмечено в форуме Hacking with Swift, всегда работайте с AttributedString, когда используете функции AGA:

swift
private func getInflectedString(_ format: String, _ arguments: CVarArg...) -> AttributedString {
    return AttributedString(localized: String(format: format, arguments))
}

3. Обрабатывайте крайние случаи явно

AGA работает лучше всего с обычными формами множественного числа, но вам может понадобиться специальная обработка:

swift
private func getPersonCountMessage(count: Int) -> AttributedString {
    switch count {
    case 0:
        return AttributedString(localized: "No people found.")
    case 1:
        return AttributedString(localized: "I have ^[\(count) person](inflect: true).")
    default:
        return AttributedString(localized: "I have ^[\(count) people](inflect: true).")
    }
}

Продвинутый контроль морфологии

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

swift
private func createAdvancedAttributedString(count: Int, item: String) -> AttributedString {
    var morphology = Morphology()
    morphology.number = count == 1 ? .singular : .plural

    var string: AttributedString
    if count == 0 {
        string = AttributedString(localized: "No \(item)s available.")
    } else {
        string = AttributedString(localized: "You have ^[\(count) \(item)](inflect: true).")
    }

    string.inflect = InflectionRule(morphology: morphology)
    return string.inflected()
}

Этот подход даёт больше контроля над грамматическими правилами и обрабатывает случаи, когда синтаксис AGA может не работать как ожидается.


Вывод

Автоматическая согласованность грамматики в Swift не работает в встроенных if‑выражениях, потому что параметр inflect: true требует специфической локализации и обработки AttributedString, которую встроенные условия не обеспечивают. Чтобы корректно реализовать условную согласованность грамматики:

  1. Разделяйте условную логику от синтаксиса AGA, создавая отдельные функции.
  2. Последовательно используйте AttributedString с правильной локализацией.
  3. При необходимости применяйте Morphology и InflectionRule для сложных грамматических требований.
  4. Явно обрабатывайте крайние случаи, когда стандартное множественное число не подходит.

Ключевой момент — понять, что AGA является функцией локализации во времени, требующей надлежащего контекста строки, который встроенные условия не могут предоставить. Перестраивая код так, чтобы он работал с объектами AttributedString и корректной локализацией, вы сможете достичь того же условного поведения, сохраняя преимущества автоматической согласованности грамматики.

Источники

  1. Automatic Grammar Agreement with an In‑line If Statement – Stack Overflow
  2. InflectionRule | Apple Developer Documentation
  3. Apple Developer Forums – Automatic Grammar Agreement
  4. Taking advantage of the iOS 15 grammar agreement feature for English strings – Stack Overflow
  5. Automatic Grammar Agreement Makes It Easy to Handle Plurals in Your iOS App – Osas Blogs
Авторы
Проверено модерацией
Модерация