03创建Vue项目并实现全球化

03创建Vue项目并实现全球化

创建Vue项目

vue create client-vue

使用Vuex作为状态管理,用于保存从后台获取的应用程序配置ApplicationConfigurationDto,该对象包含本地化的所有数据。

安装Vue-Cookies

npm install vue-cookies --force

vue-cookies用于管理cookie,用户选择的语言类型存放在cookie中。

main.ts中添加以下代码:

import Cookies from 'vue-cookies'
.use(Cookies)

安装nswag

npm install nswag --force

配置nswag

使用nswag生成客户端,在package.json文件中添加以下代码

"scripts": {
"generate-client": "nswag openapi2tsclient /input:https://localhost:7027/swagger/v1/swagger.json /Template:Fetch /UseGetBaseUrlMethod:true /GenerateClientClasses:true /operationGenerationMode:MultipleClientsFromPathSegments /useTransformOptionsMethod:true /useTransformResultMethod:true /clientBaseClass:ClientBase /configurationClass:IConfig /ImportRequiredTypes:true /ExtensionCode:\"import { ClientBase, IConfig } from './clientBase'\" /output:src/api-client/client.ts"
},

/Key:value 为命令参数 详情请见

请求参数加工/响应数据加工

openapi2tsclient:从Swagger/OpenAPI规范生成TypeScript客户端代码。

input: 数据或JSON数据本身的文件路径或URL。

Template: 异步处理的类型('JQueryCallbacks', 'JQueryPromises', 'AngularJS', 'Angular', 'Fetch', 'Aurelia')

UseGetBaseUrlMethod:指定是否使用基类中的'getBaseUrl(defaultUrl: string)'方法(默认值:false)

GenerateClientClasses:指定是否生成客户端类。

operationGenerationMode:操作生成方式('SingleClientFromOperationId' or 'MultipleClientsFromPathSegments').")]

clientBaseClass客户端代码的基类

configurationClass客户端代码的配置类

ImportRequiredTypes:指定是否应该导入所需的类型(默认值:true)。

ExtensionCode生成的客户端TS文件中的扩展代码,参数为字符串或文件路径

useTransformOptionsMethod启用请求参数转换方法

useTransformResultMethod启用响应结果转换方法

output:输出文件路径(可选)。

nswag 为node_modules\.bin中的可执行程序,如果没有配置node_modules文件夹的环境变量,则这里需要用node_modules/.bin/替代nswag

执行命令

npm run generate-client

创建ClientBase.ts

api-client文件夹中创建ClientBase.ts文件,添加以下代码

/**
* Configuration class needed in base class.
* The config is provided to the API client at initialization time.
* API clients inherit from #ClientBase and provide the config.
*/
import packageConfig from '../../package.json'
import Cookies from 'vue-cookies'
export class IConfig {
public static readonly acceptLanguageKey = 'acceptLanguage'
/**
* Returns a valid value for the Authorization header.
* Used to dynamically inject the current auth header.
*/
public getAuthorization (): string {
return ''
// return 'the-authentication-token'
}
// 从cookie中获取当前语言
public getAcceptLanguage (): string {
const cookies: any = Cookies
const acceptLanguage = cookies.get(IConfig.acceptLanguageKey)
return acceptLanguage || 'zh-Hans'
}
}
export class ClientBase {
private readonly config: IConfig;
protected constructor (config: IConfig) {
this.config = config
}
// 请求参数转换方法
protected transformOptions (options: RequestInit): Promise<RequestInit> {
options.headers = {
...options.headers,
Authorization: this.config.getAuthorization(),
myHeader: 'myValue',
'accept-language': this.config.getAcceptLanguage() || '' // 在请求头中添加当前语言
}
// 设置跨域请求发送cookie
options.credentials = 'include'
// 指示请求将使用CORS
options.mode = 'cors'
options.cache = 'default'
console.log('transformOptions', 'options:', options)
return Promise.resolve(options)
}
// 响应结果转换方法
protected transformResult (url: string, response: Response, processor: (response: Response) => Promise<any>): Promise<any> {
console.log('transformResult', 'url:', url, response)
if (response === null) return Promise.resolve()
// 判断响应头内容类型为 text/plain 则直接返回响应文本
const contentType = response.headers.get('content-type')
if (contentType != null && contentType.indexOf('text/plain') >= 0) {
return response.text()
}
// 调用回调函数
return processor(response)
}
// 基类中的 getBaseUrl 用于 client 类拼接API请求地址
protected getBaseUrl (defaultUrl: string, baseUrl?: string): string {
if (baseUrl && baseUrl.length > 0) return baseUrl
if (defaultUrl && defaultUrl.length > 0) return defaultUrl
// 从package.json文件中获取baseUrl
return packageConfig.baseUrl
}
}

.json配置文件读取配置信息必须在shims-vue.ts文件中添加以下配置

declare module '*.json' {
const value: any;
export default value;
}

实现状态管理

store文件夹中添加文件夹Modules\ApplicationConfiguration。在store\Modules\ApplicationConfiguration中添加文件interfaces.ts,添加以下代码

import { ApplicationConfigurationDto } from '@/api-client/client'
export default interface Configuration{
applicationConfiguration: ApplicationConfigurationDto // 应用程序配置数据
}

store\Modules\ApplicationConfiguration中添加文件index.ts,添加以下代码

import { AbpClient, ApplicationConfigurationDto } from '@/api-client/client'
import { IConfig } from '@/api-client/clientBase'
import RootStateTypes from '@/store/interfaces'
import { Module } from 'vuex'
import Configuration from './interfaces'
const ConfigurationModule: Module<Configuration, RootStateTypes> = {
namespaced: true,
state: {
applicationConfiguration: new ApplicationConfigurationDto()
},
getters: {
getLocalization (state) {
return state.applicationConfiguration.localization
},
l: (state) => (key:string) => { // 全球化的方法,通过该方法显示各国对应的语言
const localization = state.applicationConfiguration.localization
if (localization?.values && localization?.defaultResourceName) {
return localization?.values[localization.defaultResourceName][key]
}
return key
}
},
mutations: {
Set_ApplicationConfiguration (state, data: ApplicationConfigurationDto) {
state.applicationConfiguration = data
}
},
actions: {
// 初始化应用程序配置
initApplicationConfiguration (store): Promise<ApplicationConfigurationDto> {
if (store.state.applicationConfiguration.timing) {
return Promise.resolve(store.state.applicationConfiguration)
}
const client = new AbpClient(new IConfig())
// 获取应用程序配置,并更新状态
return client.applicationConfiguration()
.then(result => {
this.commit('ConfigurationModule/Set_ApplicationConfiguration', result)
return Promise.resolve(store.state.applicationConfiguration)
})
},
// 重置应用程序配置
resetApplicationConfiguration (store): Promise<ApplicationConfigurationDto> {
store.state.applicationConfiguration.timing = undefined
return this.dispatch('ConfigurationModule/initApplicationConfiguration')
}
}
}
export default ConfigurationModule

store\interfaces.ts文件的代码给为:

import Configuration from './Modules/ApplicationConfiguration/interfaces'
// 定义根状态类型
export default interface RootStateTypes {
isLogin: boolean
}
// 扩展更状态类型
export interface AllStateTypes extends RootStateTypes {
// 应用程序配置
ConfigurationModule: Configuration
// other state type
}

修改store\index.ts文件的代码为:

import { InjectionKey } from 'vue'
import { createStore, Store, useStore as baseUseStore } from 'vuex'
import RootStateTypes, { AllStateTypes } from './interfaces'
import ConfigurationModule from './Modules/ApplicationConfiguration'
export default createStore<RootStateTypes>({
state: {
isLogin: false
},
getters: {},
mutations: {
//
},
actions: {},
modules: {
ConfigurationModule
}
})
export const key: InjectionKey<Store<RootStateTypes>> = Symbol('CA3227F5-D73C-4E65-AA3F-BA781CA32231')
export function useStore<T = AllStateTypes> (): Store<T> {
return baseUseStore<T>(key)
}

vuex模块(Module)

TypeScript 支持

main.ts中添加以下代码:

import store, { key } from '@/store/index'
.use(store, key)

main.ts完整代码:

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store, { key } from '@/store/index'
import Cookies from 'vue-cookies'
createApp(App)
.use(store, key)
.use(router)
.use(Cookies)
.mount('#app')

App.vue里初始化应用程序配置,添加以下代码:

<script lang="ts">
import { defineComponent } from 'vue'
import { useStore } from './store'
export default defineComponent({
mounted () {
const store = useStore()
store.dispatch('ConfigurationModule/initApplicationConfiguration')
}
})
</script>

修改AboutView.vue文件的代码为:

<template>
<div class="about">
<h1>This is an about page</h1>
<div>
{{ l('LongWelcomeMessage') }} <!--显示对应的语言信息 -->
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { mapGetters } from 'vuex'
export default defineComponent({
components: {
//
},
data () {
return {
}
},
beforeMount () {
//
},
mounted () {
//
},
computed: {
// 从状态管理Vuex中映射Get方法到计算属性l中
// 对应的是 `store\Modules\ApplicationConfiguration\index.ts`中Getters中的 l
...mapGetters({
l: 'ConfigurationModule/l'
})
},
methods: {
//
}
})
</script>

到此Vue中实现全球化初步完成,还缺语言的切换,现在是默认的中文。

语言选择

components\selects文件夹中添加文件LanguageSelect.vue,添加以下代码:

<template>
<select
@change="change">
<option
v-for="item in options"
:key="item.cultureName"
:value="item.cultureName"
:selected="isSelected(item)"
>
{{ item.displayName }}
</option>
</select>
</template>
<script lang="ts">
import { LanguageInfo } from '@/api-client/client'
import { IConfig } from '@/api-client/clientBase'
import { useStore } from '@/store'
import { defineComponent } from 'vue'
export default defineComponent({
setup () {
//
},
data () {
return {
data: this.value
}
},
emits: ['onchange'],
watch: {
//
},
computed: {
store () {
return useStore()
},
// 当前语言
currentCulture () {
return this.store.state.ConfigurationModule.applicationConfiguration.localization?.currentCulture?.cultureName
},
// 支持的语言项
options () {
return this.store.state.ConfigurationModule.applicationConfiguration.localization?.languages || new Array<LanguageInfo>()
},
isSelected () {
return (item: LanguageInfo) => {
return item.cultureName === this.currentCulture
}
}
},
mounted () {
//
},
methods: {
// 当选项更改时,将更改后的值保存进cookie中,并重置应用程序配置
change (event: any) {
console.log(event, this.store)
this.data = event.target.value
// 将选择的语言保存进cookie中
this.$cookies.set(IConfig.acceptLanguageKey, this.data)
// 状态管理重置应用程序配置
this.store.dispatch('ConfigurationModule/resetApplicationConfiguration')
this.$emit('onchange', this.data)
}
}
})
</script>

LanguageSelect.vue组件添加进AboutView.vue,就可自由切换想显示的语言了。

如此全球化实现完成

posted @   $("#阿飞")  阅读(111)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示