Automattic / Automattic/wordpress-rs

Fold Swift + Kotlin localized-error codegen into wp_uniffi_bindgen

Open
#1,604 0 comments 0 reactions 1 assignee Claimed by @jkmassel View on GitHub
Kotlin Localization Swift Tooling
Dominant language
Rust
Stars
36
Forks
5
Avg merge
17h 30m
Merged PRs (30d)
43

Description

## Background

Every error type that implements `WpSupportsLocalization` carries a translated, user-facing message. Both platforms expose it as a per-type extension that resolves the device locale and calls the generated `localize` function — but each platform generates those extensions with its own post-processing step:

- **Swift**: `scripts/swift-bindings.sh` → `generate_localized_error_extension()` greps `impl WpSupportsLocalization for` across `wp_api/src` and `wp_mobile/src` and appends `extension : LocalizedError { errorDescription }` to the generated `.swift`.
- **Kotlin** (added in #1603): a Gradle `doLast` (`appendLocalizedErrorExtensions` in `native/kotlin/api/kotlin/build.gradle.kts`) scrapes the generated `fun localize(value: , …)` signatures and appends a `localizedDescription(locale)` extension to the generated `wp_api.kt` / `wp_mobile.kt`.

Both derive from the same Rust source of truth (the `WpSupportsLocalization` impls plus the `WpDeriveLocalizable`-generated `localize` exports), so they can't drift from each other in what they cover — but there are two mechanisms in two languages (shell + source-grep vs Gradle + regex), each with its own quirks to maintain.

## Proposal

Fold both into `wp_uniffi_bindgen` so the extension generation happens once, for both languages, as part of the bindgen step — then delete `generate_localized_error_extension` from `swift-bindings.sh` and `appendLocalizedErrorExtensions` from `build.gradle.kts`.

`wp_uniffi_bindgen/src/main.rs` is currently just `uniffi::uniffi_bindgen_main()`. It would become a thin custom bindgen: run the normal generation, then emit the per-type localization extensions in the target language. The localizable set is discoverable from the `ComponentInterface` — every localizable type `T` has a `localize_(value: &T, locale: Option) -> String` export — so the bindgen can enumerate those and emit `errorDescription` (Swift) / `localizedDescription` (Kotlin) without re-parsing Rust source or the generated bindings, and with the correct binding-level type names in hand.

## Constraints / gotchas

- **Don't regress Swift.** Diff the generated Swift before/after to confirm it's byte-identical; the `enable_mutability`, `Hashable`, and `SQLite3` patches in `swift-bindings.sh` stay — only the localization block moves.
- **UniFFI renames Kotlin error types** (`ParseUrlError` → `ParseUrlException`) while the function keeps the Rust name (`localizeParseUrlError`). The `ComponentInterface` carries the mapped names, so keying off it handles this — the same reason #1603 keyed off the generated signatures rather than a source grep.
- **`localizedDescription`, not `localizedMessage`** on Kotlin — the latter collides with `Throwable.localizedMessage`, which returns the untranslated `message`.
- Keep `LocalizedErrorParityTest` (Kotlin) as a cheap post-condition, or replace it with a bindgen-level assertion.
- Preserve the device-locale default semantics (Swift: `Locale.preferredLanguages`; Kotlin: `Locale.getDefault()`).

## Why not in #1603

#1603 landed the Kotlin side as a post-process to match how Swift already works, without a `wp_uniffi_bindgen` rewrite or a full Swift regen-and-diff. This issue is the cleanup: one codegen path, both hacks gone.

Follows #1603.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.