mnfst 0.5.94 → 0.5.95

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,7 @@
10
10
  "manifest.dropdowns.js": "sha384-WMrFoSpKfJuo81dyrwhVrDO8rq+rDwh2x8x4nH01BY5ZHkvjE+/SaT2gWCI0zOn+",
11
11
  "manifest.export.js": "sha384-qvdGz1TiGEDOeWJ5os1z03RURdKX+ezZEQ1KyV+9iC7X0esLK83mtY87t4MQv45t",
12
12
  "manifest.icons.js": "sha384-uOkboYrovjCpl22eey3Jaxpey+pOnot5NDnRRumcRxiR7IOVaRh1i20gYnWXR5dW",
13
- "manifest.localization.js": "sha384-Uw2x2kBJyr5u6BnPieR68Iz0kCdMK/lvIJQajxZGwqBSfa3204W9Sz7X8DYerC9b",
13
+ "manifest.localization.js": "sha384-M40EWrbWs2MoJvUiYVQaPxPiOzMYBn/ywuMR02rvoSXG77eIHT/aRoYub9r6+jC+",
14
14
  "manifest.markdown.js": "sha384-3LgPiHrftPqAIJGhxi87C0TtfJXbsH0Qj4JmfmYgV4y5UjSx7nVSP+ppsRUWT0Xs",
15
15
  "manifest.resize.js": "sha384-Ak5gf44ERfh9pOSAD1qZzJSysslpwBCkevIlz7R3dszTUyzUKGKGF4pn5arOtgG0",
16
16
  "manifest.router.js": "sha384-n6xmIfWnYzd/0kkVTFuHhFzHuxiDgZ1Lg1W0yB6/w3Myw5pQ6PgE6SJBHfVsO7/D",
@@ -1,5 +1,16 @@
1
1
  /* Manifest Localization */
2
2
 
3
+ // Snapshot the original <html lang> attribute at the moment this script
4
+ // loads, before any locale-mutation code (this plugin's own init, or any
5
+ // other script) has had a chance to overwrite it. This is the developer's
6
+ // declared default — the value baked into index.html's <html lang="…"> tag
7
+ // — and is the locale $locale.reset() restores to. Captured at module
8
+ // scope so both initializeLocalizationPlugin and the reset implementation
9
+ // can reach it through lexical closure.
10
+ const originalHtmlLang = (typeof document !== 'undefined' && document.documentElement)
11
+ ? (document.documentElement.lang || '')
12
+ : '';
13
+
3
14
  // Global setLocale wrapper - will be replaced with real implementation
4
15
  let setLocaleImpl = null;
5
16
 
@@ -24,13 +35,6 @@ window.__manifestSetLocale = setLocale;
24
35
 
25
36
  function initializeLocalizationPlugin() {
26
37
 
27
- // Snapshot the original <html lang> attribute before any locale mutation.
28
- // This is the developer's declared default — the value baked into
29
- // index.html's <html lang="…"> tag. Used by $locale.reset() to restore
30
- // the project to its declared default language regardless of current
31
- // runtime state (which gets mutated by set/toggle/URL detection).
32
- const originalHtmlLang = document.documentElement.lang || '';
33
-
34
38
  // Environment detection for debug logging
35
39
  const isDevelopment = window.location.hostname === 'localhost' ||
36
40
  window.location.hostname === '127.0.0.1' ||
@@ -530,6 +534,85 @@ function initializeLocalizationPlugin() {
530
534
  setLocaleImpl = setLocaleReal;
531
535
  window.__manifestSetLocale = setLocaleReal;
532
536
 
537
+ // $locale.reset implementation — exposed across functions via window so the
538
+ // magic registration (in registerLocaleMagic, a sibling top-level function)
539
+ // can call it. Inlining the logic in the magic's closure would put it out
540
+ // of scope from safeStorage / isValidLanguageCode / isRTL / originalHtmlLang.
541
+ function resetLocaleReal(href) {
542
+ const store = Alpine.store('locale');
543
+ const available = store?.available || [originalHtmlLang || 'en'];
544
+
545
+ // 1. Clear stored UI-toggle preference so future page loads re-detect.
546
+ safeStorage.remove('lang');
547
+
548
+ // 2. Resolve the default locale. Matches initial detection minus URL
549
+ // and localStorage layers, since reset opts out of both:
550
+ // a. Original <html lang> baked into index.html (snapshotted at
551
+ // plugin init, before any locale mutation).
552
+ // b. Browser language if it matches an available locale.
553
+ // c. First locale registered in manifest.json.
554
+ let defaultLocale = null;
555
+ if (originalHtmlLang
556
+ && isValidLanguageCode(originalHtmlLang)
557
+ && available.includes(originalHtmlLang)) {
558
+ defaultLocale = originalHtmlLang;
559
+ } else if (navigator.language) {
560
+ const browserLang = navigator.language.split('-')[0];
561
+ if (isValidLanguageCode(browserLang) && available.includes(browserLang)) {
562
+ defaultLocale = browserLang;
563
+ }
564
+ }
565
+ if (!defaultLocale) {
566
+ defaultLocale = available[0] || 'en';
567
+ }
568
+
569
+ // 3. Resolve target URL (passed-in href or current) and strip its
570
+ // leading locale segment, if any.
571
+ let target;
572
+ try {
573
+ target = new URL(href || window.location.href, window.location.href);
574
+ } catch {
575
+ return false;
576
+ }
577
+ const segs = target.pathname.split('/').filter(Boolean);
578
+ if (segs.length && available.includes(segs[0])) {
579
+ segs.shift();
580
+ }
581
+ target.pathname = '/' + segs.join('/');
582
+
583
+ // 4. Apply the default locale to the live store + DOM before
584
+ // navigating, so $locale.current and any reactive readers update
585
+ // immediately.
586
+ if (store && store.current !== defaultLocale) {
587
+ store.current = defaultLocale;
588
+ store.direction = isRTL(defaultLocale) ? 'rtl' : 'ltr';
589
+ try {
590
+ document.documentElement.lang = defaultLocale;
591
+ document.documentElement.dir = store.direction;
592
+ } catch { /* DOM unavailable */ }
593
+ try {
594
+ window.dispatchEvent(new CustomEvent('localechange', {
595
+ detail: { locale: defaultLocale }
596
+ }));
597
+ } catch { /* event dispatch unavailable */ }
598
+ }
599
+
600
+ // 5. Navigate to the locale-stripped URL. SPA hop in the live app,
601
+ // MPA hop in prerendered output so the new URL's prerendered HTML
602
+ // loads from disk.
603
+ const isSameOrigin = target.origin === window.location.origin;
604
+ const isPrerendered = !!document.querySelector('meta[name="manifest:prerendered"]:not([content="0"]):not([content="false"])');
605
+
606
+ if (isSameOrigin && !isPrerendered && typeof history?.pushState === 'function') {
607
+ history.pushState(null, '', target.pathname + target.search + target.hash);
608
+ window.dispatchEvent(new PopStateEvent('popstate'));
609
+ } else {
610
+ window.location.assign(target.toString());
611
+ }
612
+ return true;
613
+ }
614
+ window.__manifestResetLocale = resetLocaleReal;
615
+
533
616
  // Event listener cleanup tracking
534
617
  let routeChangeListener = null;
535
618
 
@@ -679,77 +762,11 @@ function registerLocaleMagic() {
679
762
  // loads from disk.
680
763
  if (prop === 'reset') {
681
764
  return (href) => {
682
- const store = Alpine.store('locale');
683
- const available = store?.available || [originalHtmlLang || 'en'];
684
-
685
- // Clear stored UI-toggle preference so future
686
- // page loads re-detect from scratch.
687
- safeStorage.remove('lang');
688
-
689
- // Resolve the default locale from declarations.
690
- let defaultLocale = null;
691
- if (originalHtmlLang
692
- && isValidLanguageCode(originalHtmlLang)
693
- && available.includes(originalHtmlLang)) {
694
- defaultLocale = originalHtmlLang;
695
- } else if (navigator.language) {
696
- const browserLang = navigator.language.split('-')[0];
697
- if (isValidLanguageCode(browserLang)
698
- && available.includes(browserLang)) {
699
- defaultLocale = browserLang;
700
- }
701
- }
702
- if (!defaultLocale) {
703
- defaultLocale = available[0] || 'en';
765
+ if (window.__manifestResetLocale) {
766
+ return window.__manifestResetLocale(href);
704
767
  }
705
-
706
- // Resolve target URL (passed-in href or current)
707
- // and strip its leading locale segment, if any.
708
- let target;
709
- try {
710
- target = new URL(href || window.location.href, window.location.href);
711
- } catch {
712
- return false;
713
- }
714
- const segs = target.pathname.split('/').filter(Boolean);
715
- if (segs.length && available.includes(segs[0])) {
716
- segs.shift();
717
- }
718
- target.pathname = '/' + segs.join('/');
719
-
720
- // Apply the default locale to the live store + DOM
721
- // before navigating, so $locale.current and any
722
- // reactive readers update immediately. Skip the
723
- // setLocale wrapper because it would attempt URL
724
- // updates of its own — we're handling navigation
725
- // explicitly below.
726
- if (store && store.current !== defaultLocale) {
727
- store.current = defaultLocale;
728
- store.direction = isRTL(defaultLocale) ? 'rtl' : 'ltr';
729
- try {
730
- document.documentElement.lang = defaultLocale;
731
- document.documentElement.dir = store.direction;
732
- } catch { /* DOM unavailable */ }
733
- try {
734
- window.dispatchEvent(new CustomEvent('localechange', {
735
- detail: { locale: defaultLocale }
736
- }));
737
- } catch { /* event dispatch unavailable */ }
738
- }
739
-
740
- // Navigate to the locale-stripped URL.
741
- const isSameOrigin = target.origin === window.location.origin;
742
- const isPrerendered = !!document.querySelector('meta[name="manifest:prerendered"]:not([content="0"]):not([content="false"])');
743
-
744
- if (isSameOrigin && !isPrerendered && typeof history?.pushState === 'function') {
745
- // SPA hop: keep the in-memory app, fire route-change.
746
- history.pushState(null, '', target.pathname + target.search + target.hash);
747
- window.dispatchEvent(new PopStateEvent('popstate'));
748
- } else {
749
- // MPA hop: load the prerendered HTML for the new URL.
750
- window.location.assign(target.toString());
751
- }
752
- return true;
768
+ console.error('[Manifest Localization] resetLocale not available');
769
+ return false;
753
770
  };
754
771
  }
755
772
  return undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnfst",
3
- "version": "0.5.94",
3
+ "version": "0.5.95",
4
4
  "private": false,
5
5
  "workspaces": [
6
6
  "templates/starter",