Чтобы удалить неиспользуемые ключи локализации в Xcode, рассматривайте записи Stale как кандидатов на проверку. Перед удалением проверьте, не формируется ли ключ во время выполнения, сохраните необходимые динамические сообщения как записи с ручным управлением и проверьте затронутые экраны приложения Mac после очистки.

Это руководство предназначено для разработчика, который поддерживает приложение Mac на SwiftUI со String Catalogs. Задача — очистить один каталог: определить сообщения, которые можно удалить, сохранив метки и сообщения со счётчиками, которые приложение по-прежнему отображает. Приведённое ниже руководство по принятию решений отделяет данные извлечения строк от поведения во время выполнения.

Что на самом деле означает устаревший ключ локализации?

Xcode обнаруживает локализуемые строки во время сборки. Apple поясняет, что извлечение охватывает текущую схему и платформу. Когда ранее извлечённая строка исчезает, Xcode может автоматически удалить непереведённую запись; запись с переводами сохраняется и получает состояние Stale. Это состояние означает, что Xcode больше не находит строку в коде. Apple прямо указывает, что удалять её следует только после подтверждения, что строка больше не нужна. Знакомство со String Catalogs

Практически отсутствие ссылки в исходном коде — повод начать проверку. Точный поиск panel.compact может найти буквальную ссылку, но не покажет, формирует ли код этот ключ, объединяя panel. с выбранным режимом. Проверьте и ключ-кандидат, и код, который создаёт ключи для поиска.

Для каждого кандидата используйте эту предлагаемую таблицу проверки. Это руководство по принятию решений основано на документированных ограничениях извлечения строк и не является дополнительной функцией Xcode.

Данные, найденные при проверке Решение Следующее действие
Единственным местом использования был удалённый экран; генераторов ключей во время выполнения не осталось Удалить кандидата Удалите запись, затем выполните сборку и проверьте изменения
Код во время выполнения может сформировать именно этот ключ Оставить Сохраните запись с помощью ручного управления либо замените поиск явными ссылками на локализуемые строки
На ключ по-прежнему ссылается другая цель или условие сборки Оставить Соберите проект и проверьте соответствующую конфигурацию
В другой таблице есть похожий ключ Проверить отдельно Убедитесь, какая таблица и пакет ресурсов используются для каждого поиска
Использований не найдено, но неясно, каким кодом создаётся ключ Отложить Проследите за генератором ключа, прежде чем принимать решение об удалении

Как задать полезную исходную точку в Xcode?

Сначала сохраните резервную копию каталога, которую можно восстановить, или зафиксируйте его текущее состояние в системе контроля версий. Затем откройте проект приложения и выберите схему Mac, которую хотите проверить. Запишите цели и условные конфигурации, из которых в затронутый интерфейс могут поступать сообщения; так проверка будет ограничена явно заданной областью.

Выберите каталог в навигаторе проекта и нажмите Product > Build. По документации Apple, сборки заполняют и обновляют String Catalogs на основе локализуемого исходного текста. Выбрав каталог, нажмите Editor > Assistant, затем выберите ключ, чтобы проверить его местоположение в исходном коде. В каталоге также можно перейти обратно к исходному коду. Локализация и изменение текста с помощью string catalog

Если ожидаемые строки Swift отсутствуют, проверьте, включён ли параметр сборки Use Compiler to Extract Swift Strings для этой цели. Apple указывает, что это необходимое условие извлечения компилятором. Каталог с неполными данными извлечения — ненадёжная отправная точка для решения, что удалить. Локализация приложения SwiftUI

Для каждого кандидата запишите ключ, каталог, предполагаемое место использования и решение. Сначала поищите точный ключ, затем его неизменяемый префикс и соответствующие средства локализации. Изучите значения модели и данные поиска в пакетах, которые передаются этим средствам. Повторяйте сборки для соответствующих конфигураций, если другая цель или условие компиляции меняет набор включённых исходников.

Не объединяйте решения только потому, что две записи отображают одинаковый текст. API локализации Apple принимают имена таблиц, а для ресурсов вне основного приложения может понадобиться другой пакет. Прежде чем считать другую запись заменой, проследите, какая таблица и пакет используются для поиска. Подготовка текста приложения к переводу

Как сохранить сообщения, на которые ссылаются динамически?

Apple описывает ручное управление специально для строк, ключи которых формируются динамически. Выберите нужную запись и в инспекторе задайте для неё ручное управление. Такие записи не обновляются и не удаляются при синхронизации локализаций Xcode после сборки. Если динамическая запись отсутствует, Apple также показывает, как добавить строку вручную с помощью кнопки «плюс» в каталоге. Знакомство со String Catalogs

Для ручного управления нужно явно задать правило обслуживания. Запишите допустимые ключи рядом с кодом или данными, которые их выбирают, и поясните их назначение в комментариях к каталогу. Если позднее поддерживаемый режим будет удалён, проверьте и его запись, созданную вручную: автоматическое извлечение не выполнит эту очистку за вас.

Проверьте, действительно ли SwiftUI выполняет поиск

Переменная типа String, переданная в Text, отображается без локализации. Чтобы использовать переменную как ключ поиска, Apple рекомендует создать из неё LocalizedStringKey. Строковый литерал, переданный непосредственно в Text, автоматически использует путь локализации. Эти перегрузки могут выводить одинаковый исходный текст, но работать по-разному. LocalizedStringKey

В следующем полном примере приложения динамически выбираемый ключ отделён от интерполируемого счётчика. В одноразовом проекте приложения Mac на SwiftUI с Xcode 15 или новее и целевой версией macOS 13 замените этим кодом объявление приложения, созданное по умолчанию. Оставьте только одно объявление @main. Код сверили с документированными API, но здесь не компилировали, поскольку инструментарий Swift был недоступен.

import SwiftUI

@main
struct CatalogReviewDemoApp: App {
    var body: some Scene {
        WindowGroup {
            CatalogReviewView()
        }
    }
}

struct CatalogReviewView: View {
    @State private var compact = true
    @State private var itemCount = 2

    private var selectedKey: String {
        "panel." + (compact ? "compact" : "expanded")
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            Toggle("Compact layout", isOn: $compact)

            Text(LocalizedStringKey(selectedKey))

            Text("\(itemCount) items",
                 comment: "Number of items in the sample panel.")

            Button("Add item") {
                itemCount += 1
            }
        }
        .padding()
        .frame(minWidth: 320)
    }
}

Добавьте Localizable.xcstrings в цель приложения. Добавьте записи с ручным управлением для panel.compact и panel.expanded со значениями исходного текста Compact panel и Expanded panel. Соберите проект, чтобы извлечь строковые литералы сообщений. Явное преобразование в LocalizedStringKey запрашивает поиск во время выполнения, но не сообщает извлекателю строк литеральные объявления каждого возможного сформированного ключа.

Для небольшого конечного набора вариантов рассмотрите возможность заменить формирование ключей явными локализуемыми литералами в каждой ветви. Для пользовательских интерфейсов, передающих сообщения между компонентами, Apple рекомендует LocalizedStringResource, который содержит сведения для локализации, такие как таблица, комментарий и значение по умолчанию. Выбирайте представление, в котором проще всего проверить полный набор поддерживаемых сообщений. Подготовка текста приложения к переводу

Чем изменяющиеся счётчики отличаются от изменяющихся ключей?

В примере выбор макета меняет ключ сообщения, по которому приложение выполняет поиск. Изменение itemCount передаёт другой аргумент одному локализуемому сообщению. Интерполяция в SwiftUI преобразует встроенные значения в заполнители формата для локализации; при отображении во время выполнения подставляются их значения. Локализация приложения SwiftUI

Поэтому для отображаемых меток 2 items, 3 items и 4 items не нужны отдельные ключи. Соберите пример, найдите извлечённое сообщение со счётчиком, щёлкните его ключ, удерживая Control, и выберите Vary by Plural. Для исходной английской локализации укажите %lld item для One и %lld items для Other, используя целочисленный заполнитель, показанный в Xcode. Apple документирует этот процесс настройки сообщений со счётчиком и добавление соответствующих вариантов множественного числа для других поддерживаемых локализаций. Локализация и изменение текста с помощью string catalog

При очистке проверяйте сообщение со счётчиком целиком, включая все его варианты. Отсутствие отображаемой фразы, например 4 items, в исходном коде ничего не говорит о том, используется ли базовое интерполируемое сообщение. Точно так же сохранение шаблона счётчика не оставит в каталоге несвязанный динамический ключ только потому, что оба сообщения появляются в одной панели.

Какие записи действительно следует удалить при очистке?

Рассмотрим условную проверку 24 кандидатов. Эти числа относятся к синтетическому примеру и не отражают результаты измерений реального проекта.

Результат проверки Записи Действие
Единственными местами использования были удалённые панели 9 Удалить после подтверждения, что панели и данные поиска для них устранены
Ключи по-прежнему доступны через динамический выбор 8 Сохранить и задокументировать ручное управление
Ссылки относятся к другой цели или условной сборке 5 Сохранить и проверить область этой сборки
Источник ключа не выяснен 2 Оставить до завершения проверки
Всего проверено 24 9 кандидатов на удаление

Этот подсчёт делает решение об очистке проверяемым: из 24 проверенных записей не следует удалять все 24. Для каждого из девяти кандидатов на удаление оставьте краткое обоснование с указанием удалённого места использования и проверенных путей динамического поиска. Для восьми динамических записей задокументируйте допустимый набор ключей, чтобы при следующей проверке можно было повторить это решение.

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

Как проверить сохранённые сообщения на Mac?

Откройте Product > Scheme > Edit Scheme, выберите Run и перейдите в раздел Options. В App Language выберите существующую поддерживаемую локализацию, закройте редактор и запустите приложение для назначения Mac. Apple документирует эти параметры схемы для тестирования локализованных сборок. Повторите проверку для локализаций, поддерживаемых приложением. Тестирование локализаций при запуске приложения

Проверьте каждый допустимый динамический вариант, включая оба макета из примера. Убедитесь, что приложение отображает ожидаемые значения из каталога, а не идентификаторы. Для сообщений со счётчиком проверьте синтетические значения, например 0, 1, 2 и 12, а также дополнительные категории множественного числа, если они нужны для поддерживаемых локализаций. Чтобы получить эти тестовые значения, достаточно изменить начальное значение счётчика в примере.

Если сохранённое сообщение отображается неправильно, прежде чем менять каталог, проверьте точный ключ, таблицу, пакет и инициализатор Text. Новый процесс генерации символов Apple также может упростить обращение к ресурсам, добавленным вручную: в Xcode 26 появилась генерация символов String Catalog, которую в существующих проектах можно включить параметром Generate String Catalog Symbols. Это необязательный путь рефакторинга, а не доказательство того, что неиспользуемый ресурс, добавленный вручную, больше не нужен. Практическое занятие: изучаем локализацию с Xcode

Завершите очистку небольшим и понятным набором удалений и задокументированным списком сохранённых динамических сообщений. Результат полезен, если для оставшихся записей можно определить места использования, а динамически выбираемые ключи и форматированные сообщения со счётчиками по-прежнему работают в интерфейсе приложения Mac.

Источники