Skip to content

Commit bfc3039

Browse files
committed
feat: refresh vue components when bundle list changes
1 parent 6f4770d commit bfc3039

File tree

9 files changed

+101
-8
lines changed

9 files changed

+101
-8
lines changed

rollup.config.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@ export default {
2626
// Compile TypeScript files
2727
typescript({ useTsconfigDeclarationDir: true }),
2828
// Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
29-
commonjs(),
29+
commonjs({
30+
namedExports: {
31+
'cached-iterable': ['CachedSyncIterable'],
32+
'@fluent/sequence': ['mapBundleSync']
33+
}
34+
}),
3035
// Allow node_modules resolution, so you can use 'external' to control
3136
// which external modules to include in the bundle
3237
// https://github.com/rollup/rollup-plugin-node-resolve#usage

src/directive.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { DirectiveBinding } from 'vue/types/options'
22
import { VNode } from 'vue/types/vnode'
33
import { warn } from './util/warn'
4-
import { FluentVueObject } from '../types'
4+
import { FluentVueObject } from './types'
55

66
function translate(el: HTMLElement, fluent: FluentVueObject, binding: DirectiveBinding) {
77
const key = binding.arg

src/fluent-vue.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,47 @@
1+
import Vue from 'vue'
12
import { CachedSyncIterable } from 'cached-iterable'
23
import { mapBundleSync } from '@fluent/sequence'
34
import { warn } from './util/warn'
45

5-
import { FluentVueObject, FluentVueOptions } from '../types'
6-
import { Vue, VueConstructor } from 'vue/types/vue'
6+
import { FluentVueObject, FluentVueOptions } from './types'
7+
import { VueConstructor } from 'vue/types/vue'
78
import { Pattern, FluentBundle } from '@fluent/bundle'
89

910
export default class FluentVue implements FluentVueObject {
10-
bundles: CachedSyncIterable
11+
private subscribers: Map<Vue, boolean>
12+
private bundlesIterable: CachedSyncIterable
13+
private _bundles: FluentBundle[]
14+
15+
subscribe(vue: Vue): void {
16+
this.subscribers.set(vue, true)
17+
}
18+
unsubscribe(vue: Vue): void {
19+
this.subscribers.delete(vue)
20+
}
21+
22+
get bundles(): FluentBundle[] {
23+
return this._bundles
24+
}
25+
26+
set bundles(bundles: FluentBundle[]) {
27+
this._bundles = bundles
28+
this.bundlesIterable = CachedSyncIterable.from(this.bundles)
29+
30+
for (const subscriber of this.subscribers.keys()) {
31+
subscriber.$forceUpdate()
32+
}
33+
}
1134

1235
static install: (vue: VueConstructor<Vue>) => void
1336

1437
constructor(options: FluentVueOptions) {
15-
this.bundles = CachedSyncIterable.from(options.bundles)
38+
this.subscribers = new Map<Vue, boolean>()
39+
this._bundles = options.bundles
40+
this.bundlesIterable = CachedSyncIterable.from(this.bundles)
1641
}
1742

1843
getBundle(key: string): FluentBundle {
19-
return mapBundleSync(this.bundles, key)
44+
return mapBundleSync(this.bundlesIterable, key)
2045
}
2146

2247
getMessage(bundle: FluentBundle | null, key: string) {

src/mixin.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,21 @@ export default {
1414
) {
1515
this._fluent = options.parent.$fluent
1616
}
17+
18+
if (!this._fluent) {
19+
return
20+
}
21+
22+
this._fluent.subscribe(this)
1723
},
1824

1925
beforeDestroy(this: Vue): void {
2026
if (!this._fluent) {
2127
return
2228
}
2329

30+
this._fluent.unsubscribe(this)
31+
2432
this.$nextTick(() => {
2533
this._fluent = undefined
2634
})

src/types/globals.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Vue } from 'vue/types/vue'
2-
import { FluentVueObject } from '../../types'
2+
import { FluentVueObject } from '.'
33

44
declare module 'vue/types/vue' {
55
interface Vue {

types/index.d.ts renamed to src/types/index.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ export interface FluentVueObject {
66
getMessage(bundle: FluentBundle | null, key: string): MessageInfo | null
77
formatPattern(bundle: FluentBundle, message: Pattern, value?: object, errors?: string[]): string
88
format(key: string, value?: object): string
9+
10+
subscribe(vue: Vue): void
11+
unsubscribe(vue: Vue): void
912
}
1013

1114
export interface FluentVueOptions {

test/__snapshots__/change-language.test.ts.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@
33
exports[`language change can work with multiple bundles 1`] = `<a href="/foo">текст посилання</a>`;
44

55
exports[`language change falls back to previous bundle 1`] = `<a href="/foo">link text</a>`;
6+
7+
exports[`language change updates when updating bundles array 1`] = `<a href="/foo">текст посилання</a>`;
8+
9+
exports[`language change updates when updating bundles array 2`] = `<a href="/foo">link text</a>`;

test/change-language.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,51 @@ describe('language change', () => {
7575
// Assert
7676
expect(mounted).toMatchSnapshot()
7777
})
78+
79+
it('updates when updating bundles array', () => {
80+
// Arrange
81+
const localVue = createLocalVue()
82+
localVue.use(FluentVue)
83+
84+
bundleEn = new FluentBundle('en-US', {
85+
useIsolating: false
86+
})
87+
88+
bundleUk = new FluentBundle('uk-UA', {
89+
useIsolating: false
90+
})
91+
92+
const fluent = new FluentVue({
93+
bundles: [bundleUk, bundleEn]
94+
})
95+
96+
bundleEn.addResource(
97+
new FluentResource(ftl`
98+
link = link text
99+
`)
100+
)
101+
102+
bundleUk.addResource(
103+
new FluentResource(ftl`
104+
link = текст посилання
105+
`)
106+
)
107+
108+
const component = {
109+
template: `<a v-t:link href="/foo">Fallback text</a>`
110+
}
111+
112+
// Act
113+
const mounted = mount(component, {
114+
fluent,
115+
localVue
116+
})
117+
118+
expect(mounted).toMatchSnapshot()
119+
120+
fluent.bundles = [bundleEn, bundleUk]
121+
122+
// Assert
123+
expect(mounted).toMatchSnapshot()
124+
})
78125
})

tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"strict": true,
88
"sourceMap": true,
99
"esModuleInterop": true,
10+
"downlevelIteration": true,
1011
"outDir": "dist",
1112
"typeRoots": [
1213
"node_modules/@types"

0 commit comments

Comments
 (0)