docs/info-plist-localization.md
Rama master · réplica de lectura del repositorio original.
# Info.plist localization
How the app's Info.plist strings (permission-prompt descriptions, app name,
copyright) are localized, and the one maintenance invariant the build's plist
structure imposes.
## What gets localized
macOS shows a handful of Info.plist values to the user: the `NS*UsageDescription`
strings in system permission dialogs ("iTerm2 wants to use the camera."),
`CFBundleName`, `CFBundleGetInfoString`, and `NSHumanReadableCopyright`. Those
localizable keys are collected in `sources/InfoPlist.xcstrings`, whose **keys are
the literal Info.plist key names** (not symbolic keys). Xcode recognizes the
`InfoPlist.xcstrings` filename and treats it as the Info.plist localization
source - it's the String Catalog successor to `InfoPlist.strings`.
Brand/license values (`CFBundleName` = "iTerm2", `NSHumanReadableCopyright` =
"GPL v2") are constants, so every language carries the same value as the base
plist.
Version keys (`CFBundleGetInfoString`, and `CFBundleShortVersionString` /
`CFBundleVersion` should they ever be extracted) must have **no** non-English
localizations and must be marked `shouldTranslate: false`. The base plist's
version is stamped in at build time, but a localized value is a frozen literal:
it compiles into `<lang>.lproj/InfoPlist.strings` and overrides the real version
(a release once showed "3.7.dev" in Get Info for every non-English UI). Without
a localized value the OS falls back to the base plist. Note that
`shouldTranslate: false` alone does not stop existing translations from being
compiled; they must be removed too. `LocalizationHygieneTests` enforces this.
## How it works (no Info.plist edit required)
The localization is a purely additive overlay - no plist had to change to enable
it:
1. The **base plist supplies the keys and English values.** These keys are
functionally required regardless of localization (the app cannot request
camera access without `NSCameraUsageDescription`), so they already existed.
2. `InfoPlist.xcstrings` holds the **extracted English source plus translations**,
keyed by the same plist keys.
3. At **build** time the catalog compiles to `<lang>.lproj/InfoPlist.strings` in
the app bundle (one file per language).
4. At **runtime** macOS overlays those `InfoPlist.strings` values onto the plist
**by key** for the current language, falling back to the base plist value for
any key not translated. The app itself does nothing; the OS does the overlay
when it renders permission dialogs and Finder metadata.
Adding the catalog therefore touched only `sources/InfoPlist.xcstrings`; the plist
was not modified, and no `CFBundleLocalizations` / `CFBundleAllowMixedLocalizations`
key was needed (the presence of the `.lproj/InfoPlist.strings` files is what the
OS keys off).
## The plist-flavor invariant (important)
There is **no single checked-in Info.plist.** `plists/iTerm2.plist` is a
**gitignored build artifact**: the Makefile copies the flavor-specific source
variant over it per build target -
| target | source variant |
|---|---|
| `make dev` (and the default backstop) | `plists/dev-iTerm2.plist` |
| `make Beta` | `plists/beta-iTerm2.plist` |
| `make Nightly` | `plists/nightly-iTerm2.plist` |
| `make Deployment` (release) | `plists/release-iTerm2.plist` |
| preview | `plists/preview-iTerm2.plist` |
The runtime overlay is **flavor-agnostic** - it keys off `NSCameraUsageDescription`
etc., not off which variant was copied - so localization works for whichever
flavor is built.
But because `InfoPlist.xcstrings` carries a **single English source per key**,
the localizable values must stay **identical across all five variants**. They are
today (e.g. every variant's `NSCameraUsageDescription` is
`"An application in iTerm2 wants to use the camera."`, matching the catalog).
Consequences if a flavor's wording ever diverges (e.g. a beta-only permission
message):
- The zh/other override still applies - it's keyed by the plist key, not the
English - so the diverged flavor would show the translation of the *catalog's*
English, which may no longer match that flavor's intended text.
- The catalog's English `source` would be stale relative to that one flavor, and
a translator working from the catalog would never see the divergent wording.
**Rule of thumb:** keep the localizable Info.plist values (the usage descriptions
in particular) identical across `dev-`/`beta-`/`nightly-`/`release-`/`preview-iTerm2.plist`.
If a flavor genuinely needs different user-facing text for one of these keys, it
cannot be localized correctly through the shared catalog key - treat that as a
special case rather than silently diverging the wording.