feat(ui): add framework-neutral localization support

- add a lightweight UI i18n provider with translation and locale contexts\n- localize accessibility labels across breadcrumb, carousel, dialog, pagination, sheet, sidebar, spinner, and toast components\n- integrate calendar locale data without coupling UI components to Lingui\n- publish tree-shakeable catalogs for eight common locales
This commit is contained in:
Maofeng
2026-07-30 14:47:51 +08:00
parent 0768e8fa29
commit ae1798f6f4
20 changed files with 551 additions and 87 deletions
+33
View File
@@ -0,0 +1,33 @@
export const uiCatalogLocales = [
"de",
"en",
"es",
"fr",
"ja",
"ko",
"zh-Hans",
"zh-Hant",
] as const
export const uiMessageIds = [
"ui.breadcrumb.label",
"ui.carousel.nextSlide",
"ui.carousel.previousSlide",
"ui.common.close",
"ui.common.loading",
"ui.common.more",
"ui.pagination.label",
"ui.pagination.more",
"ui.pagination.next",
"ui.pagination.nextPage",
"ui.pagination.previous",
"ui.pagination.previousPage",
"ui.sidebar.description",
"ui.sidebar.title",
"ui.sidebar.toggle",
"ui.toast.close",
] as const
export type UiCatalogLocale = (typeof uiCatalogLocales)[number]
export type UiMessageId = (typeof uiMessageIds)[number]
export type UiMessageCatalog = Readonly<Record<UiMessageId, string>>
+25
View File
@@ -0,0 +1,25 @@
export { de as calendarLocale } from "react-day-picker/locale/de"
import type { UiMessageCatalog } from "../catalogs"
export const locale = "de"
export const languageTag = "de-DE"
export const messages = {
"ui.breadcrumb.label": "Breadcrumb-Navigation",
"ui.carousel.nextSlide": "Nächste Folie",
"ui.carousel.previousSlide": "Vorherige Folie",
"ui.common.close": "Schließen",
"ui.common.loading": "Wird geladen",
"ui.common.more": "Mehr",
"ui.pagination.label": "Seitennavigation",
"ui.pagination.more": "Weitere Seiten",
"ui.pagination.next": "Weiter",
"ui.pagination.nextPage": "Zur nächsten Seite",
"ui.pagination.previous": "Zurück",
"ui.pagination.previousPage": "Zur vorherigen Seite",
"ui.sidebar.description": "Zeigt die mobile Seitenleiste an.",
"ui.sidebar.title": "Seitenleiste",
"ui.sidebar.toggle": "Seitenleiste umschalten",
"ui.toast.close": "Benachrichtigung schließen",
} as const satisfies UiMessageCatalog
+25
View File
@@ -0,0 +1,25 @@
export { enUS as calendarLocale } from "react-day-picker/locale/en-US"
import type { UiMessageCatalog } from "../catalogs"
export const locale = "en"
export const languageTag = "en-US"
export const messages = {
"ui.breadcrumb.label": "Breadcrumb",
"ui.carousel.nextSlide": "Next slide",
"ui.carousel.previousSlide": "Previous slide",
"ui.common.close": "Close",
"ui.common.loading": "Loading",
"ui.common.more": "More",
"ui.pagination.label": "Pagination",
"ui.pagination.more": "More pages",
"ui.pagination.next": "Next",
"ui.pagination.nextPage": "Go to next page",
"ui.pagination.previous": "Previous",
"ui.pagination.previousPage": "Go to previous page",
"ui.sidebar.description": "Displays the mobile sidebar.",
"ui.sidebar.title": "Sidebar",
"ui.sidebar.toggle": "Toggle sidebar",
"ui.toast.close": "Close notification",
} as const satisfies UiMessageCatalog
+25
View File
@@ -0,0 +1,25 @@
export { es as calendarLocale } from "react-day-picker/locale/es"
import type { UiMessageCatalog } from "../catalogs"
export const locale = "es"
export const languageTag = "es-ES"
export const messages = {
"ui.breadcrumb.label": "Ruta de navegación",
"ui.carousel.nextSlide": "Diapositiva siguiente",
"ui.carousel.previousSlide": "Diapositiva anterior",
"ui.common.close": "Cerrar",
"ui.common.loading": "Cargando",
"ui.common.more": "Más",
"ui.pagination.label": "Paginación",
"ui.pagination.more": "Más páginas",
"ui.pagination.next": "Siguiente",
"ui.pagination.nextPage": "Ir a la página siguiente",
"ui.pagination.previous": "Anterior",
"ui.pagination.previousPage": "Ir a la página anterior",
"ui.sidebar.description": "Muestra la barra lateral móvil.",
"ui.sidebar.title": "Barra lateral",
"ui.sidebar.toggle": "Alternar barra lateral",
"ui.toast.close": "Cerrar notificación",
} as const satisfies UiMessageCatalog
+25
View File
@@ -0,0 +1,25 @@
export { fr as calendarLocale } from "react-day-picker/locale/fr"
import type { UiMessageCatalog } from "../catalogs"
export const locale = "fr"
export const languageTag = "fr-FR"
export const messages = {
"ui.breadcrumb.label": "Fil d’Ariane",
"ui.carousel.nextSlide": "Diapositive suivante",
"ui.carousel.previousSlide": "Diapositive précédente",
"ui.common.close": "Fermer",
"ui.common.loading": "Chargement",
"ui.common.more": "Plus",
"ui.pagination.label": "Pagination",
"ui.pagination.more": "Plus de pages",
"ui.pagination.next": "Suivant",
"ui.pagination.nextPage": "Aller à la page suivante",
"ui.pagination.previous": "Précédent",
"ui.pagination.previousPage": "Aller à la page précédente",
"ui.sidebar.description": "Affiche la barre latérale mobile.",
"ui.sidebar.title": "Barre latérale",
"ui.sidebar.toggle": "Afficher ou masquer la barre latérale",
"ui.toast.close": "Fermer la notification",
} as const satisfies UiMessageCatalog
+25
View File
@@ -0,0 +1,25 @@
export { ja as calendarLocale } from "react-day-picker/locale/ja"
import type { UiMessageCatalog } from "../catalogs"
export const locale = "ja"
export const languageTag = "ja-JP"
export const messages = {
"ui.breadcrumb.label": "パンくずリスト",
"ui.carousel.nextSlide": "次のスライド",
"ui.carousel.previousSlide": "前のスライド",
"ui.common.close": "閉じる",
"ui.common.loading": "読み込み中",
"ui.common.more": "その他",
"ui.pagination.label": "ページネーション",
"ui.pagination.more": "その他のページ",
"ui.pagination.next": "次へ",
"ui.pagination.nextPage": "次のページへ移動",
"ui.pagination.previous": "前へ",
"ui.pagination.previousPage": "前のページへ移動",
"ui.sidebar.description": "モバイルサイドバーを表示します。",
"ui.sidebar.title": "サイドバー",
"ui.sidebar.toggle": "サイドバーを切り替える",
"ui.toast.close": "通知を閉じる",
} as const satisfies UiMessageCatalog
+25
View File
@@ -0,0 +1,25 @@
export { ko as calendarLocale } from "react-day-picker/locale/ko"
import type { UiMessageCatalog } from "../catalogs"
export const locale = "ko"
export const languageTag = "ko-KR"
export const messages = {
"ui.breadcrumb.label": "이동 경로",
"ui.carousel.nextSlide": "다음 슬라이드",
"ui.carousel.previousSlide": "이전 슬라이드",
"ui.common.close": "닫기",
"ui.common.loading": "불러오는 중",
"ui.common.more": "더 보기",
"ui.pagination.label": "페이지 탐색",
"ui.pagination.more": "더 많은 페이지",
"ui.pagination.next": "다음",
"ui.pagination.nextPage": "다음 페이지로 이동",
"ui.pagination.previous": "이전",
"ui.pagination.previousPage": "이전 페이지로 이동",
"ui.sidebar.description": "모바일 사이드바를 표시합니다.",
"ui.sidebar.title": "사이드바",
"ui.sidebar.toggle": "사이드바 전환",
"ui.toast.close": "알림 닫기",
} as const satisfies UiMessageCatalog
+25
View File
@@ -0,0 +1,25 @@
export { zhCN as calendarLocale } from "react-day-picker/locale/zh-CN"
import type { UiMessageCatalog } from "../catalogs"
export const locale = "zh-Hans"
export const languageTag = "zh-CN"
export const messages = {
"ui.breadcrumb.label": "面包屑导航",
"ui.carousel.nextSlide": "下一张",
"ui.carousel.previousSlide": "上一张",
"ui.common.close": "关闭",
"ui.common.loading": "正在加载",
"ui.common.more": "更多",
"ui.pagination.label": "分页导航",
"ui.pagination.more": "更多页面",
"ui.pagination.next": "下一页",
"ui.pagination.nextPage": "前往下一页",
"ui.pagination.previous": "上一页",
"ui.pagination.previousPage": "前往上一页",
"ui.sidebar.description": "显示移动端侧栏。",
"ui.sidebar.title": "侧栏",
"ui.sidebar.toggle": "切换侧栏",
"ui.toast.close": "关闭通知",
} as const satisfies UiMessageCatalog
+25
View File
@@ -0,0 +1,25 @@
export { zhTW as calendarLocale } from "react-day-picker/locale/zh-TW"
import type { UiMessageCatalog } from "../catalogs"
export const locale = "zh-Hant"
export const languageTag = "zh-TW"
export const messages = {
"ui.breadcrumb.label": "麵包屑導覽",
"ui.carousel.nextSlide": "下一張",
"ui.carousel.previousSlide": "上一張",
"ui.common.close": "關閉",
"ui.common.loading": "載入中",
"ui.common.more": "更多",
"ui.pagination.label": "分頁導覽",
"ui.pagination.more": "更多頁面",
"ui.pagination.next": "下一頁",
"ui.pagination.nextPage": "前往下一頁",
"ui.pagination.previous": "上一頁",
"ui.pagination.previousPage": "前往上一頁",
"ui.sidebar.description": "顯示行動版側欄。",
"ui.sidebar.title": "側欄",
"ui.sidebar.toggle": "切換側欄",
"ui.toast.close": "關閉通知",
} as const satisfies UiMessageCatalog