Files
ragflow/web/src/app.tsx
Mustafa YILDIZ e4d8cdaff3 feat: add Turkish language support (#13670)
### What problem does this PR solve?
RAGFlow had no Turkish language support. This PR adds Turkish (tr)
locale translations to the UI.

### Type of change
- [x] New Feature (non-breaking change which adds functionality)

### What problem does this PR solve?

Co-authored-by: Mustafa YILDIZ <mustafa.yildiz@cilek.com>
2026-03-18 21:09:32 +08:00

178 lines
4.7 KiB
TypeScript

import { Toaster as Sonner } from '@/components/ui/sonner';
import { Toaster } from '@/components/ui/toaster';
import i18n, { changeLanguageAsync } from '@/locales/config';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { configResponsive } from 'ahooks';
import { ConfigProvider, ConfigProviderProps, theme } from 'antd';
import pt_BR from 'antd/lib/locale/pt_BR';
import arEG from 'antd/locale/ar_EG';
import deDE from 'antd/locale/de_DE';
import enUS from 'antd/locale/en_US';
import ru_RU from 'antd/locale/ru_RU';
import trTR from 'antd/locale/tr_TR';
import vi_VN from 'antd/locale/vi_VN';
import zhCN from 'antd/locale/zh_CN';
import zh_HK from 'antd/locale/zh_HK';
import dayjs from 'dayjs';
import 'dayjs/locale/ar';
import 'dayjs/locale/tr';
import 'dayjs/locale/zh-cn';
import advancedFormat from 'dayjs/plugin/advancedFormat';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import localeData from 'dayjs/plugin/localeData';
import weekOfYear from 'dayjs/plugin/weekOfYear';
import weekYear from 'dayjs/plugin/weekYear';
import weekday from 'dayjs/plugin/weekday';
import React, { useEffect, useState } from 'react';
import { RouterProvider } from 'react-router';
import { ThemeProvider, useTheme } from './components/theme-provider';
import { TooltipProvider } from './components/ui/tooltip';
import { ThemeEnum } from './constants/common';
import { routers } from './routes';
import storage from './utils/authorization-util';
import 'react-photo-view/dist/react-photo-view.css';
configResponsive({
sm: 640,
md: 768,
lg: 1024,
xl: 1280,
'2xl': 1536,
'3xl': 1780,
'4xl': 1980,
});
dayjs.extend(customParseFormat);
dayjs.extend(advancedFormat);
dayjs.extend(weekday);
dayjs.extend(localeData);
dayjs.extend(weekOfYear);
dayjs.extend(weekYear);
const AntLanguageMap = {
en: enUS,
zh: zhCN,
'zh-TRADITIONAL': zh_HK,
ru: ru_RU,
vi: vi_VN,
'pt-BR': pt_BR,
de: deDE,
ar: arEG,
tr: trTR,
};
if (process.env.NODE_ENV === 'development') {
import('@welldone-software/why-did-you-render').then(
(whyDidYouRenderModule) => {
const whyDidYouRender = whyDidYouRenderModule.default;
whyDidYouRender(React, {
trackAllPureComponents: true,
trackExtraHooks: [],
logOnDifferentValues: true,
exclude: [/^RouterProvider$/],
});
},
);
}
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
retry: 2,
},
},
});
type Locale = ConfigProviderProps['locale'];
function Root({ children }: React.PropsWithChildren) {
const { theme: themeragflow } = useTheme();
const getLocale = (lng: string) =>
AntLanguageMap[lng as keyof typeof AntLanguageMap] ?? enUS;
const updateDocumentLocale = (lng: string) => {
document.documentElement.lang = lng;
document.documentElement.dir = 'ltr';
dayjs.locale(lng === 'zh' ? 'zh-cn' : lng);
};
const [locale, setLocal] = useState<Locale>(getLocale(storage.getLanguage()));
useEffect(() => {
const handleLanguageChanged = (lng: string) => {
storage.setLanguage(lng);
setLocal(getLocale(lng));
updateDocumentLocale(lng);
};
updateDocumentLocale(storage.getLanguage() || i18n.language || 'en');
i18n.on('languageChanged', handleLanguageChanged);
return () => {
i18n.off('languageChanged', handleLanguageChanged);
};
}, []);
return (
<>
<ConfigProvider
theme={{
token: {
fontFamily:
"'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif",
},
algorithm:
themeragflow === 'dark'
? theme.darkAlgorithm
: theme.defaultAlgorithm,
}}
locale={locale}
direction={'ltr'}
>
{children}
<Sonner position="top-right" expand richColors closeButton />
<Toaster />
</ConfigProvider>
</>
);
}
const RootProvider = ({ children }: React.PropsWithChildren) => {
useEffect(() => {
const lng = storage.getLanguage();
if (lng) {
void changeLanguageAsync(lng);
}
}, []);
return (
<TooltipProvider>
<QueryClientProvider client={queryClient}>
<ThemeProvider
defaultTheme={ThemeEnum.Dark}
storageKey="ragflow-ui-theme"
>
<Root>{children}</Root>
</ThemeProvider>
</QueryClientProvider>
</TooltipProvider>
);
};
const RouterProviderWrapper: React.FC<{ router: typeof routers }> = ({
router,
}) => {
return <RouterProvider router={router}></RouterProvider>;
};
RouterProviderWrapper.whyDidYouRender = false;
export default function AppContainer() {
return (
<RootProvider>
<RouterProviderWrapper router={routers} />
</RootProvider>
);
}