feat(i18n): 为评论系统添加国际化支持
- 在管理后台引入 vue-i18n 并添加多语言文件 - 为前端评论组件添加翻译功能,支持自动语言检测 - 在功能设置中新增管理后台和组件语言配置选项 - 更新 API 接口以支持语言设置存储 - 优化菜单项文本溢出显示样式
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "docs",
|
||||
"name": "cwd-docs",
|
||||
"description": "CWD 评论系统文档",
|
||||
"type": "module",
|
||||
"license": "Apache-2.0",
|
||||
@@ -7,7 +7,7 @@
|
||||
"dev": "vitepress dev",
|
||||
"build:docs": "vitepress build",
|
||||
"build:widget": "cd widget && npm install && npm run build",
|
||||
"build": "npm run build:widget && node copy-cwd-to-public.js && npm run build:docs",
|
||||
"build": "npm run build:widget && node build.js && npm run build:docs",
|
||||
"preview": "vitepress preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Component } from './Component.js';
|
||||
export class AdminAuthModal extends Component {
|
||||
constructor(container, props = {}) {
|
||||
super(container, props);
|
||||
this.t = props.t || ((k) => k);
|
||||
this.state = {
|
||||
key: '',
|
||||
error: '',
|
||||
@@ -24,16 +25,16 @@ export class AdminAuthModal extends Component {
|
||||
this.createElement('div', {
|
||||
className: 'cwd-modal',
|
||||
children: [
|
||||
this.createTextElement('h3', '管理员身份验证', 'cwd-modal-title'),
|
||||
this.createTextElement('h3', this.t('verifyAdminTitle'), 'cwd-modal-title'),
|
||||
this.createElement('div', {
|
||||
className: 'cwd-modal-body',
|
||||
children: [
|
||||
this.createTextElement('p', '检测到管理员邮箱,请输入密钥以继续。', 'cwd-modal-desc'),
|
||||
this.createTextElement('p', this.t('verifyAdminDesc'), 'cwd-modal-desc'),
|
||||
this.createElement('input', {
|
||||
className: `cwd-form-input ${error ? 'cwd-input-error' : ''}`,
|
||||
attributes: {
|
||||
type: 'password',
|
||||
placeholder: '请输入管理员密钥',
|
||||
placeholder: this.t('adminKeyPlaceholder'),
|
||||
value: key,
|
||||
disabled: loading,
|
||||
onInput: (e) => this.setState({ key: e.target.value, error: '' }),
|
||||
@@ -50,7 +51,7 @@ export class AdminAuthModal extends Component {
|
||||
children: [
|
||||
this.createElement('button', {
|
||||
className: 'cwd-btn cwd-btn-secondary',
|
||||
text: '取消',
|
||||
text: this.t('cancel'),
|
||||
attributes: {
|
||||
type: 'button',
|
||||
disabled: loading,
|
||||
@@ -59,7 +60,7 @@ export class AdminAuthModal extends Component {
|
||||
}),
|
||||
this.createElement('button', {
|
||||
className: 'cwd-btn cwd-btn-primary',
|
||||
text: loading ? '验证中...' : '验证',
|
||||
text: loading ? this.t('verifying') : this.t('verify'),
|
||||
attributes: {
|
||||
type: 'button',
|
||||
disabled: loading || !key,
|
||||
@@ -116,7 +117,7 @@ export class AdminAuthModal extends Component {
|
||||
|
||||
if (this.elements.submitBtn) {
|
||||
this.elements.submitBtn.disabled = loading || !key;
|
||||
this.elements.submitBtn.textContent = loading ? '验证中...' : '验证';
|
||||
this.elements.submitBtn.textContent = loading ? this.t('verifying') : this.t('verify');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +127,7 @@ export class AdminAuthModal extends Component {
|
||||
this.setState({ loading: true });
|
||||
this.props.onSubmit(this.state.key)
|
||||
.catch(err => {
|
||||
this.setState({ error: err.message || '验证失败', loading: false });
|
||||
this.setState({ error: err.message || this.t('verifyFailed'), loading: false });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export class CommentForm extends Component {
|
||||
*/
|
||||
constructor(container, props = {}) {
|
||||
super(container, props);
|
||||
this.t = props.t || ((k) => k);
|
||||
// 确保 localForm 的各个字段都有初始值
|
||||
const initialForm = props.form || {};
|
||||
this.state = {
|
||||
@@ -53,7 +54,7 @@ export class CommentForm extends Component {
|
||||
},
|
||||
children: [
|
||||
// 标题
|
||||
this.createTextElement('h3', '发表评论', 'cwd-form-title'),
|
||||
this.createTextElement('h3', this.t('formTitle'), 'cwd-form-title'),
|
||||
|
||||
// 表单字段
|
||||
this.createElement('div', {
|
||||
@@ -64,19 +65,19 @@ export class CommentForm extends Component {
|
||||
className: 'cwd-form-row',
|
||||
children: [
|
||||
// 昵称
|
||||
this.createFormField('昵称 *', 'text', 'name', localForm.name, formErrors.name),
|
||||
this.createFormField(this.t('nickname'), 'text', 'name', localForm.name, formErrors.name),
|
||||
// 邮箱
|
||||
this.createElement('div', {
|
||||
className: 'cwd-form-field-wrapper',
|
||||
children: [
|
||||
this.createFormField('邮箱 *', 'email', 'email', localForm.email, formErrors.email),
|
||||
this.createFormField(this.t('email'), 'email', 'email', localForm.email, formErrors.email),
|
||||
isVerified
|
||||
? this.createElement('div', {
|
||||
className: 'cwd-admin-controls',
|
||||
children: [
|
||||
this.createElement('button', {
|
||||
className: 'cwd-btn-text',
|
||||
text: '退出验证',
|
||||
text: this.t('verifyAdmin'),
|
||||
attributes: {
|
||||
type: 'button',
|
||||
title: '清除管理员凭证',
|
||||
@@ -92,7 +93,7 @@ export class CommentForm extends Component {
|
||||
],
|
||||
}),
|
||||
// 网址
|
||||
this.createFormField('网址', 'url', 'url', localForm.url, formErrors.url),
|
||||
this.createFormField(this.t('website'), 'url', 'url', localForm.url, formErrors.url),
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -100,7 +101,7 @@ export class CommentForm extends Component {
|
||||
this.createElement('div', {
|
||||
className: 'cwd-form-field',
|
||||
children: [
|
||||
this.createTextElement('label', '写下你的评论...', 'cwd-form-label'),
|
||||
this.createTextElement('label', this.t('writeComment'), 'cwd-form-label'),
|
||||
this.createElement('textarea', {
|
||||
className: `cwd-form-textarea ${formErrors.content ? 'cwd-input-error' : ''}`,
|
||||
attributes: {
|
||||
@@ -129,7 +130,7 @@ export class CommentForm extends Component {
|
||||
style: localForm.content?.trim() ? '' : 'display:none;',
|
||||
onClick: () => this.togglePreview(),
|
||||
},
|
||||
text: this.state.showPreview ? '关闭' : '预览',
|
||||
text: this.state.showPreview ? this.t('close') : this.t('preview'),
|
||||
}),
|
||||
this.createElement('button', {
|
||||
className: 'cwd-btn cwd-btn-primary',
|
||||
@@ -137,7 +138,7 @@ export class CommentForm extends Component {
|
||||
type: 'submit',
|
||||
disabled: submitting || !canSubmit,
|
||||
},
|
||||
text: submitting ? '提交中...' : '提交评论',
|
||||
text: submitting ? this.t('submitting') : this.t('submit'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
@@ -209,7 +210,7 @@ export class CommentForm extends Component {
|
||||
const submitBtn = this.elements.root.querySelector('button[type="submit"]');
|
||||
if (submitBtn) {
|
||||
submitBtn.disabled = submitting || !canSubmit;
|
||||
submitBtn.textContent = submitting ? '提交中...' : '提交评论';
|
||||
submitBtn.textContent = submitting ? this.t('submitting') : this.t('submit');
|
||||
}
|
||||
|
||||
// 更新预览按钮状态
|
||||
@@ -224,9 +225,9 @@ export class CommentForm extends Component {
|
||||
if (previewContainer) {
|
||||
previewContainer.remove();
|
||||
}
|
||||
previewBtn.textContent = '预览';
|
||||
previewBtn.textContent = this.t('preview');
|
||||
} else {
|
||||
previewBtn.textContent = this.state.showPreview ? '关闭' : '预览';
|
||||
previewBtn.textContent = this.state.showPreview ? this.t('close') : this.t('preview');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,6 +417,7 @@ export class CommentForm extends Component {
|
||||
this.modal = null;
|
||||
}
|
||||
},
|
||||
t: this.t
|
||||
});
|
||||
this.modal.render();
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ export class CommentItem extends Component {
|
||||
*/
|
||||
constructor(container, props = {}) {
|
||||
super(container, props);
|
||||
this.t = props.t || ((k) => k);
|
||||
this.replyEditor = null;
|
||||
this.childCommentItems = []; // 缓存嵌套回复的 CommentItem 实例
|
||||
}
|
||||
@@ -103,7 +104,7 @@ export class CommentItem extends Component {
|
||||
// 显示回复目标
|
||||
...(comment.replyToAuthor
|
||||
? [
|
||||
this.createTextElement('span', ' 回复 ', 'cwd-reply-to-separator'),
|
||||
this.createTextElement('span', ` ${this.t('reply')} `, 'cwd-reply-to-separator'),
|
||||
this.createTextElement('span', comment.replyToAuthor, 'cwd-reply-to-author'),
|
||||
]
|
||||
: []),
|
||||
@@ -119,7 +120,7 @@ export class CommentItem extends Component {
|
||||
attributes: {
|
||||
onClick: () => this.handleReply(),
|
||||
},
|
||||
text: '回复',
|
||||
text: this.t('reply'),
|
||||
}),
|
||||
...(this.props.enableCommentLike !== false
|
||||
? [
|
||||
@@ -169,7 +170,7 @@ export class CommentItem extends Component {
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
this.createTextElement('span', formatRelativeTime(comment.created), 'cwd-comment-time'),
|
||||
this.createTextElement('span', formatRelativeTime(comment.created, this.t), 'cwd-comment-time'),
|
||||
],
|
||||
}),
|
||||
],
|
||||
@@ -220,6 +221,7 @@ export class CommentItem extends Component {
|
||||
onCancel: () => this.handleCancelReply(),
|
||||
onClearError: () => this.handleClearReplyError(),
|
||||
placeholder: this.props.replyPlaceholder,
|
||||
t: this.t
|
||||
});
|
||||
this.replyEditor.render();
|
||||
this.replyEditor.focus();
|
||||
@@ -253,6 +255,7 @@ export class CommentItem extends Component {
|
||||
onCancelReply: this.props.onCancelReply,
|
||||
onUpdateReplyContent: this.props.onUpdateReplyContent,
|
||||
onClearReplyError: this.props.onClearReplyError,
|
||||
t: this.t
|
||||
});
|
||||
replyItem.render();
|
||||
this.childCommentItems.push(replyItem);
|
||||
|
||||
@@ -106,7 +106,8 @@ export class CommentList extends Component {
|
||||
onCancelReply: () => this.handleCancelReply(),
|
||||
onUpdateReplyContent: (content) => this.handleUpdateReplyContent(content),
|
||||
onClearReplyError: () => this.handleClearReplyError(),
|
||||
onLikeComment: (commentId, isLike) => this.handleLikeComment(commentId, isLike)
|
||||
onLikeComment: (commentId, isLike) => this.handleLikeComment(commentId, isLike),
|
||||
t: this.props.t
|
||||
});
|
||||
commentItem.render();
|
||||
// 缓存 CommentItem 实例
|
||||
|
||||
@@ -20,6 +20,7 @@ export class ReplyEditor extends Component {
|
||||
*/
|
||||
constructor(container, props = {}) {
|
||||
super(container, props);
|
||||
this.t = props.t || ((k) => k);
|
||||
const { currentUser } = props;
|
||||
this.state = {
|
||||
content: props.content || '',
|
||||
@@ -41,7 +42,7 @@ export class ReplyEditor extends Component {
|
||||
this.createElement('div', {
|
||||
className: 'cwd-reply-header',
|
||||
children: [
|
||||
this.createTextElement('span', `回复 @${this.props.replyToAuthor}`, 'cwd-reply-to'),
|
||||
this.createTextElement('span', `${this.t('reply')} @${this.props.replyToAuthor}`, 'cwd-reply-to'),
|
||||
this.createElement('button', {
|
||||
className: 'cwd-btn-close',
|
||||
attributes: {
|
||||
@@ -62,9 +63,9 @@ export class ReplyEditor extends Component {
|
||||
style: 'margin-bottom: 12px;',
|
||||
},
|
||||
children: [
|
||||
this.createFormField('昵称 *', 'text', 'name', currentUser?.name),
|
||||
this.createFormField('邮箱 *', 'email', 'email', currentUser?.email),
|
||||
this.createFormField('网址', 'url', 'url', currentUser?.url),
|
||||
this.createFormField(this.t('nickname'), 'text', 'name', currentUser?.name),
|
||||
this.createFormField(this.t('email'), 'email', 'email', currentUser?.email),
|
||||
this.createFormField(this.t('website'), 'url', 'url', currentUser?.url),
|
||||
],
|
||||
}),
|
||||
]
|
||||
@@ -113,7 +114,7 @@ export class ReplyEditor extends Component {
|
||||
disabled: this.props.submitting || !this.state.content.trim(),
|
||||
onClick: () => this.togglePreview(),
|
||||
},
|
||||
text: this.state.showPreview ? '关闭' : '预览',
|
||||
text: this.state.showPreview ? this.t('close') : this.t('preview'),
|
||||
}),
|
||||
this.createElement('button', {
|
||||
className: 'cwd-btn cwd-btn-primary cwd-btn-small',
|
||||
@@ -122,7 +123,7 @@ export class ReplyEditor extends Component {
|
||||
disabled: this.props.submitting || !this.state.content.trim(),
|
||||
onClick: () => this.handleSubmit(),
|
||||
},
|
||||
text: this.props.submitting ? '提交中...' : '提交回复',
|
||||
text: this.props.submitting ? this.t('submitting') : this.t('submit'),
|
||||
}),
|
||||
this.createElement('button', {
|
||||
className: 'cwd-btn cwd-btn-secondary cwd-btn-small',
|
||||
@@ -131,7 +132,7 @@ export class ReplyEditor extends Component {
|
||||
disabled: this.props.submitting,
|
||||
onClick: () => this.handleCancel(),
|
||||
},
|
||||
text: '取消',
|
||||
text: this.t('cancel'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -9,6 +9,7 @@ import { CommentForm } from '@/components/CommentForm.js';
|
||||
import { CommentList } from '@/components/CommentList.js';
|
||||
import { ImagePreview } from '@/components/ImagePreview.js';
|
||||
import styles from '@/styles/main.css?inline';
|
||||
import { locales } from '@/locales/index.js';
|
||||
|
||||
/**
|
||||
* CWDComments 评论组件主类
|
||||
@@ -60,6 +61,20 @@ export class CWDComments {
|
||||
this._likeCountEl = null;
|
||||
|
||||
this._mounted = false;
|
||||
|
||||
this.localeData = locales['zh-CN'];
|
||||
this.t = this.t.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 翻译函数
|
||||
*/
|
||||
t(key, params = {}) {
|
||||
let text = this.localeData[key] || key;
|
||||
for (const [k, v] of Object.entries(params)) {
|
||||
text = text.replace(`{${k}}`, v);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,6 +124,7 @@ export class CWDComments {
|
||||
enableImageLightbox: typeof data.enableImageLightbox === 'boolean' ? data.enableImageLightbox : false,
|
||||
commentPlaceholder:
|
||||
typeof data.commentPlaceholder === 'string' ? data.commentPlaceholder : undefined,
|
||||
widgetLanguage: typeof data.widgetLanguage === 'string' ? data.widgetLanguage : undefined,
|
||||
};
|
||||
} catch (e) {
|
||||
return {};
|
||||
@@ -152,16 +168,44 @@ export class CWDComments {
|
||||
return currentHostname === domain || currentHostname.endsWith('.' + domain);
|
||||
});
|
||||
|
||||
// 设置语言
|
||||
let lang = serverConfig.widgetLanguage || 'auto';
|
||||
if (lang === 'auto' && typeof navigator !== 'undefined') {
|
||||
const browserLang = navigator.language || navigator.userLanguage;
|
||||
if (browserLang.toLowerCase().startsWith('en')) {
|
||||
lang = 'en-US';
|
||||
} else {
|
||||
lang = 'zh-CN';
|
||||
}
|
||||
}
|
||||
if (locales[lang]) {
|
||||
this.localeData = locales[lang];
|
||||
}
|
||||
|
||||
if (!isAllowed) {
|
||||
if (this.mountPoint) {
|
||||
this.mountPoint.innerHTML = `
|
||||
<div style="padding: 20px; text-align: center; color: #666; font-size: 14px; border: 1px solid #eee; border-radius: 8px; background: #f9f9f9;">
|
||||
当前域名 (${currentHostname}) 未获得评论组件调用授权
|
||||
${this.t('domainUnauthorized', { domain: currentHostname })}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// 即使没有域名限制,也需要设置语言
|
||||
let lang = serverConfig.widgetLanguage || 'auto';
|
||||
if (lang === 'auto' && typeof navigator !== 'undefined') {
|
||||
const browserLang = navigator.language || navigator.userLanguage;
|
||||
if (browserLang.toLowerCase().startsWith('en')) {
|
||||
lang = 'en-US';
|
||||
} else {
|
||||
lang = 'zh-CN';
|
||||
}
|
||||
}
|
||||
if (locales[lang]) {
|
||||
this.localeData = locales[lang];
|
||||
}
|
||||
}
|
||||
|
||||
if (serverConfig.avatarPrefix) {
|
||||
@@ -341,7 +385,7 @@ export class CWDComments {
|
||||
<path d="M12 21c-.4 0-.8-.1-1.1-.4L4.5 15C3 13.6 2 11.7 2 9.6 2 6.5 4.5 4 7.6 4c1.7 0 3.3.8 4.4 2.1C13.1 4.8 14.7 4 16.4 4 19.5 4 22 6.5 22 9.6c0 2.1-1 4-2.5 5.4l-6.4 5.6c-.3.3-.7.4-1.1.4z"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<div>已有 <span class="cwd-like-count">0</span>人喜欢~ </div>
|
||||
<div>${this.t('likes', { count: '<span class="cwd-like-count">0</span>' })}</div>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
@@ -366,6 +410,7 @@ export class CWDComments {
|
||||
adminEmail: this.config.adminEmail,
|
||||
onVerifyAdmin: (key) => this.api.verifyAdminKey(key),
|
||||
placeholder: this.config.commentPlaceholder,
|
||||
t: this.t
|
||||
});
|
||||
this.commentForm.render();
|
||||
}
|
||||
@@ -376,7 +421,7 @@ export class CWDComments {
|
||||
countHeading = document.createElement('h3');
|
||||
countHeading.className = 'cwd-comments-count';
|
||||
countHeading.innerHTML = `
|
||||
共 <span class="cwd-comments-count-number">0</span> 条评论
|
||||
${this.t('totalComments', { count: '<span class="cwd-comments-count-number">0</span>' })}
|
||||
`;
|
||||
if (this.formContainer && this.formContainer.parentNode === this.mountPoint) {
|
||||
this.mountPoint.insertBefore(countHeading, this.formContainer.nextSibling);
|
||||
@@ -424,6 +469,7 @@ export class CWDComments {
|
||||
this.store.likeComment(commentId, isLike);
|
||||
}
|
||||
},
|
||||
t: this.t
|
||||
});
|
||||
this.commentList.render();
|
||||
}
|
||||
|
||||
632
docs/widget/src/locales/index.js
Normal file
632
docs/widget/src/locales/index.js
Normal file
@@ -0,0 +1,632 @@
|
||||
export const locales = {
|
||||
'en-US': {
|
||||
submit: 'Submit',
|
||||
submitting: 'Submitting...',
|
||||
preview: 'Preview',
|
||||
close: 'Close',
|
||||
nickname: 'Name *',
|
||||
email: 'Email *',
|
||||
website: 'Website',
|
||||
writeComment: 'Write a comment...',
|
||||
reply: 'Reply',
|
||||
cancel: 'Cancel',
|
||||
admin: 'Admin',
|
||||
like: 'Like',
|
||||
liked: 'Liked',
|
||||
likes: '{count} Likes',
|
||||
comments: 'Comments',
|
||||
totalComments: '{count} Comments',
|
||||
domainUnauthorized: 'Domain ({domain}) not authorized',
|
||||
errorTitle: 'Error',
|
||||
successTitle: 'Success',
|
||||
verifyAdmin: 'Sign out',
|
||||
formTitle: 'Leave a Comment',
|
||||
loadMore: 'Load More',
|
||||
noComments: 'No comments yet',
|
||||
delete: 'Delete',
|
||||
confirmDelete: 'Are you sure you want to delete this comment?',
|
||||
deleteSuccess: 'Deleted successfully',
|
||||
deleteFailed: 'Failed to delete',
|
||||
adminKeyPlaceholder: 'Enter admin key',
|
||||
verifyAdminTitle: 'Admin Verification',
|
||||
verifyAdminDesc: 'Please enter admin key to continue',
|
||||
verify: 'Verify',
|
||||
verifying: 'Verifying...',
|
||||
verifyFailed: 'Verification failed, please try again',
|
||||
clearError: '✕',
|
||||
clearSuccess: '✕',
|
||||
'time.yesterday': 'Yesterday',
|
||||
'time.daysAgo': '{count} days ago',
|
||||
'time.hoursAgo': '{count} hours ago',
|
||||
'time.minutesAgo': '{count} minutes ago',
|
||||
'time.justNow': 'Just now',
|
||||
},
|
||||
'zh-CN': {
|
||||
submit: '提交评论',
|
||||
submitting: '提交中...',
|
||||
preview: '预览',
|
||||
close: '关闭',
|
||||
nickname: '昵称 *',
|
||||
email: '邮箱 *',
|
||||
website: '网址',
|
||||
writeComment: '写下你的评论...',
|
||||
reply: '回复',
|
||||
cancel: '取消',
|
||||
admin: '博主',
|
||||
like: '喜欢',
|
||||
liked: '已赞',
|
||||
likes: '{count}人喜欢',
|
||||
comments: '条评论',
|
||||
totalComments: '共 {count} 条评论',
|
||||
domainUnauthorized: '当前域名 ({domain}) 未获得评论组件调用授权',
|
||||
errorTitle: '错误',
|
||||
successTitle: '成功',
|
||||
verifyAdmin: '退出验证',
|
||||
formTitle: '发表评论',
|
||||
loadMore: '加载更多',
|
||||
noComments: '暂无评论',
|
||||
delete: '删除',
|
||||
confirmDelete: '确定删除这条评论吗?',
|
||||
deleteSuccess: '删除成功',
|
||||
deleteFailed: '删除失败',
|
||||
adminKeyPlaceholder: '输入密钥以设置或修改',
|
||||
verifyAdminTitle: '管理员验证',
|
||||
verifyAdminDesc: '请输入管理员密钥以继续',
|
||||
verify: '验证',
|
||||
verifying: '验证中...',
|
||||
verifyFailed: '验证失败,请重试',
|
||||
clearError: '✕',
|
||||
clearSuccess: '✕',
|
||||
'time.yesterday': '昨天',
|
||||
'time.daysAgo': '{count}天前',
|
||||
'time.hoursAgo': '{count}小时前',
|
||||
'time.minutesAgo': '{count}分钟前',
|
||||
'time.justNow': '刚刚',
|
||||
},
|
||||
'zh-TW': {
|
||||
submit: '提交評論',
|
||||
submitting: '提交中...',
|
||||
preview: '預覽',
|
||||
close: '關閉',
|
||||
nickname: '暱稱 *',
|
||||
email: '信箱 *',
|
||||
website: '網址',
|
||||
writeComment: '寫下你的評論...',
|
||||
reply: '回覆',
|
||||
cancel: '取消',
|
||||
admin: '站長',
|
||||
like: '喜歡',
|
||||
liked: '已讚',
|
||||
likes: '{count}人喜歡',
|
||||
comments: '條評論',
|
||||
totalComments: '共 {count} 條評論',
|
||||
domainUnauthorized: '當前域名 ({domain}) 未獲得評論組件調用授權',
|
||||
errorTitle: '錯誤',
|
||||
successTitle: '成功',
|
||||
verifyAdmin: '退出驗證',
|
||||
formTitle: '發表評論',
|
||||
loadMore: '加載更多',
|
||||
noComments: '暫無評論',
|
||||
delete: '刪除',
|
||||
confirmDelete: '確定刪除這條評論嗎?',
|
||||
deleteSuccess: '刪除成功',
|
||||
deleteFailed: '刪除失敗',
|
||||
adminKeyPlaceholder: '輸入密鑰以設置或修改',
|
||||
verifyAdminTitle: '管理員驗證',
|
||||
verifyAdminDesc: '請輸入管理員密鑰以繼續',
|
||||
verify: '驗證',
|
||||
verifying: '驗證中...',
|
||||
verifyFailed: '驗證失敗,請重試',
|
||||
clearError: '✕',
|
||||
clearSuccess: '✕',
|
||||
'time.yesterday': '昨天',
|
||||
'time.daysAgo': '{count}天前',
|
||||
'time.hoursAgo': '{count}小時前',
|
||||
'time.minutesAgo': '{count}分鐘前',
|
||||
'time.justNow': '剛剛',
|
||||
},
|
||||
es: {
|
||||
submit: 'Enviar',
|
||||
submitting: 'Enviando...',
|
||||
preview: 'Vista previa',
|
||||
close: 'Cerrar',
|
||||
nickname: 'Nombre *',
|
||||
email: 'Correo *',
|
||||
website: 'Sitio web',
|
||||
writeComment: 'Escribe un comentario...',
|
||||
reply: 'Responder',
|
||||
cancel: 'Cancelar',
|
||||
admin: 'Admin',
|
||||
like: 'Me gusta',
|
||||
liked: 'Te gusta',
|
||||
likes: '{count} Me gusta',
|
||||
comments: 'Comentarios',
|
||||
totalComments: '{count} Comentarios',
|
||||
domainUnauthorized: 'Dominio ({domain}) no autorizado',
|
||||
errorTitle: 'Error',
|
||||
successTitle: 'Éxito',
|
||||
verifyAdmin: 'Cerrar sesión',
|
||||
formTitle: 'Deja un comentario',
|
||||
loadMore: 'Cargar más',
|
||||
noComments: 'Sin comentarios aún',
|
||||
delete: 'Eliminar',
|
||||
confirmDelete: '¿Estás seguro de querer eliminar este comentario?',
|
||||
deleteSuccess: 'Eliminado con éxito',
|
||||
deleteFailed: 'Fallo al eliminar',
|
||||
adminKeyPlaceholder: 'Ingresa clave de admin',
|
||||
verifyAdminTitle: 'Verificación de Admin',
|
||||
verifyAdminDesc: 'Por favor ingresa la clave de admin para continuar',
|
||||
verify: 'Verificar',
|
||||
verifying: 'Verificando...',
|
||||
verifyFailed: 'Verificación fallida, intenta de nuevo',
|
||||
clearError: '✕',
|
||||
clearSuccess: '✕',
|
||||
'time.yesterday': 'Ayer',
|
||||
'time.daysAgo': 'Hace {count} días',
|
||||
'time.hoursAgo': 'Hace {count} horas',
|
||||
'time.minutesAgo': 'Hace {count} minutos',
|
||||
'time.justNow': 'Justo ahora',
|
||||
},
|
||||
pt: {
|
||||
submit: 'Enviar',
|
||||
submitting: 'Enviando...',
|
||||
preview: 'Prévia',
|
||||
close: 'Fechar',
|
||||
nickname: 'Nome *',
|
||||
email: 'Email *',
|
||||
website: 'Site',
|
||||
writeComment: 'Escreva um comentário...',
|
||||
reply: 'Responder',
|
||||
cancel: 'Cancelar',
|
||||
admin: 'Admin',
|
||||
like: 'Curtir',
|
||||
liked: 'Curtido',
|
||||
likes: '{count} Curtidas',
|
||||
comments: 'Comentários',
|
||||
totalComments: '{count} Comentários',
|
||||
domainUnauthorized: 'Domínio ({domain}) não autorizado',
|
||||
errorTitle: 'Erro',
|
||||
successTitle: 'Sucesso',
|
||||
verifyAdmin: 'Sair',
|
||||
formTitle: 'Deixe um comentário',
|
||||
loadMore: 'Carregar mais',
|
||||
noComments: 'Sem comentários ainda',
|
||||
delete: 'Excluir',
|
||||
confirmDelete: 'Tem certeza que deseja excluir este comentário?',
|
||||
deleteSuccess: 'Excluído com sucesso',
|
||||
deleteFailed: 'Falha ao excluir',
|
||||
adminKeyPlaceholder: 'Digite a chave de admin',
|
||||
verifyAdminTitle: 'Verificação de Admin',
|
||||
verifyAdminDesc: 'Por favor digite a chave de admin para continuar',
|
||||
verify: 'Verificar',
|
||||
verifying: 'Verificando...',
|
||||
verifyFailed: 'Verificação falhou, tente novamente',
|
||||
clearError: '✕',
|
||||
clearSuccess: '✕',
|
||||
'time.yesterday': 'Ontem',
|
||||
'time.daysAgo': 'Há {count} dias',
|
||||
'time.hoursAgo': 'Há {count} horas',
|
||||
'time.minutesAgo': 'Há {count} minutos',
|
||||
'time.justNow': 'Agora mesmo',
|
||||
},
|
||||
fr: {
|
||||
submit: 'Envoyer',
|
||||
submitting: 'Envoi...',
|
||||
preview: 'Aperçu',
|
||||
close: 'Fermer',
|
||||
nickname: 'Nom *',
|
||||
email: 'Email *',
|
||||
website: 'Site web',
|
||||
writeComment: 'Écrire un commentaire...',
|
||||
reply: 'Répondre',
|
||||
cancel: 'Annuler',
|
||||
admin: 'Admin',
|
||||
like: "J'aime",
|
||||
liked: 'Aimé',
|
||||
likes: "{count} J'aime",
|
||||
comments: 'Commentaires',
|
||||
totalComments: '{count} Commentaires',
|
||||
domainUnauthorized: 'Domaine ({domain}) non autorisé',
|
||||
errorTitle: 'Erreur',
|
||||
successTitle: 'Succès',
|
||||
verifyAdmin: 'Déconnexion',
|
||||
formTitle: 'Laisser un commentaire',
|
||||
loadMore: 'Charger plus',
|
||||
noComments: "Aucun commentaire pour l'instant",
|
||||
delete: 'Supprimer',
|
||||
confirmDelete: 'Êtes-vous sûr de vouloir supprimer ce commentaire ?',
|
||||
deleteSuccess: 'Supprimé avec succès',
|
||||
deleteFailed: 'Échec de la suppression',
|
||||
adminKeyPlaceholder: 'Entrer la clé admin',
|
||||
verifyAdminTitle: 'Vérification Admin',
|
||||
verifyAdminDesc: 'Veuillez entrer la clé admin pour continuer',
|
||||
verify: 'Vérifier',
|
||||
verifying: 'Vérification...',
|
||||
verifyFailed: 'Échec de la vérification, réessayez',
|
||||
clearError: '✕',
|
||||
clearSuccess: '✕',
|
||||
'time.yesterday': 'Hier',
|
||||
'time.daysAgo': 'Il y a {count} jours',
|
||||
'time.hoursAgo': 'Il y a {count} heures',
|
||||
'time.minutesAgo': 'Il y a {count} minutes',
|
||||
'time.justNow': "À l'instant",
|
||||
},
|
||||
de: {
|
||||
submit: 'Senden',
|
||||
submitting: 'Senden...',
|
||||
preview: 'Vorschau',
|
||||
close: 'Schließen',
|
||||
nickname: 'Name *',
|
||||
email: 'E-Mail *',
|
||||
website: 'Webseite',
|
||||
writeComment: 'Schreibe einen Kommentar...',
|
||||
reply: 'Antworten',
|
||||
cancel: 'Abbrechen',
|
||||
admin: 'Admin',
|
||||
like: 'Gefällt mir',
|
||||
liked: 'Gefällt mir',
|
||||
likes: '{count} Gefällt mir',
|
||||
comments: 'Kommentare',
|
||||
totalComments: '{count} Kommentare',
|
||||
domainUnauthorized: 'Domain ({domain}) nicht autorisiert',
|
||||
errorTitle: 'Fehler',
|
||||
successTitle: 'Erfolg',
|
||||
verifyAdmin: 'Abmelden',
|
||||
formTitle: 'Hinterlasse einen Kommentar',
|
||||
loadMore: 'Mehr laden',
|
||||
noComments: 'Noch keine Kommentare',
|
||||
delete: 'Löschen',
|
||||
confirmDelete: 'Möchtest du diesen Kommentar wirklich löschen?',
|
||||
deleteSuccess: 'Erfolgreich gelöscht',
|
||||
deleteFailed: 'Löschen fehlgeschlagen',
|
||||
adminKeyPlaceholder: 'Admin-Schlüssel eingeben',
|
||||
verifyAdminTitle: 'Admin-Verifizierung',
|
||||
verifyAdminDesc: 'Bitte gib den Admin-Schlüssel ein',
|
||||
verify: 'Verifizieren',
|
||||
verifying: 'Verifiziere...',
|
||||
verifyFailed: 'Verifizierung fehlgeschlagen, bitte erneut versuchen',
|
||||
clearError: '✕',
|
||||
clearSuccess: '✕',
|
||||
'time.yesterday': 'Gestern',
|
||||
'time.daysAgo': 'Vor {count} Tagen',
|
||||
'time.hoursAgo': 'Vor {count} Stunden',
|
||||
'time.minutesAgo': 'Vor {count} Minuten',
|
||||
'time.justNow': 'Gerade eben',
|
||||
},
|
||||
ja: {
|
||||
submit: '送信',
|
||||
submitting: '送信中...',
|
||||
preview: 'プレビュー',
|
||||
close: '閉じる',
|
||||
nickname: '名前 *',
|
||||
email: 'メール *',
|
||||
website: 'ウェブサイト',
|
||||
writeComment: 'コメントを書く...',
|
||||
reply: '返信',
|
||||
cancel: 'キャンセル',
|
||||
admin: '管理者',
|
||||
like: 'いいね',
|
||||
liked: 'いいね済み',
|
||||
likes: '{count} いいね',
|
||||
comments: 'コメント',
|
||||
totalComments: '{count} コメント',
|
||||
domainUnauthorized: 'ドメイン ({domain}) は許可されていません',
|
||||
errorTitle: 'エラー',
|
||||
successTitle: '成功',
|
||||
verifyAdmin: 'ログアウト',
|
||||
formTitle: 'コメントを残す',
|
||||
loadMore: 'もっと読み込む',
|
||||
noComments: 'まだコメントはありません',
|
||||
delete: '削除',
|
||||
confirmDelete: 'このコメントを削除してもよろしいですか?',
|
||||
deleteSuccess: '削除しました',
|
||||
deleteFailed: '削除に失敗しました',
|
||||
adminKeyPlaceholder: '管理者キーを入力',
|
||||
verifyAdminTitle: '管理者認証',
|
||||
verifyAdminDesc: '続行するには管理者キーを入力してください',
|
||||
verify: '認証',
|
||||
verifying: '認証中...',
|
||||
verifyFailed: '認証に失敗しました。再試行してください',
|
||||
clearError: '✕',
|
||||
clearSuccess: '✕',
|
||||
'time.yesterday': '昨日',
|
||||
'time.daysAgo': '{count}日前',
|
||||
'time.hoursAgo': '{count}時間前',
|
||||
'time.minutesAgo': '{count}分前',
|
||||
'time.justNow': 'たった今',
|
||||
},
|
||||
ko: {
|
||||
submit: '제출',
|
||||
submitting: '제출 중...',
|
||||
preview: '미리보기',
|
||||
close: '닫기',
|
||||
nickname: '이름 *',
|
||||
email: '이메일 *',
|
||||
website: '웹사이트',
|
||||
writeComment: '댓글을 작성하세요...',
|
||||
reply: '답글',
|
||||
cancel: '취소',
|
||||
admin: '관리자',
|
||||
like: '좋아요',
|
||||
liked: '좋아요 함',
|
||||
likes: '{count} 좋아요',
|
||||
comments: '댓글',
|
||||
totalComments: '{count} 댓글',
|
||||
domainUnauthorized: '도메인 ({domain}) 승인되지 않음',
|
||||
errorTitle: '오류',
|
||||
successTitle: '성공',
|
||||
verifyAdmin: '로그아웃',
|
||||
formTitle: '댓글 남기기',
|
||||
loadMore: '더 보기',
|
||||
noComments: '아직 댓글이 없습니다',
|
||||
delete: '삭제',
|
||||
confirmDelete: '이 댓글을 삭제하시겠습니까?',
|
||||
deleteSuccess: '삭제 성공',
|
||||
deleteFailed: '삭제 실패',
|
||||
adminKeyPlaceholder: '관리자 키 입력',
|
||||
verifyAdminTitle: '관리자 인증',
|
||||
verifyAdminDesc: '계속하려면 관리자 키를 입력하세요',
|
||||
verify: '인증',
|
||||
verifying: '인증 중...',
|
||||
verifyFailed: '인증 실패, 다시 시도하세요',
|
||||
clearError: '✕',
|
||||
clearSuccess: '✕',
|
||||
'time.yesterday': '어제',
|
||||
'time.daysAgo': '{count}일 전',
|
||||
'time.hoursAgo': '{count}시간 전',
|
||||
'time.minutesAgo': '{count}분 전',
|
||||
'time.justNow': '방금',
|
||||
},
|
||||
ru: {
|
||||
submit: 'Отправить',
|
||||
submitting: 'Отправка...',
|
||||
preview: 'Предпросмотр',
|
||||
close: 'Закрыть',
|
||||
nickname: 'Имя *',
|
||||
email: 'Email *',
|
||||
website: 'Сайт',
|
||||
writeComment: 'Напишите комментарий...',
|
||||
reply: 'Ответить',
|
||||
cancel: 'Отмена',
|
||||
admin: 'Админ',
|
||||
like: 'Нравится',
|
||||
liked: 'Понравилось',
|
||||
likes: '{count} лайков',
|
||||
comments: 'Комментарии',
|
||||
totalComments: '{count} Комментариев',
|
||||
domainUnauthorized: 'Домен ({domain}) не авторизован',
|
||||
errorTitle: 'Ошибка',
|
||||
successTitle: 'Успешно',
|
||||
verifyAdmin: 'Выйти',
|
||||
formTitle: 'Оставить комментарий',
|
||||
loadMore: 'Загрузить еще',
|
||||
noComments: 'Комментариев пока нет',
|
||||
delete: 'Удалить',
|
||||
confirmDelete: 'Вы уверены, что хотите удалить этот комментарий?',
|
||||
deleteSuccess: 'Успешно удалено',
|
||||
deleteFailed: 'Ошибка удаления',
|
||||
adminKeyPlaceholder: 'Введите ключ админа',
|
||||
verifyAdminTitle: 'Проверка админа',
|
||||
verifyAdminDesc: 'Пожалуйста, введите ключ админа для продолжения',
|
||||
verify: 'Проверить',
|
||||
verifying: 'Проверка...',
|
||||
verifyFailed: 'Ошибка проверки, попробуйте снова',
|
||||
clearError: '✕',
|
||||
clearSuccess: '✕',
|
||||
'time.yesterday': 'Вчера',
|
||||
'time.daysAgo': '{count} дн. назад',
|
||||
'time.hoursAgo': '{count} ч. назад',
|
||||
'time.minutesAgo': '{count} мин. назад',
|
||||
'time.justNow': 'Только что',
|
||||
},
|
||||
it: {
|
||||
submit: 'Invia',
|
||||
submitting: 'Invio...',
|
||||
preview: 'Anteprima',
|
||||
close: 'Chiudi',
|
||||
nickname: 'Nome *',
|
||||
email: 'Email *',
|
||||
website: 'Sito web',
|
||||
writeComment: 'Scrivi un commento...',
|
||||
reply: 'Rispondi',
|
||||
cancel: 'Annulla',
|
||||
admin: 'Admin',
|
||||
like: 'Mi piace',
|
||||
liked: 'Piaciuto',
|
||||
likes: '{count} Mi piace',
|
||||
comments: 'Commenti',
|
||||
totalComments: '{count} Commenti',
|
||||
domainUnauthorized: 'Dominio ({domain}) non autorizzato',
|
||||
errorTitle: 'Errore',
|
||||
successTitle: 'Successo',
|
||||
verifyAdmin: 'Esci',
|
||||
formTitle: 'Lascia un commento',
|
||||
loadMore: 'Carica altro',
|
||||
noComments: 'Nessun commento ancora',
|
||||
delete: 'Elimina',
|
||||
confirmDelete: 'Sei sicuro di voler eliminare questo commento?',
|
||||
deleteSuccess: 'Eliminato con successo',
|
||||
deleteFailed: 'Eliminazione fallita',
|
||||
adminKeyPlaceholder: 'Inserisci chiave admin',
|
||||
verifyAdminTitle: 'Verifica Admin',
|
||||
verifyAdminDesc: 'Inserisci la chiave admin per continuare',
|
||||
verify: 'Verifica',
|
||||
verifying: 'Verifica in corso...',
|
||||
verifyFailed: 'Verifica fallita, riprova',
|
||||
clearError: '✕',
|
||||
clearSuccess: '✕',
|
||||
'time.yesterday': 'Ieri',
|
||||
'time.daysAgo': '{count} giorni fa',
|
||||
'time.hoursAgo': '{count} ore fa',
|
||||
'time.minutesAgo': '{count} minuti fa',
|
||||
'time.justNow': 'Proprio ora',
|
||||
},
|
||||
nl: {
|
||||
submit: 'Verzenden',
|
||||
submitting: 'Verzenden...',
|
||||
preview: 'Voorbeeld',
|
||||
close: 'Sluiten',
|
||||
nickname: 'Naam *',
|
||||
email: 'E-mail *',
|
||||
website: 'Website',
|
||||
writeComment: 'Schrijf een reactie...',
|
||||
reply: 'Beantwoorden',
|
||||
cancel: 'Annuleren',
|
||||
admin: 'Admin',
|
||||
like: 'Leuk',
|
||||
liked: 'Geliket',
|
||||
likes: '{count} Likes',
|
||||
comments: 'Reacties',
|
||||
totalComments: '{count} Reacties',
|
||||
domainUnauthorized: 'Domein ({domain}) niet geautoriseerd',
|
||||
errorTitle: 'Fout',
|
||||
successTitle: 'Succes',
|
||||
verifyAdmin: 'Uitloggen',
|
||||
formTitle: 'Laat een reactie achter',
|
||||
loadMore: 'Meer laden',
|
||||
noComments: 'Nog geen reacties',
|
||||
delete: 'Verwijderen',
|
||||
confirmDelete: 'Weet je zeker dat je deze reactie wilt verwijderen?',
|
||||
deleteSuccess: 'Succesvol verwijderd',
|
||||
deleteFailed: 'Verwijderen mislukt',
|
||||
adminKeyPlaceholder: 'Voer admin-sleutel in',
|
||||
verifyAdminTitle: 'Admin Verificatie',
|
||||
verifyAdminDesc: 'Voer de admin-sleutel in om door te gaan',
|
||||
verify: 'Verifiëren',
|
||||
verifying: 'Verifiëren...',
|
||||
verifyFailed: 'Verificatie mislukt, probeer opnieuw',
|
||||
clearError: '✕',
|
||||
clearSuccess: '✕',
|
||||
'time.yesterday': 'Gisteren',
|
||||
'time.daysAgo': '{count} dagen geleden',
|
||||
'time.hoursAgo': '{count} uur geleden',
|
||||
'time.minutesAgo': '{count} minuten geleden',
|
||||
'time.justNow': 'Zojuist',
|
||||
},
|
||||
ar: {
|
||||
submit: 'إرسال',
|
||||
submitting: 'جاري الإرسال...',
|
||||
preview: 'معاينة',
|
||||
close: 'إغلاق',
|
||||
nickname: 'الاسم *',
|
||||
email: 'البريد الإلكتروني *',
|
||||
website: 'الموقع الإلكتروني',
|
||||
writeComment: 'أكتب تعليقاً...',
|
||||
reply: 'رد',
|
||||
cancel: 'إلغاء',
|
||||
admin: 'مسؤول',
|
||||
like: 'إعجاب',
|
||||
liked: 'أعجبني',
|
||||
likes: '{count} إعجاب',
|
||||
comments: 'تعليقات',
|
||||
totalComments: '{count} تعليق',
|
||||
domainUnauthorized: 'المجال ({domain}) غير مصرح به',
|
||||
errorTitle: 'خطأ',
|
||||
successTitle: 'نجاح',
|
||||
verifyAdmin: 'تسجيل الخروج',
|
||||
formTitle: 'اترك تعليقاً',
|
||||
loadMore: 'تحميل المزيد',
|
||||
noComments: 'لا توجد تعليقات بعد',
|
||||
delete: 'حذف',
|
||||
confirmDelete: 'هل أنت متأكد أنك تريد حذف هذا التعليق؟',
|
||||
deleteSuccess: 'تم الحذف بنجاح',
|
||||
deleteFailed: 'فشل الحذف',
|
||||
adminKeyPlaceholder: 'أدخل مفتاح المسؤول',
|
||||
verifyAdminTitle: 'تحقق المسؤول',
|
||||
verifyAdminDesc: 'الرجاء إدخال مفتاح المسؤول للمتابعة',
|
||||
verify: 'تحقق',
|
||||
verifying: 'جاري التحقق...',
|
||||
verifyFailed: 'فشل التحقق، حاول مرة أخرى',
|
||||
clearError: '✕',
|
||||
clearSuccess: '✕',
|
||||
'time.yesterday': 'أمس',
|
||||
'time.daysAgo': 'منذ {count} يوم',
|
||||
'time.hoursAgo': 'منذ {count} ساعة',
|
||||
'time.minutesAgo': 'منذ {count} دقيقة',
|
||||
'time.justNow': 'الآن',
|
||||
},
|
||||
hi: {
|
||||
submit: 'जमा करें',
|
||||
submitting: 'जमा हो रहा है...',
|
||||
preview: 'पूर्वावलोकन',
|
||||
close: 'बंद करें',
|
||||
nickname: 'नाम *',
|
||||
email: 'ईमेल *',
|
||||
website: 'वेबसाइट',
|
||||
writeComment: 'टिप्पणी लिखें...',
|
||||
reply: 'उत्तर दें',
|
||||
cancel: 'रद्द करें',
|
||||
admin: 'एडमिन',
|
||||
like: 'पसंद',
|
||||
liked: 'पसंद किया',
|
||||
likes: '{count} पसंद',
|
||||
comments: 'टिप्पणियाँ',
|
||||
totalComments: '{count} टिप्पणियाँ',
|
||||
domainUnauthorized: 'डोमेन ({domain}) अधिकृत नहीं है',
|
||||
errorTitle: 'त्रुटि',
|
||||
successTitle: 'सफलता',
|
||||
verifyAdmin: 'साइन आउट',
|
||||
formTitle: 'टिप्पणी छोड़ें',
|
||||
loadMore: 'और लोड करें',
|
||||
noComments: 'अभी कोई टिप्पणी नहीं',
|
||||
delete: 'हटाएं',
|
||||
confirmDelete: 'क्या आप वाकई इस टिप्पणी को हटाना चाहते हैं?',
|
||||
deleteSuccess: 'सफलतापूर्वक हटा दिया गया',
|
||||
deleteFailed: 'हटाने में विफल',
|
||||
adminKeyPlaceholder: 'एडमिन कुंजी दर्ज करें',
|
||||
verifyAdminTitle: 'एडमिन सत्यापन',
|
||||
verifyAdminDesc: 'जारी रखने के लिए कृपया एडमिन कुंजी दर्ज करें',
|
||||
verify: 'सत्यापित करें',
|
||||
verifying: 'सत्यापित हो रहा है...',
|
||||
verifyFailed: 'सत्यापन विफल, पुनः प्रयास करें',
|
||||
clearError: '✕',
|
||||
clearSuccess: '✕',
|
||||
'time.yesterday': 'कल',
|
||||
'time.daysAgo': '{count} दिन पहले',
|
||||
'time.hoursAgo': '{count} घंटे पहले',
|
||||
'time.minutesAgo': '{count} मिनट पहले',
|
||||
'time.justNow': 'अभी',
|
||||
},
|
||||
id: {
|
||||
submit: 'Kirim',
|
||||
submitting: 'Mengirim...',
|
||||
preview: 'Pratinjau',
|
||||
close: 'Tutup',
|
||||
nickname: 'Nama *',
|
||||
email: 'Email *',
|
||||
website: 'Situs Web',
|
||||
writeComment: 'Tulis komentar...',
|
||||
reply: 'Balas',
|
||||
cancel: 'Batal',
|
||||
admin: 'Admin',
|
||||
like: 'Suka',
|
||||
liked: 'Disukai',
|
||||
likes: '{count} Suka',
|
||||
comments: 'Komentar',
|
||||
totalComments: '{count} Komentar',
|
||||
domainUnauthorized: 'Domain ({domain}) tidak diizinkan',
|
||||
errorTitle: 'Kesalahan',
|
||||
successTitle: 'Sukses',
|
||||
verifyAdmin: 'Keluar',
|
||||
formTitle: 'Tinggalkan Komentar',
|
||||
loadMore: 'Muat Lebih Banyak',
|
||||
noComments: 'Belum ada komentar',
|
||||
delete: 'Hapus',
|
||||
confirmDelete: 'Apakah Anda yakin ingin menghapus komentar ini?',
|
||||
deleteSuccess: 'Berhasil dihapus',
|
||||
deleteFailed: 'Gagal menghapus',
|
||||
adminKeyPlaceholder: 'Masukkan kunci admin',
|
||||
verifyAdminTitle: 'Verifikasi Admin',
|
||||
verifyAdminDesc: 'Silakan masukkan kunci admin untuk melanjutkan',
|
||||
verify: 'Verifikasi',
|
||||
verifying: 'Memverifikasi...',
|
||||
verifyFailed: 'Verifikasi gagal, coba lagi',
|
||||
clearError: '✕',
|
||||
clearSuccess: '✕',
|
||||
'time.yesterday': 'Kemarin',
|
||||
'time.daysAgo': '{count} hari yang lalu',
|
||||
'time.hoursAgo': '{count} jam yang lalu',
|
||||
'time.minutesAgo': '{count} menit yang lalu',
|
||||
'time.justNow': 'Baru saja',
|
||||
},
|
||||
};
|
||||
@@ -5,9 +5,10 @@
|
||||
/**
|
||||
* 格式化时间(3天内显示相对时间,超过3天显示完整日期)
|
||||
* @param {string|number} dateValue - 日期字符串或时间戳
|
||||
* @param {Function} t - 翻译函数
|
||||
* @returns {string}
|
||||
*/
|
||||
export function formatRelativeTime(dateValue) {
|
||||
export function formatRelativeTime(dateValue, t = (k, p) => k) {
|
||||
const date = new Date(dateValue);
|
||||
const now = new Date();
|
||||
const diff = now.getTime() - date.getTime();
|
||||
@@ -20,15 +21,15 @@ export function formatRelativeTime(dateValue) {
|
||||
// 3天内显示相对时间
|
||||
if (days < 3) {
|
||||
if (days > 0) {
|
||||
return days === 1 ? '昨天' : `${days}天前`;
|
||||
return days === 1 ? t('time.yesterday') : t('time.daysAgo', { count: days });
|
||||
}
|
||||
if (hours > 0) {
|
||||
return `${hours}小时前`;
|
||||
return t('time.hoursAgo', { count: hours });
|
||||
}
|
||||
if (minutes > 0) {
|
||||
return `${minutes}分钟前`;
|
||||
return t('time.minutesAgo', { count: minutes });
|
||||
}
|
||||
return '刚刚';
|
||||
return t('time.justNow');
|
||||
}
|
||||
|
||||
// 超过3天显示完整日期
|
||||
|
||||
Reference in New Issue
Block a user