mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-12-04 20:27:44 +08:00
fix(hooks): provide root locale (#5218)
* fix: provide root locale * refactor(locale): refactor locale * fix: tests * revert: play
This commit is contained in:
parent
f5b7e3accc
commit
81e6c377ba
@ -1,6 +1,6 @@
|
||||
import { h, ref, inject, reactive, nextTick } from 'vue'
|
||||
import { h, ref, reactive, nextTick } from 'vue'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { localeContextKey } from '@element-plus/hooks'
|
||||
import { useLocale } from '@element-plus/hooks'
|
||||
import Chinese from '@element-plus/locale/lang/zh-cn'
|
||||
import English from '@element-plus/locale/lang/en'
|
||||
import { ElButton } from '@element-plus/components'
|
||||
@ -9,7 +9,7 @@ import type { Language } from '@element-plus/locale'
|
||||
|
||||
const TestComp = {
|
||||
setup() {
|
||||
const { t } = inject(localeContextKey)
|
||||
const { t } = useLocale()
|
||||
return () => {
|
||||
return h('div', t('el.popconfirm.confirmButtonText'))
|
||||
}
|
||||
|
@ -1,14 +1,13 @@
|
||||
import { defineComponent, renderSlot } from 'vue'
|
||||
import { buildProps, definePropType } from '@element-plus/utils/props'
|
||||
import {
|
||||
useLocaleProps,
|
||||
provideLocale,
|
||||
provideGlobalConfig,
|
||||
} from '@element-plus/hooks'
|
||||
import { provideGlobalConfig } from '@element-plus/hooks'
|
||||
import type { Language } from '@element-plus/locale'
|
||||
import type { ButtonConfigContext } from '@element-plus/components/button'
|
||||
|
||||
export const configProviderProps = buildProps({
|
||||
...useLocaleProps,
|
||||
locale: {
|
||||
type: definePropType<Language>(Object),
|
||||
},
|
||||
|
||||
size: {
|
||||
type: String,
|
||||
@ -29,7 +28,6 @@ export default defineComponent({
|
||||
props: configProviderProps,
|
||||
|
||||
setup(props, { slots }) {
|
||||
provideLocale()
|
||||
const config = provideGlobalConfig(props)
|
||||
return () => renderSlot(slots, 'default', { config: config?.value })
|
||||
},
|
||||
|
@ -1,13 +1,9 @@
|
||||
import { h, nextTick } from 'vue'
|
||||
import { h, nextTick, computed } from 'vue'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import Chinese from '@element-plus/locale/lang/zh-cn'
|
||||
import English from '@element-plus/locale/lang/en'
|
||||
import {
|
||||
provideLocale,
|
||||
useLocaleProps,
|
||||
useLocale,
|
||||
buildTranslator,
|
||||
} from '../use-locale'
|
||||
import { useLocale, buildTranslator } from '../use-locale'
|
||||
import { provideGlobalConfig } from '..'
|
||||
|
||||
const TestComp = {
|
||||
setup() {
|
||||
@ -27,12 +23,14 @@ describe('use-locale', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = mount(
|
||||
{
|
||||
props: useLocaleProps,
|
||||
props: {
|
||||
locale: Object,
|
||||
},
|
||||
components: {
|
||||
'el-test': TestComp,
|
||||
},
|
||||
setup(_, { slots }) {
|
||||
provideLocale()
|
||||
setup(props, { slots }) {
|
||||
provideGlobalConfig(computed(() => ({ locale: props.locale })))
|
||||
return () => slots.default()
|
||||
},
|
||||
},
|
||||
|
@ -6,14 +6,17 @@ import type { MaybeRef } from '@vueuse/core'
|
||||
import type { Ref, App } from 'vue'
|
||||
import type { ConfigProviderContext } from '@element-plus/tokens'
|
||||
|
||||
const fallback = ref<ConfigProviderContext>({})
|
||||
// this is meant to fix global methods like `ElMessage(opts)`, this way we can inject current locale
|
||||
// into the component as default injection value.
|
||||
// refer to: https://github.com/element-plus/element-plus/issues/2610#issuecomment-887965266
|
||||
const cache = ref<ConfigProviderContext>({})
|
||||
|
||||
export function useGlobalConfig<K extends keyof ConfigProviderContext>(
|
||||
key: K
|
||||
): Ref<ConfigProviderContext[K]>
|
||||
export function useGlobalConfig(): Ref<ConfigProviderContext>
|
||||
export function useGlobalConfig(key?: keyof ConfigProviderContext) {
|
||||
const config = inject(configProviderContextKey, fallback)
|
||||
const config = inject(configProviderContextKey, cache)
|
||||
if (key) {
|
||||
return isObject(config.value) && hasOwn(config.value, key)
|
||||
? computed(() => config.value[key])
|
||||
@ -45,5 +48,6 @@ export const provideGlobalConfig = (
|
||||
return merge(oldConfig.value, cfg)
|
||||
})
|
||||
provideFn(configProviderContextKey, context)
|
||||
cache.value = context.value
|
||||
return context
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { computed, getCurrentInstance, inject, provide, ref, unref } from 'vue'
|
||||
import { computed, ref, unref, isRef } from 'vue'
|
||||
import get from 'lodash/get'
|
||||
import English from '@element-plus/locale/lang/en'
|
||||
import { buildProps, definePropType } from '@element-plus/utils/props'
|
||||
import { useGlobalConfig } from '../use-global-config'
|
||||
import type { MaybeRef } from '@vueuse/core'
|
||||
import type { InjectionKey, Ref } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
import type { Language } from '@element-plus/locale'
|
||||
|
||||
export type TranslatorOption = Record<string, string | number>
|
||||
@ -14,48 +14,6 @@ export type LocaleContext = {
|
||||
t: Translator
|
||||
}
|
||||
|
||||
export const useLocaleProps = buildProps({
|
||||
locale: {
|
||||
type: definePropType<Language>(Object),
|
||||
},
|
||||
})
|
||||
|
||||
export const localeContextKey: InjectionKey<LocaleContext> =
|
||||
Symbol('localeContextKey')
|
||||
|
||||
// this is meant to fix global methods like `ElMessage(opts)`, this way we can inject current locale
|
||||
// into the component as default injection value.
|
||||
// refer to: https://github.com/element-plus/element-plus/issues/2610#issuecomment-887965266
|
||||
let cache: LocaleContext
|
||||
|
||||
export const provideLocale = () => {
|
||||
const vm = getCurrentInstance()!
|
||||
const props = vm.props as {
|
||||
locale: Language
|
||||
}
|
||||
const locale = computed(() => props.locale || English)
|
||||
const lang = computed(() => locale.value.name)
|
||||
|
||||
const t = buildTranslator(locale)
|
||||
const provides: LocaleContext = {
|
||||
locale,
|
||||
lang,
|
||||
t,
|
||||
}
|
||||
|
||||
// this could be broken if someone tries to do following:
|
||||
|
||||
/**
|
||||
* <config-provider :locale="lang1">
|
||||
* <config-provider :locale="lang2">
|
||||
* Something calls modal component.
|
||||
* </config-provider>
|
||||
* </config-provider>
|
||||
*/
|
||||
cache = provides
|
||||
provide(localeContextKey, provides)
|
||||
}
|
||||
|
||||
export const buildTranslator =
|
||||
(locale: MaybeRef<Language>): Translator =>
|
||||
(path, option) =>
|
||||
@ -71,16 +29,19 @@ export const translate = (
|
||||
(_, key) => `${option?.[key] ?? `{${key}}`}`
|
||||
)
|
||||
|
||||
export const localeProviderMaker = (locale = English) => {
|
||||
const lang = ref(locale.name)
|
||||
const localeRef = ref(locale)
|
||||
export const buildLocaleContext = (
|
||||
locale: MaybeRef<Language>
|
||||
): LocaleContext => {
|
||||
const lang = computed(() => unref(locale).name)
|
||||
const localeRef = isRef(locale) ? locale : ref(locale)
|
||||
return {
|
||||
lang,
|
||||
locale: localeRef,
|
||||
t: buildTranslator(localeRef),
|
||||
t: buildTranslator(locale),
|
||||
}
|
||||
}
|
||||
|
||||
export const useLocale = () => {
|
||||
return inject(localeContextKey, cache || localeProviderMaker(English))
|
||||
const locale = useGlobalConfig('locale')
|
||||
return buildLocaleContext(computed(() => locale.value || English))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user