That header described a bug that had already been fixed
check-embedded-rtl opens with "TWO DEFECTS", in the present tense, describing library/i18n/index.js reflecting RTL at construction time and writing document.documentElement.dir unconditionally. Both were fixed. The header was not. It cost a real wrong answer today: I read it as a description of current code and reported a live library defect on that basis, when main already guards the documentElement write behind window.MAP_OWNS_PAGE === true, and the plugin's own direction has moved to ProfileLoader, which computes dirAttr from effectiveLocale and binds it on .profile-loader. effectiveLocale falls back through lang.value, which is the profile-config channel -- the very path the header says never arrives. So the section is now marked as history, dated, and written in the past tense, with a pointer to the two places to look before believing either defect is live again. What the check asserts is unchanged and stated plainly at the end: the plugin's own root carries direction, the partner's page must not, which is why it reads .profile-loader inside the shadow root and records partnerHtmlDir separately. The trap is worth naming in the file rather than only in a commit message, because the next reader is likely to be someone interpreting a FAILURE of this gate, which is the worst moment to be handed a stale account of the code. A gate's header is evidence of what was true when it was written. Comment-only: 33 insertions, 9 deletions, no executable line touched.
This commit is contained in:
parent
b7cd91d3e3
commit
ee3a121ae9
1 changed files with 34 additions and 10 deletions
|
|
@ -3,17 +3,41 @@
|
|||
* check-embedded-rtl — an RTL locale must turn the PLUGIN right-to-left, and must NEVER
|
||||
* turn the PARTNER'S PAGE right-to-left.
|
||||
*
|
||||
* TWO DEFECTS, one block (library/i18n/index.js, createAppI18n):
|
||||
* 1. TIMING. It reflects RTL at CONSTRUCTION time from detectLocale(), which reads only the URL
|
||||
* and <html lang>. A locale arriving later through profile-config — the channel a HOST uses —
|
||||
* never reaches it, so Arabic text renders inside a left-to-right layout. Measured: htmlDir
|
||||
* null on every host-channel run, including leaves whose chrome was fully Arabic.
|
||||
* 2. TARGET. It writes document.documentElement.dir. An EMBEDDED widget doing that flips the
|
||||
* partner's WHOLE PAGE. The existing comment already worries about the host ("a WordPress RTL
|
||||
* theme owns that decision") but only guards against CLEARING it, not against setting it.
|
||||
* ⚠ THE TWO DEFECTS BELOW WERE FIXED. This section is HISTORY, kept because it explains what the
|
||||
* check asserts and why — not a description of the code today. Read it in the past tense; verified
|
||||
* against main 2026-09-28.
|
||||
*
|
||||
* So direction belongs on the plugin's OWN element, driven by the locale ProfileLoader actually
|
||||
* applies; <html dir> stays only where the plugin owns the page (a standalone leaf).
|
||||
* WHAT USED TO BE WRONG, both in one block (library/i18n/index.js, createAppI18n):
|
||||
* 1. TIMING. It reflected RTL at CONSTRUCTION time from detectLocale(), which reads only the URL
|
||||
* and <html lang>. A locale arriving later through profile-config — the channel a HOST uses —
|
||||
* never reached it, so Arabic text rendered inside a left-to-right layout. Measured at the time:
|
||||
* htmlDir null on every host-channel run, including leaves whose chrome was fully Arabic.
|
||||
* 2. TARGET. It wrote document.documentElement.dir unconditionally. An EMBEDDED widget doing that
|
||||
* flips the partner's WHOLE PAGE. The comment of the day worried about the host ("a WordPress
|
||||
* RTL theme owns that decision") but guarded only against CLEARING dir, not against setting it.
|
||||
*
|
||||
* HOW THEY WERE FIXED, and where to look before believing either is still live:
|
||||
* - (2) library/i18n/index.js guards the documentElement write with
|
||||
* `const ownsPage = window.MAP_OWNS_PAGE === true`, so only a page the plugin OWNS gets <html
|
||||
* dir>/<html lang>. An embed cannot touch the partner's page. (lang travels with dir there: an
|
||||
* owned page that flipped to rtl while keeping lang="en" had a screen reader speak Arabic in an
|
||||
* English voice.)
|
||||
* - (1) direction on the plugin's own root is ProfileLoader's job, not this block's:
|
||||
* ProfileLoader.vue computes dirAttr from effectiveLocale and binds :dir="dirAttr" on
|
||||
* .profile-loader (see its :208 and :285). effectiveLocale is `lang.value || appI18n locale ||
|
||||
* 'en'`, and lang.value IS the profile-config channel — so a host-supplied locale does flip the
|
||||
* embedded root.
|
||||
*
|
||||
* ★ A STALE HEADER IS A TRAP, WHICH IS WHY THIS ONE IS DATED. Written in the present tense, this
|
||||
* block read as a live defect long after both were fixed, and cost a reader a wrong bug report:
|
||||
* the header was cited as current instead of the code being read. A gate's header is evidence of
|
||||
* what WAS true when it was written. If you are about to act on one, check the source it names.
|
||||
*
|
||||
* SO WHAT THIS CHECK ASSERTS, which has not changed: direction belongs on the plugin's OWN element,
|
||||
* driven by the locale ProfileLoader actually applies; <html dir> stays only where the plugin owns
|
||||
* the page (a standalone leaf). It reads .profile-loader inside the shadow root for the plugin's
|
||||
* own direction, and records partnerHtmlDir separately, because for an embed that one must stay
|
||||
* unset.
|
||||
*
|
||||
* ⚠ THE HOST PAGE IS ON A DIFFERENT ORIGIN, deliberately: same-origin would let a bug pass that
|
||||
* only bites a real partner. The tree is served on one port, the partner page on another.
|
||||
|
|
|
|||
Loading…
Reference in a new issue