mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-24 00:40:34 +01:00
feat(module): support i18n in components (#2553)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
@@ -74,6 +74,7 @@ const emits = defineEmits<AlertEmits>()
|
||||
const slots = defineSlots<AlertSlots>()
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
const { t } = useLocale()
|
||||
|
||||
const multiline = computed(() => !!props.title && !!props.description)
|
||||
|
||||
@@ -123,7 +124,7 @@ const ui = computed(() => alert({
|
||||
size="md"
|
||||
color="neutral"
|
||||
variant="link"
|
||||
aria-label="Close"
|
||||
:aria-label="t('ui.alert.close')"
|
||||
v-bind="typeof close === 'object' ? close : undefined"
|
||||
:class="ui.close({ class: props.ui?.close })"
|
||||
@click="emits('update:open', false)"
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<script lang="ts">
|
||||
import type { ConfigProviderProps, TooltipProviderProps } from 'radix-vue'
|
||||
import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
|
||||
import type { ToasterProps } from '../types'
|
||||
import type { ToasterProps, Locale } from '../types'
|
||||
|
||||
export interface AppProps extends Omit<ConfigProviderProps, 'useId'> {
|
||||
tooltip?: TooltipProviderProps
|
||||
toaster?: ToasterProps | null
|
||||
locale?: Locale
|
||||
}
|
||||
|
||||
export interface AppSlots {
|
||||
@@ -26,6 +27,7 @@ import { reactivePick } from '@vueuse/core'
|
||||
import UToaster from './Toaster.vue'
|
||||
import UModalProvider from './ModalProvider.vue'
|
||||
import USlideoverProvider from './SlideoverProvider.vue'
|
||||
import { localeContextInjectionKey } from '../composables/useLocale'
|
||||
|
||||
const props = defineProps<AppProps>()
|
||||
defineSlots<AppSlots>()
|
||||
@@ -33,6 +35,8 @@ defineSlots<AppSlots>()
|
||||
const configProviderProps = useForwardProps(reactivePick(props, 'dir', 'scrollBody'))
|
||||
const tooltipProps = toRef(() => props.tooltip)
|
||||
const toasterProps = toRef(() => props.toaster)
|
||||
|
||||
provide(localeContextInjectionKey, computed(() => props.locale))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -134,6 +134,7 @@ const props = withDefaults(defineProps<CarouselProps<T>>(), {
|
||||
defineSlots<CarouselSlots<T>>()
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
const { t } = useLocale()
|
||||
const rootProps = useForwardProps(reactivePick(props, 'active', 'align', 'breakpoints', 'containScroll', 'dragFree', 'dragThreshold', 'duration', 'inViewThreshold', 'loop', 'skipSnaps', 'slidesToScroll', 'startIndex', 'watchDrag', 'watchResize', 'watchSlides', 'watchFocus'))
|
||||
|
||||
const ui = computed(() => carousel({
|
||||
@@ -279,7 +280,7 @@ defineExpose({
|
||||
size="md"
|
||||
color="neutral"
|
||||
variant="outline"
|
||||
aria-label="Prev"
|
||||
:aria-label="t('ui.carousel.prev')"
|
||||
v-bind="typeof prev === 'object' ? prev : undefined"
|
||||
:class="ui.prev({ class: props.ui?.prev })"
|
||||
@click="scrollPrev"
|
||||
@@ -290,7 +291,7 @@ defineExpose({
|
||||
size="md"
|
||||
color="neutral"
|
||||
variant="outline"
|
||||
aria-label="Next"
|
||||
:aria-label="t('ui.carousel.next')"
|
||||
v-bind="typeof next === 'object' ? next : undefined"
|
||||
:class="ui.next({ class: props.ui?.next })"
|
||||
@click="scrollNext"
|
||||
@@ -300,7 +301,7 @@ defineExpose({
|
||||
<div v-if="dots" :class="ui.dots({ class: props.ui?.dots })">
|
||||
<template v-for="(_, index) in scrollSnaps" :key="index">
|
||||
<button
|
||||
:aria-label="`Go to slide ${index + 1}`"
|
||||
:aria-label="t('ui.carousel.goto', { slide: index + 1 })"
|
||||
:class="ui.dot({ class: props.ui?.dot, active: selectedIndex === index })"
|
||||
@click="scrollTo(index)"
|
||||
/>
|
||||
|
||||
@@ -144,6 +144,7 @@ const slots = defineSlots<CommandPaletteSlots<G, T>>()
|
||||
const searchTerm = defineModel<string>('searchTerm', { default: '' })
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
const { t } = useLocale()
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'disabled', 'multiple', 'modelValue', 'defaultValue', 'selectedValue', 'resetSearchTermOnBlur'), emits)
|
||||
const inputProps = useForwardProps(reactivePick(props, 'loading', 'loadingIcon', 'placeholder'))
|
||||
|
||||
@@ -245,7 +246,7 @@ const groups = computed(() => {
|
||||
size="md"
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
aria-label="Close"
|
||||
:aria-label="t('ui.commandPalette.close')"
|
||||
v-bind="typeof close === 'object' ? close : undefined"
|
||||
:class="ui.close({ class: props.ui?.close })"
|
||||
@click="emits('update:open', false)"
|
||||
@@ -259,7 +260,7 @@ const groups = computed(() => {
|
||||
<ComboboxContent :class="ui.content({ class: props.ui?.content })" :dismissable="false">
|
||||
<ComboboxEmpty :class="ui.empty({ class: props.ui?.empty })">
|
||||
<slot name="empty" :search-term="searchTerm">
|
||||
{{ searchTerm ? `No results for ${searchTerm}` : 'No results' }}
|
||||
{{ searchTerm ? t('ui.commandPalette.noMatch', { searchTerm }) : t('ui.commandPalette.noData') }}
|
||||
</slot>
|
||||
</ComboboxEmpty>
|
||||
|
||||
|
||||
@@ -141,6 +141,7 @@ import { get, escapeRegExp } from '../utils'
|
||||
import UIcon from './Icon.vue'
|
||||
import UAvatar from './Avatar.vue'
|
||||
import UChip from './Chip.vue'
|
||||
import { useLocale } from '../composables/useLocale'
|
||||
|
||||
defineOptions({ inheritAttrs: false })
|
||||
|
||||
@@ -157,6 +158,7 @@ const slots = defineSlots<InputMenuSlots<T>>()
|
||||
const searchTerm = defineModel<string>('searchTerm', { default: '' })
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
const { t } = useLocale()
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'selectedValue', 'open', 'defaultOpen', 'resetSearchTermOnBlur'), emits)
|
||||
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, position: 'popper' }) as ComboboxContentProps)
|
||||
const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
|
||||
@@ -347,7 +349,7 @@ defineExpose({
|
||||
<ComboboxContent :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
|
||||
<ComboboxEmpty :class="ui.empty({ class: props.ui?.empty })">
|
||||
<slot name="empty" :search-term="searchTerm">
|
||||
{{ searchTerm ? `No results for ${searchTerm}` : 'No results' }}
|
||||
{{ searchTerm ? t('ui.inputMenu.noMatch', { searchTerm }) : t('ui.inputMenu.noData') }}
|
||||
</slot>
|
||||
</ComboboxEmpty>
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ const contentEvents = computed(() => {
|
||||
})
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
const { t } = useLocale()
|
||||
|
||||
const ui = computed(() => modal({
|
||||
transition: props.transition,
|
||||
@@ -143,7 +144,7 @@ const ui = computed(() => modal({
|
||||
size="md"
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
aria-label="Close"
|
||||
:aria-label="t('ui.modal.close')"
|
||||
v-bind="typeof close === 'object' ? close : undefined"
|
||||
:class="ui.close({ class: props.ui?.close })"
|
||||
/>
|
||||
|
||||
@@ -147,6 +147,8 @@ const slots = defineSlots<SelectMenuSlots<T>>()
|
||||
const searchTerm = defineModel<string>('searchTerm', { default: '' })
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const { t } = useLocale()
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'modelValue', 'defaultValue', 'selectedValue', 'open', 'defaultOpen', 'resetSearchTermOnBlur'), emits)
|
||||
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, position: 'popper' }) as ComboboxContentProps)
|
||||
const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
|
||||
@@ -284,7 +286,7 @@ function onUpdateOpen(value: boolean) {
|
||||
|
||||
<ComboboxEmpty :class="ui.empty({ class: props.ui?.empty })">
|
||||
<slot name="empty" :search-term="searchTerm">
|
||||
{{ searchTerm ? `No results for ${searchTerm}` : 'No results' }}
|
||||
{{ searchTerm ? t('ui.selectMenu.noMatch', { searchTerm }) : t('ui.selectMenu.noData') }}
|
||||
</slot>
|
||||
</ComboboxEmpty>
|
||||
|
||||
|
||||
@@ -102,6 +102,7 @@ const contentEvents = computed(() => {
|
||||
})
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
const { t } = useLocale()
|
||||
|
||||
const ui = computed(() => slideover({
|
||||
transition: props.transition,
|
||||
@@ -142,7 +143,7 @@ const ui = computed(() => slideover({
|
||||
size="md"
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
aria-label="Close"
|
||||
:aria-label="t('ui.slideover.close')"
|
||||
v-bind="typeof close === 'object' ? close : undefined"
|
||||
:class="ui.close({ class: props.ui?.close })"
|
||||
/>
|
||||
|
||||
@@ -114,6 +114,7 @@ import { upperFirst } from 'scule'
|
||||
const props = defineProps<TableProps<T>>()
|
||||
defineSlots<TableSlots<T>>()
|
||||
|
||||
const { t } = useLocale()
|
||||
const data = computed(() => props.data ?? [])
|
||||
const columns = computed<TableColumn<T>[]>(() => props.columns ?? Object.keys(data.value[0] ?? {}).map((accessorKey: string) => ({ accessorKey, header: upperFirst(accessorKey) })))
|
||||
|
||||
@@ -231,7 +232,7 @@ defineExpose({
|
||||
<tr v-else :class="ui.tr({ class: [props.ui?.tr] })">
|
||||
<td :colspan="columns?.length" :class="ui.empty({ class: props.ui?.empty })">
|
||||
<slot name="empty">
|
||||
No results
|
||||
{{ t('ui.table.noData') }}
|
||||
</slot>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -74,6 +74,7 @@ const emits = defineEmits<ToastEmits>()
|
||||
const slots = defineSlots<ToastSlots>()
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
const { t } = useLocale()
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'defaultOpen', 'open', 'duration', 'type'), emits)
|
||||
|
||||
const multiline = computed(() => !!props.title && !!props.description)
|
||||
@@ -151,7 +152,7 @@ defineExpose({
|
||||
size="md"
|
||||
color="neutral"
|
||||
variant="link"
|
||||
aria-label="Close"
|
||||
:aria-label="t('ui.toast.close')"
|
||||
v-bind="typeof close === 'object' ? close : undefined"
|
||||
:class="ui.close({ class: props.ui?.close })"
|
||||
@click.stop
|
||||
|
||||
Reference in New Issue
Block a user