Skip to content

Localization: exclude SwiftUI preview strings from translation + CI lint (narrowed scope)#25701

Draft
jkmassel wants to merge 3 commits into
trunkfrom
issue-25700
Draft

Localization: exclude SwiftUI preview strings from translation + CI lint (narrowed scope)#25701
jkmassel wants to merge 3 commits into
trunkfrom
issue-25700

Conversation

@jkmassel

@jkmassel jkmassel commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Description

Narrowed focus: this PR does two tightly-related things — exclude SwiftUI preview strings from translation, and add a CI lint so they can't regress. The broader non-translatable cleanup from the original audit (glyphs, brand names, debug screens, the unwired Realtime feature) has been rolled back to a separate PR; see Deferred below.

xcstringstool extract --SwiftUI-Text (the extractor #25688's catalog lane will enable) pulls in every Text("literal"), including the placeholder/sample strings in preview blocks, which never ship to users. This PR:

  1. Wraps the 23 such literals (10 files, all in Modules/) in Text(verbatim:) so they're excluded.
  2. Adds a lint that fails CI if a localizable Text("…") ever lands in a #Preview again.

No behavior change — verbatim: renders these strings identically.

The lint: lint_swiftui_preview_strings

New fastlane lane + Buildkite step (Lint SwiftUI Preview Strings, in the Linters group):

  • Reuses the extractor as its own oracle — xcstringstool tags every extracted string's visibility, and #Preview / PreviewProvider literals come out as "visibility": "preview". No source parsing or brace-tracking, tautologically consistent with what extraction pulls, and zero false positives (preview code never ships, so a localizable literal there is always wrong).
  • On failure prints the exact file:line + the fix.
  • Self-contained — no dependency on Localization: String Catalog pipeline (plurals + catalog generation) #25688's catalog lane, so it runs on trunk today.

Proof — the lint catches a real regression in CI

Verified on CI, not just locally. Temporarily re-introducing one preview literal and pushing it tripped the step: failing build #32839 → Lint SwiftUI Preview Strings (red in ~1 min), with the actionable output:

Scanning 2555 Swift files for localizable Text("…") literals in previews…
  Modules/Sources/WordPressUI/Views/CardView.swift:36  "Card Content"
1 localizable SwiftUI `Text("…")` literal(s) found in `#Preview` / `PreviewProvider`.
Preview strings must not be extracted for translation — wrap each in `Text(verbatim:)`.

That demonstration commit has since been reverted, so this branch is green. (It also caught a real wiring bug: the first attempt, #32838, died in the Fastfile before_all hook because the lint script wasn't seeding project.env — fixed by copying project.env-example, same as the sibling localization lint.)

Documented in docs/localization.md.

Deferred to a follow-up

The broader non-translatable cleanup the original audit covered — glyphs/dividers (Text("·")), brand names (Text("WordPress.com")), pure interpolations (Text("@\(username)")), developer/debug-menu screens, and the unwired Realtime stats feature (~60 literals) — is not in this PR. Those are judgment calls the lint can't decide (is this glyph translatable? should this debug screen localize?), so they belong in a separate, reviewable change. Flipping swiftui: true on generate_strings_catalog likewise lives in #25688's branch. Both follow once this and #25688 land.

Testing instructions

No user-facing change — Text(verbatim:) renders byte-identical for these preview placeholders.

  • CI proved the Lint SwiftUI Preview Strings step fails on a preview regression — build #32839 — then went green once the demonstration was reverted.
  • swiftc -parse clean across the changed Swift files.
  • Lint verified locally — green on the cleaned tree; red (correct file:line) on an injected preview Text("…").

Related: #25700, #25688

@dangermattic

dangermattic commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator
1 Warning
⚠️ View files have been modified, but no screenshot or video is included in the pull request. Consider adding some for clarity.
1 Message
📖 This PR is still a Draft: some checks will be skipped.

Generated by 🚫 Danger

@jkmassel jkmassel marked this pull request as draft June 25, 2026 01:22
@wpmobilebot

wpmobilebot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor
App Icon📲 You can test the changes from this Pull Request in Jetpack by scanning the QR code below to install the corresponding build.
App NameJetpack
ConfigurationRelease-Alpha
Build Number32844
VersionPR #25701
Bundle IDcom.jetpack.alpha
Commitc4c5e74
Installation URL21u9ec4sf0g5g
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot

wpmobilebot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor
App Icon📲 You can test the changes from this Pull Request in WordPress by scanning the QR code below to install the corresponding build.
App NameWordPress
ConfigurationRelease-Alpha
Build Number32844
VersionPR #25701
Bundle IDorg.wordpress.alpha
Commitc4c5e74
Installation URL54o9lia2pftcg
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@jkmassel jkmassel changed the title Localization: convert non-translatable SwiftUI Text literals to Text(verbatim:) Localization: convert non-translatable SwiftUI Text literals to verbatim (+ CI lint for previews) Jun 25, 2026
`xcstringstool extract --SwiftUI-Text` extracts every `Text("literal")` —
including the placeholder/sample strings inside `#Preview` and
`PreviewProvider` blocks, which never ship to users. Wrap those 23 literals in
`Text(verbatim:)` so they're excluded from translation.

Scoped to preview strings; the broader non-translatable cleanup (glyphs, brand
names, developer/debug screens, the unwired Realtime feature) is deferred to a
separate PR.
@jkmassel jkmassel changed the title Localization: convert non-translatable SwiftUI Text literals to verbatim (+ CI lint for previews) Localization: use Text(verbatim:) for SwiftUI preview strings + CI lint Jun 25, 2026
…view`

Adds a `lint_swiftui_preview_strings` fastlane lane and a "Lint SwiftUI
Preview Strings" Buildkite step so preview strings can't regress: a `#Preview`
shipping a translatable `Text("literal")` now fails CI with the exact file:line
and the fix (wrap in `Text(verbatim:)`).

Reuses Apple's extractor as its own oracle — `xcstringstool extract
--SwiftUI-Text` tags every extracted string's `visibility`, and #Preview /
PreviewProvider literals come out as `visibility: "preview"`. No source parsing
or brace-tracking, and tautologically consistent with what extraction pulls.
Self-contained (no dependency on the #25688 catalog lane). Green on the current
tree; verified it fails on an injected preview literal.

Documents the `verbatim:` rule and the gate in docs/localization.md.
@jkmassel jkmassel changed the title Localization: use Text(verbatim:) for SwiftUI preview strings + CI lint Localization: exclude SwiftUI preview strings from translation + CI lint (narrowed scope) Jun 25, 2026
Adversarial testing surfaced that a `#Preview` wrapped in `#if DEBUG` gets a
compound `visibility` — {"type":"conjunction","values":[{"type":"defined",
"value":"DEBUG"},"preview"]} — that the exact `== "preview"` check missed, so a
conditionally-compiled preview literal slipped through. Recurse the visibility
values (new `preview_visibility?`) so `#if`-gated previews are caught; a bare
`#if FLAG` with no preview leaf stays correctly unflagged (no new false
positives — verified green on the full tree).

Also documents the remaining by-design gaps the testing confirmed: preview-only
strings hoisted into free helper views/funcs are indistinguishable from shipping
code, and modern `String(localized:)` / `LocalizedStringResource` APIs aren't on
the `--SwiftUI-Text` surface (both latent — the cleanup is `Text("…")`-only).

# Run `xcstringstool extract --SwiftUI-Text` over the files and return a sorted "file:line \"key\"" entry
# for every extracted string tagged `visibility: preview` (i.e. originating from #Preview / PreviewProvider).
def preview_localizable_text_literals(files)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 Metrics/AbcSize: Assignment Branch Condition size for preview_localizable_text_literals is too high. [<13, 28, 7> 31.65/17]


# Run `xcstringstool extract --SwiftUI-Text` over the files and return a sorted "file:line \"key\"" entry
# for every extracted string tagged `visibility: preview` (i.e. originating from #Preview / PreviewProvider).
def preview_localizable_text_literals(files)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 Metrics/CyclomaticComplexity: Cyclomatic complexity for preview_localizable_text_literals is too high. [8/7]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants