To audit every localization key in a Mac app, build the relevant targets, check each string table against every supported language, then test message variants in the running app. Catalog completion and correct runtime display require separate checks.

This workflow is for a developer maintaining a Mac desktop app in Xcode. Its concrete task is to produce a traceable record of missing messages, unfinished translations, incorrect arguments, and display problems. The examples use synthetic labels and counts; they describe an audit method you can apply to your own project.

Define what counts as a complete message

Begin with a small audit worksheet. Record the app target, resource bundle, string table, key, supported localization, required variants, translation state, and runtime result. Treat each bundle–table–key combination as a separate message identity so that identical key text in different resources does not hide an omission.

Apple documents that localizable APIs can specify a table and bundle, and that resources outside the main bundle need the appropriate bundle for lookup. Checking only the default Localizable.xcstrings file can therefore miss messages elsewhere in the app. See Preparing your app’s text for translation.

Read the project’s supported localizations in the project editor: select the project under Project, open Info, and inspect Localizations. Also inspect which resources participate in those localizations. Apple’s Adding support for languages and regions explains these project settings and resource selections.

For the worksheet, you can use synthetic aliases such as Localization A, Localization B, and Localization C. Keep their mapping to the project’s actual localization identifiers in your working record. These aliases are worksheet labels, not values to enter into Xcode.

Use the following completion contract for the audit. This is a proposed review method, rather than an Apple-defined completion status.

Check Evidence to record
Inventory The message has an identified target, bundle, table, and key.
Discovery The message is extracted from code or deliberately maintained manually.
Coverage Every required localization has the necessary message variants.
Arguments Each argument retains its intended meaning and compatible type.
Runtime The correct message and values appear in the relevant Mac interface.
Disposition Each finding is fixed, deliberately excluded with a reason, or still open.

Build the catalog inventory before reviewing translations

Open the project’s existing string catalogs. If a target has no catalog, Apple’s documented creation path is File > New > File from Template, then select String Catalog. The default name is Localizable; use the table name your code expects. Choose Product > Build to populate and update the catalog. See Localizing and varying text with a string catalog.

Build each relevant Mac scheme rather than treating one successful build as the complete inventory. Apple explains that extraction discovers strings for the current scheme and platform. A message absent from one build deserves investigation before you conclude that it is unused. This boundary is described in Discover String Catalogs.

Check the Use Compiler to Extract Swift Strings build setting. Apple explicitly requires it to include all localizable Swift text in localization exports. If you need an exchange copy for translation work, select the project and choose Product > Export Localizations, then choose the required localizations. The exported .xcloc package is an Xcode Localization Catalog, distinct from an individual .xcstrings string table. See Exporting localizations.

Next, walk through the app’s ordinary desktop surfaces: its main window, menus, toolbar, settings, panels, empty states, and count-dependent labels. For every app-owned message you encounter, locate its worksheet entry. This reverse check—from visible interface to inventory—helps uncover text that never reached a catalog.

Do not assume that extraction discovers every arbitrary string expression. Apple describes extraction through localizable APIs. When an expected message is absent, inspect how the code creates and passes it before adding a second entry manually. See Preparing your app’s text for translation.

Separate extraction, lookup, and runtime formatting

These operations answer different questions. Extraction asks whether Xcode can discover a message during development. Lookup asks which localized resource the running app requests. Runtime formatting supplies the variable content that the selected message displays.

For SwiftUI, argument types matter. A literal such as Text("Open collection") participates in localized lookup. Passing a plain String variable to the corresponding initializer normally displays that variable without localization. Apple documents this distinction in LocalizedStringKey.

Explicitly creating a LocalizedStringKey from a variable requests lookup, but that does not establish that build-time extraction discovered every possible variable value. For dynamically selected keys, compare the complete allowed key set with the catalog. Investigate every unmatched value instead of relying on whichever value happened to appear during a test.

Interpolation also has a message-level role. SwiftUI can look up a localized message containing a format specifier and substitute the interpolated value before rendering. Apple recommends interpolation for composing localizable text in the Text documentation.

Consider an illustrative message that reports an item count. The catalog stores its localizable message structure and variants; the changing count belongs to runtime behavior. Testing counts of 1 and 24 should not require two independently maintained keys solely because the number changed.

A plausible-looking label is weak evidence of successful lookup. Apple states that SwiftUI can display the key itself when it cannot find the localized value. If a key is readable source text, a lookup problem can look like an ordinary label. Verify the selected localization and catalog entry alongside the displayed result. See Preparing views for localization.

Review every language and every required variant

Work through one table at a time and one localization at a time. For each message, check its translation state, text, arguments, and expanded variations. Keep unfinished rows open even when surrounding messages are complete.

Apple’s catalog workflow distinguishes New, Needs Review, translated entries, and Stale strings. A stale entry was no longer found in code; manually managed entries are not automatically updated or removed during synchronization. Confirm a stale key is unnecessary before deleting its translations. See Discover String Catalogs.

For count-dependent messages, Control-click the interpolated key and choose Vary by Plural. Review every form Xcode supplies for each localization. The required forms can differ, so matching the source localization’s row count is not a sufficient check. If the catalog includes device variations, inspect the Mac-specific value and the general value. Apple documents both controls in Localizing and varying text with a string catalog.

Check arguments by meaning as well as appearance. For a synthetic message reporting items across groups, identify which argument represents the item count and which represents the group count. A translation may change their placement while still needing to preserve those meanings. Apple’s catalog session explains argument positions, type specifiers, and plural substitutions in Discover String Catalogs.

Add context where a short label is ambiguous. A comment for Open might identify it as the action on a collection row. SwiftUI’s comment parameter carries that context into localization output; Apple describes it in Preparing views for localization.

Use a coverage matrix that exposes unfinished work

A single percentage is useful for tracking catalog progress, but the audit needs separate columns for coverage and behavior. The following worked example illustrates why. Its numbers are synthetic and represent message–localization pairs, not measurements from an app.

Suppose the inventory contains 48 required messages and three supported localizations. That produces 144 required pairs: 48 multiplied by 3. Each pair can contain additional plural or device branches, which need their own checks.

Localization Required pairs Catalog checks complete Runtime checks complete
Localization A 48 48 48
Localization B 48 46 44
Localization C 48 48 45
Total 144 142 137

Here, two pairs still need catalog work and seven still lack completed runtime checks. Those groups may overlap, so adding them would not produce a reliable count of distinct unfinished messages. Keep both findings attached to their actual rows.

For each unfinished row, record a specific next action: locate a missing source message, complete a plural branch, verify an argument, investigate bundle selection, or revisit the interface at a narrower width. This converts the matrix into a repair queue rather than a decorative progress report.

Run the Mac app in every supported localization

Use Xcode’s scheme settings for repeatable app-level checks. Choose Product > Scheme > Edit Scheme, select Run, open Options, and choose App Language and App Region. Close the dialog, select the Mac run destination, and run the app. Repeat for the supported combinations in your audit. Apple documents this sequence in Testing localizations when running your app.

Follow the same route through the interface on every run. Exercise each message with its relevant states: an empty collection, a single item, several items, and longer synthetic labels. For plural messages, choose additional values needed to exercise the branches present in that localization; a small fixed count set does not establish complete branch coverage.

Inspect full sentences, substituted values, wrapping, truncation, and menu or control widths. When a message has two counts, vary them independently. For example, changing the item count while holding the group count constant helps reveal an argument mapping mistake.

SwiftUI previews can shorten the repair loop. Apple supports setting the preview’s locale environment value and creating multiple localized previews after adding or importing those localizations. Use them to revisit a troublesome view, then verify the actual app path. See Previewing localizations.

Close the audit when every required message–localization pair has a documented disposition and its necessary branches have been checked. Preserve the inventory, test route, and unresolved findings together. That record makes the next audit actionable: a changed message has a known location, expected arguments, required variants, and a repeatable way to inspect its display.

Sources