From fbfa484c00870485f58ed86d039a390028901509 Mon Sep 17 00:00:00 2001 From: Steve Axtmann Date: Thu, 23 Feb 2023 17:32:53 +0100 Subject: [PATCH 1/3] feat(options): allow t and ta globals and directive to be renamed --- __tests__/vue/globals.spec.ts | 98 +++++++++++++++++++++++++++++++++++ src/index.ts | 17 +++--- src/types/index.d.ts | 8 ++- 3 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 __tests__/vue/globals.spec.ts diff --git a/__tests__/vue/globals.spec.ts b/__tests__/vue/globals.spec.ts new file mode 100644 index 00000000..be48ba5c --- /dev/null +++ b/__tests__/vue/globals.spec.ts @@ -0,0 +1,98 @@ +import { beforeEach, describe, expect, it } from 'vitest' + +import { FluentBundle, FluentResource } from '@fluent/bundle' +import ftl from '@fluent/dedent' + +import { mountWithFluent } from '../utils' + +import { createFluentVue } from '../../src' + +describe('globals', () => { + let bundle: FluentBundle + + beforeEach(() => { + bundle = new FluentBundle('en-US') + }) + + it('can rename t directive', () => { + const fluent = createFluentVue({ + bundles: [bundle], + globals: { + t: 'test', + }, + }) + + // Arrange + bundle.addResource( + new FluentResource(ftl` + link = Link text + `), + ) + + const component = { + template: 'Fallback text', + } + + // Act + const mounted = mountWithFluent(fluent, component) + + // Assert + expect(mounted.html()).toEqual('Link text') + }) + + it('can rename global $t', () => { + const fluent = createFluentVue({ + bundles: [bundle], + globals: { + t: 'test', + }, + }) + + // Arrange + bundle.addResource( + new FluentResource(ftl` + message = Hello, { $name }! + `), + ) + + const component = { + data: () => ({ + name: 'John', + }), + template: '
{{ $test("message", { name }) }}
', + } + + // Act + const mounted = mountWithFluent(fluent, component) + + // Assert + expect(mounted.html()).toEqual('
Hello, \u{2068}John\u{2069}!
') + }) + + it('can rename global $ta', () => { + const fluent = createFluentVue({ + bundles: [bundle], + globals: { + ta: 'test', + }, + }) + + // Arrange + bundle.addResource( + new FluentResource(ftl` + key = + .attr = Attr value + `), + ) + + const component = { + template: '
', + } + + // Act + const mounted = mountWithFluent(fluent, component) + + // Assert + expect(mounted.html()).toEqual('
') + }) +}) diff --git a/src/index.ts b/src/index.ts index df0fb29f..b9da5e12 100644 --- a/src/index.ts +++ b/src/index.ts @@ -51,25 +51,30 @@ export function createFluentVue(options: FluentVueOptions): FluentVue { formatWithAttrs: rootContext.formatWithAttrs.bind(rootContext), install(vue) { + const rawGlobalT = options.globals?.t || 't' + const rawGlobalTa = options.globals?.ta || 'ta' + const globalT = `$${rawGlobalT}` + const globalTa = `$${rawGlobalTa}` + if (isVue3) { const vue3 = vue as Vue3 vue3.provide(RootContextSymbol, rootContext) - vue3.config.globalProperties.$t = function ( + vue3.config.globalProperties[globalT] = function ( key: string, value?: Record, ) { return getContext(rootContext, this as Vue3Component).format(key, value) } - vue3.config.globalProperties.$ta = function ( + vue3.config.globalProperties[globalTa] = function ( key: string, value?: Record, ) { return getContext(rootContext, this as Vue3Component).formatAttrs(key, value) } - vue3.directive('t', createVue3Directive(rootContext)) + vue3.directive(rawGlobalT, createVue3Directive(rootContext)) } else { const vue2 = vue as Vue2 @@ -82,14 +87,14 @@ export function createFluentVue(options: FluentVueOptions): FluentVue { }, }) - vue2.prototype.$t = function (key: string, value?: Record) { + vue2.prototype[globalT] = function (key: string, value?: Record) { return getContext(rootContext, this).format(key, value) } - vue2.prototype.$ta = function (key: string, value?: Record) { + vue2.prototype[globalTa] = function (key: string, value?: Record) { return getContext(rootContext, this).formatAttrs(key, value) } - vue2.directive('t', createVue2Directive(rootContext)) + vue2.directive(rawGlobalT, createVue2Directive(rootContext)) } (vue as Vue).component('i18n', component) diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 46747cb9..dabc75e2 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -10,7 +10,13 @@ export interface FluentVueOptions { warnMissing?: ((key: string) => void) | boolean /** Custom function for parsing markup */ - parseMarkup?: (markup: string) => SimpleNode[] + parseMarkup?: (markup: string) => SimpleNode[], + + /** Override the names of the global functions and directive to avoid conflicts */ + globals?: { + t?: string; + ta?: string; + } } export interface TranslationContextOptions { From da377be9908377de7b1ab1d0e3b5de00ac9857c0 Mon Sep 17 00:00:00 2001 From: Steve Axtmann Date: Fri, 24 Feb 2023 17:24:34 +0100 Subject: [PATCH 2/3] refactor(options): improve structure of the global config - split out renaming so that the user can individually rename the functions, directive and component --- __tests__/vue/globals.spec.ts | 36 ++++++++++++++++++++++++++++++++--- src/index.ts | 22 ++++++++++----------- src/types/index.d.ts | 11 +++++++---- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/__tests__/vue/globals.spec.ts b/__tests__/vue/globals.spec.ts index be48ba5c..7b5b60af 100644 --- a/__tests__/vue/globals.spec.ts +++ b/__tests__/vue/globals.spec.ts @@ -18,7 +18,7 @@ describe('globals', () => { const fluent = createFluentVue({ bundles: [bundle], globals: { - t: 'test', + directive: 'test', }, }) @@ -44,7 +44,9 @@ describe('globals', () => { const fluent = createFluentVue({ bundles: [bundle], globals: { - t: 'test', + functions: { + format: '$test', + }, }, }) @@ -73,7 +75,9 @@ describe('globals', () => { const fluent = createFluentVue({ bundles: [bundle], globals: { - ta: 'test', + functions: { + formatAttrs: '$test', + }, }, }) @@ -95,4 +99,30 @@ describe('globals', () => { // Assert expect(mounted.html()).toEqual('
') }) + + it('can rename component', () => { + const fluent = createFluentVue({ + bundles: [bundle], + globals: { + component: 'test', + }, + }) + + // Arrange + bundle.addResource( + new FluentResource(ftl` + key = Inner data + `), + ) + + const component = { + template: '', + } + + // Act + const mounted = mountWithFluent(fluent, component) + + // Assert + expect(mounted.html()).toEqual('Inner data') + }) }) diff --git a/src/index.ts b/src/index.ts index b9da5e12..8de8c195 100644 --- a/src/index.ts +++ b/src/index.ts @@ -51,30 +51,30 @@ export function createFluentVue(options: FluentVueOptions): FluentVue { formatWithAttrs: rootContext.formatWithAttrs.bind(rootContext), install(vue) { - const rawGlobalT = options.globals?.t || 't' - const rawGlobalTa = options.globals?.ta || 'ta' - const globalT = `$${rawGlobalT}` - const globalTa = `$${rawGlobalTa}` + const globalFormatName = options.globals?.functions?.format || '$t' + const globalFormatAttrsName = options.globals?.functions?.formatAttrs || '$ta' + const directiveName = options.globals?.directive || 't' + const componentName = options.globals?.component || 'i18n'; if (isVue3) { const vue3 = vue as Vue3 vue3.provide(RootContextSymbol, rootContext) - vue3.config.globalProperties[globalT] = function ( + vue3.config.globalProperties[globalFormatName] = function ( key: string, value?: Record, ) { return getContext(rootContext, this as Vue3Component).format(key, value) } - vue3.config.globalProperties[globalTa] = function ( + vue3.config.globalProperties[globalFormatAttrsName] = function ( key: string, value?: Record, ) { return getContext(rootContext, this as Vue3Component).formatAttrs(key, value) } - vue3.directive(rawGlobalT, createVue3Directive(rootContext)) + vue3.directive(directiveName, createVue3Directive(rootContext)) } else { const vue2 = vue as Vue2 @@ -87,17 +87,17 @@ export function createFluentVue(options: FluentVueOptions): FluentVue { }, }) - vue2.prototype[globalT] = function (key: string, value?: Record) { + vue2.prototype[globalFormatName] = function (key: string, value?: Record) { return getContext(rootContext, this).format(key, value) } - vue2.prototype[globalTa] = function (key: string, value?: Record) { + vue2.prototype[globalFormatAttrsName] = function (key: string, value?: Record) { return getContext(rootContext, this).formatAttrs(key, value) } - vue2.directive(rawGlobalT, createVue2Directive(rootContext)) + vue2.directive(directiveName, createVue2Directive(rootContext)) } - (vue as Vue).component('i18n', component) + (vue as Vue).component(componentName, component) }, } } diff --git a/src/types/index.d.ts b/src/types/index.d.ts index dabc75e2..750d0685 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -14,10 +14,13 @@ export interface FluentVueOptions { /** Override the names of the global functions and directive to avoid conflicts */ globals?: { - t?: string; - ta?: string; - } -} + functions?: { + format?: string + formatAttrs?: string + }, + component?: string + directive?: string + }} export interface TranslationContextOptions { warnMissing: (key: string) => void From ced7f390e28ac0f186711ba43f78090c9652e35d Mon Sep 17 00:00:00 2001 From: Steve Axtmann Date: Fri, 24 Feb 2023 17:26:12 +0100 Subject: [PATCH 3/3] style(index): remove bad ; --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 8de8c195..cc2c49c5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -54,7 +54,7 @@ export function createFluentVue(options: FluentVueOptions): FluentVue { const globalFormatName = options.globals?.functions?.format || '$t' const globalFormatAttrsName = options.globals?.functions?.formatAttrs || '$ta' const directiveName = options.globals?.directive || 't' - const componentName = options.globals?.component || 'i18n'; + const componentName = options.globals?.component || 'i18n' if (isVue3) { const vue3 = vue as Vue3