• vue3+ts项目04-国际化


    yarn add vue-i18n
    yarn add js-cookie
    yarn add @types/js-cookie
    
    • 1
    • 2
    • 3

    src下新建i18n文件夹,该文件夹下新建lang和pages文件夹,
    lang文件夹下新建en.ts

    // 定义内容
    export default {
    	router: {
    		home: 'home',
    		system: {
    			system: 'system',
    			menu: 'systemMenu',
    			role: 'systemRole',
    			user: 'systemUser',
    			dic: 'systemDic',
    			city: 'systemDept'
    		},
    		personal: 'personal',
    	},
    	staticRoutes: {
    		signIn: 'signIn',
    		notFound: 'notFound',
    		noPower: 'noPower',
    	},
    	user: {
    		title0: 'Component size',
    		title1: 'Language switching',
    		title2: 'Menu search',
    		title3: 'Layout configuration',
    		title4: 'news',
    		title5: 'Full screen on',
    		title6: 'Full screen off',
    		dropdownLarge: 'large',
    		dropdownDefault: 'default',
    		dropdownSmall: 'small',
    		dropdown1: 'home page',
    		dropdown2: 'Personal Center',
    		dropdown3: '404',
    		dropdown4: '401',
    		dropdown5: 'Log out',
    		dropdown6: 'Code warehouse',
    		searchPlaceholder: 'Menu search: support Chinese, routing path',
    		newTitle: 'notice',
    		newBtn: 'All read',
    		newGo: 'Go to the notification center',
    		newDesc: 'No notice',
    		logOutTitle: 'Tips',
    		logOutMessage: 'This operation will log out. Do you want to continue?',
    		logOutConfirm: 'determine',
    		logOutCancel: 'cancel',
    		logOutExit: 'Exiting',
    	},
    	tagsView: {
    		refresh: 'refresh',
    		close: 'close',
    		closeOther: 'closeOther',
    		closeAll: 'closeAll',
    		fullscreen: 'fullscreen',
    		closeFullscreen: 'closeFullscreen',
    	},
    	notFound: {
    		foundTitle: 'Wrong address input, please re-enter the address~',
    		foundMsg: 'You can check the web address first, and then re-enter or give us feedback.',
    		foundBtn: 'Back to home page',
    	},
    	noAccess: {
    		accessTitle: 'You are not authorized to operate~',
    		accessMsg: 'Contact information: add QQ group discussion 665452019',
    		accessBtn: 'Reauthorization',
    	},
    	layout: {
    		configTitle: 'Layout configuration',
    		oneTitle: 'Global Themes',
    		twoTopTitle: 'top bar set up',
    		twoMenuTitle: 'Menu set up',
    		twoColumnsTitle: 'Columns set up',
    		twoTopBar: 'Top bar background',
    		twoTopBarColor: 'Top bar default font color',
    		twoIsTopBarColorGradual: 'Top bar gradient',
    		twoMenuBar: 'Menu background',
    		twoMenuBarColor: 'Menu default font color',
    		twoIsMenuBarColorGradual: 'Menu gradient',
    		twoColumnsMenuBar: 'Column menu background',
    		twoColumnsMenuBarColor: 'Default font color bar menu',
    		twoIsColumnsMenuBarColorGradual: 'Column gradient',
    		twoIsColumnsMenuHoverPreload: 'Column Menu Hover Preload',
    		threeTitle: 'Interface settings',
    		threeIsCollapse: 'Menu horizontal collapse',
    		threeIsUniqueOpened: 'Menu accordion',
    		threeIsFixedHeader: 'Fixed header',
    		threeIsClassicSplitMenu: 'Classic layout split menu',
    		threeIsLockScreen: 'Open the lock screen',
    		threeLockScreenTime: 'screen locking(s/s)',
    		fourTitle: 'Interface display',
    		fourIsShowLogo: 'Sidebar logo',
    		fourIsBreadcrumb: 'Open breadcrumb',
    		fourIsBreadcrumbIcon: 'Open breadcrumb icon',
    		fourIsTagsview: 'Open tagsview',
    		fourIsTagsviewIcon: 'Open tagsview Icon',
    		fourIsCacheTagsView: 'Enable tagsview cache',
    		fourIsSortableTagsView: 'Enable tagsview drag',
    		fourIsShareTagsView: 'Enable tagsview sharing',
    		fourIsFooter: 'Open footer',
    		fourIsGrayscale: 'Grey model',
    		fourIsInvert: 'Color weak mode',
    		fourIsDark: 'Dark Mode',
    		fourIsWartermark: 'Turn on watermark',
    		fourWartermarkText: 'Watermark copy',
    		fiveTitle: 'Other settings',
    		fiveTagsStyle: 'Tagsview style',
    		fiveAnimation: 'page animation',
    		fiveColumnsAsideStyle: 'Column style',
    		fiveColumnsAsideLayout: 'Column layout',
    		sixTitle: 'Layout switch',
    		sixDefaults: 'One',
    		sixClassic: 'Two',
    		sixTransverse: 'Three',
    		sixColumns: 'Four',
    		tipText: 'Click the button below to copy the layout configuration to `/src/stores/themeConfig.ts` It has been modified in.',
    		copyText: 'replication configuration',
    		resetText: 'restore default',
    		copyTextSuccess: 'Copy succeeded!',
    		copyTextError: 'Copy failed!',
    	},
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121

    lang文件夹下新建zh-cn.ts

    // 定义内容
    export default {
    	router: {
    		home: '首页',
    		system: {
    			system: '系统设置',
    			menu: '菜单管理',
    			role: '角色管理',
    			user: '用户管理',
    			dic: '字典管理',
    			city: '城市管理'
    		},
    		personal: '个人中心',
    	},
    	staticRoutes: {
    		signIn: '登录',
    		notFound: '找不到此页面',
    		noPower: '没有权限',
    	},
    	user: {
    		title0: '组件大小',
    		title1: '语言切换',
    		title2: '菜单搜索',
    		title3: '布局配置',
    		title4: '消息',
    		title5: '开全屏',
    		title6: '关全屏',
    		dropdownLarge: '大型',
    		dropdownDefault: '默认',
    		dropdownSmall: '小型',
    		dropdown1: '首页',
    		dropdown2: '个人中心',
    		dropdown3: '404',
    		dropdown4: '401',
    		dropdown5: '退出登录',
    		dropdown6: '代码仓库',
    		searchPlaceholder: '菜单搜索:支持中文、路由路径',
    		newTitle: '通知',
    		newBtn: '全部已读',
    		newGo: '前往通知中心',
    		newDesc: '暂无通知',
    		logOutTitle: '提示',
    		logOutMessage: '此操作将退出登录, 是否继续?',
    		logOutConfirm: '确定',
    		logOutCancel: '取消',
    		logOutExit: '退出中',
    	},
    	tagsView: {
    		refresh: '刷新',
    		close: '关闭',
    		closeOther: '关闭其它',
    		closeAll: '全部关闭',
    		fullscreen: '当前页全屏',
    		closeFullscreen: '关闭全屏',
    	},
    	notFound: {
    		foundTitle: '地址输入错误,请重新输入地址~',
    		foundMsg: '您可以先检查网址,然后重新输入或给我们反馈问题。',
    		foundBtn: '返回首页',
    	},
    	noAccess: {
    		accessTitle: '您未被授权,没有操作权限~',
    		accessMsg: '联系方式:加QQ群探讨 665452019',
    		accessBtn: '重新授权',
    	},
    	layout: {
    		configTitle: '布局配置',
    		oneTitle: '全局主题',
    		twoTopTitle: '顶栏设置',
    		twoMenuTitle: '菜单设置',
    		twoColumnsTitle: '分栏设置',
    		twoTopBar: '顶栏背景',
    		twoTopBarColor: '顶栏默认字体颜色',
    		twoIsTopBarColorGradual: '顶栏背景渐变',
    		twoMenuBar: '菜单背景',
    		twoMenuBarColor: '菜单默认字体颜色',
    		twoIsMenuBarColorGradual: '菜单背景渐变',
    		twoColumnsMenuBar: '分栏菜单背景',
    		twoColumnsMenuBarColor: '分栏菜单默认字体颜色',
    		twoIsColumnsMenuBarColorGradual: '分栏菜单背景渐变',
    		twoIsColumnsMenuHoverPreload: '分栏菜单鼠标悬停预加载',
    		threeTitle: '界面设置',
    		threeIsCollapse: '菜单水平折叠',
    		threeIsUniqueOpened: '菜单手风琴',
    		threeIsFixedHeader: '固定 Header',
    		threeIsClassicSplitMenu: '经典布局分割菜单',
    		threeIsLockScreen: '开启锁屏',
    		threeLockScreenTime: '自动锁屏(s/秒)',
    		fourTitle: '界面显示',
    		fourIsShowLogo: '侧边栏 Logo',
    		fourIsBreadcrumb: '开启 Breadcrumb',
    		fourIsBreadcrumbIcon: '开启 Breadcrumb 图标',
    		fourIsTagsview: '开启 Tagsview',
    		fourIsTagsviewIcon: '开启 Tagsview 图标',
    		fourIsCacheTagsView: '开启 TagsView 缓存',
    		fourIsSortableTagsView: '开启 TagsView 拖拽',
    		fourIsShareTagsView: '开启 TagsView 共用',
    		fourIsFooter: '开启 Footer',
    		fourIsGrayscale: '灰色模式',
    		fourIsInvert: '色弱模式',
    		fourIsDark: '深色模式',
    		fourIsWartermark: '开启水印',
    		fourWartermarkText: '水印文案',
    		fiveTitle: '其它设置',
    		fiveTagsStyle: 'Tagsview 风格',
    		fiveAnimation: '主页面切换动画',
    		fiveColumnsAsideStyle: '分栏高亮风格',
    		fiveColumnsAsideLayout: '分栏布局风格',
    		sixTitle: '布局切换',
    		sixDefaults: '默认',
    		sixClassic: '经典',
    		sixTransverse: '横向',
    		sixColumns: '分栏',
    		tipText: '点击下方按钮,复制布局配置去 `src/stores/themeConfig.ts` 中修改。',
    		copyText: '一键复制配置',
    		resetText: '一键恢复默认',
    		copyTextSuccess: '复制成功!',
    		copyTextError: '复制失败!',
    	},
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121

    pages下新建login文件夹,该文件下新建en.ts和zh-cn.ts

    // 定义内容
    export default {
    	label: {
    		one1: 'User name login',
    		two2: 'Mobile number',
    	},
    	link: {
    		one3: 'Third party login',
    		two4: 'Links',
    	},
    	account: {
    		accountPlaceholder1: 'The user name admin or not is common',
    		accountPlaceholder2: 'Password: 123456',
    		accountPlaceholder3: 'Please enter the verification code',
    		accountBtnText: 'Sign in',
    	},
    	mobile: {
    		placeholder1: 'Please input mobile phone number',
    		placeholder2: 'Please enter the verification code',
    		codeText: 'Get code',
    		btnText: 'Sign in',
    		msgText:
    			'Warm tip: it is recommended to use Google, Microsoft edge, version 79.0.1072.62 and above browsers, and 360 browser, please use speed mode',
    	},
    	scan: {
    		text: 'Open the mobile phone to scan and quickly log in / register',
    	},
    	signInText: 'welcome back!',
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    zh-cn.ts

    // 定义内容
    export default {
    	label: {
    		one1: '用户名登录',
    		two2: '手机号登录',
    	},
    	link: {
    		one3: '第三方登录',
    		two4: '友情链接',
    	},
    	account: {
    		accountPlaceholder1: '用户名 admin 或不输均为 common',
    		accountPlaceholder2: '密码:123456',
    		accountPlaceholder3: '请输入验证码',
    		accountBtnText: '登 录',
    	},
    	mobile: {
    		placeholder1: '请输入手机号',
    		placeholder2: '请输入验证码',
    		codeText: '获取验证码',
    		btnText: '登 录',
    		msgText: '* 温馨提示:建议使用谷歌、Microsoft Edge,版本 79.0.1072.62 及以上浏览器,360浏览器请使用极速模式',
    	},
    	scan: {
    		text: '打开手机扫一扫,快速登录/注册',
    	},
    	signInText: '欢迎回来!',
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    stores下interface下新建index.ts

    //定义接口来定义对象的类型 `stores` 全部类型定义在这里
    
    /**
     * 用户信息
     */
    export interface UserInfosState {
    	authBtnList: string[];
    	photo: string;
    	time: number;
    	userName: string;
    	roleId: number;
    }
    export interface UserInfosStates {
    	userInfos: UserInfosState;
    }
    
    /**
     * 路由缓存列表
     */
    export interface KeepAliveNamesState {
    	keepAliveNames: string[];
    	cachedViews: string[];
    }
    
    /**
     * 后端返回原始路由(未处理时)
     */
    export interface RequestOldRoutesState {
    	requestOldRoutes: string[];
    }
    
    /**
     * TagsView 路由列表
     */
    export interface TagsViewRoutesState {
    	tagsViewRoutes: string[];
    	isTagsViewCurrenFull: Boolean;
    }
    
    /**
     * 路由列表
     */
    export interface RoutesListState {
    	routesList: string[];
    	isColumnsMenuHover: Boolean;
    	isColumnsNavHover: Boolean;
    }
    
    /**
     * 布局配置
     */
    export interface ThemeConfigState {
    	passwordKey: string;
    	isDrawer: boolean;
    	primary: string;
    	topBar: string;
    	topBarColor: string;
    	isTopBarColorGradual: boolean;
    	menuBar: string;
    	menuBarColor: string;
    	isMenuBarColorGradual: boolean;
    	columnsMenuBar: string;
    	columnsMenuBarColor: string;
    	isColumnsMenuBarColorGradual: boolean;
    	isColumnsMenuHoverPreload: boolean;
    	isCollapse: boolean;
    	isUniqueOpened: boolean;
    	isFixedHeader: boolean;
    	isFixedHeaderChange: boolean;
    	isClassicSplitMenu: boolean;
    	isLockScreen: boolean;
    	lockScreenTime: number;
    	isShowLogo: boolean;
    	isShowLogoChange: boolean;
    	isBreadcrumb: boolean;
    	isTagsview: boolean;
    	isBreadcrumbIcon: boolean;
    	isTagsviewIcon: boolean;
    	isCacheTagsView: boolean;
    	isSortableTagsView: boolean;
    	isShareTagsView: boolean;
    	isFooter: boolean;
    	isGrayscale: boolean;
    	isInvert: boolean;
    	isIsDark: boolean;
    	isWartermark: boolean;
    	wartermarkText: string;
    	tagsStyle: string;
    	animation: string;
    	columnsAsideStyle: string;
    	columnsAsideLayout: string;
    	layout: string;
    	isRequestRoutes: boolean;
    	globalTitle: string;
    	globalViceTitle: string;
    	globalViceTitleMsg: string;
    	globalI18n: string;
    	globalComponentSize: string;
    }
    
    /**
     * 布局配置
     */
    export interface ThemeConfigStates {
    	themeConfig: ThemeConfigState;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107

    stores下新建themeConfig.ts

    import { defineStore } from 'pinia';
    import { ThemeConfigStates, ThemeConfigState } from './interface';
    
    export const useThemeConfig = defineStore('themeConfig', {
    	state: (): ThemeConfigStates => ({
    		themeConfig: {
    			//密码加密盐
    			passwordKey: `4vRk^ga52xVP$B2vYK$%r8a8hctLgbU9`,
    			isDrawer: false,
    			primary: '#409eff',
    			isIsDark: false,
    			topBar: '#ffffff',
    			topBarColor: '#606266',
    			isTopBarColorGradual: false,
    			menuBar: '#545c64',
    			menuBarColor: '#eaeaea',
    			isMenuBarColorGradual: false,
    			columnsMenuBar: '#545c64',
    			columnsMenuBarColor: '#e6e6e6',
    			isColumnsMenuBarColorGradual: false,
    			isColumnsMenuHoverPreload: false,
    			isCollapse: false,
    			isUniqueOpened: true,
    			isFixedHeader: false,
    			isFixedHeaderChange: false,
    			isClassicSplitMenu: false,
    			isLockScreen: false,
    			lockScreenTime: 30,
    			isShowLogo: true,
    			isShowLogoChange: false,
    			isBreadcrumb: true,
    			isTagsview: true,
    			isBreadcrumbIcon: true,
    			isTagsviewIcon: true,
    			isCacheTagsView: false,
    			isSortableTagsView: true,
    			isShareTagsView: false,
    			isFooter: true,
    			isGrayscale: false,
    			isInvert: false,
    			isWartermark: false,
    			wartermarkText: 'vue-next-admin',
    			tagsStyle: 'tags-style-five',
    			animation: 'opacitys',
    			columnsAsideStyle: 'columns-round',
    			columnsAsideLayout: 'columns-vertical',
    			layout: 'defaults',
    			isRequestRoutes: true,
    			globalTitle: '甜蜜蜜开放平台',
    			globalViceTitle: '甜蜜蜜开放平台',
    			globalViceTitleMsg: '专注、免费、开源、维护、解疑',
    			globalI18n: 'zh-cn',
    			globalComponentSize: 'large',
    		},
    	}),
    	actions: {
    		setThemeConfig(data: ThemeConfigState) {
    			this.themeConfig = data;
    		},
    	},
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    i18n文件下新建index.ts

    import { createI18n } from 'vue-i18n';
    import pinia from '@/stores/index';
    import { storeToRefs } from 'pinia';
    import { useThemeConfig } from '@/stores/themeConfig';
    import zhcnLocale from 'element-plus/es/locale/lang/zh-cn';
    import enLocale from 'element-plus/es/locale/lang/en';
    
    import nextZhcn from '@/i18n/lang/zh-cn';
    import nextEn from '@/i18n/lang/en';
    
    import pagesLoginZhcn from '@/i18n/pages/login/zh-cn';
    import pagesLoginEn from '@/i18n/pages/login/en';
    
    // 定义语言国际化内容
    /**
     * 说明:
     * /src/i18n/lang 下的 ts 为框架的国际化内容
     * /src/i18n/pages 下的 ts 为各页面的国际化内容
     */
    const messages = {
    	[zhcnLocale.name]: {
    		...zhcnLocale,
    		message: {
    			...nextZhcn,
    			...pagesLoginZhcn,
    		},
    	},
    	[enLocale.name]: {
    		...enLocale,
    		message: {
    			...nextEn,
    			...pagesLoginEn,
    		},
    	},
    };
    
    // 读取 pinia 默认语言
    const stores = useThemeConfig(pinia);
    const { themeConfig } = storeToRefs(stores);
    
    // 导出语言国际化
    //https://vue-i18n.intlify.dev/
    // https://vue-i18n.intlify.dev/guide/essentials/fallback.html#explicit-fallback-with-one-locale
    export const i18n = createI18n({
    	//是否在您的 Vue 应用程序上使用 vue-i18n Legacy API 模式,默认使用 Legacy API 模式。如果要使用Composition API模式,需要将其设置为false。
    	legacy: false,
    	//是否抑制本地化失败时输出的警告。如果为 true,则抑制本地化失败警告。如果您使用正则表达式,则可以抑制与翻译键(例如 t)匹配的本地化失败警告。
    	silentTranslationWarn: true,
    	//丢失的警告
    	missingWarn: false,
    	//当您的语言缺少键的翻译时,是否对翻译键进行模板插值。如果为 true,则跳过为您的“基本”语言编写模板;key是你的模板。
    	silentFallbackWarn: true,
    	//失败时的警告
    	fallbackWarn: false,
    	//当前语言,本地化的语言环境
    	locale: themeConfig.value.globalI18n,
    	//都失败的情况下使用的语言,此 VueI18n 实例正在使用的当前后备区域设置。
    	fallbackLocale: zhcnLocale.name,
    	messages,
    });
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    utils下新建storage.ts

    import Cookies from 'js-cookie';
    
    /**
     * window.localStorage 浏览器永久缓存
     * @method set 设置永久缓存
     * @method get 获取永久缓存
     * @method remove 移除永久缓存
     * @method clear 移除全部永久缓存
     */
    export const Local = {
    	// 设置永久缓存
    	set(key: string, val: any) {
    		window.localStorage.setItem(key, JSON.stringify(val));
    	},
    	// 获取永久缓存
    	get(key: string) {
    		const json: any = window.localStorage.getItem(key);
    		return JSON.parse(json);
    	},
    	// 移除永久缓存
    	remove(key: string) {
    		window.localStorage.removeItem(key);
    	},
    	// 移除全部永久缓存
    	clear() {
    		window.localStorage.clear();
    	},
    };
    
    /**
     * window.sessionStorage 浏览器临时缓存
     * @method set 设置临时缓存
     * @method get 获取临时缓存
     * @method remove 移除临时缓存
     * @method clear 移除全部临时缓存
     */
    export const Session = {
    	// 设置临时缓存
    	set(key: string, val: any) {
    		if (key === 'token') return Cookies.set(key, val);
    		window.sessionStorage.setItem(key, JSON.stringify(val));
    	},
    	// 获取临时缓存
    	get(key: string) {
    		if (key === 'token') return Cookies.get(key);
    		const json: any = window.sessionStorage.getItem(key);
    		return JSON.parse(json);
    	},
    	// 移除临时缓存
    	remove(key: string) {
    		if (key === 'token') return Cookies.remove(key);
    		window.sessionStorage.removeItem(key);
    	},
    	// 移除全部临时缓存
    	clear() {
    		Cookies.remove('token');
    		window.sessionStorage.clear();
    	},
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    components下新建svgIcon该文件夹下新建index.vue

    <template>
    	<i v-if="isShowIconSvg" class="el-icon" :style="setIconSvgStyle">
    		<component :is="getIconName" />
    	i>
    	<div v-else-if="isShowIconImg" :style="setIconImgOutStyle">
    		<img :src="getIconName" :style="setIconSvgInsStyle" />
    	div>
    	<i v-else :class="getIconName" :style="setIconSvgStyle" />
    template>
    
    <script lang="ts">
    import { computed, defineComponent } from 'vue';
    
    export default defineComponent({
    	name: 'svgIcon',
    	props: {
    		// svg 图标组件名字
    		name: {
    			type: String,
    		},
    		// svg 大小
    		size: {
    			type: Number,
    			default: () => 14,
    		},
    		// svg 颜色
    		color: {
    			type: String,
    		},
    	},
    	setup(props) {
    		// 在线链接、本地引入地址前缀
    		const linesString = ['https', 'http', '/src', '/assets', import.meta.env.VITE_PUBLIC_PATH];
    
    		// 获取 icon 图标名称
    		const getIconName = computed(() => {
    			return props?.name;
    		});
    		// 用于判断 element plus 自带 svg 图标的显示、隐藏
    		const isShowIconSvg = computed(() => {
    			return props?.name?.startsWith('ele-');
    		});
    		// 用于判断在线链接、本地引入等图标显示、隐藏
    		const isShowIconImg = computed(() => {
    			return linesString.find((str) => props.name?.startsWith(str));
    		});
    		// 设置图标样式
    		const setIconSvgStyle = computed(() => {
    			return `font-size: ${props.size}px;color: ${props.color};`;
    		});
    		// 设置图片样式
    		const setIconImgOutStyle = computed(() => {
    			return `width: ${props.size}px;height: ${props.size}px;display: inline-block;overflow: hidden;`;
    		});
    		// 设置图片样式
    		// https://gitee.com/lyt-top/vue-next-admin/issues/I59ND0
    		const setIconSvgInsStyle = computed(() => {
    			const filterStyle: string[] = [];
    			const compatibles: string[] = ['-webkit', '-ms', '-o', '-moz'];
    			compatibles.forEach((j) => filterStyle.push(`${j}-filter: drop-shadow(${props.color} 30px 0);`));
    			return `width: ${props.size}px;height: ${props.size}px;position: relative;left: -${props.size}px;${filterStyle.join('')}`;
    		});
    		return {
    			getIconName,
    			isShowIconSvg,
    			isShowIconImg,
    			setIconSvgStyle,
    			setIconImgOutStyle,
    			setIconSvgInsStyle,
    		};
    	},
    });
    script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    utils下新建other.ts

    import { nextTick } from 'vue';
    import type { App } from 'vue';
    import * as svg from '@element-plus/icons-vue';
    import router from '@/router/index';
    import pinia from '@/stores/index';
    import { storeToRefs } from 'pinia';
    import { useThemeConfig } from '@/stores/themeConfig';
    import { i18n } from '@/i18n/index';
    import { Local } from '@/utils/storage';
    import SvgIcon from '@/components/svgIcon/index.vue';
    
    /**
     * 导出全局注册 element plus svg 图标
     * @param app vue 实例
     * @description 使用:https://element-plus.gitee.io/zh-CN/component/icon.html
     */
    export function elSvg(app: App) {
    	const icons = svg as any;
    	for (const i in icons) {
    		app.component(`ele-${icons[i].name}`, icons[i]);
    	}
    	app.component('SvgIcon', SvgIcon);
    }
    
    /**
     * 设置浏览器标题国际化
     * @method const title = useTitle(); ==> title()
     */
    export function useTitle() {
    	const stores = useThemeConfig(pinia);
    	const { themeConfig } = storeToRefs(stores);
    	nextTick(() => {
    		let webTitle = '';
    		const globalTitle: string = themeConfig.value.globalTitle;
    		const { path, meta } = router.currentRoute.value;
    		if (path === '/login') {
    			webTitle = <any>meta.title;
    		} else {
    			webTitle = setTagsViewNameI18n(router.currentRoute.value);
    		}
    		document.title = `${webTitle} - ${globalTitle}` || globalTitle;
    	});
    }
    
    /**
     * 设置 自定义 tagsView 名称、 自定义 tagsView 名称国际化
     * @param params 路由 query、params 中的 tagsViewName
     * @returns 返回当前 tagsViewName 名称
     */
    export function setTagsViewNameI18n(item: any) {
    	let tagsViewName: any = '';
    	const { query, params, meta } = item;
    	if (query?.tagsViewName || params?.tagsViewName) {
    		if (/\/zh-cn|en|zh-tw\//.test(query?.tagsViewName) || /\/zh-cn|en|zh-tw\//.test(params?.tagsViewName)) {
    			// 国际化
    			const urlTagsParams = (query?.tagsViewName && JSON.parse(query?.tagsViewName)) || (params?.tagsViewName && JSON.parse(params?.tagsViewName));
    			tagsViewName = urlTagsParams[i18n.global.locale.value];
    		} else {
    			// 非国际化
    			tagsViewName = query?.tagsViewName || params?.tagsViewName;
    		}
    	} else {
    		// 非自定义 tagsView 名称
    		tagsViewName = i18n.global.t(<any>meta.title);
    	}
    	return tagsViewName;
    }
    
    /**
     * 图片懒加载
     * @param el dom 目标元素
     * @param arr 列表数据
     * @description data-xxx 属性用于存储页面或应用程序的私有自定义数据
     */
    export const lazyImg = (el: any, arr: any) => {
    	const io = new IntersectionObserver((res) => {
    		res.forEach((v: any) => {
    			if (v.isIntersecting) {
    				const { img, key } = v.target.dataset;
    				v.target.src = img;
    				v.target.onload = () => {
    					io.unobserve(v.target);
    					arr[key]['loading'] = false;
    				};
    			}
    		});
    	});
    	nextTick(() => {
    		document.querySelectorAll(el).forEach((img) => io.observe(img));
    	});
    };
    
    /**
     * 全局组件大小
     * @returns 返回 `window.localStorage` 中读取的缓存值 `globalComponentSize`
     */
    export const globalComponentSize = (): string => {
    	const stores = useThemeConfig(pinia);
    	const { themeConfig } = storeToRefs(stores);
    	return Local.get('themeConfig')?.globalComponentSize || themeConfig.value?.globalComponentSize;
    };
    
    /**
     * 对象深克隆
     * @param obj 源对象
     * @returns 克隆后的对象
     */
    export function deepClone(obj: any) {
    	let newObj: any;
    	try {
    		newObj = obj.push ? [] : {};
    	} catch (error) {
    		newObj = {};
    	}
    	for (const attr in obj) {
    		if (obj[attr] && typeof obj[attr] === 'object') {
    			newObj[attr] = deepClone(obj[attr]);
    		} else {
    			newObj[attr] = obj[attr];
    		}
    	}
    	return newObj;
    }
    
    /**
     * 判断是否是移动端
     */
    export function isMobile() {
    	if (
    		navigator.userAgent.match(
    			/('phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone')/i
    		)
    	) {
    		return true;
    	} else {
    		return false;
    	}
    }
    
    /**
     * 判断数组对象中所有属性是否为空,为空则删除当前行对象
     * @description @感谢大黄
     * @param list 数组对象
     * @returns 删除空值后的数组对象
     */
    export function handleEmpty(list: any) {
    	const arr = [];
    	for (const i in list) {
    		const d = [];
    		for (const j in list[i]) {
    			d.push(list[i][j]);
    		}
    		const leng = d.filter((item) => item === '').length;
    		if (leng !== d.length) {
    			arr.push(list[i]);
    		}
    	}
    	return arr;
    }
    
    /**
     * 统一批量导出
     * @method elSvg 导出全局注册 element plus svg 图标
     * @method useTitle 设置浏览器标题国际化
     * @method setTagsViewNameI18n 设置 自定义 tagsView 名称、 自定义 tagsView 名称国际化
     * @method lazyImg 图片懒加载
     * @method globalComponentSize() element plus 全局组件大小
     * @method deepClone 对象深克隆
     * @method isMobile 判断是否是移动端
     * @method handleEmpty 判断数组对象中所有属性是否为空,为空则删除当前行对象
     */
    const other = {
    	elSvg: (app: App) => {
    		elSvg(app);
    	},
    	useTitle: () => {
    		useTitle();
    	},
    	setTagsViewNameI18n(route: any) {
    		return setTagsViewNameI18n(route);
    	},
    	lazyImg: (el: any, arr: any) => {
    		lazyImg(el, arr);
    	},
    	globalComponentSize: () => {
    		return globalComponentSize();
    	},
    	deepClone: (obj: any) => {
    		return deepClone(obj);
    	},
    	isMobile: () => {
    		return isMobile();
    	},
    	handleEmpty: (list: any) => {
    		return handleEmpty(list);
    	},
    };
    
    // 统一批量导出
    export default other;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201

    修改main.ts

    import { createApp } from 'vue';
    import pinia from '@/stores/index';
    import App from './App.vue';
    import router from '@/router/index';
    import { i18n } from '@/i18n/index';
    import ElementPlus from 'element-plus';
    import 'element-plus/dist/index.css';
    
    const app = createApp(App);
    
    app.use(pinia).use(router).use(ElementPlus).use(i18n);
    
    app.mount('#app');
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    修改App.vue

    <script setup lang="ts">
    import { useI18n } from 'vue-i18n';
    import { computed } from 'vue';
    import other from '@/utils/other';
    // 获取全局组件大小
    const getGlobalComponentSize = computed(() => {
    	return other.globalComponentSize();
    });
    const { messages, locale } = useI18n();
    // 获取全局 i18n
    const getGlobalI18n = computed(() => {
    	return messages.value[locale.value];
    });
    script>
    
    <template>
    	
    	<el-config-provider :size="getGlobalComponentSize" :locale="getGlobalI18n">
    		<el-table mb-1 :data="[]" />
    		<el-pagination :total="100" />
    	el-config-provider>
    template>
    
    <style scoped>style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    运行项目查看结果

    yarn dev
    
    • 1

    在这里插入图片描述
    在这里插入图片描述

    修改为en就会变成英文

    参考学习代码地址vue-next-admin

  • 相关阅读:
    阿里云架构实战之ALB(应用型负载均衡)介绍与搭建
    网络期货开户业务是怎样办理的?
    HTML+CSS+Jquery实现北大官网所有效果
    Coinbase Ventures团队亲述CV简史及投资版图
    简单爬虫案例——爬取快手视频
    Flutter 中的 ListWheelViewport 小部件:全面指南
    CTFshow web42 43 44 45 46 47
    wps文件误删除了怎么恢复?如何找回被误删的WPS文件?
    什么是AIGC?
    我参加NVIDIA Sky Hackathon 环境安装(编程环境)
  • 原文地址:https://blog.csdn.net/qq_36437991/article/details/133746864