Skip to content

Commit

Permalink
feat: support for vue-i18n-bridge (#1385)
Browse files Browse the repository at this point in the history
* feat: support for vue-i18n-bridge

* bump chromedriver
  • Loading branch information
kazupon committed Sep 22, 2021
1 parent 2f48a55 commit a40d46c
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 138 deletions.
1 change: 1 addition & 0 deletions decls/i18n.js
Expand Up @@ -82,6 +82,7 @@ declare type I18nOptions = {
fallbackLocale?: FallbackLocale,
messages?: LocaleMessages,
dateTimeFormats?: DateTimeFormats,
datetimeFormats?: DateTimeFormats,
numberFormats?: NumberFormats,
formatter?: Formatter,
missing?: MissingHandler,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -36,7 +36,7 @@
"babel-plugin-istanbul": "^6.0.0",
"babel-preset-power-assert": "^3.0.0",
"buble": "^0.19.3",
"chromedriver": "^92.0.0",
"chromedriver": "^93.0.0",
"core-js": "^3.6.5",
"cross-env": "^7.0.2",
"cross-spawn": "^7.0.3",
Expand Down
4 changes: 2 additions & 2 deletions src/index.js
Expand Up @@ -82,7 +82,7 @@ export default class VueI18n {
? false
: options.fallbackLocale || 'en-US'
const messages: LocaleMessages = options.messages || {}
const dateTimeFormats = options.dateTimeFormats || {}
const dateTimeFormats = options.dateTimeFormats || options.datetimeFormats || {}
const numberFormats = options.numberFormats || {}

this._vm = null
Expand Down Expand Up @@ -232,7 +232,7 @@ export default class VueI18n {
}): void {
const silent = Vue.config.silent
Vue.config.silent = true
this._vm = new Vue({ data })
this._vm = new Vue({ data, __VUE18N__INSTANCE__: true })
Vue.config.silent = silent
}

Expand Down
6 changes: 3 additions & 3 deletions src/install.js
@@ -1,13 +1,13 @@
import { warn } from './util'
import extend from './extend'
import mixin from './mixin'
import defineMixin from './mixin'
import interpolationComponent from './components/interpolation'
import numberComponent from './components/number'
import { bind, update, unbind } from './directive'

export let Vue

export function install (_Vue) {
export function install (_Vue, options = { bridge: false }) {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && install.installed && _Vue === Vue) {
warn('already installed.')
Expand All @@ -25,7 +25,7 @@ export function install (_Vue) {
}

extend(Vue)
Vue.mixin(mixin)
Vue.mixin(defineMixin(options.bridge))
Vue.directive('t', { bind, update, unbind })
Vue.component(interpolationComponent.name, interpolationComponent)
Vue.component(numberComponent.name, numberComponent)
Expand Down
242 changes: 127 additions & 115 deletions src/mixin.js
Expand Up @@ -3,143 +3,155 @@
import VueI18n from './index'
import { isPlainObject, warn, error, merge } from './util'

export default {
beforeCreate (): void {
const options: any = this.$options
options.i18n = options.i18n || (options.__i18n ? {} : null)

if (options.i18n) {
if (options.i18n instanceof VueI18n) {
// init locale messages via custom blocks
if (options.__i18n) {
try {
let localeMessages = options.i18n && options.i18n.messages ? options.i18n.messages : {}
options.__i18n.forEach(resource => {
localeMessages = merge(localeMessages, JSON.parse(resource))
})
Object.keys(localeMessages).forEach((locale: Locale) => {
options.i18n.mergeLocaleMessage(locale, localeMessages[locale])
})
} catch (e) {
if (process.env.NODE_ENV !== 'production') {
error(`Cannot parse locale messages via custom blocks.`, e)
/**
* Mixin
*
* If `bridge` mode, empty mixin is returned,
* else regulary mixin implementation is returned.
*/
export default function defineMixin (bridge: boolean = false) {
function mounted (): void {
if (this !== this.$root && this.$options.__INTLIFY_META__ && this.$el) {
this.$el.setAttribute('data-intlify', this.$options.__INTLIFY_META__)
}
}

return bridge
? { mounted } // delegate `vue-i18n-bridge` mixin implementation
: { // regulary
beforeCreate (): void {
const options: any = this.$options
options.i18n = options.i18n || (options.__i18n ? {} : null)

if (options.i18n) {
if (options.i18n instanceof VueI18n) {
// init locale messages via custom blocks
if (options.__i18n) {
try {
let localeMessages = options.i18n && options.i18n.messages ? options.i18n.messages : {}
options.__i18n.forEach(resource => {
localeMessages = merge(localeMessages, JSON.parse(resource))
})
Object.keys(localeMessages).forEach((locale: Locale) => {
options.i18n.mergeLocaleMessage(locale, localeMessages[locale])
})
} catch (e) {
if (process.env.NODE_ENV !== 'production') {
error(`Cannot parse locale messages via custom blocks.`, e)
}
}
}
}
this._i18n = options.i18n
this._i18nWatcher = this._i18n.watchI18nData()
} else if (isPlainObject(options.i18n)) {
const rootI18n = this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n
? this.$root.$i18n
: null
// component local i18n
if (rootI18n) {
options.i18n.root = this.$root
options.i18n.formatter = rootI18n.formatter
options.i18n.fallbackLocale = rootI18n.fallbackLocale
options.i18n.formatFallbackMessages = rootI18n.formatFallbackMessages
options.i18n.silentTranslationWarn = rootI18n.silentTranslationWarn
options.i18n.silentFallbackWarn = rootI18n.silentFallbackWarn
options.i18n.pluralizationRules = rootI18n.pluralizationRules
options.i18n.preserveDirectiveContent = rootI18n.preserveDirectiveContent
}
this._i18n = options.i18n
this._i18nWatcher = this._i18n.watchI18nData()
} else if (isPlainObject(options.i18n)) {
const rootI18n = this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n
? this.$root.$i18n
: null
// component local i18n
if (rootI18n) {
options.i18n.root = this.$root
options.i18n.formatter = rootI18n.formatter
options.i18n.fallbackLocale = rootI18n.fallbackLocale
options.i18n.formatFallbackMessages = rootI18n.formatFallbackMessages
options.i18n.silentTranslationWarn = rootI18n.silentTranslationWarn
options.i18n.silentFallbackWarn = rootI18n.silentFallbackWarn
options.i18n.pluralizationRules = rootI18n.pluralizationRules
options.i18n.preserveDirectiveContent = rootI18n.preserveDirectiveContent
}

// init locale messages via custom blocks
if (options.__i18n) {
try {
let localeMessages = options.i18n && options.i18n.messages ? options.i18n.messages : {}
options.__i18n.forEach(resource => {
localeMessages = merge(localeMessages, JSON.parse(resource))
})
options.i18n.messages = localeMessages
} catch (e) {
if (process.env.NODE_ENV !== 'production') {
warn(`Cannot parse locale messages via custom blocks.`, e)
// init locale messages via custom blocks
if (options.__i18n) {
try {
let localeMessages = options.i18n && options.i18n.messages ? options.i18n.messages : {}
options.__i18n.forEach(resource => {
localeMessages = merge(localeMessages, JSON.parse(resource))
})
options.i18n.messages = localeMessages
} catch (e) {
if (process.env.NODE_ENV !== 'production') {
warn(`Cannot parse locale messages via custom blocks.`, e)
}
}
}
}

const { sharedMessages } = options.i18n
if (sharedMessages && isPlainObject(sharedMessages)) {
options.i18n.messages = merge(options.i18n.messages, sharedMessages)
}
const { sharedMessages } = options.i18n
if (sharedMessages && isPlainObject(sharedMessages)) {
options.i18n.messages = merge(options.i18n.messages, sharedMessages)
}

this._i18n = new VueI18n(options.i18n)
this._i18nWatcher = this._i18n.watchI18nData()
this._i18n = new VueI18n(options.i18n)
this._i18nWatcher = this._i18n.watchI18nData()

if (options.i18n.sync === undefined || !!options.i18n.sync) {
this._localeWatcher = this.$i18n.watchLocale()
}
if (options.i18n.sync === undefined || !!options.i18n.sync) {
this._localeWatcher = this.$i18n.watchLocale()
}

if (rootI18n) {
rootI18n.onComponentInstanceCreated(this._i18n)
}
} else {
if (process.env.NODE_ENV !== 'production') {
warn(`Cannot be interpreted 'i18n' option.`)
if (rootI18n) {
rootI18n.onComponentInstanceCreated(this._i18n)
}
} else {
if (process.env.NODE_ENV !== 'production') {
warn(`Cannot be interpreted 'i18n' option.`)
}
}
} else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
// root i18n
this._i18n = this.$root.$i18n
} else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
// parent i18n
this._i18n = options.parent.$i18n
}
} else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
// root i18n
this._i18n = this.$root.$i18n
} else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
// parent i18n
this._i18n = options.parent.$i18n
}
},
},

beforeMount (): void {
const options: any = this.$options
options.i18n = options.i18n || (options.__i18n ? {} : null)
beforeMount (): void {
const options: any = this.$options
options.i18n = options.i18n || (options.__i18n ? {} : null)

if (options.i18n) {
if (options.i18n instanceof VueI18n) {
// init locale messages via custom blocks
if (options.i18n) {
if (options.i18n instanceof VueI18n) {
// init locale messages via custom blocks
this._i18n.subscribeDataChanging(this)
this._subscribing = true
} else if (isPlainObject(options.i18n)) {
this._i18n.subscribeDataChanging(this)
this._subscribing = true
} else {
if (process.env.NODE_ENV !== 'production') {
warn(`Cannot be interpreted 'i18n' option.`)
}
}
} else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
this._i18n.subscribeDataChanging(this)
this._subscribing = true
} else if (isPlainObject(options.i18n)) {
} else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
this._i18n.subscribeDataChanging(this)
this._subscribing = true
} else {
if (process.env.NODE_ENV !== 'production') {
warn(`Cannot be interpreted 'i18n' option.`)
}
}
} else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
this._i18n.subscribeDataChanging(this)
this._subscribing = true
} else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
this._i18n.subscribeDataChanging(this)
this._subscribing = true
}
},
},

mounted (): void {
if (this !== this.$root && this.$options.__INTLIFY_META__ && this.$el) {
this.$el.setAttribute('data-intlify', this.$options.__INTLIFY_META__)
}
},
mounted,

beforeDestroy (): void {
if (!this._i18n) { return }
beforeDestroy (): void {
if (!this._i18n) { return }

const self = this
this.$nextTick(() => {
if (self._subscribing) {
self._i18n.unsubscribeDataChanging(self)
delete self._subscribing
}
const self = this
this.$nextTick(() => {
if (self._subscribing) {
self._i18n.unsubscribeDataChanging(self)
delete self._subscribing
}

if (self._i18nWatcher) {
self._i18nWatcher()
self._i18n.destroyVM()
delete self._i18nWatcher
}
if (self._i18nWatcher) {
self._i18nWatcher()
self._i18n.destroyVM()
delete self._i18nWatcher
}

if (self._localeWatcher) {
self._localeWatcher()
delete self._localeWatcher
}
})
if (self._localeWatcher) {
self._localeWatcher()
delete self._localeWatcher
}
})
}
}
}
4 changes: 2 additions & 2 deletions test/unit/mixin.test.js
@@ -1,4 +1,4 @@
import mixin from '../../src/mixin'
import defineMixin from '../../src/mixin'

describe('mixin', () => {
describe('beforeCreate', () => {
Expand All @@ -19,7 +19,7 @@ describe('mixin', () => {
describe('beforeDestroy', () => {
describe('not assign VueI18n instance', () => {
it('should be succeeded', () => {
assert(mixin.beforeDestroy() === undefined)
assert(defineMixin().beforeDestroy() === undefined)
})
})
})
Expand Down
5 changes: 4 additions & 1 deletion types/index.d.ts
Expand Up @@ -157,6 +157,9 @@ export type MissingHandler = VueI18n.MissingHandler;
export type PostTranslationHandler = VueI18n.PostTranslationHandler;
export type IntlAvailability = VueI18n.IntlAvailability;
export type I18nOptions = VueI18n.I18nOptions;
export type PluignOptions = {
bridge?: boolean
}

export declare interface IVueI18n {
readonly messages: VueI18n.LocaleMessages;
Expand Down Expand Up @@ -257,7 +260,7 @@ declare class VueI18n {
*/
getChoiceIndex: (choice: number, choicesLength: number) => number;

static install: PluginFunction<never>;
static install: PluginFunction<PluignOptions>;
static version: string;
static availabilities: VueI18n.IntlAvailability;
}
Expand Down

0 comments on commit a40d46c

Please sign in to comment.