@fy-/fws-vue 2.4.2 → 2.4.3

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.
Files changed (2) hide show
  1. package/index.ts +30 -3
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -1,8 +1,10 @@
1
+ import type { TFunction } from 'i18next'
1
2
  import type { Emitter } from 'mitt'
2
3
  import type { App, Plugin } from 'vue'
3
4
  import type { Events } from './composables/event-bus'
4
5
  import i18next from 'i18next'
5
6
  import mitt from 'mitt'
7
+ import { shallowRef } from 'vue'
6
8
  import CmsArticleBoxed from './components/fws/CmsArticleBoxed.vue'
7
9
  import CmsArticleSingle from './components/fws/CmsArticleSingle.vue'
8
10
  import DataTable from './components/fws/DataTable.vue'
@@ -70,15 +72,40 @@ function createFWS(): Plugin {
70
72
  // @ts-expect-error: Emitter<Events> is not assignable to Emitter<Events>
71
73
  const eventBus: Emitter<Events> = mitt<Events>()
72
74
 
75
+ // i18next's `t` is NOT reactive. If a component renders a key during a window
76
+ // where the resource isn't loaded yet (cold deep-link, client-nav before a late
77
+ // locale fetch, hydration race) it paints the RAW token and Vue never re-renders
78
+ // — nothing reactive changed, so the miss sticks. Wrap `t` so it depends on a
79
+ // tick bumped by i18next's own events: any raw key then self-heals the instant
80
+ // resources land, and `changeLanguage` live-updates every string. Client-only:
81
+ // on the server strings are already resolved by the `await i18nextPromise` before
82
+ // render, and `install()` runs per-request there — adding listeners to the global
83
+ // i18next singleton each request would leak. So SSR keeps the plain `t`.
84
+ let translate: TFunction = i18next.t
85
+ if (typeof window !== 'undefined') {
86
+ const tick = shallowRef(0)
87
+ const bump = (): void => {
88
+ tick.value++
89
+ }
90
+ i18next.on('loaded', bump)
91
+ i18next.on('added', bump)
92
+ i18next.on('languageChanged', bump)
93
+ const rawT = i18next.t as unknown as (...a: unknown[]) => unknown
94
+ translate = ((...args: Parameters<typeof i18next.t>) => {
95
+ void tick.value
96
+ return rawT(...args)
97
+ }) as unknown as TFunction
98
+ }
99
+
73
100
  return {
74
101
  install(app: App) {
75
102
  if (app.config.globalProperties) {
76
103
  app.config.globalProperties.$eventBus = eventBus
77
104
  app.provide('fwsVueEventBus', eventBus)
78
105
 
79
- // i18next
80
- app.config.globalProperties.$t = i18next.t
81
- app.provide('fwsVueTranslate', i18next.t)
106
+ // i18next (reactive wrapper — see note above)
107
+ app.config.globalProperties.$t = translate
108
+ app.provide('fwsVueTranslate', translate)
82
109
 
83
110
  // Templating
84
111
  app.config.globalProperties.$cropText = cropText
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fy-/fws-vue",
3
- "version": "2.4.2",
3
+ "version": "2.4.3",
4
4
  "author": "Florian 'Fy' Gasquez <m@fy.to>",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/fy-to/FWJS#readme",