Files
go_blog/i18n/i18n.go
T
kevinandClaude Fable 5 b600eac21c feat: add favicon settings to site configuration
- Add Favicon field to SiteSetting model with FaviconIsURL() helper
- Implement favicon upload and management in site settings page
- Support both external URL and local file upload for favicon
- Add favicon display in page header with automatic URL detection
- Add i18n translations for favicon settings (EN/ZH)
- Update middleware and helpers to pass favicon data to templates
- Include migration script for existing databases

Users can now customize their site's favicon from /admin/settings/site
by either providing an external URL or uploading a local image file
(recommended formats: .ico, .png, .svg, 16x16 or 32x32 pixels).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-22 20:09:05 +08:00

773 lines
32 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package i18n
import (
"strings"
)
// Lang represents a supported language code.
type Lang string
const (
EN Lang = "en"
ZH Lang = "zh"
)
// translations holds all UI strings keyed by language then translation key.
var translations = map[Lang]map[string]string{
EN: {
// Nav
"site_title": "Go Blog",
"home": "Home",
"login": "Login",
"dashboard": "Dashboard",
"logout": "Logout",
// Home page
"home_welcome": "Welcome to Go Blog",
"home_subtitle": "A simple, fast blog engine built with Go, Gin, and Tailwind CSS.",
"home_sign_in": "Sign In",
"home_to_dash": "Dashboard",
"home_latest": "Latest Posts",
"home_read_more": "Read more",
"home_post1_tit": "Getting Started",
"home_post1_dsc": "Welcome to your new blog! This is a placeholder post. Start writing to see your content here.",
"home_post2_tit": "Hello World",
"home_post2_dsc": "Blog posts will appear here once you start publishing from the admin dashboard.",
"home_post3_tit": "Built with Go",
"home_post3_dsc": "This blog engine uses Go, Gin web framework, GORM, and Tailwind CSS for a modern experience.",
"home_no_posts": "No published posts yet.",
// Login page
"login_title": "Sign In",
"login_username": "Username",
"login_password": "Password",
"login_ph_user": "Enter your username",
"login_ph_pass": "Enter your password",
"login_submit": "Sign In",
"login_error": "Invalid username or password.",
"login_required": "Please fill in all fields.",
// Dashboard
"dash_title": "Dashboard",
"dash_welcome": "Welcome back,",
"dash_posts": "Posts",
"dash_pages": "Pages",
"dash_users": "Users",
"dash_published": "Published",
"dash_mgmt_title": "Blog Management",
"dash_mgmt_desc": "Post management, categories, and settings will appear here in future updates.",
"dash_new_article": "New Article",
"dash_page_title": "Dashboard",
// Footer
"footer_text": "© 2026 Go Blog. Powered by Go & Gin.",
// Page titles
"page_home": "Home",
"page_login": "Login",
// Language switcher
"lang_switch": "中文",
// Profile dropdown & page
"profile": "Profile",
"admin_panel": "Admin Panel",
"my_articles": "My Articles",
"profile_title": "Edit Profile",
"profile_avatar": "Avatar",
"profile_change_avatar": "Change Avatar",
"profile_display_name": "Display Name",
"profile_gender": "Gender",
"profile_birthday": "Birthday",
"profile_email": "Email",
"profile_change_password": "Change Password",
"profile_current_password": "Current Password",
"profile_new_password": "New Password",
"profile_save": "Save Changes",
"profile_saved": "Profile updated.",
"profile_wrong_password": "Current password is incorrect.",
"profile_upload_invalid": "File type not allowed.",
"profile_upload_disabled": "Uploads are currently disabled.",
"profile_upload_too_large": "File is too large. Limit: %s",
"gender_male": "Male",
"gender_female": "Female",
"gender_other": "Other",
// Avatar cropping
"crop_avatar_title": "Crop Avatar",
"crop_cancel": "Cancel",
"crop_confirm": "Confirm",
"crop_uploading": "Uploading...",
"crop_success": "Avatar updated.",
"crop_error": "Failed to upload avatar. Please try again.",
// Article creation
"article_create_title": "Create Article",
"article_field_title": "Title",
"article_title": "Title",
"article_field_slug": "Slug",
"article_slug": "Slug",
"article_slug_hint": "Auto-generated from title if empty",
"article_slug_help": "Auto-generated from title if empty",
"article_field_summary": "Summary",
"article_summary": "Summary",
"article_field_content": "Content",
"article_content": "Content",
"article_field_cover": "Cover Image URL",
"article_cover": "Cover Image URL",
"article_cover_help": "Optional cover image URL",
"article_field_status": "Status",
"article_status": "Status",
"article_draft": "Draft",
"article_published": "Published",
"article_field_is_top": "Pin to top",
"article_is_top": "Pin to top",
"article_save_draft": "Save Draft",
"article_save": "Save",
"article_cancel": "Cancel",
"article_publish": "Publish",
"article_created": "Article created successfully.",
"article_error": "Failed to create article.",
"article_new": "New Article",
"article_title_required": "Title is required.",
"article_content_required": "Content is required.",
"article_back_home": "Back to Home",
"article_not_found": "Article not found.",
"article_attachments": "Attachments",
"article_upload": "Upload",
"article_att_name": "File",
"article_att_size": "Size",
"article_att_insert": "Insert",
"article_att_set_cover": "Set as Cover",
"article_att_cover_set": "Cover URL set.",
"article_att_pick": "Please choose a file.",
"article_att_uploading": "Uploading...",
"article_att_error": "Upload failed. Please try again.",
"article_att_delete_confirm": "Delete this attachment?",
// Article management
"article_list_title": "Articles",
"my_articles_title": "My Articles",
"article_edit_title": "Edit Article",
"article_manage": "Manage Articles",
"article_edit": "Edit",
"article_delete": "Delete",
"article_delete_confirm": "Delete this article?",
"article_updated": "Article updated.",
"article_deleted": "Article deleted.",
"article_archived": "Archived",
"article_col_title": "Title",
"article_col_status": "Status",
"article_col_published": "Published",
"article_col_actions": "Actions",
// Settings (platform configuration)
"settings_nav": "Platform Settings",
"settings_saved": "Settings saved.",
"settings_site_title": "Site Settings",
"settings_site_desc": "Logo, top-left title, header banner, and footer text.",
"settings_logo": "Logo",
"settings_logo_url": "Logo URL (external link)",
"settings_logo_upload": "Or upload a logo image",
"settings_logo_clear": "Remove current logo",
"settings_favicon": "Favicon",
"settings_favicon_url": "Favicon URL (external link)",
"settings_favicon_current": "Current favicon",
"settings_favicon_hint": "Recommended: .ico, .png or .svg format, 32x32 or 16x16 pixels",
"settings_favicon_clear": "Remove current favicon",
"settings_logo_text_zh": "Site Title (Chinese)",
"settings_logo_text_en": "Site Title (English)",
"settings_header_text_zh": "Header Banner Text (Chinese)",
"settings_header_text_en": "Header Banner Text (English)",
"settings_home_welcome_zh": "Home Welcome Heading (Chinese)",
"settings_home_welcome_en": "Home Welcome Heading (English)",
"settings_home_subtitle_zh": "Home Subtitle (Chinese)",
"settings_home_subtitle_en": "Home Subtitle (English)",
"settings_footer_text_zh": "Footer Text (Chinese)",
"settings_footer_text_en": "Footer Text (English)",
"settings_leave_blank": "Leave blank to use the built-in default.",
"settings_save": "Save",
"settings_upload_title": "Upload Settings",
"settings_upload_desc": "Attachment upload policy and permitted file types.",
"settings_uploads_enabled":"Enable attachments",
"settings_default_size": "Default max size (MB)",
"settings_storage_dir": "Storage sub-directory",
"settings_file_types": "Permitted File Types",
"settings_add_type": "Add File Type",
"settings_extension": "Extension",
"settings_mime": "MIME Type",
"settings_category": "Category",
"settings_max_size": "Max Size (MB)",
"settings_enabled": "Enabled",
"settings_actions": "Actions",
"settings_toggle": "Toggle",
"settings_delete": "Delete",
"settings_update": "Update",
"settings_download_title": "Download Settings",
"settings_download_desc": "Base URLs used to build attachment download links.",
"settings_add_url": "Add Base URL",
"settings_url_name": "Name",
"settings_base_url": "Base URL",
"settings_priority": "Priority",
"settings_is_default": "Default",
"settings_set_default": "Set Default",
"cat_image": "Image",
"cat_document": "Document",
"cat_archive": "Archive",
"cat_video": "Video",
"cat_other": "Other",
// Comments
"comments_title": "Comments",
"comments_count": "%d Comments",
"comments_empty": "No comments yet. Be the first to comment.",
"comments_reply": "Reply",
"comments_cancel_reply": "Cancel reply",
"comments_replying_to": "Replying to %s",
"comments_name": "Name",
"comments_email": "Email",
"comments_email_hint": "Used for your Gravatar avatar; never shown publicly.",
"comments_website": "Website (optional)",
"comments_content": "Comment",
"comments_content_ph": "Markdown is supported...",
"comments_private": "Private comment",
"comments_private_hint": "Only you and the administrator can see this.",
"comments_preview": "Preview",
"comments_edit": "Edit",
"comments_emoji": "Emoji",
"comments_markdown_help": "Markdown help",
"comments_submit": "Post Comment",
"comments_posted": "Comment posted.",
"comments_pending_notice": "Your comment is awaiting moderation.",
"comments_disabled": "Comments are disabled.",
"comments_guests_disabled": "You must sign in to comment.",
"comments_required_name": "Name is required.",
"comments_required_email": "Email is required.",
"comments_required_content":"Comment is required.",
"comments_invalid_email": "Please enter a valid email address.",
"comments_invalid_url": "Please enter a valid URL.",
"comments_too_long": "Comment is too long (max %d characters).",
"comments_pending": "Pending",
"comments_approved": "Approved",
"comments_rejected": "Rejected",
"comments_private_badge": "Private",
"comments_markdown_bold": "**bold**",
"comments_markdown_italic": "*italic*",
"comments_markdown_code": "`code`",
"comments_markdown_link": "[text](url)",
"comments_markdown_quote": "> quote",
// Admin: comments
"admin_comments": "Comments",
"comment_manage": "Manage Comments",
"admin_comments_title": "Comments",
"comment_status_pending": "Pending",
"comment_status_approved": "Approved",
"comment_status_rejected": "Rejected",
"comment_status_all": "All",
"comment_approve": "Approve",
"comment_reject": "Reject",
"comment_delete": "Delete",
"comment_delete_confirm": "Delete this comment?",
"comment_col_author": "Author",
"comment_col_article": "Article",
"comment_col_content": "Content",
"comment_col_status": "Status",
"comment_col_time": "Time",
"comment_col_actions": "Actions",
"comment_empty": "No comments.",
"comment_approved": "Comment approved.",
"comment_rejected": "Comment rejected.",
"comment_deleted": "Comment deleted.",
// Admin: comment settings
"comment_settings_title": "Comment Settings",
"comment_settings_desc": "Control whether comments are enabled and how they are moderated.",
"comment_settings_enabled": "Enable comments",
"comment_settings_allow_guest": "Allow anonymous comments",
"comment_settings_guest_approval": "Require approval for guest comments",
"comment_settings_use_gravatar": "Use Gravatar avatars",
"comment_settings_use_gravatar_hint": "When off, avatars show the author's initial on a colored background.",
// Admin: user management
"admin_users": "Users",
"admin_users_title": "Users",
"user_list_title": "User Management",
"user_new": "New User",
"user_create_title": "Create User",
"user_edit_title": "Edit User",
"user_col_username": "Username",
"user_col_display": "Display Name",
"user_col_email": "Email",
"user_col_role": "Role",
"user_col_status": "Status",
"user_col_created": "Created",
"user_col_actions": "Actions",
"user_username": "Username",
"user_password": "Password",
"user_password_hint": "Leave blank to keep the current password.",
"user_display_name": "Display Name",
"user_email": "Email",
"user_gender": "Gender",
"user_birthday": "Birthday",
"user_role": "Role",
"user_status": "Status",
"role_admin": "Admin",
"role_author": "Author",
"status_normal": "Normal",
"status_disabled": "Disabled",
"status_locked": "Locked",
"status_unactivated": "Unactivated",
"user_created": "User created.",
"user_updated": "User updated.",
"user_deleted": "User deleted.",
"user_delete_confirm": "Delete this user?",
"user_empty": "No users.",
"user_username_required": "Username is required.",
"user_password_required": "Password is required.",
"user_username_exists": "Username already exists.",
"user_cannot_delete_self": "You cannot delete your own account.",
"user_cannot_disable_self": "You cannot disable or lock your own account.",
"user_cannot_remove_last_admin": "Cannot remove the last administrator.",
"dash_user_mgmt": "Manage Users",
// Analytics
"analytics_views_title": "Reading Analytics",
"analytics_views_desc": "Track article views, identify unique visitors and detect bots.",
"analytics_stats_total": "Total Views",
"analytics_stats_human_views": "Human Views",
"analytics_stats_bot_views": "Bot Views",
"analytics_stats_unique_ips": "Unique IPs",
"analytics_stats_unique_users": "Unique Users",
"analytics_article_stats": "Article Statistics (Top 20)",
"analytics_col_article": "Article",
"analytics_col_total_views": "Total Views",
"analytics_col_human_views": "Human",
"analytics_col_bot_views": "Bots",
"analytics_col_unique_ips": "Unique IPs",
"analytics_col_time": "Time",
"analytics_col_user": "User",
"analytics_col_ip": "IP Address",
"analytics_col_user_agent": "User Agent",
"analytics_col_is_bot": "Type",
"analytics_filters": "Filters",
"analytics_filter_article": "Article Title",
"analytics_filter_article_placeholder": "Search article title",
"analytics_filter_ip": "IP Address",
"analytics_filter_ip_placeholder": "Search by IP",
"analytics_filter_show_bots": "Show Bots",
"analytics_include_bots": "Include bot traffic",
"analytics_apply_filters": "Apply Filters",
"analytics_recent_views": "Recent Views",
"analytics_bot": "Bot",
"analytics_human": "Human",
"analytics_anonymous": "Anonymous",
"analytics_article_deleted": "(Deleted)",
"analytics_no_data": "No data available.",
"analytics_no_views": "No view records found.",
"analytics_showing": "Showing",
"analytics_of": "of",
"analytics_load_more": "Load More",
},
ZH: {
// 导航
"site_title": "Go 博客",
"home": "首页",
"login": "登录",
"dashboard": "后台",
"logout": "退出",
// 首页
"home_welcome": "欢迎来到 Go Blog",
"home_subtitle": "一个使用 Go、Gin 和 Tailwind CSS 构建的简洁快速的博客引擎。",
"home_sign_in": "登录",
"home_to_dash": "后台管理",
"home_latest": "最新文章",
"home_read_more": "阅读全文",
"home_post1_tit": "入门指南",
"home_post1_dsc": "欢迎来到你的新博客!这是一篇占位文章。开始写作后,你的内容将显示在这里。",
"home_post2_tit": "你好,世界",
"home_post2_dsc": "当你从后台管理面板发布文章后,博客文章将显示在这里。",
"home_post3_tit": "使用 Go 构建",
"home_post3_dsc": "此博客引擎使用 Go、Gin Web 框架、GORM 和 Tailwind CSS 构建,提供现代化的体验。",
"home_no_posts": "暂无已发布的文章。",
// 登录页
"login_title": "登录",
"login_username": "用户名",
"login_password": "密码",
"login_ph_user": "请输入用户名",
"login_ph_pass": "请输入密码",
"login_submit": "登录",
"login_error": "用户名或密码错误。",
"login_required": "请填写所有字段。",
// 后台
"dash_title": "后台管理",
"dash_welcome": "欢迎回来,",
"dash_posts": "文章",
"dash_pages": "页面",
"dash_users": "用户",
"dash_published": "已发布",
"dash_mgmt_title": "博客管理",
"dash_mgmt_desc": "文章管理、分类和设置将在后续版本中添加。",
"dash_new_article": "新建文章",
"dash_page_title": "后台管理",
// 页脚
"footer_text": "© 2026 Go Blog。由 Go & Gin 驱动。",
"page_home": "首页",
"page_login": "登录",
// 语言切换
"lang_switch": "English",
// 个人中心下拉菜单 & 页面
"profile": "个人信息",
"admin_panel": "后台管理",
"my_articles": "我的文章",
"profile_title": "编辑个人信息",
"profile_avatar": "头像",
"profile_change_avatar": "更换头像",
"profile_display_name": "显示名称",
"profile_gender": "性别",
"profile_birthday": "生日",
"profile_email": "邮箱",
"profile_change_password": "修改密码",
"profile_current_password": "当前密码",
"profile_new_password": "新密码",
"profile_save": "保存修改",
"profile_saved": "个人信息已更新。",
"profile_wrong_password": "当前密码错误。",
"profile_upload_invalid": "不允许的文件类型。",
"profile_upload_disabled": "上传功能已关闭。",
"profile_upload_too_large": "文件过大。限制:%s",
"gender_male": "男",
"gender_female": "女",
"gender_other": "其他",
// 头像裁剪
"crop_avatar_title": "裁剪头像",
"crop_cancel": "取消",
"crop_confirm": "确认",
"crop_uploading": "上传中...",
"crop_success": "头像已更新。",
"crop_error": "头像上传失败,请重试。",
// 文章创建
"article_create_title": "新建文章",
"article_field_title": "标题",
"article_title": "标题",
"article_field_slug": "Slug",
"article_slug": "Slug",
"article_slug_hint": "留空则从标题自动生成",
"article_slug_help": "留空则从标题自动生成",
"article_field_summary": "摘要",
"article_summary": "摘要",
"article_field_content": "正文",
"article_content": "正文",
"article_field_cover": "封面图 URL",
"article_cover": "封面图 URL",
"article_cover_help": "可选的封面图片链接",
"article_field_status": "状态",
"article_status": "状态",
"article_draft": "草稿",
"article_published": "已发布",
"article_field_is_top": "置顶",
"article_is_top": "置顶",
"article_save_draft": "保存草稿",
"article_save": "保存",
"article_cancel": "取消",
"article_publish": "发布",
"article_created": "文章创建成功。",
"article_error": "创建文章失败。",
"article_new": "新建文章",
"article_title_required": "标题不能为空。",
"article_content_required": "正文不能为空。",
"article_back_home": "返回首页",
"article_not_found": "文章不存在。",
"article_attachments": "附件",
"article_upload": "上传",
"article_att_name": "文件",
"article_att_size": "大小",
"article_att_insert": "插入正文",
"article_att_set_cover": "设为封面",
"article_att_cover_set": "已设为封面。",
"article_att_pick": "请先选择文件。",
"article_att_uploading": "上传中...",
"article_att_error": "上传失败,请重试。",
"article_att_delete_confirm": "删除该附件?",
// 文章管理
"article_list_title": "文章管理",
"my_articles_title": "我的文章",
"article_edit_title": "编辑文章",
"article_manage": "文章管理",
"article_edit": "编辑",
"article_delete": "删除",
"article_delete_confirm": "确认删除这篇文章?",
"article_updated": "文章已更新。",
"article_deleted": "文章已删除。",
"article_archived": "已归档",
"article_col_title": "标题",
"article_col_status": "状态",
"article_col_published": "发布时间",
"article_col_actions": "操作",
// 平台设置
"settings_nav": "平台设置",
"settings_saved": "设置已保存。",
"settings_site_title": "站点设置",
"settings_site_desc": "Logo、左上角标题、顶部横幅文本和页脚文本。",
"settings_logo": "Logo",
"settings_logo_url": "Logo 链接(外链地址)",
"settings_logo_upload": "或上传 Logo 图片",
"settings_logo_clear": "移除当前 Logo",
"settings_favicon": "网站图标(Favicon",
"settings_favicon_url": "Favicon 链接(外链地址)",
"settings_favicon_current": "当前 Favicon",
"settings_favicon_hint": "推荐:.ico、.png 或 .svg 格式,32x32 或 16x16 像素",
"settings_favicon_clear": "移除当前 Favicon",
"settings_logo_text_zh": "站点标题(中文)",
"settings_logo_text_en": "站点标题(英文)",
"settings_header_text_zh": "顶部横幅文本(中文)",
"settings_header_text_en": "顶部横幅文本(英文)",
"settings_home_welcome_zh": "主页欢迎标题(中文)",
"settings_home_welcome_en": "主页欢迎标题(英文)",
"settings_home_subtitle_zh": "主页副标题(中文)",
"settings_home_subtitle_en": "主页副标题(英文)",
"settings_footer_text_zh": "页脚文本(中文)",
"settings_footer_text_en": "页脚文本(英文)",
"settings_leave_blank": "留空则使用内置默认值。",
"settings_save": "保存",
"settings_upload_title": "上传设置",
"settings_upload_desc": "附件上传策略与允许的文件类型。",
"settings_uploads_enabled":"启用附件上传",
"settings_default_size": "默认最大大小(MB",
"settings_storage_dir": "存储子目录",
"settings_file_types": "允许的文件类型",
"settings_add_type": "添加文件类型",
"settings_extension": "扩展名",
"settings_mime": "MIME 类型",
"settings_category": "分组",
"settings_max_size": "最大大小(MB",
"settings_enabled": "启用",
"settings_actions": "操作",
"settings_toggle": "切换",
"settings_delete": "删除",
"settings_update": "更新",
"settings_download_title": "下载设置",
"settings_download_desc": "用于拼接附件下载链接的基础地址。",
"settings_add_url": "添加基础地址",
"settings_url_name": "名称",
"settings_base_url": "基础地址",
"settings_priority": "优先级",
"settings_is_default": "默认",
"settings_set_default": "设为默认",
"cat_image": "图片",
"cat_document": "文档",
"cat_archive": "压缩包",
"cat_video": "视频",
"cat_other": "其他",
// 评论
"comments_title": "评论",
"comments_count": "%d 条评论",
"comments_empty": "暂无评论,快来抢沙发吧。",
"comments_reply": "回复",
"comments_cancel_reply": "取消回复",
"comments_replying_to": "回复 %s",
"comments_name": "名称",
"comments_email": "邮箱",
"comments_email_hint": "用于显示 Gravatar 头像,不会公开。",
"comments_website": "网址(可选)",
"comments_content": "评论内容",
"comments_content_ph": "支持 Markdown 语法...",
"comments_private": "私密评论",
"comments_private_hint": "仅你和管理员可见。",
"comments_preview": "预览",
"comments_edit": "编辑",
"comments_emoji": "表情",
"comments_markdown_help": "Markdown 帮助",
"comments_submit": "发表评论",
"comments_posted": "评论已发表。",
"comments_pending_notice": "你的评论正在等待审核。",
"comments_disabled": "评论功能已关闭。",
"comments_guests_disabled": "请先登录后再评论。",
"comments_required_name": "请填写名称。",
"comments_required_email": "请填写邮箱。",
"comments_required_content":"请填写评论内容。",
"comments_invalid_email": "请输入有效的邮箱地址。",
"comments_invalid_url": "请输入有效的网址。",
"comments_too_long": "评论内容过长(最多 %d 字)。",
"comments_pending": "待审核",
"comments_approved": "已通过",
"comments_rejected": "已拒绝",
"comments_private_badge": "私密",
"comments_markdown_bold": "**粗体**",
"comments_markdown_italic": "*斜体*",
"comments_markdown_code": "`代码`",
"comments_markdown_link": "[文本](网址)",
"comments_markdown_quote": "> 引用",
// 后台:评论
"admin_comments": "评论管理",
"comment_manage": "评论管理",
"admin_comments_title": "评论管理",
"comment_status_pending": "待审核",
"comment_status_approved": "已通过",
"comment_status_rejected": "已拒绝",
"comment_status_all": "全部",
"comment_approve": "通过",
"comment_reject": "拒绝",
"comment_delete": "删除",
"comment_delete_confirm": "删除该评论?",
"comment_col_author": "评论者",
"comment_col_article": "文章",
"comment_col_content": "内容",
"comment_col_status": "状态",
"comment_col_time": "时间",
"comment_col_actions": "操作",
"comment_empty": "暂无评论。",
"comment_approved": "评论已通过。",
"comment_rejected": "评论已拒绝。",
"comment_deleted": "评论已删除。",
// 后台:评论设置
"comment_settings_title": "评论设置",
"comment_settings_desc": "控制是否启用评论以及评论的审核方式。",
"comment_settings_enabled": "启用评论",
"comment_settings_allow_guest": "允许匿名评论",
"comment_settings_guest_approval": "非登录用户评论需审核",
"comment_settings_use_gravatar": "使用 Gravatar 头像",
"comment_settings_use_gravatar_hint": "关闭后,头像将显示作者名称首字母的彩色占位。",
// 后台:用户管理
"admin_users": "用户",
"admin_users_title": "用户",
"user_list_title": "用户管理",
"user_new": "新建用户",
"user_create_title": "新建用户",
"user_edit_title": "编辑用户",
"user_col_username": "用户名",
"user_col_display": "显示名称",
"user_col_email": "邮箱",
"user_col_role": "角色",
"user_col_status": "状态",
"user_col_created": "创建时间",
"user_col_actions": "操作",
"user_username": "用户名",
"user_password": "密码",
"user_password_hint": "留空则保持原密码不变。",
"user_display_name": "显示名称",
"user_email": "邮箱",
"user_gender": "性别",
"user_birthday": "生日",
"user_role": "角色",
"user_status": "状态",
"role_admin": "管理员",
"role_author": "作者",
"status_normal": "正常",
"status_disabled": "禁用",
"status_locked": "锁定",
"status_unactivated": "未激活",
"user_created": "用户已创建。",
"user_updated": "用户已更新。",
"user_deleted": "用户已删除。",
"user_delete_confirm": "确认删除该用户?",
"user_empty": "暂无用户。",
"user_username_required": "请填写用户名。",
"user_password_required": "请填写密码。",
"user_username_exists": "用户名已存在。",
"user_cannot_delete_self": "不能删除自己的账号。",
"user_cannot_disable_self": "不能禁用或锁定自己的账号。",
"user_cannot_remove_last_admin": "不能移除最后一个管理员。",
"dash_user_mgmt": "用户管理",
// 阅读统计
"analytics_views_title": "阅读统计",
"analytics_views_desc": "追踪文章阅读量,识别独立访客和爬虫。",
"analytics_stats_total": "总阅读量",
"analytics_stats_human_views": "真人阅读",
"analytics_stats_bot_views": "爬虫访问",
"analytics_stats_unique_ips": "独立IP",
"analytics_stats_unique_users": "独立用户",
"analytics_article_stats": "文章统计(前20篇)",
"analytics_col_article": "文章",
"analytics_col_total_views": "总阅读量",
"analytics_col_human_views": "真人",
"analytics_col_bot_views": "爬虫",
"analytics_col_unique_ips": "独立IP",
"analytics_col_time": "时间",
"analytics_col_user": "用户",
"analytics_col_ip": "IP地址",
"analytics_col_user_agent": "User Agent",
"analytics_col_is_bot": "类型",
"analytics_filters": "筛选条件",
"analytics_filter_article": "文章标题",
"analytics_filter_article_placeholder": "搜索文章标题",
"analytics_filter_ip": "IP地址",
"analytics_filter_ip_placeholder": "按IP搜索",
"analytics_filter_show_bots": "显示爬虫",
"analytics_include_bots": "包含爬虫流量",
"analytics_apply_filters": "应用筛选",
"analytics_recent_views": "最近访问记录",
"analytics_bot": "爬虫",
"analytics_human": "真人",
"analytics_anonymous": "匿名用户",
"analytics_article_deleted": "(已删除)",
"analytics_no_data": "暂无数据。",
"analytics_no_views": "未找到访问记录。",
"analytics_showing": "显示",
"analytics_of": "共",
"analytics_load_more": "加载更多",
},
}
// T returns a copy of the translation map for the given language.
// Falls back to English if the language is not supported.
func T(l Lang) map[string]string {
t, ok := translations[l]
if !ok {
t = translations[EN]
}
// Return a shallow copy so callers cannot mutate the original map values.
out := make(map[string]string, len(t))
for k, v := range t {
out[k] = v
}
return out
}
// DetectLang parses the Accept-Language header and returns the best matching
// supported language. Returns EN for unsupported languages.
func DetectLang(acceptHeader string) Lang {
if acceptHeader == "" {
return EN
}
// Accept-Language format: "zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7"
// Split by comma, then extract primary language from each entry.
entries := strings.Split(acceptHeader, ",")
for _, entry := range entries {
// Trim spaces and remove quality values.
entry = strings.TrimSpace(entry)
if idx := strings.Index(entry, ";"); idx != -1 {
entry = entry[:idx]
}
// Extract primary language (before any "-" subtag).
primary := strings.ToLower(entry)
if idx := strings.Index(primary, "-"); idx != -1 {
primary = primary[:idx]
}
switch primary {
case "zh":
return ZH
case "en":
return EN
}
}
return EN
}