Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fd269348b4 | |||
| 58af2af37b |
+5
-3
@@ -4,8 +4,10 @@ npx tsc --noEmit
|
|||||||
|
|
||||||
# ESLint 严格检查(仅检查本次推送的变更文件,不阻塞不相关的旧代码)
|
# ESLint 严格检查(仅检查本次推送的变更文件,不阻塞不相关的旧代码)
|
||||||
# 新分支无 upstream 时,回退到与 origin/main 对比
|
# 新分支无 upstream 时,回退到与 origin/main 对比
|
||||||
BASE=$(git rev-parse --verify @{upstream} 2>/dev/null && echo "@{upstream}" || echo "origin/main")
|
MERGE_BASE=$(git merge-base HEAD @{upstream} 2>/dev/null || git merge-base HEAD origin/main 2>/dev/null)
|
||||||
CHANGED_FILES=$(git diff --name-only --diff-filter=d "$BASE"...HEAD -- '*.ts' '*.tsx' '*.js' '*.jsx' '*.mjs')
|
if [ -n "$MERGE_BASE" ]; then
|
||||||
if [ -n "$CHANGED_FILES" ]; then
|
CHANGED_FILES=$(git diff --name-only --diff-filter=d "$MERGE_BASE" HEAD -- '*.ts' '*.tsx' '*.js' '*.jsx' '*.mjs')
|
||||||
|
if [ -n "$CHANGED_FILES" ]; then
|
||||||
echo "$CHANGED_FILES" | xargs npx eslint --max-warnings=0
|
echo "$CHANGED_FILES" | xargs npx eslint --max-warnings=0
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { Toaster as Sonner } from 'sonner';
|
||||||
|
import { useThemeMode } from '@/providers/ThemeModeProvider';
|
||||||
|
|
||||||
|
type ToasterProps = React.ComponentProps<typeof Sonner>;
|
||||||
|
|
||||||
|
export function Toaster(props: ToasterProps) {
|
||||||
|
const { resolvedMode } = useThemeMode();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Sonner
|
||||||
|
theme={resolvedMode}
|
||||||
|
className="toaster group"
|
||||||
|
position="bottom-center"
|
||||||
|
toastOptions={{
|
||||||
|
classNames: {
|
||||||
|
toast:
|
||||||
|
'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',
|
||||||
|
description: 'group-[.toast]:text-muted-foreground',
|
||||||
|
actionButton: 'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',
|
||||||
|
cancelButton: 'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ThemeModeProvider } from './ThemeModeProvider';
|
import { ThemeModeProvider } from './ThemeModeProvider';
|
||||||
import { RouterProvider } from './RouterProvider';
|
import { RouterProvider } from './RouterProvider';
|
||||||
|
import { Toaster } from '@/components/ui/sonner';
|
||||||
|
|
||||||
interface AppRootProps {
|
interface AppRootProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
@@ -11,6 +12,7 @@ export default function AppRoot({ children }: AppRootProps) {
|
|||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<ThemeModeProvider>
|
<ThemeModeProvider>
|
||||||
<RouterProvider>{children}</RouterProvider>
|
<RouterProvider>{children}</RouterProvider>
|
||||||
|
<Toaster />
|
||||||
</ThemeModeProvider>
|
</ThemeModeProvider>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -26,12 +26,8 @@ export function useI18n(namespace?: string | string[]) {
|
|||||||
const namespaces = Array.isArray(namespace) ? namespace : namespace ? [namespace] : [];
|
const namespaces = Array.isArray(namespace) ? namespace : namespace ? [namespace] : [];
|
||||||
|
|
||||||
const t = (key: string, options?: Record<string, unknown>): string => {
|
const t = (key: string, options?: Record<string, unknown>): string => {
|
||||||
let msgId = key;
|
// 统一将分隔符转换为下划线,兼容 'namespace:key.path' 和 'key.path' 两种写法
|
||||||
|
const msgId = key.replace(':', '_').replace(/\./g, '_');
|
||||||
// 处理 namespace:key 格式(兼容原 i18next 用法)
|
|
||||||
if (key.includes(':')) {
|
|
||||||
msgId = key.replace(':', '_').replace(/\./g, '_');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 先尝试直接查找 key
|
// 先尝试直接查找 key
|
||||||
let message = getMessage(msgId);
|
let message = getMessage(msgId);
|
||||||
|
|||||||
Reference in New Issue
Block a user