Repository navigation
Conversation
|
Important Review skippedWe couldn't safely recover the incremental review. No full review was started, and the last reviewed checkpoint was preserved. Retry later, or explicitly request a full review by commenting You can disable this status message by setting the Use the checkbox below for a quick retry:
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 Walkthrough
🚥 Pre-merge checks | ✅ 5
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/renderer/src/i18n/plugin-plural-locale.ts (1)
4-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueShorten the module comment.
Keep one concise comment that states why plural resolution uses the declared locale while resource lookup uses the synthetic language. The current block restates implementation details.
As per coding guidelines, comments must be concise, limited to non-obvious information, and preferably one line.
Source: Coding guidelines
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 2f7335c8-82a8-4867-a51e-e310e85db824
📥 Commits
Reviewing files that changed from the base of the PR and between 2548b81 and b20e09c533df4e6ce883f5541aa7ecd327a3f263.
📒 Files selected for processing (3)
src/renderer/src/i18n/i18n.tssrc/renderer/src/i18n/plugin-plural-locale.test.tssrc/renderer/src/i18n/plugin-plural-locale.ts
|
Addressed in 188ca64bb. Canonicalizing alone turned out not to be enough. So the declared tag is now canonicalized (underscores folded first, so a Tests cover both directions: |
87feaa1 to
188ca64
Compare
A pack registers under the synthetic plugin<hex> resource language, which carries no locale, so Intl.PluralRules cannot be built from it and selection falls back to two English forms. A Russian pack renders 5 сессии where the language needs 5 сессий. Feed the locale the pack declares to the plural resolver, and only to the resolver: resource lookup keeps running on the synthetic tag. Every count-based call site benefits at once. Prototype for stablyai#12106, option (1).
The manifest accepts any string as a pack's locale, so a pack can declare ru_RU, not_a_locale, or xx. Two silent failures follow. Intl rejects a malformed tag outright, and for a well-formed but unknown one it falls back to the host locale: the pack would then select plural forms by whichever language the user's machine runs, which is impossible to reproduce for its author. Canonicalize the declared tag before it reaches the resolver and keep it only when Intl.PluralRules actually has data for it. A slip like ru_RU still lands on ru-RU; anything unresolvable leaves the lookup empty, so the resolver stays on the synthetic tag and the pack degrades to i18next's default instead of borrowing the host's rules. Addresses the review note on stablyai#12505.
188ca64 to
6e9e889
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/renderer/src/i18n/pack-locale.ts (1)
1-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCondense the locale rationale comments.
Keep the non-obvious rationale in one short comment at each site.
src/renderer/src/i18n/pack-locale.ts#L1-L14: replace the multi-paragraph block with one sentence that states canonicalization occurs before caller-specific Intl support checks.src/renderer/src/i18n/intl-locale.test.ts#L1-L9: replace the multi-paragraph block with one sentence that states ICU support is stubbed for deterministic tests.As per coding guidelines, comments must be concise, limited to non-obvious information, and preferably one line.
Source: Coding guidelines
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 7a07260b-b824-4f64-b421-ffa85a191c0f
📥 Commits
Reviewing files that changed from the base of the PR and between 188ca64bb09f32d36999540ebe004f3982d3f7c3 and 6e9e88961e1b204a0ca2e1e31c798acc5c7ace2f.
📒 Files selected for processing (5)
src/renderer/src/i18n/i18n.tssrc/renderer/src/i18n/intl-locale.test.tssrc/renderer/src/i18n/pack-locale.tssrc/renderer/src/i18n/plugin-plural-locale.test.tssrc/renderer/src/i18n/plugin-plural-locale.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- src/renderer/src/i18n/i18n.ts
- src/renderer/src/i18n/plugin-plural-locale.ts
- src/renderer/src/i18n/plugin-plural-locale.test.ts
|
Scope note: while rebasing this branch onto current That fix and the shared |
…consumer getIntlLocale() and the plural resolver both read the locale a language pack declares, and both trusted it verbatim. The manifest accepts any string there, so `ru_RU` — an ordinary slip — made Intl throw, and a Russian pack silently fell back to English dates while plural selection went down a separate path. Move canonicalization into one helper both call: underscores fold to dashes and Intl.getCanonicalLocales() settles the tag's shape. Whether a tag is actually supported stays per-consumer, because DateTimeFormat and PluralRules carry different data.
6e9e889 to
e219481
Compare
|
@nwparker — this and #12533 have no reviewer, and the reason looks like a gap worth fixing rather than something to ping around each time.
If you agree the whole directory belongs to the same owner, one line does it: Happy to send that as a one-line PR if you'd rather have it in the queue than in a comment. On the two PRs themselves, both are green and the split is deliberate:
No rush on either — mainly flagging that the routing gap is what's keeping them invisible, not the content. |
Upstream replaced the eagerly bundled English catalog with a trimmed boot catalog (en-runtime-required.json), which collided with this branch's two added imports in i18n.ts. Resolution: keep upstream's import — the body already reads enRuntimeRequired — and keep canonicalizePackLocale and applyPluginPluralLocales, both still used at their call sites.
|
Heads-up on the red check here, since it is misleading: the Run 34408566433 was created 9 Sep 21:44 and concluded
So the red mark carries no information about the code — but it does make these PRs look broken to anyone scanning the queue, which seemed worth stating explicitly rather than leaving to inference. What I can confirm locally for this branch at
That rebase resolved one conflict: upstream replaced the eagerly bundled English catalog with The one thing that would help: a single "Approve and run" on these four would let CI actually execute, and the checks would then say something real either way. If any of them is unwanted, closing it is just as useful to me — #13020 was closed as superseded by #13118 last month and that was the right call, no complaints from me. |
…e tools Plural forms. The catalog now carries `_few` and `_many` for the 18 plural families whose form i18next picks from a `count`: 36 entries. Orca resolves a pack's plurals with the two English forms today (stablyai/orca#12106), so nothing changes on screen; an i18next probe under the synthetic resource language gives the same output as before for every family. Under ru-RU the forms read "сохранены 2 ветки", "сохранено 5 веток", "сохранена 21 ветка", which is what users get the day stablyai/orca#12505 lands. The nine families where the component picks the suffixed key itself get no extra forms: nothing would read them. One of those, the Warp theme import limit, had an `_other` that was wrong for 21; it is now count-neutral like the rest. Tools. The build, the release check and a pack audit move from an untracked working directory into tools/. audit-pack.py is new and works on any Orca language pack: engine verdict, coverage, stale keys, placeholder drift, all against a release tag rather than main. The build accepts a `_few`/`_many` form only while its family lives in Orca's catalog; the string count and coverage leave those forms out. READMEs, checked against the v1.4.224 UI code: - the marketplace card is titled "Russian", from the plugin key, not "Русский"; - installing is not enabling: the Review plugin step was missing from all three install paths; - sources are added through Manage sources, and updates are fetched with Check for update; Orca does not announce them; - the catalog file is 1.4 MB, not 1 MB; - the coverage figure is of what a pack may translate, not of the whole catalog; - the Russian README names the buttons as they appear before the pack is active, and its term counts follow the release. 15,433 strings, unchanged, plus 36 extra plural forms.
Summary
Prototype for #12106, option (1) — routing plural resolution through the locale a plugin pack declares. @nwparker asked for one and said (1) is fine "if perf isn't weird"; it is not, and the measurement below turned out to favour the change for a reason worth reading.
A plugin language pack registers its catalog under the synthetic resource language from
pluginLanguageResourceId()—pluginfollowed by fixed-width hex — because i18next parses punctuation in language tags during resource lookup. That tag carries no locale, soIntl.PluralRulescannot be built from it and i18next falls back to a two-form English rule:ru-RUonefewmanyoneplugin<hex>oneotherotherotherFor a Russian pack that renders
5 сессииwhere the language needs5 сессий—fewandmanyare different words, and no catalog content can express the difference while selection happens on the synthetic tag.What changed
The pack already declares the locale its translations were written for.
plugin-plural-locale.tsfeeds that declared locale to the plural resolver, and only to the resolver — resource lookup keeps running on the synthetic tag exactly as before:setRendererPluginLanguagePacks()refreshes the mapping whenever packs change and clears the rule cache, so a pack that changes its declared locale is followed rather than stuck on the previous one. Everycount-based call site benefits at once; no call site changes.Perf: it gets faster, and the reason is a bug in the fallback path
Same instance, same key,
t()withcount, 200,000 calls after a 2,000-call warmup:That is not noise, and the change does no extra work — it removes work.
PluralResolver.getRulecaches its result at the end of the method, but the fallback for a code with no-or_returns early:A synthetic
plugin<hex>tag has no separator, so it takes that branch on every call: a freshnew Intl.PluralRules()over a 90-character invalid tag, a thrownRangeError, caught, discarded. Measured pergetRule:ru-RUenplugin<hex>Mapping the code to a real locale before the lookup puts it back on the cached path. So the answer to "is perf weird" is that it was already weird, and this removes a throw-per-call from the hot path.
(Worth a separate upstream report to i18next, since any consumer with a non-BCP-47 resource language hits it. Happy to file that if you agree with the reading.)
Testing
pnpm lintpnpm typecheckpnpm testpnpm buildplugin-plural-locale.test.tscovers four things: that Russian forms appear only after the pack declares its locale (asserting the wrong values first, so the test fails if the fix silently stops working); that resource lookup still resolves on the synthetic tag; that a pack with a missing or self-referential locale is ignored; and that a pack changing its declared locale is followed, including back to no mapping.Verified against the real 11,742-string
smwbev.russiancatalog as well — with_few/_manypresent it renders2 темы/5 темwhere it previously rendered the_otherform for both.Full suite on
2548b816c: 45,359 passed, 24 failures across 9 files. Eight of those files reproduce on a cleanupstream/maincheckout on this machine —omp-shell-wrapper.node-pty,ssh-posix-command-wrapper, bothterminal-ime-*,automation-schedules,external-automation-jobs-file,headless-emulator-fidelity.fuzz,terminal-snapshot-color-parity. The ninth,transcript-watch, flaked once under full-suite load on a file-watcher timing assertion and passes four out of four in isolation on this branch.AI Review Report
Map, no paths, no shell, no platform APIs, no Electron surface.Intl.PluralRulesavailability is unchanged — the code that consults it is untouched; only the tag handed to it differs.en/es/ja/ko/zhtake the identical path they take today. That is asserted by the "keeps resource lookup on the synthetic tag" case.services.pluralResolveris public API surface on the instance, but the wrapper is deliberately narrow — it rewrites the argument, never the rule, so i18next keeps owning selection semantics.Security Audit
Intl.PluralRules, which rejects malformed tags by throwing — the same behavior the synthetic tag hits today, and it degrades to the current two-form rule rather than failing the render.Notes
This is option (1) from #12106 in isolation, so nothing regresses if it is rejected: with the mapping absent, behavior is exactly today's. Option (2) — moving the seven
=== 1 ? … : …call sites tocount— only becomes worthwhile on top of this, and is intentionally not bundled here so the two can be judged separately.