feat(@vben/docs): support english documents (#4202)
* chore(@vben/docs): 完成guide文档的翻译 * chore(@vben/docs): 完成other文档的翻译 * chore: 翻译部分文档 * chore: 完成英文config的配置 * chore: 完成in-depth的文档翻译 * chore: 调整调整链接 * chore: typo * chore: typo * chore: update links --------- Co-authored-by: Li Kui <90845831+likui628@users.noreply.github.com>
This commit is contained in:
314
docs/src/en/guide/in-depth/access.md
Normal file
314
docs/src/en/guide/in-depth/access.md
Normal file
@@ -0,0 +1,314 @@
|
||||
---
|
||||
outline: deep
|
||||
---
|
||||
|
||||
# Access Control
|
||||
|
||||
The framework has built-in two types of access control methods:
|
||||
|
||||
- Determining whether a menu or button can be accessed based on user roles
|
||||
- Determining whether a menu or button can be accessed through an API
|
||||
|
||||
## Frontend Access Control
|
||||
|
||||
**Implementation Principle**: The permissions for routes are hardcoded on the frontend, specifying which permissions are required to view certain routes. Only general routes are initialized, and routes that require permissions are not added to the route table. After logging in or obtaining user roles through other means, the roles are used to traverse the route table to generate a route table that the role can access. This table is then added to the router instance using `router.addRoutes`, achieving permission filtering.
|
||||
|
||||
**Disadvantage**: The permissions are relatively inflexible; if the backend changes roles, the frontend needs to be adjusted accordingly. This is suitable for systems with relatively fixed roles.
|
||||
|
||||
### Steps
|
||||
|
||||
- Ensure the current mode is set to frontend access control
|
||||
|
||||
Adjust `preferences.ts` in the corresponding application directory to ensure `accessMode='frontend'`.
|
||||
|
||||
```ts
|
||||
import { defineOverridesPreferences } from '@vben/preferences';
|
||||
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
// overrides
|
||||
app: {
|
||||
// Default value, optional
|
||||
accessMode: 'frontend',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
- Configure route permissions
|
||||
|
||||
#### If not configured, it is visible by default
|
||||
|
||||
```ts {3}
|
||||
{
|
||||
meta: {
|
||||
authority: ['super'],
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
- Ensure the roles returned by the interface match the permissions in the route table
|
||||
|
||||
You can look under `src/store/auth` in the application to find the following code:
|
||||
|
||||
```ts
|
||||
// Set the login user information, ensuring that userInfo.roles is an array and contains permissions from the route table
|
||||
// For example: userInfo.roles=['super', 'admin']
|
||||
authStore.setUserInfo(userInfo);
|
||||
```
|
||||
|
||||
At this point, the configuration is complete. You need to ensure that the roles returned by the interface after login match the permissions in the route table; otherwise, access will not be possible.
|
||||
|
||||
### Menu Visible but Access Forbidden
|
||||
|
||||
Sometimes, we need the menu to be visible but access to it forbidden. This can be achieved by setting `menuVisibleWithForbidden` to `true`. In this case, the menu will be visible, but access will be forbidden, redirecting to a 403 page.
|
||||
|
||||
```ts
|
||||
{
|
||||
meta: {
|
||||
menuVisibleWithForbidden: true,
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
## Backend Access Control
|
||||
|
||||
**Implementation Principle**: It is achieved by dynamically generating a routing table through an API, which returns data following a certain structure. The frontend processes this data into a recognizable structure, then adds it to the routing instance using `router.addRoutes`, realizing the dynamic generation of permissions.
|
||||
|
||||
**Disadvantage**: The backend needs to provide a data structure that meets the standards, and the frontend needs to process this structure. This is suitable for systems with more complex permissions.
|
||||
|
||||
### Steps
|
||||
|
||||
- Ensure the current mode is set to backend access control
|
||||
|
||||
Adjust `preferences.ts` in the corresponding application directory to ensure `accessMode='backend'`.
|
||||
|
||||
```ts
|
||||
import { defineOverridesPreferences } from '@vben/preferences';
|
||||
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
// overrides
|
||||
app: {
|
||||
accessMode: 'backend',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
- Ensure the structure of the menu data returned by the interface is correct
|
||||
|
||||
You can look under `src/router/access.ts` in the application to find the following code:
|
||||
|
||||
```ts
|
||||
async function generateAccess(options: GenerateMenuAndRoutesOptions) {
|
||||
return await generateAccessible(preferences.app.accessMode, {
|
||||
fetchMenuListAsync: async () => {
|
||||
// This interface is for the menu data returned by the backend
|
||||
return await getAllMenus();
|
||||
},
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
- Interface returns menu data, see comments for explanation
|
||||
|
||||
::: details Example of Interface Returning Menu Data
|
||||
|
||||
```ts
|
||||
const dashboardMenus = [
|
||||
{
|
||||
// Here, 'BasicLayout' is hardcoded and cannot be changed
|
||||
component: 'BasicLayout',
|
||||
meta: {
|
||||
order: -1,
|
||||
title: 'page.dashboard.title',
|
||||
},
|
||||
name: 'Dashboard',
|
||||
path: '/',
|
||||
redirect: '/analytics',
|
||||
children: [
|
||||
{
|
||||
name: 'Analytics',
|
||||
path: '/analytics',
|
||||
// Here is the path of the page, need to remove 'views/' and '.vue'
|
||||
component: '/dashboard/analytics/index',
|
||||
meta: {
|
||||
affixTab: true,
|
||||
title: 'page.dashboard.analytics',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Workspace',
|
||||
path: '/workspace',
|
||||
component: '/dashboard/workspace/index',
|
||||
meta: {
|
||||
title: 'page.dashboard.workspace',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
At this point, the configuration is complete. You need to ensure that after logging in, the format of the menu returned by the interface is correct; otherwise, access will not be possible.
|
||||
|
||||
## Fine-grained Control of Buttons
|
||||
|
||||
In some cases, we need to control the display of buttons with fine granularity. We can control the display of buttons through interfaces or roles.
|
||||
|
||||
### Permission Code
|
||||
|
||||
The permission code is the code returned by the interface. The logic to determine whether a button is displayed is located under `src/store/auth`:
|
||||
|
||||
```ts
|
||||
const [fetchUserInfoResult, accessCodes] = await Promise.all([
|
||||
fetchUserInfo(),
|
||||
getAccessCodes(),
|
||||
]);
|
||||
|
||||
userInfo = fetchUserInfoResult;
|
||||
authStore.setUserInfo(userInfo);
|
||||
accessStore.setAccessCodes(accessCodes);
|
||||
```
|
||||
|
||||
Locate the `getAccessCodes` corresponding interface, which can be adjusted according to business logic.
|
||||
|
||||
The data structure returned by the permission code is an array of strings, for example: `['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010']`
|
||||
|
||||
With the permission codes, you can use the `AccessControl` component and API provided by `@vben/access` to show and hide buttons.
|
||||
|
||||
#### Component Method
|
||||
|
||||
```vue
|
||||
<script lang="ts" setup>
|
||||
import { AccessControl, useAccess } from '@vben/access';
|
||||
|
||||
const { accessMode, hasAccessByCodes } = useAccess();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- You need to specify type="code" -->
|
||||
<AccessControl :codes="['AC_100100']" type="code">
|
||||
<Button> Visible to Super account ["AC_1000001"] </Button>
|
||||
</AccessControl>
|
||||
<AccessControl :codes="['AC_100030']" type="code">
|
||||
<Button> Visible to Admin account ["AC_100010"] </Button>
|
||||
</AccessControl>
|
||||
<AccessControl :codes="['AC_1000001']" type="code">
|
||||
<Button> Visible to User account ["AC_1000001"] </Button>
|
||||
</AccessControl>
|
||||
<AccessControl :codes="['AC_100100', 'AC_100010']" type="code">
|
||||
<Button>
|
||||
Visible to Super & Admin account ["AC_100100","AC_1000001"]
|
||||
</Button>
|
||||
</AccessControl>
|
||||
</template>
|
||||
```
|
||||
|
||||
#### API Method
|
||||
|
||||
```vue
|
||||
<script lang="ts" setup>
|
||||
import { AccessControl, useAccess } from '@vben/access';
|
||||
|
||||
const { hasAccessByCodes } = useAccess();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Button v-if="hasAccessByCodes(['AC_100100'])">
|
||||
Visible to Super account ["AC_1000001"]
|
||||
</Button>
|
||||
<Button v-if="hasAccessByCodes(['AC_100030'])">
|
||||
Visible to Admin account ["AC_100010"]
|
||||
</Button>
|
||||
<Button v-if="hasAccessByCodes(['AC_1000001'])">
|
||||
Visible to User account ["AC_1000001"]
|
||||
</Button>
|
||||
<Button v-if="hasAccessByCodes(['AC_100100', 'AC_1000001'])">
|
||||
Visible to Super & Admin account ["AC_100100","AC_1000001"]
|
||||
</Button>
|
||||
</template>
|
||||
```
|
||||
|
||||
#### Directive Method
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<Button class="mr-4" v-access:code="['AC_100100']">
|
||||
Visible to Super account ["AC_1000001"]
|
||||
</Button>
|
||||
<Button class="mr-4" v-access:code="['AC_100030']">
|
||||
Visible to Admin account ["AC_100010"]
|
||||
</Button>
|
||||
<Button class="mr-4" v-access:code="['AC_1000001']">
|
||||
Visible to User account ["AC_1000001"]
|
||||
</Button>
|
||||
<Button class="mr-4" v-access:code="['AC_100100', 'AC_1000001']">
|
||||
Visible to Super & Admin account ["AC_100100","AC_1000001"]
|
||||
</Button>
|
||||
</template>
|
||||
```
|
||||
|
||||
### Roles
|
||||
|
||||
The method of determining roles does not require permission codes returned by the interface; it directly determines whether buttons are displayed based on roles.
|
||||
|
||||
#### Component Method
|
||||
|
||||
```vue
|
||||
<script lang="ts" setup>
|
||||
import { AccessControl } from '@vben/access';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AccessControl :codes="['super']">
|
||||
<Button> Visible to Super account </Button>
|
||||
</AccessControl>
|
||||
<AccessControl :codes="['admin']">
|
||||
<Button> Visible to Admin account </Button>
|
||||
</AccessControl>
|
||||
<AccessControl :codes="['user']">
|
||||
<Button> Visible to User account </Button>
|
||||
</AccessControl>
|
||||
<AccessControl :codes="['super', 'admin']">
|
||||
<Button> Super & Visible to Admin account </Button>
|
||||
</AccessControl>
|
||||
</template>
|
||||
```
|
||||
|
||||
#### API Method
|
||||
|
||||
```vue
|
||||
<script lang="ts" setup>
|
||||
import { useAccess } from '@vben/access';
|
||||
|
||||
const { hasAccessByRoles } = useAccess();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Button v-if="hasAccessByRoles(['super'])"> Visible to Super account </Button>
|
||||
<Button v-if="hasAccessByRoles(['admin'])"> Visible to Admin account </Button>
|
||||
<Button v-if="hasAccessByRoles(['user'])"> Visible to User account </Button>
|
||||
<Button v-if="hasAccessByRoles(['super', 'admin'])">
|
||||
Super & Visible to Admin account
|
||||
</Button>
|
||||
</template>
|
||||
```
|
||||
|
||||
#### Directive Method
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<Button class="mr-4" v-access:role="['super']">
|
||||
Visible to Super account
|
||||
</Button>
|
||||
<Button class="mr-4" v-access:role="['admin']">
|
||||
Visible to Admin account
|
||||
</Button>
|
||||
<Button class="mr-4" v-access:role="['user']">
|
||||
Visible to User account
|
||||
</Button>
|
||||
<Button class="mr-4" v-access:role="['super', 'admin']">
|
||||
Super & Visible to Admin account
|
||||
</Button>
|
||||
</template>
|
||||
```
|
48
docs/src/en/guide/in-depth/check-updates.md
Normal file
48
docs/src/en/guide/in-depth/check-updates.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Check Updates
|
||||
|
||||
## Introduction
|
||||
|
||||
When there are updates to the website, you might need to check for updates. The framework provides this functionality. By periodically checking for updates, you can configure the `checkUpdatesInterval` and `enableCheckUpdates` fields in your application's preferences.ts file to enable and set the interval for checking updates (in minutes).
|
||||
|
||||
```ts
|
||||
import { defineOverridesPreferences } from '@vben/preferences';
|
||||
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
// overrides
|
||||
app: {
|
||||
// Whether to enable check for updates
|
||||
enableCheckUpdates: true,
|
||||
// The interval for checking updates, in minutes
|
||||
checkUpdatesInterval: 1,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Effect
|
||||
|
||||
When an update is detected, a prompt will pop up asking the user whether to refresh the page:
|
||||
|
||||

|
||||
|
||||
## Replacing with Other Update Checking Methods
|
||||
|
||||
If you need to check for updates in other ways, such as through an API to more flexibly control the update logic (such as force refresh, display update content, etc.), you can do so by modifying the `src/widgets/check-updates/check-updates.vue` file under `@vben/layouts`.
|
||||
|
||||
```ts
|
||||
// Replace this with your update checking logic
|
||||
async function getVersionTag() {
|
||||
try {
|
||||
const response = await fetch('/', {
|
||||
cache: 'no-cache',
|
||||
method: 'HEAD',
|
||||
});
|
||||
|
||||
return (
|
||||
response.headers.get('etag') || response.headers.get('last-modified')
|
||||
);
|
||||
} catch {
|
||||
console.error('Failed to fetch version tag');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
84
docs/src/en/guide/in-depth/features.md
Normal file
84
docs/src/en/guide/in-depth/features.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# Common Features
|
||||
|
||||
A collection of some commonly used features.
|
||||
|
||||
## Login Authentication Expiry
|
||||
|
||||
When the interface returns a `401` status code, the framework will consider the login authentication to have expired. Upon login timeout, it will redirect to the login page or open a login popup. This can be configured in `preferences.ts` in the application directory:
|
||||
|
||||
### Redirect to Login Page
|
||||
|
||||
Upon login timeout, it will redirect to the login page.
|
||||
|
||||
```ts
|
||||
import { defineOverridesPreferences } from '@vben/preferences';
|
||||
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
// overrides
|
||||
app: {
|
||||
loginExpiredMode: 'page',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Open Login Popup
|
||||
|
||||
When login times out, a login popup will open.
|
||||
|
||||

|
||||
|
||||
Configuration:
|
||||
|
||||
```ts
|
||||
import { defineOverridesPreferences } from '@vben/preferences';
|
||||
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
// overrides
|
||||
app: {
|
||||
loginExpiredMode: 'model',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Dynamic Title
|
||||
|
||||
- Default value: `true`
|
||||
|
||||
When enabled, the webpage title changes according to the route's `title`. You can enable or disable this in the `preferences.ts` file in your application directory.
|
||||
|
||||
```ts
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
// overrides
|
||||
app: {
|
||||
dynamicTitle: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Page Watermark
|
||||
|
||||
- Default value: `false`
|
||||
|
||||
When enabled, the webpage will display a watermark. You can enable or disable this in the `preferences.ts` file in your application directory.
|
||||
|
||||
```ts
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
// overrides
|
||||
app: {
|
||||
watermark: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
If you want to update the content of the watermark, you can do so. The parameters can be referred to [watermark-js-plus](https://zhensherlock.github.io/watermark-js-plus/):
|
||||
|
||||
```ts
|
||||
import { useWatermark } from '@vben/hooks';
|
||||
|
||||
const { destroyWatermark, updateWatermark } = useWatermark();
|
||||
|
||||
await updateWatermark({
|
||||
// watermark content
|
||||
content: 'hello my watermark',
|
||||
});
|
||||
```
|
1
docs/src/en/guide/in-depth/layout.md
Normal file
1
docs/src/en/guide/in-depth/layout.md
Normal file
@@ -0,0 +1 @@
|
||||
# Layout
|
44
docs/src/en/guide/in-depth/loading.md
Normal file
44
docs/src/en/guide/in-depth/loading.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Global Loading
|
||||
|
||||
Global loading refers to the loading effect that appears when the page is refreshed, usually a spinning icon:
|
||||
|
||||

|
||||
|
||||
## Principle
|
||||
|
||||
Implemented by the `vite-plugin-inject-app-loading` plugin, the plugin injects a global `loading html` into each application.
|
||||
|
||||
## Disable
|
||||
|
||||
If you do not need global loading, you can disable it in the `.env` file:
|
||||
|
||||
```bash
|
||||
VITE_INJECT_APP_LOADING=false
|
||||
```
|
||||
|
||||
## Customization
|
||||
|
||||
If you want to customize the global loading, you can create a `loading.html` file in the application directory, at the same level as `index.html`. The plugin will automatically read and inject this HTML. You can define the style and animation of this HTML as you wish.
|
||||
|
||||
::: tip
|
||||
|
||||
- You can use the same syntax as in `index.html`, such as the `VITE_APP_TITLE` variable, to get the application's title.
|
||||
- You must ensure there is an element with `id="__app-loading__"`.
|
||||
- Add a `hidden` class to the element with `id="__app-loading__"`.
|
||||
- You must ensure there is a `style[data-app-loading="inject-css"]` element.
|
||||
|
||||
```html{1,4}
|
||||
<style data-app-loading="inject-css">
|
||||
#__app-loading__.hidden {
|
||||
pointer-events: none;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: all 1s ease-out;
|
||||
}
|
||||
/* ... */
|
||||
</style>
|
||||
<div id="__app-loading__">
|
||||
<!-- ... -->
|
||||
<div class="title"><%= VITE_APP_TITLE %></div>
|
||||
</div>
|
||||
```
|
227
docs/src/en/guide/in-depth/locale.md
Normal file
227
docs/src/en/guide/in-depth/locale.md
Normal file
@@ -0,0 +1,227 @@
|
||||
# Internationalization
|
||||
|
||||
The project has integrated [Vue i18n](https://kazupon.github.io/vue-i18n/), and Chinese and English language packs have been configured.
|
||||
|
||||
## IDE Plugin
|
||||
|
||||
If you are using vscode as your development tool, it is recommended to install the [i18n Ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) plugin. It can help you manage internationalization copy more conveniently. After installing this plugin, you can see the corresponding language content in your code in real-time:
|
||||
|
||||

|
||||
|
||||
## Configure Default Language
|
||||
|
||||
You just need to override the default preferences. In the corresponding application, find the `src/preferences.ts` file and modify the value of `locale`:
|
||||
|
||||
```ts {3}
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
app: {
|
||||
locale: 'en-US',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Dynamic Language Switching
|
||||
|
||||
Switching languages consists of two parts:
|
||||
|
||||
- Updating preferences
|
||||
- Loading the corresponding language pack
|
||||
|
||||
```ts
|
||||
import type { SupportedLanguagesType } from '@vben/locales';
|
||||
import { loadLocaleMessages } from '@vben/locales';
|
||||
import { updatePreferences } from '@vben/preferences';
|
||||
|
||||
async function updateLocale(value: string) {
|
||||
// 1. Update preferences
|
||||
const locale = value as SupportedLanguagesType;
|
||||
updatePreferences({
|
||||
app: {
|
||||
locale,
|
||||
},
|
||||
});
|
||||
// 2. Load the corresponding language pack
|
||||
await loadLocaleMessages(locale);
|
||||
}
|
||||
|
||||
updateLocale('en-US');
|
||||
```
|
||||
|
||||
## Adding Translation Texts
|
||||
|
||||
::: warning Attention
|
||||
|
||||
- Do not place business translation texts inside `@vben/locales` to better manage business and general translation texts.
|
||||
- When adding new translation texts and multiple language packs are available, ensure to add the corresponding texts in all language packs.
|
||||
|
||||
:::
|
||||
|
||||
To add new translation texts, simply find `src/locales/langs/` in the corresponding application and add the texts accordingly, for example:
|
||||
|
||||
**src/locales/langs/zh-CN.ts**
|
||||
|
||||
````ts
|
||||
```json
|
||||
{
|
||||
"about": {
|
||||
"desc": "Vben Admin 是一个现代的管理模版。"
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
**src/locales/langs/en-US.ts**
|
||||
|
||||
````ts
|
||||
```json
|
||||
{
|
||||
"about": {
|
||||
"desc": "Vben Admin is a modern management template."
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
## Using Translation Texts
|
||||
|
||||
With `@vben/locales`, you can easily use translation texts:
|
||||
|
||||
### In Code
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
const items = computed(() => [{ title: $t('about.desc') }]);
|
||||
</script>
|
||||
<template>
|
||||
<div>{{ $t('about.desc') }}</div>
|
||||
<template v-for="item in items.value">
|
||||
<div>{{ item.title }}</div>
|
||||
</template>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Adding a New Language Pack
|
||||
|
||||
If you need to add a new language pack, follow these steps:
|
||||
|
||||
- Add the corresponding language pack file in the `packages/locales/langs` directory, for example, `zh-TW.json`, and translate the respective texts.
|
||||
- In the corresponding application, locate the `src/locales/langs` file and add the new language pack `zh-TW.json`.
|
||||
- Add the corresponding language in `packages/constants/src/core.ts`:
|
||||
|
||||
```ts
|
||||
export interface LanguageOption {
|
||||
label: string;
|
||||
value: 'en-US' | 'zh-CN'; // [!code --]
|
||||
value: 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]
|
||||
}
|
||||
export const SUPPORT_LANGUAGES: LanguageOption[] = [
|
||||
{
|
||||
label: '简体中文',
|
||||
value: 'zh-CN',
|
||||
},
|
||||
{
|
||||
label: 'English',
|
||||
value: 'en-US',
|
||||
},
|
||||
{
|
||||
label: '繁体中文', // [!code ++]
|
||||
value: 'zh-TW', // [!code ++]
|
||||
},
|
||||
];
|
||||
```
|
||||
|
||||
- In `packages/locales/typing.ts`, add a new TypeScript type:
|
||||
|
||||
```ts
|
||||
export type SupportedLanguagesType = 'en-US' | 'zh-CN'; // [!code --]
|
||||
export type SupportedLanguagesType = 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]
|
||||
```
|
||||
|
||||
At this point, you can use the newly added language pack in the project.
|
||||
|
||||
## Interface Language Switching Function
|
||||
|
||||
If you want to disable the language switching display button on the interface, in the corresponding application, find the `src/preferences.ts` file and modify the value of `locale` accordingly:
|
||||
|
||||
```ts {3}
|
||||
export const overridesPreferences = defineOverridesPreferences({
|
||||
widget: {
|
||||
languageToggle: false,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Remote Loading of Language Packs
|
||||
|
||||
::: tip Tip
|
||||
|
||||
When making interface requests through the project's built-in `request` tool, the default request header will include [Accept-Language](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language), allowing the server to dynamically internationalize data based on the request header.
|
||||
|
||||
:::
|
||||
|
||||
Each application has an independent language pack that can override the general language configuration. You can remotely load the corresponding language pack by finding the `src/locales/index.ts` file in the corresponding application and modifying the `loadMessages` method accordingly:
|
||||
|
||||
```ts {3-4}
|
||||
async function loadMessages(lang: SupportedLanguagesType) {
|
||||
const [appLocaleMessages] = await Promise.all([
|
||||
// Modify here to load data via a remote interface
|
||||
localesMap[lang](),
|
||||
loadThirdPartyMessage(lang),
|
||||
]);
|
||||
return appLocaleMessages.default;
|
||||
}
|
||||
```
|
||||
|
||||
## Third-Party Language Packs
|
||||
|
||||
Different applications may use third-party component libraries or plugins with varying internationalization methods, so they need to be handled differently. If you need to introduce a third-party language pack, you can find the `src/locales/index.ts` file in the corresponding application and modify the `loadThirdPartyMessage` method accordingly:
|
||||
|
||||
```ts
|
||||
/**
|
||||
* Load the dayjs language pack
|
||||
* @param lang
|
||||
*/
|
||||
async function loadDayjsLocale(lang: SupportedLanguagesType) {
|
||||
let locale;
|
||||
switch (lang) {
|
||||
case 'zh-CN': {
|
||||
locale = await import('dayjs/locale/zh-cn');
|
||||
break;
|
||||
}
|
||||
case 'en-US': {
|
||||
locale = await import('dayjs/locale/en');
|
||||
break;
|
||||
}
|
||||
// Default to using English
|
||||
default: {
|
||||
locale = await import('dayjs/locale/en');
|
||||
}
|
||||
}
|
||||
if (locale) {
|
||||
dayjs.locale(locale);
|
||||
} else {
|
||||
console.error(`Failed to load dayjs locale for ${lang}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Removing Internationalization
|
||||
|
||||
Firstly, it is not recommended to remove internationalization, as it is a good development practice. However, if you really need to remove it, you can directly use Chinese copy and then retain the project's built-in language pack, which will not affect the overall development experience. The steps to remove internationalization are as follows:
|
||||
|
||||
- Hide the language switching button on the interface, see: [Interface Language Switching Function](#interface-language-switching-function)
|
||||
- Modify the default language, see: [Configure Default Language](#configure-default-language)
|
||||
- Disable `vue-i18n` warning prompts, in the `src/locales/index.ts` file, modify `missingWarn` to `false`:
|
||||
|
||||
```ts
|
||||
async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
|
||||
await coreSetup(app, {
|
||||
defaultLocale: preferences.app.locale,
|
||||
loadMessages,
|
||||
missingWarn: !import.meta.env.PROD, // [!code --]
|
||||
missingWarn: false, // [!code ++]
|
||||
...options,
|
||||
});
|
||||
}
|
||||
```
|
131
docs/src/en/guide/in-depth/login.md
Normal file
131
docs/src/en/guide/in-depth/login.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# Login
|
||||
|
||||
This document explains how to customize the login page of your application.
|
||||
|
||||
## Login Page Adjustment
|
||||
|
||||
If you want to adjust the title, description, icon, and toolbar of the login page, you can do so by configuring the `props` parameter of the `AuthPageLayout` component.
|
||||
|
||||

|
||||
|
||||
You just need to configure the `props` parameter of `AuthPageLayout` in `src/router/routes/core.ts` within your application:
|
||||
|
||||
```ts {4-8}
|
||||
{
|
||||
component: AuthPageLayout,
|
||||
props: {
|
||||
sloganImage: "xxx/xxx.png",
|
||||
pageTitle: "开箱即用的大型中后台管理系统",
|
||||
pageDescription: "工程化、高性能、跨组件库的前端模版",
|
||||
toolbar: true,
|
||||
toolbarList: () => ['color', 'language', 'layout', 'theme'],
|
||||
}
|
||||
// ...
|
||||
},
|
||||
```
|
||||
|
||||
::: tip
|
||||
|
||||
If these configurations do not meet your needs, you can implement your own login page. Simply implement your own `AuthPageLayout`.
|
||||
|
||||
:::
|
||||
|
||||
## Login Form Adjustment
|
||||
|
||||
If you want to adjust the content of the login form, you can configure the `AuthenticationLogin` component parameters in `src/views/_core/authentication/login.vue` within your application:
|
||||
|
||||
```vue
|
||||
<AuthenticationLogin
|
||||
:loading="authStore.loginLoading"
|
||||
password-placeholder="123456"
|
||||
username-placeholder="vben"
|
||||
@submit="authStore.authLogin"
|
||||
/>
|
||||
```
|
||||
|
||||
::: details AuthenticationLogin Component Props
|
||||
|
||||
```ts
|
||||
{
|
||||
/**
|
||||
* @en Verification code login path
|
||||
*/
|
||||
codeLoginPath?: string;
|
||||
/**
|
||||
* @en Forget password path
|
||||
*/
|
||||
forgetPasswordPath?: string;
|
||||
|
||||
/**
|
||||
* @en Whether it is in loading state
|
||||
*/
|
||||
loading?: boolean;
|
||||
|
||||
/**
|
||||
* @en Password placeholder
|
||||
*/
|
||||
passwordPlaceholder?: string;
|
||||
|
||||
/**
|
||||
* @en QR code login path
|
||||
*/
|
||||
qrCodeLoginPath?: string;
|
||||
|
||||
/**
|
||||
* @en Registration path
|
||||
*/
|
||||
registerPath?: string;
|
||||
|
||||
/**
|
||||
* @en Whether to show verification code login
|
||||
*/
|
||||
showCodeLogin?: boolean;
|
||||
/**
|
||||
* @en Whether to show forget password
|
||||
*/
|
||||
showForgetPassword?: boolean;
|
||||
|
||||
/**
|
||||
* @en Whether to show QR code login
|
||||
*/
|
||||
showQrcodeLogin?: boolean;
|
||||
|
||||
/**
|
||||
* @en Whether to show registration button
|
||||
*/
|
||||
showRegister?: boolean;
|
||||
|
||||
/**
|
||||
* @en Whether to show remember account
|
||||
*/
|
||||
showRememberMe?: boolean;
|
||||
|
||||
/**
|
||||
* @en Whether to show third-party login
|
||||
*/
|
||||
showThirdPartyLogin?: boolean;
|
||||
|
||||
/**
|
||||
* @en Login box subtitle
|
||||
*/
|
||||
subTitle?: string;
|
||||
|
||||
/**
|
||||
* @en Login box title
|
||||
*/
|
||||
title?: string;
|
||||
|
||||
/**
|
||||
* @en Username placeholder
|
||||
*/
|
||||
usernamePlaceholder?: string;
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tip
|
||||
|
||||
If these configurations do not meet your needs, you can implement your own login form and related login logic.
|
||||
|
||||
:::
|
1293
docs/src/en/guide/in-depth/theme.md
Normal file
1293
docs/src/en/guide/in-depth/theme.md
Normal file
File diff suppressed because it is too large
Load Diff
17
docs/src/en/guide/in-depth/ui-framework.md
Normal file
17
docs/src/en/guide/in-depth/ui-framework.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# UI Framework Switching
|
||||
|
||||
`Vue Admin` supports your freedom to choose the UI framework. The default UI framework for the demo site is `Ant Design Vue`, consistent with the older version. The framework also has built-in versions for `Element Plus` and `Naive UI`, allowing you to choose according to your preference.
|
||||
|
||||
## Adding a New UI Framework
|
||||
|
||||
If you want to use a different UI framework, you only need to follow these steps:
|
||||
|
||||
1. Create a new folder inside `apps`, for example, `apps/web-xxx`.
|
||||
2. Change the `name` field in `apps/web-xxx/package.json` to `web-xxx`.
|
||||
3. Remove dependencies and code from other UI frameworks and replace them with your chosen UI framework's logic, which requires minimal changes.
|
||||
4. Adjust the language files within `locales`.
|
||||
5. Adjust the components in `app.vue`.
|
||||
6. Adapt the theme of the UI framework to match `Vben Admin`.
|
||||
7. Adjust the application name in `.env`.
|
||||
8. Add a `dev:xxx` script in the root directory of the repository.
|
||||
9. Run `pnpm install` to install dependencies.
|
Reference in New Issue
Block a user