Backend part (Go)
1. First create a data model related to the article
package model import ( "/gorm" ) // Article Main articletype Article struct { Status uint8 `json:"status" gorm:"default:1"` // Status: 0-Disable 1-Enable Sort int `json:"sort" gorm:"default:0"` // Sort AuthorId uint `json:"authorId"` // Author ID CategoryId uint `json:"categoryId"` // Classification ID Thumbnail string `json:"thumbnail"` // Thumbnail // Related Translations []ArticleTranslation `json:"translations"` Category ArticleCategory `json:"category"` } // ArticleTranslation Article Translation Tabletype ArticleTranslation struct { ArticleId uint `json:"articleId"` Lang string `json:"lang" gorm:"size:5"` // Language codes such as: zh-CN, en-US Title string `json:"title"` // Title Description string `json:"description"` // describe Content string `json:"content" gorm:"type:text"` // content Keywords string `json:"keywords"` // SEO keywords Slug string `json:"slug" gorm:"uniqueIndex"` // URL friendly title} // ArticleCategory Article Categorytype ArticleCategory struct { ParentId uint `json:"parentId"` Status uint8 `json:"status" gorm:"default:1"` Sort int `json:"sort" gorm:"default:0"` Translations []ArticleCategoryTranslation `json:"translations"` } // ArticleCategoryTranslation Classification Translation Tabletype ArticleCategoryTranslation struct { CategoryId uint `json:"categoryId"` Lang string `json:"lang" gorm:"size:5"` Name string `json:"name"` Description string `json:"description"` Slug string `json:"slug" gorm:"uniqueIndex"` }
2. Create a service layer
package service import ( "dagisku-server/app/model" "dagisku-server/global" ) type ArticleService struct{} type ArticleListRequest struct { Page int `json:"page" form:"page"` PageSize int `json:"pageSize" form:"pageSize"` Lang string `json:"lang" form:"lang"` Status *uint8 `json:"status" form:"status"` CategoryId *uint `json:"categoryId" form:"categoryId"` } func (s *ArticleService) GetList(req ArticleListRequest) (list [], total int64, err error) { limit := offset := * ( - 1) db := (&{}) // Build query conditions if != nil { db = ("status = ?", *) } if != nil { db = ("category_id = ?", *) } // Preload translation data db = ("Translations", "lang = ?", ) db = ("Category").Preload("", "lang = ?", ) err = (&total).Error if err != nil { return } err = ("sort desc, id desc").Limit(limit).Offset(offset).Find(&list).Error return } func (s *ArticleService) Create(article *) error { return (article).Error } func (s *ArticleService) Update(article *) error { return (article).Error } func (s *ArticleService) Delete(id uint) error { return (&{}, id).Error }
3. Create a controller
package article import ( "dagisku-server/app/model" "dagisku-server/app/service" "dagisku-server/utils/response" "/gin-gonic/gin" ) type ArticleApi struct{} // List Get the article listfunc (api *ArticleApi) List(c *) { var req if err := (&req); err != nil { ((), c) return } if == 0 { = 1 } if == 0 { = 10 } service := {} list, total, err := (req) if err != nil { ((), c) return } ({ "list": list, "total": total, }, c) } // Create Create articlefunc (api *ArticleApi) Create(c *) { var article if err := (&article); err != nil { ((), c) return } service := {} if err := (&article); err != nil { ((), c) return } (c) } // Update Update articlefunc (api *ArticleApi) Update(c *) { var article if err := (&article); err != nil { ((), c) return } service := {} if err := (&article); err != nil { ((), c) return } (c) } // Delete Delete Articlefunc (api *ArticleApi) Delete(c *) { id := ("id") service := {} if err := (uint(id)); err != nil { ((), c) return } (c) }
4. Register a route
// ... existing code ... type ApiGroup struct { LoginApi // ... other existing APIs ... } // ... existing code ...
func InitAdminRouter(Router *) { adminRouter := ("admin") // ... existing routes ... // Article related routes articleRouter := ("article") { ("list", ) ("create", ) ("update", ) ("delete/:id", ) } }
Front-end part (Nuxt 3)
1. Create API Request
import { useFetch } from '#app' export const useArticleApi = () => { const config = useRuntimeConfig() const baseURL = const getList = async (params: { page: number pageSize: number lang: string status?: number categoryId?: number }) => { return await useFetch('/admin/article/list', { baseURL, method: 'GET', params }) } const create = async (data: any) => { return await useFetch('/admin/article/create', { baseURL, method: 'POST', body: data }) } const update = async (data: any) => { return await useFetch('/admin/article/update', { baseURL, method: 'PUT', body: data }) } const remove = async (id: number) => { return await useFetch(`/admin/article/delete/${id}`, { baseURL, method: 'DELETE' }) } return { getList, create, update, remove } }
2. Create an article list page
<template> <div> <el-card> <!-- Search bar --> <el-form :inline="true" :model="searchForm"> <el-form-item> <el-select v-model="" placeholder="Select a language"> <el-option label="Chinese" value="zh-CN" /> <el-option label="English" value="en-US" /> </el-select> </el-form-item> <el-form-item> <el-button type="primary" @click="loadData">search</el-button> <el-button @click="handleAdd">New</el-button> </el-form-item> </el-form> <!-- Data table --> <el-table :data="tableData" v-loading="loading"> <el-table-column prop="id" label="ID" width="80" /> <el-table-column label="title"> <template #default="{ row }"> {{ ?.[0]?.title }} </template> </el-table-column> <el-table-column label="Classification"> <template #default="{ row }"> {{ ?.translations?.[0]?.name }} </template> </el-table-column> <el-table-column prop="status" label="state"> <template #default="{ row }"> <el-tag :type=" === 1 ? 'success' : 'info'"> {{ === 1 ? 'Enable' : 'Disable' }} </el-tag> </template> </el-table-column> <el-table-column label="operate" width="200"> <template #default="{ row }"> <el-button type="primary" link @click="handleEdit(row)">edit</el-button> <el-button type="danger" link @click="handleDelete(row)">delete</el-button> </template> </el-table-column> </el-table> <!-- Pagination --> <div class="pagination-container"> <el-pagination v-model:current-page="page" v-model:page-size="pageSize" :total="total" @current-change="loadData" /> </div> </el-card> <!-- edit弹窗 --> <el-dialog :title="dialogTitle" v-model="dialogVisible" width="800px" > <article-form v-if="dialogVisible" :form-data="formData" @submit="handleSubmit" @cancel="dialogVisible = false" /> </el-dialog> </div> </template> <script setup lang="ts"> const { getList, remove } = useArticleApi() // Status definitionconst searchForm = ref({ lang: 'zh-CN' }) const loading = ref(false) const tableData = ref([]) const page = ref(1) const pageSize = ref(10) const total = ref(0) const dialogVisible = ref(false) const dialogTitle = ref('') const formData = ref<any>({}) // Load dataconst loadData = async () => { = true try { const { data } = await getList({ page: , pageSize: , lang: }) = = } finally { = false } } // Process newconst handleAdd = () => { = { status: 1, translations: [{ lang: }] } = 'Added Article' = true } // Processing Editconst handleEdit = (row: any) => { = { ...row } = 'Edit article' = true } // Handle deletionconst handleDelete = async (row: any) => { try { await ('Confirm to delete the article? ') await remove() ('Delete successfully') loadData() } catch (err) { // No error is displayed when canceling deletion if (err !== 'cancel') { ('Delete failed') } } } // Process form submissionconst handleSubmit = async (data: any) => { try { if () { await update(data) } else { await create(data) } ('Save successfully') = false loadData() } catch (err) { ('Save failed') } } // Initial loadingonMounted(() => { loadData() }) </script> <style scoped> .pagination-container { margin-top: 20px; text-align: right; } </style>
3. Create article form components
<template> <el-form ref="formRef" :model="form" :rules="rules" label-width="100px" > <el-tabs v-model="activeLang"> <el-tab-pane v-for="lang in languages" :key="" :label="" :name="" > <el-form-item :prop="`translations.${getTransIndex()}.title`" label="title" > <el-input v-model="getTranslation().title" placeholder="Please enter the title" /> </el-form-item> <el-form-item :prop="`translations.${getTransIndex()}.description`" label="describe" > <el-input type="textarea" v-model="getTranslation().description" placeholder="Please enter a description" /> </el-form-item> <el-form-item :prop="`translations.${getTransIndex()}.content`" label="content" > <editor v-model="getTranslation().content" :height="400" /> </el-form-item> </el-tab-pane> </el-tabs> <el-form-item label="Classification" prop="categoryId"> <el-select v-model=""> <el-option v-for="item in categories" :key="" :label="[0].name" :value="" /> </el-select> </el-form-item> <el-form-item label="Thumbnail" prop="thumbnail"> <upload v-model="" /> </el-form-item> <el-form-item label="state" prop="status"> <el-switch v-model="" :active-value="1" :inactive-value="0" /> </el-form-item> <el-form-item> <el-button type="primary" @click="handleSubmit">save</el-button> <el-button @click="$emit('cancel')">Cancel</el-button> </el-form-item> </el-form> </template> <script setup lang="ts"> const props = defineProps<{ formData: any }>() const emit = defineEmits(['submit', 'cancel']) // Form dataconst form = ref({ ..., translations: || [] }) // Language configurationconst languages = [ { label: 'Chinese', value: 'zh-CN' }, { label: 'English', value: 'en-US' } ] const activeLang = ref(languages[0].value) // Get translation indexconst getTransIndex = (lang: string) => { return ((t: any) => === lang) } // Get or create a translationconst getTranslation = (lang: string) => { let trans = ((t: any) => === lang) if (!trans) { trans = { lang } (trans) } return trans } // Form verification rulesconst rules = { categoryId: [{ required: true, message: 'Please select a category' }], translations: { title: [{ required: true, message: 'Please enter the title' }], content: [{ required: true, message: 'Please enter content' }] } } // Submit the formconst formRef = ref() const handleSubmit = async () => { if (!) return await () emit('submit', ) } </script>
4. Multilingual configuration
import { createI18n } from 'vue-i18n' export default defineNuxtPlugin(({ vueApp }) => { const i18n = createI18n({ legacy: false, globalInjection: true, locale: 'zh-CN', messages: { 'zh-CN': { article: { title: 'Article Management', list: 'Article List', add: 'Added Article', edit: 'Edit article', // ... Other translations } }, 'en-US': { article: { title: 'Article Management', list: 'Article List', add: 'New Article', edit: 'Edit Article', // ... Other translations } } } }) (i18n) })
5. Front-end routing configuration
export default defineNuxtRouteMiddleware((to) => { const token = useCookie('token') if (! && ('/admin')) { return navigateTo('/login') } })
This implementation includes:
- Complete CRUD interface on the backend
- Multilingual support (Chinese and English)
- Rich text editor support
- Image upload function
- Classification Management
- Permission control
The above is the detailed content of the complete guide to creating an efficient multilingual blog system for golang+vue. For more information about govue multilingual blogs, please follow my other related articles!