feat(useLocale): handle generic messages (#3100)

Co-authored-by: hywax <me@hywax.space>
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
Alex
2025-03-10 22:37:28 +05:00
committed by GitHub
parent 04fc367568
commit a9c8eb3f60
46 changed files with 369 additions and 86 deletions

View File

@@ -1,12 +1,11 @@
<script lang="ts">
import type { ConfigProviderProps, TooltipProviderProps } from 'reka-ui'
import { localeContextInjectionKey } from '../composables/useLocale'
import type { ToasterProps, Locale } from '../types'
import type { ToasterProps, Locale, Messages } from '../types'
export interface AppProps extends Omit<ConfigProviderProps, 'useId' | 'dir' | 'locale'> {
export interface AppProps<T extends Messages = Messages> extends Omit<ConfigProviderProps, 'useId' | 'dir' | 'locale'> {
tooltip?: TooltipProviderProps
toaster?: ToasterProps | null
locale?: Locale
locale?: Locale<T>
}
export interface AppSlots {
@@ -18,14 +17,15 @@ export default {
}
</script>
<script setup lang="ts">
<script setup lang="ts" generic="T extends Messages = Messages">
import { toRef, useId, provide } from 'vue'
import { ConfigProvider, TooltipProvider, useForwardProps } from 'reka-ui'
import { reactivePick } from '@vueuse/core'
import { localeContextInjectionKey } from '../composables/useLocale'
import UToaster from './Toaster.vue'
import UOverlayProvider from './OverlayProvider.vue'
const props = defineProps<AppProps>()
const props = defineProps<AppProps<T>>()
defineSlots<AppSlots>()
const configProviderProps = useForwardProps(reactivePick(props, 'scrollBody'))

View File

@@ -1,13 +1,13 @@
import { defu } from 'defu'
import type { Locale, Direction, Messages } from '../types/locale'
import type { Locale, Direction } from '../types/locale'
interface DefineLocaleOptions {
interface DefineLocaleOptions<M> {
name: string
code: string
dir?: Direction
messages: Messages
messages: M
}
export function defineLocale(options: DefineLocaleOptions): Locale {
return defu<DefineLocaleOptions, [{ dir: Direction }]>(options, { dir: 'ltr' })
export function defineLocale<M>(options: DefineLocaleOptions<M>): Locale<M> {
return defu<DefineLocaleOptions<M>, [{ dir: Direction }]>(options, { dir: 'ltr' })
}

View File

@@ -1,16 +1,16 @@
import { computed, inject, ref } from 'vue'
import { computed, inject, toRef } from 'vue'
import type { InjectionKey, Ref } from 'vue'
import type { Locale } from '../types/locale'
import { createSharedComposable } from '@vueuse/core'
import type { Locale, Messages } from '../types/locale'
import { buildLocaleContext } from '../utils/locale'
import en from '../locale/en'
import { createSharedComposable } from '@vueuse/core'
export const localeContextInjectionKey: InjectionKey<Ref<Locale | undefined>> = Symbol('nuxt-ui.locale-context')
export const localeContextInjectionKey: InjectionKey<Ref<Locale<unknown> | undefined>> = Symbol('nuxt-ui.locale-context')
const _useLocale = (localeOverrides?: Ref<Locale | undefined>) => {
const locale = localeOverrides || inject(localeContextInjectionKey, ref())!
const _useLocale = (localeOverrides?: Ref<Locale<Messages> | undefined>) => {
const locale = localeOverrides || toRef(inject<Locale<Messages>>(localeContextInjectionKey))
return buildLocaleContext(computed(() => locale.value || en))
return buildLocaleContext<Messages>(computed(() => locale.value || en))
}
export const useLocale = createSharedComposable(_useLocale)

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'العربية',
code: 'ar',
dir: 'rtl',

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Azərbaycanca',
code: 'az',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'বাংলা',
code: 'bn',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Čeština',
code: 'cs',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Danish',
code: 'da',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Deutsch',
code: 'de',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Ελληνικά',
code: 'el',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'English',
code: 'en',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Español',
code: 'es',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Eesti',
code: 'et',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'فارسی',
code: 'fa-IR',
dir: 'rtl',

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Suomeksi',
code: 'fi',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Français',
code: 'fr',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Hebrew',
code: 'he',
dir: 'rtl',

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Hindi',
code: 'hi',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Magyar',
code: 'hu',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Indonesia',
code: 'id',
messages: {

View File

@@ -5,13 +5,15 @@ export { default as cs } from './cs'
export { default as da } from './da'
export { default as de } from './de'
export { default as el } from './el'
export { default as et } from './et'
export { default as en } from './en'
export { default as es } from './es'
export { default as et } from './et'
export { default as fa_ir } from './fa_ir'
export { default as fi } from './fi'
export { default as fr } from './fr'
export { default as he } from './he'
export { default as hi } from './hi'
export { default as hu } from './hu'
export { default as id } from './id'
export { default as it } from './it'
export { default as ja } from './ja'
@@ -31,4 +33,3 @@ export { default as uk } from './uk'
export { default as vi } from './vi'
export { default as zh_cn } from './zh_cn'
export { default as zh_tw } from './zh_tw'
export { default as he } from './he'

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Italiano',
code: 'it',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: '日本語',
code: 'ja',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'ភាសាខ្មែរ',
code: 'km',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: '한국어',
code: 'ko',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Norsk Bokmål',
code: 'nb-NO',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Nederlands',
code: 'nl',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Polski',
code: 'pl',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Português',
code: 'pt',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Português (Brasil)',
code: 'pt-BR',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Русский',
code: 'ru',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Slovenčina',
code: 'sk',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Svenska',
code: 'sv',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'ไทย',
code: 'th',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Türkçe',
code: 'tr',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Українська',
code: 'uk',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: 'Tiếng Việt',
code: 'vi',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: '简体中文',
code: 'zh-CN',
messages: {

View File

@@ -1,6 +1,7 @@
import type { Messages } from '../types'
import { defineLocale } from '../composables/defineLocale'
export default defineLocale({
export default defineLocale<Messages>({
name: '繁體中文',
code: 'zh-TW',
messages: {

View File

@@ -50,9 +50,9 @@ export type Messages = {
export type Direction = 'ltr' | 'rtl'
export type Locale = {
export type Locale<M> = {
name: string
code: string
dir: Direction
messages: Messages
messages: M
}

View File

@@ -6,19 +6,19 @@ import { get } from './index'
export type TranslatorOption = Record<string, string | number>
export type Translator = (path: string, option?: TranslatorOption) => string
export type LocaleContext = {
locale: Ref<Locale>
export type LocaleContext<M> = {
locale: Ref<Locale<M>>
lang: Ref<string>
dir: Ref<Direction>
code: Ref<string>
t: Translator
}
export function buildTranslator(locale: MaybeRef<Locale>): Translator {
export function buildTranslator<M>(locale: MaybeRef<Locale<M>>): Translator {
return (path, option) => translate(path, option, unref(locale))
}
export function translate(path: string, option: undefined | TranslatorOption, locale: Locale): string {
export function translate<M>(path: string, option: undefined | TranslatorOption, locale: Locale<M>): string {
const prop: string = get(locale, `messages.${path}`, path)
return prop.replace(
@@ -27,11 +27,11 @@ export function translate(path: string, option: undefined | TranslatorOption, lo
)
}
export function buildLocaleContext(locale: MaybeRef<Locale>): LocaleContext {
export function buildLocaleContext<M>(locale: MaybeRef<Locale<M>>): LocaleContext<M> {
const lang = computed(() => unref(locale).name)
const code = computed(() => unref(locale).code)
const dir = computed(() => unref(locale).dir)
const localeRef = isRef(locale) ? locale : ref(locale)
const localeRef = isRef(locale) ? locale : ref(locale) as Ref<Locale<M>>
return {
lang,

View File

@@ -9,6 +9,7 @@ export { useHead } from '@unhead/vue'
export { useRoute, useRouter } from 'vue-router'
export { defineShortcuts } from '../composables/defineShortcuts'
export { defineLocale } from '../composables/defineLocale'
export { useLocale } from '../composables/useLocale'
export const useColorMode = () => {