Skip to content

Commit

Permalink
Implement mergedWith helper method for global translations (#877)
Browse files Browse the repository at this point in the history
  • Loading branch information
Demivan committed May 14, 2024
1 parent 24a6969 commit 89f400f
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 16 deletions.
70 changes: 70 additions & 0 deletions __tests__/globalTranslations.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { beforeEach, describe, expect, it } from 'vitest'

import { FluentBundle, FluentResource } from '@fluent/bundle'

import type { FluentVue } from '../src'
import { createFluentVue } from '../src'

describe('mergedWith', () => {
let bundleEn: FluentBundle
let bundleUk: FluentBundle

let fluent: FluentVue

beforeEach(() => {
bundleEn = new FluentBundle('en')
bundleUk = new FluentBundle('uk')

fluent = createFluentVue({
bundles: [bundleEn, bundleUk],
})
})

it('returns global translations', () => {
// Arrange
bundleEn.addResource(new FluentResource('hello = Hello, World!'))

// Act
const { $t } = fluent.mergedWith({ en: new FluentResource('hello-two = Hello, World!') })
const translation = $t('hello')

// Assert
expect(translation).toEqual('Hello, World!')
})

it('returns merged translation', () => {
// Arrange
bundleEn.addResource(new FluentResource('hello = Hello, World!'))

// Act
const { $t } = fluent.mergedWith({ en: new FluentResource('hello-two = Hello, World merged!') })
const translation = $t('hello-two')

// Assert
expect(translation).toEqual('Hello, World merged!')
})

it('returns overridden global translations', () => {
// Arrange
bundleEn.addResource(new FluentResource('hello = Hello, World!'))

// Act
const { $t } = fluent.mergedWith({ en: new FluentResource('hello = Hello, World overridden!') })
const translation = $t('hello')

// Assert
expect(translation).toEqual('Hello, World overridden!')
})

it('falls back to the next bundle', () => {
// Arrange
bundleEn.addResource(new FluentResource('hello = Hello, World!'))

// Act
const { $t } = fluent.mergedWith({ uk: new FluentResource('hello-two = Привіт, Світ!') })
const translation = $t('hello-two')

// Assert
expect(translation).toEqual('Привіт, Світ!')
})
})
41 changes: 27 additions & 14 deletions src/getContext.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { computed } from 'vue-demi'
import { CachedSyncIterable } from 'cached-iterable'
import type { FluentResource } from '@fluent/bundle'
import type { VueComponent } from './types/typesCompat'

import { TranslationContext } from './TranslationContext'
Expand All @@ -20,13 +21,34 @@ export function getContext(

const options = instance.$options

const fluent = options.fluent
if (fluent == null)
return rootContext

if (options._fluent != null)
return options._fluent

const context = getMergedContext(rootContext, options.fluent)

// If we are in script setup, we cannot cache the context
// because after component is unmounted, computed will not be updated
// Additionally we cannot cache on the server, because server is not reactive
const isServer = typeof window === 'undefined'
if (!fromSetup && !isServer)
options._fluent = context

return context
}

/**
* Get new translation context with overridden bundles
* @param rootContext Root context with all bundles
* @param fluent Fluent resources to override
* @returns New translation context with overridden bundles
*/
export function getMergedContext(
rootContext: TranslationContext,
fluent?: Record<string, FluentResource>,
): TranslationContext {
if (fluent == null)
return rootContext

// If we override messages in a component
// create new translation context with new bundles
const overriddenBundles = computed(() =>
Expand All @@ -48,14 +70,5 @@ export function getContext(
),
)

const context = new TranslationContext(overriddenBundles, rootContext.options)

// If we are in script setup, we cannot cache the context
// because after component is unmounted, computed will not be updated
// Additionally we cannot cache on the server, because server is not reactive
const isServer = typeof window === 'undefined'
if (!fromSetup && !isServer)
options._fluent = context

return context
return new TranslationContext(overriddenBundles, rootContext.options)
}
16 changes: 14 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import './types/volar'
import type { FluentBundle, FluentVariable } from '@fluent/bundle'
import type { FluentBundle, FluentResource, FluentVariable } from '@fluent/bundle'
import { isVue3, shallowRef } from 'vue-demi'
import type { FluentVueOptions } from './types'

Expand All @@ -8,7 +8,7 @@ import type { TranslationWithAttrs } from './TranslationContext'
import { TranslationContext } from './TranslationContext'
import { createVue2Directive, createVue3Directive } from './vue/directive'
import { createComponent } from './vue/component'
import { getContext } from './getContext'
import { getContext, getMergedContext } from './getContext'
import { RootContextSymbol } from './symbols'
import { resolveOptions } from './util/options'

Expand All @@ -24,6 +24,11 @@ export interface FluentVue {

formatWithAttrs: (key: string, value?: Record<string, FluentVariable>) => TranslationWithAttrs

mergedWith: (extraTranslations?: Record<string, FluentResource>) => TranslationContext

$t: (key: string, value?: Record<string, FluentVariable>) => string
$ta: (key: string, value?: Record<string, FluentVariable>) => Record<string, string>

install: InstallFunction
}

Expand All @@ -47,10 +52,17 @@ export function createFluentVue(options: FluentVueOptions): FluentVue {
bundles.value = value
},

mergedWith: (extraTranslations?: Record<string, FluentResource>) => {
return getMergedContext(rootContext, extraTranslations)
},

format: rootContext.format.bind(rootContext),
formatAttrs: rootContext.formatAttrs.bind(rootContext),
formatWithAttrs: rootContext.formatWithAttrs.bind(rootContext),

$t: rootContext.format.bind(rootContext),
$ta: rootContext.formatAttrs.bind(rootContext),

install(vue) {
if (isVue3) {
const vue3 = vue as Vue3
Expand Down

0 comments on commit 89f400f

Please sign in to comment.