Skip to content

[2.x] feat(gambits): localization alias support — English keywords always work regardless of locale - #4570

Merged
imorland merged 9 commits into
2.xfrom
im/gambit-localization-alias
Oct 20, 2026
Merged

imorland merged 9 commits into
2.xfrom
im/gambit-localization-alias

Conversation

@imorland

@imorland imorland commented Apr 14, 2026 •

Copy link
Copy Markdown
Member

Fixes #4566

Changes proposed in this pull request:
Translating a gambit keyword broke search: subscriptions sent the translated word to an API filter that only understood English, and in a translated forum the English keywords stopped matching. Gambits now have a canonicalKey() (defaulting to key()), and GambitManager falls back to the English pattern when the translated one doesn't match. Every core and bundled gambit with a translated keyword returns its English keyword there. The subscription gambit always sends follow or ignore, and SubscriptionFilter accepts a fixed list of values in any case, returning no results for an unknown value instead of a 500.

Reviewers should focus on:

  • Additive for extensions: canonicalPattern() is optional on IGambit, and a gambit that doesn't override canonicalKey() behaves as before, just without the English fallback.
  • filter[subscription]=following (the following page, Deck) still works; follow/ignore and any case are now accepted too.

Screenshot
N/A

Necessity

  • Has the problem that is being solved here been clearly explained?
  • If applicable, have various options for solving this problem been considered?
  • For core PRs, does this need to be in core, or could it be in an extension?
  • Are we willing to maintain this for years / potentially forever?

Confirmed

  • Frontend changes: tested on a local Flarum installation.
  • Frontend changes: tests are green (run yarn test in js/).
  • Frontend changes: tests have been added, or are not appropriate here.
  • Backend changes: tests are green (run composer test).
  • Backend changes: tests have been added, or are not appropriate here.
  • Where applicable, changes are suitable for all supported database drivers (MySQL, MariaDB, PostgreSQL, SQLite).
  • Core developer confirmed locally this works as intended.
  • The description above is written by me and describes what this pull request actually does.

Required changes:

@imorland
imorland requested a review from a team as a code owner April 14, 2026 16:33
@imorland imorland changed the title feat(gambits): localization alias support — English keywords always work regardless of locale [2.x] feat(gambits): localization alias support — English keywords always work regardless of locale Apr 14, 2026
@imorland imorland added this to the 2.0.0-rc.1 milestone Apr 14, 2026
@imorland imorland modified the milestones: 2.0.0-rc.1, 2.1 Apr 14, 2026
imorland and others added 8 commits October 19, 2026 19:10
…ork regardless of locale

Adds `canonicalKey()` and `canonicalPattern()` to `BooleanGambit` and `KeyValueGambit`.
`GambitManager.match()` now tries the canonical English pattern as an alias when the
translated pattern doesn't match, so English keywords like `is:hidden` or `author:behz`
are always accepted even when the site locale has translated them.

Fixes `SubscriptionFilter` accepting raw locale strings from the frontend; it now
only accepts the stable canonical values `follow`/`ignore`. `SubscriptionGambit.toFilter()`
maps matched keywords to canonical values before sending them to the API.

Closes #4566
…on types

Adds a Flarum\Subscriptions\Extend\Subscription extender so third-party
extensions can register custom subscription types (e.g. 'lurk') with their
accepted filter aliases:

    (new Extend\Subscription())
        ->addSubscriptionType('lurk', ['lurk', 'lurking', 'lurked'])

SubscriptionFilter now resolves values through a container-bound registry
('flarum-subscriptions.subscription_types') rather than a hardcoded match
expression. The built-in 'follow' and 'ignore' types are seeded by the
subscriptions extension's own extend.php via the same extender.
…tures

- Add canonicalPattern() to the IGambit object literal in GambitsAutocomplete.tsx
  so it satisfies the updated interface (TS2345)
- Add __esModule: true to the nanoid Jest mock so Jest's CJS/ESM interop resolves
  the named export correctly
- Move lurk discussion/post/discussion_user fixtures into setUp() so the
  subscription_extender_registers_custom_type test can find them
Jest runs with --experimental-vm-modules which does real ESM linking, so CJS
mock files cannot satisfy named ESM imports. Replace emptyModule.js and
nanoid.js with proper .mjs equivalents using ESM export syntax.

Fix SubscriptionFilterTest: seed the 'lurk-user' fixture under user 3 (not
user 2) to avoid polluting the negation tests' result sets; switch negation
assertions from assertEqualsCanonicalizing to assertContains/assertNotContains
so they remain correct regardless of how many discussions exist.

Replace the lurk custom-type test (which required seeding an invalid enum value)
with a test that registers an additional alias for the existing 'follow' type,
which is a valid use of the extender and exercises the same code path.
- Add canonicalKey() to the translated core and bundled gambits, so English
  keywords work in every locale, as the alias was meant to.
- Keep the gambit's own group key (is/has/allows) in canonicalPattern().
- Make IGambit::canonicalPattern() optional, so gambits that implement the
  interface directly keep working.
- Match subscription keywords without regard to case, in the gambit and in
  SubscriptionFilter, as the previous pattern did.
- Write the subscription gambit back with the translated group key, and treat
  a legacy following/ignoring filter value correctly.
- Drop the jest moduleNameMapper override and its mocks: it replaced
  @flarum/jest-config's own mappings and is no longer needed.
@imorland
imorland force-pushed the im/gambit-localization-alias branch from 1234807 to 870b30d Compare October 19, 2026 18:22
@imorland
imorland marked this pull request as draft October 19, 2026 18:27
… of an extender

Remove the Subscription extender. discussion_user.subscription only stores
follow or ignore, so an extension could not store a new type it registered.
SubscriptionFilter now maps its accepted values to those two directly.
@imorland
imorland marked this pull request as ready for review October 19, 2026 18:30
@imorland
imorland merged commit 46405d1 into 2.x Oct 20, 2026
35 of 36 checks passed
@imorland
imorland deleted the im/gambit-localization-alias branch October 20, 2026 05:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[2.x] Hardcoded gambit keywords prevent localization

2 participants