|
@@ -1,78 +1,78 @@
|
|
|
import i18next from 'i18next';
|
|
import i18next from 'i18next';
|
|
|
|
|
+import { matchPath } from 'react-router-dom';
|
|
|
|
|
|
|
|
import routerConfig from './routes';
|
|
import routerConfig from './routes';
|
|
|
|
|
|
|
|
import type { AppRouteObject } from './types';
|
|
import type { AppRouteObject } from './types';
|
|
|
|
|
|
|
|
-// 扁平化路由配置
|
|
|
|
|
-const flattenRoutes = (routes: AppRouteObject[], parentNames: string[] = []): AppRouteObject[] => {
|
|
|
|
|
- return routes.reduce((acc: AppRouteObject[], route: AppRouteObject) => {
|
|
|
|
|
- // 添加当前路由,并添加 locale 字段
|
|
|
|
|
- if (route.name && !route.index) {
|
|
|
|
|
- const currentNames = [...parentNames, route.name];
|
|
|
|
|
- acc.push({
|
|
|
|
|
- ...route,
|
|
|
|
|
- locale: `menus.${currentNames.join('.')}`,
|
|
|
|
|
- });
|
|
|
|
|
- } else {
|
|
|
|
|
- acc.push(route);
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 扁平化路由配置,提取所有有 name 的路由
|
|
|
|
|
+ */
|
|
|
|
|
+function getAllRoutes(
|
|
|
|
|
+ routes: AppRouteObject[],
|
|
|
|
|
+ parentNames: string[] = []
|
|
|
|
|
+): Array<{
|
|
|
|
|
+ path: string;
|
|
|
|
|
+ locale: string;
|
|
|
|
|
+}> {
|
|
|
|
|
+ const result: Array<{ path: string; locale: string }> = [];
|
|
|
|
|
+
|
|
|
|
|
+ for (const route of routes) {
|
|
|
|
|
+ if (route.name && route.path && !route.index) {
|
|
|
|
|
+ const locale = route.locale || `menus.${[...parentNames, route.name].join('.')}`;
|
|
|
|
|
+ result.push({ path: route.path, locale });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 如果有子路由,递归处理
|
|
|
|
|
if (route.children) {
|
|
if (route.children) {
|
|
|
- acc.push(
|
|
|
|
|
- ...flattenRoutes(
|
|
|
|
|
- route.children,
|
|
|
|
|
- route.name ? [...parentNames, route.name] : parentNames
|
|
|
|
|
- )
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ const currentNames = route.name ? [...parentNames, route.name] : parentNames;
|
|
|
|
|
+ result.push(...getAllRoutes(route.children, currentNames));
|
|
|
}
|
|
}
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- return acc;
|
|
|
|
|
- }, []);
|
|
|
|
|
-};
|
|
|
|
|
|
|
+ return result;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-const flatRoutes = flattenRoutes(routerConfig);
|
|
|
|
|
-console.log('flatRoutes:', flatRoutes);
|
|
|
|
|
|
|
+let allRoutesCache: Array<{ path: string; locale: string }> | null = null;
|
|
|
|
|
+function getAllRoutesCache(): Array<{ path: string; locale: string }> {
|
|
|
|
|
+ if (!allRoutesCache) {
|
|
|
|
|
+ allRoutesCache = getAllRoutes(routerConfig);
|
|
|
|
|
+ }
|
|
|
|
|
+ return allRoutesCache;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 获取路由路径对应的标题
|
|
|
|
|
|
|
+ * 根据路径获取 locale key
|
|
|
* @param pathname 路由路径
|
|
* @param pathname 路由路径
|
|
|
- * @returns 路由标题
|
|
|
|
|
|
|
+ * @returns locale key
|
|
|
*/
|
|
*/
|
|
|
-export const getTitleByPath = (pathname: string): string => {
|
|
|
|
|
- console.log('getTitleByPath ~ pathname:', pathname);
|
|
|
|
|
-
|
|
|
|
|
- // 先尝试精确匹配
|
|
|
|
|
- let route = flatRoutes.find((route) => route.path === pathname);
|
|
|
|
|
-
|
|
|
|
|
- // 处理带参路由
|
|
|
|
|
- if (!route) {
|
|
|
|
|
- route = flatRoutes.find((route) => {
|
|
|
|
|
- if (!route.path) return false;
|
|
|
|
|
|
|
+export const getLocaleByPath = (pathname: string): string => {
|
|
|
|
|
+ const allRoutes = getAllRoutesCache();
|
|
|
|
|
+ // 按路径长度降序排序,优先匹配更具体的路由
|
|
|
|
|
+ const matchedRoute = allRoutes
|
|
|
|
|
+ .filter((route) => {
|
|
|
if (route.path === '*') return true;
|
|
if (route.path === '*') return true;
|
|
|
- // 将路由路径转换为正则表达式
|
|
|
|
|
- const routePattern = route.path
|
|
|
|
|
- .replace(/\/:([^/?]+)\?/g, '(?:/[^/]+)?') // 处理可选参数
|
|
|
|
|
- .replace(/\/:([^/?]+)/g, '(?:/[^/]+)'); // 处理必选参数
|
|
|
|
|
|
|
+ return matchPath({ path: route.path, end: false }, pathname) !== null;
|
|
|
|
|
+ })
|
|
|
|
|
+ .sort((a, b) => {
|
|
|
|
|
+ if (a.path === '*') return 1;
|
|
|
|
|
+ if (b.path === '*') return -1;
|
|
|
|
|
+ return b.path.length - a.path.length;
|
|
|
|
|
+ })[0];
|
|
|
|
|
|
|
|
- try {
|
|
|
|
|
- return new RegExp(`^${routePattern}$`).test(pathname);
|
|
|
|
|
- } catch {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (route) {
|
|
|
|
|
- if (route.locale) {
|
|
|
|
|
- return i18next.t(route.locale, { defaultValue: '' });
|
|
|
|
|
- }
|
|
|
|
|
- return '';
|
|
|
|
|
|
|
+ if (matchedRoute) {
|
|
|
|
|
+ return matchedRoute.locale;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 如果找不到对应的路由,将路径转换为 i18n key
|
|
// 如果找不到对应的路由,将路径转换为 i18n key
|
|
|
- const i18nKey = `menus.${pathname.slice(1).replace(/\//g, '.')}`;
|
|
|
|
|
- console.log(' getTitleByPath ~ i18nKey:', i18nKey);
|
|
|
|
|
- return i18next.t(i18nKey, { defaultValue: '' });
|
|
|
|
|
|
|
+ return `menus.${pathname.slice(1).replace(/\//g, '.')}`;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 获取路由路径对应的标题
|
|
|
|
|
+ * @param pathname 路由路径
|
|
|
|
|
+ * @returns 路由标题
|
|
|
|
|
+ */
|
|
|
|
|
+export const getTitleByPath = (pathname: string): string => {
|
|
|
|
|
+ const locale = getLocaleByPath(pathname);
|
|
|
|
|
+ return i18next.t(locale, { defaultValue: '' });
|
|
|
};
|
|
};
|