The command palette's search field took the keyboard with `request_focus()`
on every frame it was drawn. egui's `Memory::request_focus` interrupts the
IME composition, and `egui-winit` acts on `should_interrupt_composition`
with `set_ime_allowed(false)` + `(true)` — on Windows that is
`ImmAssociateContextEx(hwnd, 0, IACE_CHILDREN/IACE_DEFAULT)`, which drops the
composition in progress. With Microsoft Pinyin the pre-edit text was
cancelled over and over, so the pinyin never accumulated and nothing could be
committed: Chinese (and Japanese/Korean) could not be typed into Quick Apply
at all, while Latin typing was unaffected.
Ask for the focus only when the field hasn't got it, the same guard the
inline editors use (`widgets::keep_focus`): the palette still takes the
keyboard when it opens, and takes it back when something else takes it away.
Tests: panels::dialogs::tests::the_palette_leaves_a_pinyin_composition_alone
opens the palette, feeds Preedit("n".."nihao") frame by frame and asserts that
the frame never asks the platform to cancel the composition, that the whole
pre-edit text is in the query, and that the field claims the keyboard back
when another widget takes it. Failed before: "typing `n` cancelled the
composition".
A single selected_layers list kept ids from every comp, so the active comp looked selected whenever another comp was. Opening a comp and running a script against a different comp now park and restore that selection.
sanitize_state dropped every selected layer not in the active comp at the
end of each script run, so a layer selected by script in a comp that was not
open was gone by the next script call. Every comp keeps its own selection as
in After Effects; only ids gone from every comp are dropped now. UI and
engine lookups resolve selections per comp and tolerate foreign ids.
The Japanese data point in #821 (zitann2020) offered to write its rows against whatever mechanism
this PR lands, so both languages share one catalog instead of inventing two. This makes adding a
language a data change and reserves `ja`:
- `Catalog` holds a language's effect rows and its category labels, and `catalog()` resolves a
language code to one; adding a language is two tables and one arm, with no change to the lookups
or to any panel.
- `JAPANESE_EFFECTS` and `JAPANESE_CATEGORIES` are declared, keyed by the same effect ids and by
the registry's English category names, and `ja` resolves to them. Both are empty, so a Japanese
interface draws exactly what it drew before — the slot changes no behaviour on its own.
- `a_pending_language_only_uses_known_ids` guards the pending tables (Japanese and Traditional
Chinese) as rows arrive: an id Simplified Chinese does not know, a different English name for one
of them, an empty translation or a repeated id fails. `languages_without_rows_draw_the_registry_name`
asserts each pending language has an arm in `catalog()` (a table with no arm would leave a
translator's rows dead) and is still row-less, so the day one gets rows the test says where its
coverage moved.
- `only_the_brand_names_stay_in_english` now documents that it pins *Simplified Chinese's* five
brand names and is deliberately not shared: AE's Japanese interface keeps the whole `CC`, `VR`
and `OCIO` sets in English while its Chinese one translates them, so repeating the English name
is a language's choice and not an unfinished row. The row check reflects that (a repeated English
name is accepted, an empty one is not).
docs/localization-parity.md records the two empty tables and that each language decides for itself
which names stay in English.
Refs #821
Verification against the installed After Effects 2026 (26.5.0.89) Simplified Chinese interface
(the checklist's `07-类别` sheet) finds two of the 21 category names differ from our first
suggestion:
- `Keying` is 抠像, not 键控 — the interface names the folder 抠像 while the effects inside it keep
键 (颜色差值键, 亮度键, 内部/外部键), so the two do not contradict each other;
- `Obsolete` is 过时, not 已废弃 — the effects in the folder say 旧版 for the legacy ones.
The other nineteen are confirmed as they were. `Color Correction` (颜色校正), `Matte` (遮罩) and
`Noise & Grain` (杂色和颗粒) were the three where the checklist's older machine-translated
suggestion differed; the interface's wording matches what the catalog already had, so those stay.
`CATEGORIES`' doc comment now records where the 21 names come from instead of calling them our
wording.
Refs #821
The interface below the menu bar is localized (618 fixed menu entries, ~490 panel rows) but an
effect's name still rendered in English everywhere it appeared: the generated Effect menu, Effect
Controls, the Timeline and Effects & Presets.
The registry's English name is the effect's identity: `effect.list`, `effect.apply {"effect": …}`,
scripts, expressions and the property tree's group name all match on it. Only the drawing changes.
`crates/ui-egui/src/i18n/effects.rs` keys the names by effect **id** rather than by the English
string — a repeat is stored as `Gaussian Blur 2` (an English key would miss it) and upstream
renames a display name now and then, while the id is stable. It carries 306 rows for Simplified
Chinese, one per effect in the registry, taken from the installed After Effects 2026 (26.5.0.89)
Simplified Chinese interface, with the `CC` series following Adobe's Chinese documentation (which
names 68 of the 69 that its interface leaves in English). `Cryptomatte`, `EXtractoR`, `IDentifier`,
`Key Light` and `Unmult` stay in English as brand names; `Face Measurements` and `Face Track
Points` are EffectCraft's own effects. The 21 category folder names are in the same file, worded
after the effect names (channel → 通道, noise → 杂色, matte → 遮罩 …).
What draws the catalog now:
- **Effect menu:** the entries and the category submenus. The command and its `{"effect": <id>}`
params are untouched, so the menu still applies by id.
- **Effect Controls:** the header, its Rename field, the accessible name and the About popup.
- **Timeline:** effect group rows, and the search (a Chinese interface is searchable in Chinese).
- **Effects & Presets:** the rows, the drag ghost, the folder rows and the search.
Kept as they are: the effect id, the property tree's `PropGroup.name`, every automation id and
label, `effect.list`'s `name`/`category`, and the undo label (`Apply Gaussian Blur`). A name the
user typed in Effect Controls stays verbatim, and a repeated instance keeps the index the engine
appends (`Gaussian Blur 2` → `高斯模糊 2`). No other language has rows yet, Traditional Chinese
included, so those draw the registry's English name.
Tests: nine unit tests under `cargo test -p effectcraft-ui-egui --lib i18n` cover the data (every
effect has a row, the row still carries the registry's English name, ids are unique, only the five
brand names repeat their English name, every category has a row, a row names an effect the registry
knows) and the behaviour (the instance index, user renames, English and untranslated languages,
search) plus a scan pinning the drawing sites. `crates/ui-egui/tests/ui_effect_names.rs` checks the
Effect Controls header, the generated Effect menu and that the ids, automation labels and
`effect.list` stay English.
`docs/localization-parity.md` and `docs/gaps.md` no longer record effect names as deliberately
English; effect *parameter* names are still untranslated and stay the next piece.
Refs #821