fix: merge ui-V0.3

This commit is contained in:
shuai 2022-11-09 10:36:05 +08:00
commit 91732e26be
29 changed files with 4100 additions and 2054 deletions

View File

@ -179,4 +179,942 @@ notification:
other: "Your answer has been deleted"
your_comment_was_deleted:
other: "Your comment has been deleted"
# The following fields are used for interface presentation(Front-end)
ui:
how_to_format:
title: How to Format
description: >-
<ul class="mb-0"><li><p class="mb-2">to make links</p><pre
class="mb-2"><code>&lt;https://url.com&gt;<br/><br/>[Title](https://url.com)</code></pre></li><li><p
class="mb-2">put returns between paragraphs</p></li><li><p
class="mb-2"><em>_italic_</em> or **<strong>bold</strong>**</p></li><li><p
class="mb-2">indent code by 4 spaces</p></li><li><p class="mb-2">quote by
placing <code>&gt;</code> at start of line</p></li><li><p
class="mb-2">backtick escapes <code>`like _this_`</code></p></li><li><p
class="mb-2">create code fences with backticks <code>`</code></p><pre
class="mb-0"><code>```<br/>code here<br/>```</code></pre></li></ul>
pagination:
prev: Prev
next: Next
page_title:
question: Question
questions: Questions
tag: Tag
tags: Tags
tag_wiki: tag wiki
edit_tag: Edit Tag
ask_a_question: Add Question
edit_question: Edit Question
edit_answer: Edit Answer
search: Search
posts_containing: Posts containing
settings: Settings
notifications: Notifications
login: Log In
sign_up: Sign Up
account_recovery: Account Recovery
account_activation: Account Activation
confirm_email: Confirm Email
account_suspended: Account Suspended
admin: Admin
change_email: Modify Email
install: Answer Installation
upgrade: Answer Upgrade
maintenance: Webite Maintenance
notifications:
title: Notifications
inbox: Inbox
achievement: Achievements
all_read: Mark all as read
show_more: Show more
suspended:
title: Your Account has been Suspended
until_time: 'Your account was suspended until {{ time }}.'
forever: This user was suspended forever.
end: You don't meet a community guideline.
editor:
blockquote:
text: Blockquote
bold:
text: Strong
chart:
text: Chart
flow_chart: Flow chart
sequence_diagram: Sequence diagram
class_diagram: Class diagram
state_diagram: State diagram
entity_relationship_diagram: Entity relationship diagram
user_defined_diagram: User defined diagram
gantt_chart: Gantt chart
pie_chart: Pie chart
code:
text: Code Sample
add_code: Add code sample
form:
fields:
code:
label: Code
msg:
empty: Code cannot be empty.
language:
label: Language (optional)
placeholder: Automatic detection
btn_cancel: Cancel
btn_confirm: Add
formula:
text: Formula
options:
inline: Inline formula
block: Block formula
heading:
text: Heading
options:
h1: Heading 1
h2: Heading 2
h3: Heading 3
h4: Heading 4
h5: Heading 5
h6: Heading 6
help:
text: Help
hr:
text: Horizontal Rule
image:
text: Image
add_image: Add image
tab_image: Upload image
form_image:
fields:
file:
label: Image File
btn: Select image
msg:
empty: File cannot be empty.
only_image: Only image files are allowed.
max_size: File size cannot exceed 4MB.
description:
label: Description (optional)
tab_url: Image URL
form_url:
fields:
url:
label: Image URL
msg:
empty: Image URL cannot be empty.
name:
label: Description (optional)
btn_cancel: Cancel
btn_confirm: Add
uploading: Uploading
indent:
text: Indent
outdent:
text: Outdent
italic:
text: Emphasis
link:
text: Hyperlink
add_link: Add hyperlink
form:
fields:
url:
label: URL
msg:
empty: URL cannot be empty.
name:
label: Description (optional)
btn_cancel: Cancel
btn_confirm: Add
ordered_list:
text: Numbered List
unordered_list:
text: Bulleted List
table:
text: Table
heading: Heading
cell: Cell
close_modal:
title: I am closing this post as...
btn_cancel: Cancel
btn_submit: Submit
remark:
empty: Cannot be empty.
msg:
empty: Please select a reason.
report_modal:
flag_title: I am flagging to report this post as...
close_title: I am closing this post as...
review_question_title: Review question
review_answer_title: Review answer
review_comment_title: Review comment
btn_cancel: Cancel
btn_submit: Submit
remark:
empty: Cannot be empty.
msg:
empty: Please select a reason.
tag_modal:
title: Create new tag
form:
fields:
display_name:
label: Display Name
msg:
empty: Display name cannot be empty.
range: Display name up to 35 characters.
slug_name:
label: URL Slug
description: 'Must use the character set "a-z", "0-9", "+ # - ."'
msg:
empty: URL slug cannot be empty.
range: URL slug up to 35 characters.
character: URL slug contains unallowed character set.
description:
label: Description (optional)
btn_cancel: Cancel
btn_submit: Submit
tag_info:
created_at: Created
edited_at: Edited
synonyms:
title: Synonyms
text: The following tags will be remapped to
empty: No synonyms found.
btn_add: Add a synonym
btn_edit: Edit
btn_save: Save
synonyms_text: The following tags will be remapped to
delete:
title: Delete this tag
content: >-
<p>We do not allowed deleting tag with posts.</p><p>Please remove this tag
from the posts first.</p>
content2: Are you sure you wish to delete?
close: Close
edit_tag:
title: Edit Tag
default_reason: Edit tag
form:
fields:
revision:
label: Revision
display_name:
label: Display Name
slug_name:
label: URL Slug
info: 'Must use the character set "a-z", "0-9", "+ # - ."'
description:
label: Description
edit_summary:
label: Edit Summary
placeholder: >-
Briefly explain your changes (corrected spelling, fixed grammar,
improved formatting)
btn_save_edits: Save edits
btn_cancel: Cancel
dates:
long_date: MMM D
long_date_with_year: 'MMM D, YYYY'
long_date_with_time: 'MMM D, YYYY [at] HH:mm'
now: now
x_seconds_ago: '{{count}}s ago'
x_minutes_ago: '{{count}}m ago'
x_hours_ago: '{{count}}h ago'
hour: hour
day: day
comment:
btn_add_comment: Add comment
reply_to: Reply to
btn_reply: Reply
btn_edit: Edit
btn_delete: Delete
btn_flag: Flag
btn_save_edits: Save edits
btn_cancel: Cancel
show_more: Show more comment
tip_question: >-
Use comments to ask for more information or suggest improvements. Avoid
answering questions in comments.
tip_answer: >-
Use comments to reply to other users or notify them of changes. If you are
adding new information, edit your post instead of commenting.
edit_answer:
title: Edit Answer
default_reason: Edit answer
form:
fields:
revision:
label: Revision
answer:
label: Answer
edit_summary:
label: Edit Summary
placeholder: >-
Briefly explain your changes (corrected spelling, fixed grammar,
improved formatting)
btn_save_edits: Save edits
btn_cancel: Cancel
tags:
title: Tags
sort_buttons:
popular: Popular
name: Name
newest: newest
button_follow: Follow
button_following: Following
tag_label: questions
search_placeholder: Filter by tag name
no_description: The tag has no description.
more: More
ask:
title: Add Question
edit_title: Edit Question
default_reason: Edit question
similar_questions: Similar questions
form:
fields:
revision:
label: Revision
title:
label: Title
placeholder: Be specific and imagine you're asking a question to another person
msg:
empty: Title cannot be empty.
range: Title up to 150 characters
body:
label: Body
msg:
empty: Body cannot be empty.
tags:
label: Tags
msg:
empty: Tags cannot be empty.
answer:
label: Answer
msg:
empty: Answer cannot be empty.
btn_post_question: Post your question
btn_save_edits: Save edits
answer_question: Answer your own question
post_question&answer: Post your question and answer
tag_selector:
add_btn: Add tag
create_btn: Create new tag
search_tag: Search tag
hint: 'Describe what your question is about, at least one tag is required.'
no_result: No tags matched
header:
nav:
question: Questions
tag: Tags
user: Users
profile: Profile
setting: Settings
logout: Log out
admin: Admin
search:
placeholder: Search
footer:
build_on: >-
Built on <1> Answer </1>- the open-source software that power Q&A
communities<br />Made with love © 2022 Answer
upload_img:
name: Change
loading: loading...
pic_auth_code:
title: Captcha
placeholder: Type the text above
msg:
empty: Captcha cannot be empty.
inactive:
first: >-
You're almost done! We sent an activation mail to <bold>{{mail}}</bold>.
Please follow the instructions in the mail to activate your account.
info: 'If it doesn''t arrive, check your spam folder.'
another: >-
We sent another activation email to you at <bold>{{mail}}</bold>. It might
take a few minutes for it to arrive; be sure to check your spam folder.
btn_name: Resend activation email
change_btn_name: Change email
msg:
empty: Cannot be empty.
login:
page_title: Welcome to Answer
info_sign: Don't have an account? <1>Sign up</1>
info_login: Already have an account? <1>Log in</1>
forgot_pass: Forgot password?
name:
label: Name
msg:
empty: Name cannot be empty.
range: Name up to 30 characters.
email:
label: Email
msg:
empty: Email cannot be empty.
password:
label: Password
msg:
empty: Password cannot be empty.
different: The passwords entered on both sides are inconsistent
account_forgot:
page_title: Forgot Your Password
btn_name: Send me recovery email
send_success: >-
If an account matches <strong>{{mail}}</strong>, you should receive an email
with instructions on how to reset your password shortly.
email:
label: Email
msg:
empty: Email cannot be empty.
change_email:
page_title: Welcome to Answer
btn_cancel: Cancel
btn_update: Update email address
send_success: >-
If an account matches <strong>{{mail}}</strong>, you should receive an email
with instructions on how to reset your password shortly.
email:
label: New Email
msg:
empty: Email cannot be empty.
password_reset:
page_title: Password Reset
btn_name: Reset my password
reset_success: >-
You successfully changed your password; you will be redirected to the log in
page.
link_invalid: >-
Sorry, this password reset link is no longer valid. Perhaps your password is
already reset?
to_login: Continue to log in page
password:
label: Password
msg:
empty: Password cannot be empty.
length: The length needs to be between 8 and 32
different: The passwords entered on both sides are inconsistent
password_confirm:
label: Confirm New Password
settings:
page_title: Settings
nav:
profile: Profile
notification: Notifications
account: Account
interface: Interface
profile:
btn_name: Update profile
display_name:
label: Display Name
msg: Display name cannot be empty.
msg_range: Display name up to 30 characters
username:
label: Username
caption: People can mention you as "@username".
msg: Username cannot be empty.
msg_range: Username up to 30 characters
character: 'Must use the character set "a-z", "0-9", " - . _"'
avatar:
label: Profile Image
gravatar: Gravatar
gravatar_text: You can change image on <1>gravatar.com</1>
custom: Custom
btn_refresh: Refresh
custom_text: You can upload your image.
default: Default
msg: Please upload an avatar
bio:
label: About Me (optional)
website:
label: Website (optional)
placeholder: 'https://example.com'
msg: Website incorrect format
location:
label: Location (optional)
placeholder: 'City, Country'
notification:
email:
label: Email Notifications
radio: 'Answers to your questions, comments, and more'
account:
change_email_btn: Change email
change_pass_btn: Change password
change_email_info: >-
We've sent an email to that address. Please follow the confirmation
instructions.
email:
label: Email
msg: Email cannot be empty.
password_title: Password
current_pass:
label: Current Password
msg:
empty: Current Password cannot be empty.
length: The length needs to be between 8 and 32.
different: The two entered passwords do not match.
new_pass:
label: New Password
pass_confirm:
label: Confirm New Password
interface:
lang:
label: Interface Language
text: User interface language. It will change when you refresh the page.
toast:
update: update success
update_password: Password changed successfully.
flag_success: Thanks for flagging.
related_question:
title: Related Questions
btn: Add question
answers: answers
question_detail:
Asked: Asked
asked: asked
update: Modified
edit: edited
Views: Viewed
Follow: Follow
Following: Following
answered: answered
closed_in: Closed in
show_exist: Show existing question.
answers:
title: Answers
score: Score
newest: Newest
btn_accept: Accept
btn_accepted: Accepted
write_answer:
title: Your Answer
btn_name: Post your answer
confirm_title: Continue to answer
continue: Continue
confirm_info: >-
<p>Are you sure you want to add another answer?</p><p>You could use the
edit link to refine and improve your existing answer, instead.</p>
empty: Answer cannot be empty.
delete:
title: Delete this post
question: >-
We do not recommend <strong>deleting questions with answers</strong> because
doing so deprives future readers of this knowledge.</p><p>Repeated deletion
of answered questions can result in your account being blocked from asking.
Are you sure you wish to delete?
answer_accepted: >-
<p>We do not recommend <strong>deleting accepted answer</strong> because
doing so deprives future readers of this knowledge. </p> Repeated deletion
of accepted answers can result in your account being blocked from answering.
Are you sure you wish to delete?
other: Are you sure you wish to delete?
tip_question_deleted: This post has been deleted
tip_answer_deleted: This answer has been deleted
btns:
confirm: Confirm
cancel: Cancel
save: Save
delete: Delete
login: Log in
signup: Sign up
logout: Log out
verify: Verify
add_question: Add question
search:
title: Search Results
keywords: Keywords
options: Options
follow: Follow
following: Following
counts: '{{count}} Results'
more: More
sort_btns:
relevance: Relevance
newest: Newest
active: Active
score: Score
more: More
tips:
title: Advanced Search Tips
tag: '<1>[tag]</1> search withing a tag'
user: '<1>user:username</1> search by author'
answer: '<1>answers:0</1> unanswered questions'
score: '<1>score:3</1> posts with a 3+ score'
question: '<1>is:question</1> search questions'
is_answer: '<1>is:answer</1> search answers'
empty: We couldn't find anything. <br /> Try different or less specific keywords.
share:
name: Share
copy: Copy link
via: Share post via...
copied: Copied
facebook: Share to Facebook
twitter: Share to Twitter
cannot_vote_for_self: You can't vote for your own post
modal_confirm:
title: Error...
account_result:
page_title: Welcome to Answer
success: Your new account is confirmed; you will be redirected to the home page.
link: Continue to homepage
invalid: >-
Sorry, this account confirmation link is no longer valid. Perhaps your
account is already active?
confirm_new_email: Your email has been updated.
confirm_new_email_invalid: >-
Sorry, this confirmation link is no longer valid. Perhaps your email was
already changed?
question:
following_tags: Following Tags
edit: Edit
save: Save
follow_tag_tip: Follow tags to curate your list of questions.
hot_questions: Hot Questions
all_questions: All Questions
x_questions: '{{ count }} Questions'
x_answers: '{{ count }} answers'
questions: Questions
answers: Answers
newest: Newest
active: Active
frequent: Frequent
score: Score
unanswered: Unanswered
modified: modified
answered: answered
asked: asked
closed: closed
follow_a_tag: Follow a tag
more: More
personal:
overview: Overview
answers: Answers
answer: answer
questions: Questions
question: question
bookmarks: Bookmarks
reputation: Reputation
comments: Comments
votes: Votes
newest: Newest
score: Score
edit_profile: Edit Profile
visited_x_days: 'Visited {{ count }} days'
viewed: Viewed
joined: Joined
last_login: Seen
about_me: About Me
about_me_empty: '// Hello, World !'
top_answers: Top Answers
top_questions: Top Questions
stats: Stats
list_empty: No posts found.<br />Perhaps you'd like to select a different tab?
accepted: Accepted
answered: answered
asked: asked
upvote: upvote
downvote: downvote
mod_short: Mod
mod_long: Moderators
x_reputation: reputation
x_votes: votes received
x_answers: answers
x_questions: questions
install:
title: Answer
next: Next
done: Done
config_yaml_error: Cant create the config.yaml file.
lang:
label: Please Choose a Language
db_type:
label: Database Engine
db_username:
label: Username
placeholder: root
msg: Username cannot be empty.
db_password:
label: Password
placeholder: root
msg: Password cannot be empty.
db_host:
label: Database Host
placeholder: 'db:3306'
msg: Database Host cannot be empty.
db_name:
label: Database Name
placeholder: answer
msg: Database Name cannot be empty.
db_file:
label: Database File
placeholder: /data/answer.db
msg: Database File cannot be empty.
config_yaml:
title: Create config.yaml
label: The config.yaml file created.
description: >-
You can create the <1>config.yaml</1> file manually in the
<1>/var/wwww/xxx/</1> directory and paste the following text into it.
info: 'After youve done that, click “Next” button.'
site_information: Site Information
admin_account: Admin Account
site_name:
label: Site Name
msg: Site Name cannot be empty.
site_url:
label: Site URL
text: The address of your site.
msg:
empty: Site URL cannot be empty.
incorrect: Site URL incorrect format.
contact_email:
label: Contact Email
text: Email address of key contact responsible for this site.
msg:
empty: Contact Email cannot be empty.
incorrect: Contact Email incorrect format.
admin_name:
label: Name
msg: Name cannot be empty.
admin_password:
label: Password
text: >-
You will need this password to log in. Please store it in a secure
location.
msg: Password cannot be empty.
admin_email:
label: Email
text: You will need this email to log in.
msg:
empty: Email cannot be empty.
incorrect: Email incorrect format.
ready_title: Your Answer is Ready!
ready_description: >-
If you ever feel like changing more settings, visit <1>admin section</1>;
find it in the site menu.
good_luck: 'Have fun, and good luck!'
warn_title: Warning
warn_description: >-
The file <1>config.yaml</1> already exists. If you need to reset any of the
configuration items in this file, please delete it first.
install_now: You may try <1>installing now</1>.
installed: Already installed
installed_description: >-
You appear to have already installed. To reinstall please clear your old
database tables first.
page_404:
description: 'Unfortunately, this page doesn''t exist.'
back_home: Back to homepage
page_50X:
description: The server encountered an error and could not complete your request.
back_home: Back to homepage
page_maintenance:
description: 'We are under maintenance, well be back soon.'
admin:
admin_header:
title: Admin
nav_menus:
dashboard: Dashboard
contents: Contents
questions: Questions
answers: Answers
users: Users
flags: Flags
settings: Settings
general: General
interface: Interface
smtp: SMTP
dashboard:
title: Dashboard
welcome: Welcome to Answer Admin!
site_statistics: Site Statistics
questions: 'Questions:'
answers: 'Answers:'
comments: 'Comments:'
votes: 'Votes:'
active_users: 'Active users:'
flags: 'Flags:'
site_health_status: Site Health Status
version: 'Version:'
https: 'HTTPS:'
uploading_files: 'Uploading files:'
smtp: 'SMTP:'
timezone: 'Timezone:'
system_info: System Info
storage_used: 'Storage used:'
uptime: 'Uptime:'
answer_links: Answer Links
documents: Documents
feedback: Feedback
review: Review
config: Config
update_to: Update to
latest: Latest
check_failed: Check failed
'yes': 'Yes'
'no': 'No'
not_allowed: Not allowed
allowed: Allowed
enabled: Enabled
disabled: Disabled
flags:
title: Flags
pending: Pending
completed: Completed
flagged: Flagged
created: Created
action: Action
review: Review
change_modal:
title: Change user status to...
btn_cancel: Cancel
btn_submit: Submit
normal_name: normal
normal_description: A normal user can ask and answer questions.
suspended_name: suspended
suspended_description: A suspended user can't log in.
deleted_name: deleted
deleted_description: 'Delete profile, authentication associations.'
inactive_name: inactive
inactive_description: An inactive user must re-validate their email.
confirm_title: Delete this user
confirm_content: Are you sure you want to delete this user? This is permanent!
confirm_btn: Delete
msg:
empty: Please select a reason.
status_modal:
title: 'Change {{ type }} status to...'
normal_name: normal
normal_description: A normal post available to everyone.
closed_name: closed
closed_description: 'A closed question can''t answer, but still can edit, vote and comment.'
deleted_name: deleted
deleted_description: All reputation gained and lost will be restored.
btn_cancel: Cancel
btn_submit: Submit
btn_next: Next
users:
title: Users
name: Name
email: Email
reputation: Reputation
created_at: Created Time
delete_at: Deleted Time
suspend_at: Suspended Time
status: Status
action: Action
change: Change
all: All
inactive: Inactive
suspended: Suspended
deleted: Deleted
normal: Normal
filter:
placeholder: 'Filter by name, user:id'
questions:
page_title: Questions
normal: Normal
closed: Closed
deleted: Deleted
post: Post
votes: Votes
answers: Answers
created: Created
status: Status
action: Action
change: Change
filter:
placeholder: 'Filter by title, question:id'
answers:
page_title: Answers
normal: Normal
deleted: Deleted
post: Post
votes: Votes
created: Created
status: Status
action: Action
change: Change
filter:
placeholder: 'Filter by title, answer:id'
general:
page_title: General
name:
label: Site Name
msg: Site name cannot be empty.
text: 'The name of this site, as used in the title tag.'
site_url:
label: Site URL
msg: Site url cannot be empty.
validate: Please enter a valid URL.
text: The address of your site.
short_description:
label: Short Site Description (optional)
msg: Short site description cannot be empty.
text: 'Short description, as used in the title tag on homepage.'
description:
label: Site Description (optional)
msg: Site description cannot be empty.
text: 'Describe this site in one sentence, as used in the meta description tag.'
contact_email:
label: Contact Email
msg: Contact email cannot be empty.
validate: Contact email is not valid.
text: Email address of key contact responsible for this site.
interface:
page_title: Interface
logo:
label: Logo (optional)
msg: Site logo cannot be empty.
text: You can upload your image or <1>reset</1> it to the site title text.
theme:
label: Theme
msg: Theme cannot be empty.
text: Select an existing theme.
language:
label: Interface Language
msg: Interface language cannot be empty.
text: User interface language. It will change when you refresh the page.
time_zone:
label: Timezone
msg: Timezone cannot be empty.
text: Choose a city in the same timezone as you.
smtp:
page_title: SMTP
from_email:
label: From Email
msg: From email cannot be empty.
text: The email address which emails are sent from.
from_name:
label: From Name
msg: From name cannot be empty.
text: The name which emails are sent from.
smtp_host:
label: SMTP Host
msg: SMTP host cannot be empty.
text: Your mail server.
encryption:
label: Encryption
msg: Encryption cannot be empty.
text: For most servers SSL is the recommended option.
ssl: SSL
none: None
smtp_port:
label: SMTP Port
msg: SMTP port must be number 1 ~ 65535.
text: The port to your mail server.
smtp_username:
label: SMTP Username
msg: SMTP username cannot be empty.
smtp_password:
label: SMTP Password
msg: SMTP password cannot be empty.
test_email_recipient:
label: Test Email Recipients
text: Provide email address that will receive test sends.
msg: Test email recipients is invalid
smtp_authentication:
label: SMTP Authentication
msg: SMTP authentication cannot be empty.
'yes': 'Yes'
'no': 'No'

View File

@ -170,3 +170,751 @@ notification:
other: "你的答案已被删除"
your_comment_was_deleted:
other: "你的评论已被删除"
# The following fields are used for interface presentation(Front-end)
ui:
how_to_format:
title: 如何设定文本格式
description: >-
<ul class="mb-0"><li><p class="mb-2">添加链接:</p><pre
class="mb-2"><code>&lt;https://url.com&gt;<br/><br/>[标题](https://url.com)</code></pre></li><li><p
class="mb-2">段落之间使用空行分隔</p></li><li><p class="mb-2"><em>_斜体_</em> 或者
**<strong>粗体</strong>**</p></li><li><p class="mb-2">使用 4
个空格缩进代码</p></li><li><p
class="mb-2">在行首添加<code>&gt;</code>表示引用</p></li><li><p class="mb-2">反引号进行转义
<code>`像 _这样_`</code></p></li><li><p
class="mb-2">使用<code>```</code>创建代码块</p><pre class="mb-0"><code>```<br/>//
这是代码<br/>```</code></pre></li></ul>
pagination:
prev: 上一页
next: 下一页
page_title:
question: 问题
questions: 问题
tag: 标签
tags: 标签
tag_wiki: 标签 wiki
edit_tag: 编辑标签
ask_a_question: 提问题
edit_question: 编辑问题
edit_answer: 编辑回答
search: 搜索
posts_containing: 包含
settings: 设定
notifications: 通知
login: 登录
sign_up: 注册
account_recovery: 账号恢复
account_activation: 账号激活
confirm_email: 确认电子邮件
account_suspended: 账号已封禁
admin: 后台管理
notifications:
title: 通知
inbox: 收件箱
achievement: 成就
all_read: 全部标记为已读
show_more: 显示更多
suspended:
title: 账号已封禁
until_time: '你的账号被封禁至{{ time }}。'
forever: 你的账号已被永久封禁。
end: 违反了我们的社区准则。
editor:
blockquote:
text: 引用
bold:
text: 粗体
chart:
text: 图表
flow_chart: 流程图
sequence_diagram: 时序图
class_diagram: 类图
state_diagram: 状态图
entity_relationship_diagram: ER 图
user_defined_diagram: User defined diagram
gantt_chart: 甘特图
pie_chart: 饼图
code:
text: 代码块
add_code: 添加代码块
form:
fields:
code:
label: 代码块
msg:
empty: 代码块不能为空
language:
label: 语言 (可选)
placeholder: 自动识别
btn_cancel: 取消
btn_confirm: 添加
formula:
text: 公式
options:
inline: 行内公式
block: 公式块
heading:
text: 标题
options:
h1: 标题 1
h2: 标题 2
h3: 标题 3
h4: 标题 4
h5: 标题 5
h6: 标题 6
help:
text: 帮助
hr:
text: 水平分割线
image:
text: 图片
add_image: 添加图片
tab_image: 上传图片
form_image:
fields:
file:
label: 图片文件
btn: 选择图片
msg:
empty: 请选择图片文件。
only_image: 只能上传图片文件。
max_size: 图片文件大小不能超过 4 MB。
description:
label: 图片描述(可选)
tab_url: 网络图片
form_url:
fields:
url:
label: 图片地址
msg:
empty: 图片地址不能为空
name:
label: 图片描述(可选)
btn_cancel: 取消
btn_confirm: 添加
uploading: 上传中...
indent:
text: 添加缩进
outdent:
text: 减少缩进
italic:
text: 斜体
link:
text: 超链接
add_link: 添加超链接
form:
fields:
url:
label: 链接
msg:
empty: 链接不能为空。
name:
label: 链接描述(可选)
btn_cancel: 取消
btn_confirm: 添加
ordered_list:
text: 有编号列表
unordered_list:
text: 无编号列表
table:
text: 表格
heading: 表头
cell: 单元格
close_modal:
title: 关闭原因是...
btn_cancel: 取消
btn_submit: 提交
remark:
empty: 不能为空。
msg:
empty: 请选择一个原因。
report_modal:
flag_title: 举报原因是...
close_title: 关闭原因是...
review_question_title: 审查问题
review_answer_title: 审查回答
review_comment_title: 审查评论
btn_cancel: 取消
btn_submit: 提交
remark:
empty: 不能为空
msg:
empty: 请选择一个原因。
tag_modal:
title: 创建新标签
form:
fields:
display_name:
label: 显示名称(别名)
msg:
empty: 不能为空
range: 不能超过 35 个字符
slug_name:
label: URL 固定链接
description: '必须由 "a-z", "0-9", "+ # - ." 组成'
msg:
empty: 不能为空
range: 不能超过 35 个字符
character: 包含非法字符
description:
label: 标签描述(可选)
btn_cancel: 取消
btn_submit: 提交
tag_info:
created_at: 创建于
edited_at: 编辑于
synonyms:
title: 同义词
text: 以下标签等同于
empty: 此标签目前没有同义词。
btn_add: 添加同义词
btn_edit: 编辑
btn_save: 保存
synonyms_text: 以下标签等同于
delete:
title: 删除标签
content: <p>不允许删除有关联问题的标签。</p><p>请先从关联的问题中删除此标签的引用。</p>
content2: 确定要删除吗?
close: 关闭
edit_tag:
title: 编辑标签
default_reason: 编辑标签
form:
fields:
revision:
label: 编辑历史
display_name:
label: 名称
slug_name:
label: URL 固定链接
info: '必须由 "a-z", "0-9", "+ # - ." 组成'
description:
label: 描述
edit_summary:
label: 编辑概要
placeholder: 简单描述更改原因 (错别字、文字表达、格式等等)
btn_save_edits: 保存更改
btn_cancel: 取消
dates:
long_date: MM月DD日
long_date_with_year: YYYY年MM月DD日
long_date_with_time: 'YYYY年MM月DD日 HH:mm'
now: 刚刚
x_seconds_ago: '{{count}} 秒前'
x_minutes_ago: '{{count}} 分钟前'
x_hours_ago: '{{count}} 小时前'
comment:
btn_add_comment: 添加评论
reply_to: 回复
btn_reply: 回复
btn_edit: 编辑
btn_delete: 删除
btn_flag: 举报
btn_save_edits: 保存
btn_cancel: 取消
show_more: 显示更多评论
tip_question: 使用评论提问更多信息或者提出改进意见。尽量避免使用评论功能回答问题。
tip_answer: 使用评论对回答者进行回复,或者通知回答者你已更新了问题的内容。如果要补充或者完善问题的内容,请在原问题中更改。
edit_answer:
title: 编辑回答
default_reason: 编辑回答
form:
fields:
revision:
label: 编辑历史
answer:
label: 回答内容
edit_summary:
label: 编辑概要
placeholder: 简单描述更改原因 (错别字、文字表达、格式等等)
btn_save_edits: 保存更改
btn_cancel: 取消
tags:
title: 标签
sort_buttons:
popular: 热门
name: 名称
newest: 最新
button_follow: 关注
button_following: 已关注
tag_label: 个问题
search_placeholder: 通过标签名过滤
no_description: 此标签无描述。
more: 更多
ask:
title: 提交新的问题
edit_title: 编辑问题
default_reason: 编辑问题
similar_questions: 相似的问题
form:
fields:
revision:
label: 编辑历史
title:
label: 标题
placeholder: 请详细描述你的问题
msg:
empty: 标题不能为空
range: 标题最多 150 个字符
body:
label: 内容
msg:
empty: 内容不能为空
tags:
label: 标签
msg:
empty: 必须选择一个标签
answer:
label: 回答内容
msg:
empty: 回答内容不能为空
btn_post_question: 提交问题
btn_save_edits: 保存更改
answer_question: 直接发表回答
post_question&answer: 提交问题和回答
tag_selector:
add_btn: 添加标签
create_btn: 创建新标签
search_tag: 搜索标签
hint: 选择至少一个与问题相关的标签。
no_result: 没有匹配的标签
header:
nav:
question: 问题
tag: 标签
user: 用户
profile: 用户主页
setting: 账号设置
logout: 退出登录
admin: 后台管理
search:
placeholder: 搜索
footer:
build_on: >-
Built on <1> Answer </1>- the open-source software that power Q&A
communities<br />Made with love © 2022 Answer
upload_img:
name: 更改图片
loading: 加载中...
pic_auth_code:
title: 验证码
placeholder: 输入图片中的文字
msg:
empty: 不能为空
inactive:
first: '马上就好了!我们发送了一封激活邮件到 <bold>{{mail}}</bold>。请按照邮件中的说明激活您的帐户。'
info: 如果没有收到,请检查您的垃圾邮件文件夹。
another: '我们向您发送了另一封激活电子邮件,地址为 <bold>{{mail}}</bold>。它可能需要几分钟才能到达;请务必检查您的垃圾邮件文件夹。'
btn_name: 重新发送激活邮件
msg:
empty: 不能为空
login:
page_title: 欢迎来到 Answer
info_sign: 没有帐户?<1>注册</1>
info_login: 已经有一个帐户?<1>登录</1>
forgot_pass: 忘记密码?
name:
label: 昵称
msg:
empty: 昵称不能为空
range: 昵称最多 30 个字符
email:
label: 邮箱
msg:
empty: 邮箱不能为空
password:
label: 密码
msg:
empty: 密码不能为空
different: 两次输入密码不一致
account_forgot:
page_title: 忘记密码
btn_name: 发送恢复邮件
send_success: '如无意外,你的邮箱 <strong>{{mail}}</strong> 将会收到一封重置密码的邮件,请根据指引重置你的密码。'
email:
label: 邮箱
msg:
empty: 邮箱不能为空
password_reset:
page_title: 密码重置
btn_name: 重置我的密码
reset_success: 你已经成功更改密码,将返回登录页面
link_invalid: 抱歉,此密码重置链接已失效。也许是你已经重置过密码了?
to_login: 前往登录页面
password:
label: 密码
msg:
empty: 密码不能为空
length: 密码长度在8-32个字符之间
different: 两次输入密码不一致
password_confirm:
label: 确认新密码
settings:
page_title: 设置
nav:
profile: 我的资料
notification: 通知
account: 账号
interface: 界面
profile:
btn_name: 保存更改
display_name:
label: 昵称
msg: 昵称不能为空
msg_range: 昵称不能超过 30 个字符
username:
label: 用户名
caption: 用户之间可以通过 "@用户名" 进行交互。
msg: 用户名不能为空
msg_range: 用户名不能超过 30 个字符
character: '用户名只能由 "a-z", "0-9", " - . _" 组成'
avatar:
label: 头像
text: 您可以上传图片作为头像,也可以 <1>重置</1> 为
bio:
label: 关于我 (可选)
website:
label: 网站 (可选)
placeholder: 'https://example.com'
msg: 格式不正确
location:
label: 位置 (可选)
placeholder: '城市, 国家'
notification:
email:
label: 邮件通知
radio: 你的提问有新的回答,评论,和其他
account:
change_email_btn: 更改邮箱
change_pass_btn: 更改密码
change_email_info: 邮件已发送。请根据指引完成验证。
email:
label: 邮箱
msg: 邮箱不能为空
password_title: 密码
current_pass:
label: 当前密码
msg:
empty: 当前密码不能为空
length: 密码长度必须在 8 至 32 之间
different: 两次输入的密码不匹配
new_pass:
label: 新密码
pass_confirm:
label: 确认新密码
interface:
lang:
label: 界面语言
text: 设置用户界面语言,在刷新页面后生效。
toast:
update: 更新成功
update_password: 更改密码成功。
flag_success: 感谢您的标记,我们会尽快处理。
related_question:
title: 相关问题
btn: 我要提问
answers: 个回答
question_detail:
Asked: 提问于
asked: 提问于
update: 修改于
edit: 最后编辑于
Views: 阅读次数
Follow: 关注此问题
Following: 已关注
answered: 回答于
closed_in: 关闭于
show_exist: 查看相关问题。
answers:
title: 个回答
score: 评分
newest: 最新
btn_accept: 采纳
btn_accepted: 已被采纳
write_answer:
title: 你的回答
btn_name: 提交你的回答
confirm_title: 继续回答
continue: 继续
confirm_info: <p>您确定要提交一个新的回答吗?</p><p>您可以直接编辑和改善您之前的回答的。</p>
empty: 回答内容不能为空。
delete:
title: 删除
question: >-
我们不建议<strong>删除有回答的帖子</strong>。因为这样做会使得后来的读者无法从该问题中获得帮助。</p><p>如果删除过多有回答的帖子,你的账号将会被禁止提问。你确定要删除吗?
answer_accepted: >-
<p>我们不建议<strong>删除被采纳的回答</strong>。因为这样做会使得后来的读者无法从该回答中获得帮助。</p>如果删除过多被采纳的回答,你的账号将会被禁止回答任何提问。你确定要删除吗?
other: 你确定要删除?
tip_question_deleted: 此问题已被删除
tip_answer_deleted: 此回答已被删除
btns:
confirm: 确认
cancel: 取消
save: 保存
delete: 删除
login: 登录
signup: 注册
logout: 退出登录
verify: 验证
add_question: 我要提问
search:
title: 搜索结果
keywords: 关键词
options: 选项
follow: 关注
following: 已关注
counts: '{{count}} 个结果'
more: 更多
sort_btns:
relevance: 相关性
newest: 最新的
active: 活跃的
score: 评分
tips:
title: 高级搜索提示
tag: '<1>[tag]</1> 在指定标签中搜索'
user: '<1>user:username</1> 根据作者搜索'
answer: '<1>answers:0</1> 搜索未回答的问题'
score: '<1>score:3</1> 评分 3 分或以上'
question: '<1>is:question</1> 只搜索问题'
is_answer: '<1>is:answer</1> 只搜索回答'
empty: 找不到任何相关的内容。<br /> 请尝试其他关键字,或者减少查找内容的长度。
share:
name: 分享
copy: 复制链接
via: 分享在...
copied: 已复制
facebook: 分享到 Facebook
twitter: 分享到 Twitter
cannot_vote_for_self: 不能给自己投票
modal_confirm:
title: 发生错误...
account_result:
page_title: 欢迎来到 Answer
success: 你的账号已通过验证,即将返回首页。
link: 返回首页
invalid: 抱歉,此验证链接已失效。也许是你的账号已经通过验证了?
confirm_new_email: 你的电子邮箱已更新
confirm_new_email_invalid: 抱歉,此验证链接已失效。也许是你的邮箱已经成功更改了?
question:
following_tags: 已关注的标签
edit: 编辑
save: 保存
follow_tag_tip: 按照标签整理您的问题列表。
hot_questions: 热点问题
all_questions: 全部问题
x_questions: '{{ count }} 个问题'
x_answers: '{{ count }} 个回答'
questions: 个问题
answers: 回答
newest: 最新
active: 活跃
frequent: 浏览量
score: 评分
unanswered: 未回答
modified: 修改于
answered: 回答于
asked: 提问于
closed: 已关闭
follow_a_tag: 关注一个标签
more: 更多
personal:
overview: 概览
answers: 回答
answer: 回答
questions: 问题
question: 问题
bookmarks: 收藏
reputation: 声望
comments: 评论
votes: 得票
newest: 最新
score: 评分
edit_profile: 编辑我的资料
visited_x_days: 'Visited {{ count }} days'
viewed: Viewed
joined: 加入于
last_login: 上次登录
about_me: 关于我
about_me_empty: '// Hello, World !'
top_answers: 热门回答
top_questions: 热门问题
stats: 状态
list_empty: 没有找到相关的内容。<br />试试看其他标签?
accepted: 已采纳
answered: 回答于
asked: 提问于
upvote: 赞同
downvote: 反对
mod_short: 管理员
mod_long: 管理员
x_reputation: 声望
x_votes: 得票
x_answers: 个回答
x_questions: 个问题
page_404:
description: 页面不存在
back_home: 回到主页
page_50X:
description: 服务器遇到了一个错误,无法完成你的请求。
back_home: 回到主页
admin:
admin_header:
title: 后台管理
nav_menus:
dashboard: 后台管理
contents: 内容管理
questions: 问题
answers: 回答
users: 用户管理
flags: 举报管理
settings: 站点设置
general: 一般
interface: 界面
smtp: SMTP
dashboard:
title: 后台管理
welcome: 欢迎来到 Answer 后台管理!
version: 版本
flags:
title: 举报
pending: 等待处理
completed: 已完成
flagged: 被举报内容
created: 创建于
action: 操作
review: 审查
change_modal:
title: 更改用户状态为...
btn_cancel: 取消
btn_submit: 提交
normal_name: 正常
normal_description: 正常状态的用户可以提问和回答。
suspended_name: 封禁
suspended_description: 被封禁的用户将无法登录。
deleted_name: 删除
deleted_description: 删除用户的个人信息,认证等等。
inactive_name: 不活跃
inactive_description: 不活跃的用户必须重新验证邮箱。
confirm_title: 删除此用户
confirm_content: 确定要删除此用户?此操作无法撤销!
confirm_btn: 删除
msg:
empty: 请选择一个原因
status_modal:
title: '更改 {{ type }} 状态为...'
normal_name: 正常
normal_description: 所有用户都可以访问
closed_name: 关闭
closed_description: 不能回答,但仍然可以编辑、投票和评论。
deleted_name: 删除
deleted_description: 所有获得/损失的声望将会恢复。
btn_cancel: 取消
btn_submit: 提交
btn_next: 下一步
users:
title: 用户
name: 名称
email: 邮箱
reputation: 声望
created_at: 创建时间
delete_at: 删除时间
suspend_at: 封禁时间
status: 状态
action: 操作
change: 更改
all: 全部
inactive: 不活跃
suspended: 已封禁
deleted: 已删除
normal: 正常
questions:
page_title: 问题
normal: 正常
closed: 已关闭
deleted: 已删除
post: 标题
votes: 得票数
answers: 回答数
created: 创建于
status: 状态
action: 操作
change: 更改
answers:
page_title: 回答
normal: 正常
deleted: 已删除
post: 标题
votes: 得票数
created: 创建于
status: 状态
action: 操作
change: 更改
general:
page_title: 一般
name:
label: 站点名称
msg: 不能为空
text: 站点的名称作为站点的标题HTML 的 title 标签)。
short_description:
label: 简短的站点标语 (可选)
msg: 不能为空
text: 简短的标语作为网站主页的标题HTML 的 title 标签)。
description:
label: 网站描述 (可选)
msg: 不能为空
text: 使用一句话描述本站作为网站的描述HTML 的 meta 标签)。
interface:
page_title: 界面
logo:
label: Logo (可选)
msg: 不能为空
text: 可以上传图片,或者<1>重置</1>为站点标题。
theme:
label: 主题
msg: 不能为空
text: 选择一个主题
language:
label: 界面语言
msg: 不能为空
text: 设置用户界面语言,在刷新页面后生效。
smtp:
page_title: SMTP
from_email:
label: 发件人地址
msg: 不能为空
text: 用于发送邮件的地址。
from_name:
label: 发件人名称
msg: 不能为空
text: 发件人的名称
smtp_host:
label: SMTP 主机
msg: 不能为空
text: 邮件服务器
encryption:
label: 加密
msg: 不能为空
text: 对于大多数服务器而言SSL 是推荐开启的。
ssl: SSL
none: 无加密
smtp_port:
label: SMTP 端口
msg: SMTP 端口必须在 1 ~ 65535 之间。
text: 邮件服务器的端口号。
smtp_username:
label: SMTP 用户名
msg: 不能为空
smtp_password:
label: SMTP 密码
msg: 不能为空
test_email_recipient:
label: 测试邮件收件人
text: 提供用于接收测试邮件的邮箱地址。
msg: 地址无效
smtp_authentication:
label: SMTP 认证
msg: 不能为空
'yes':
'no':

View File

@ -1,4 +1,5 @@
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
@ -19,7 +20,8 @@ module.exports = {
},
ecmaVersion: 'latest',
sourceType: 'module',
project: './tsconfig.json',
tsconfigRootDir: __dirname,
project: ['./tsconfig.json'],
},
plugins: ['react', '@typescript-eslint'],
rules: {

View File

@ -1,10 +1,23 @@
const path = require('path');
const i18nLocaleTool = require('./scripts/i18n-locale-tool');
module.exports = {
webpack: function (config, env) {
if (env === 'production') {
config.output.publicPath = process.env.REACT_APP_PUBLIC_PATH;
i18nLocaleTool.resolvePresetLocales();
}
for (let _rule of config.module.rules) {
if (_rule.oneOf) {
_rule.oneOf.unshift({
test: /\.ya?ml$/,
use: 'yaml-loader'
});
break;
}
}
config.resolve.alias = {
...config.resolve.alias,
'@': path.resolve(__dirname, 'src'),
@ -14,6 +27,8 @@ module.exports = {
},
devServer: function (configFunction) {
i18nLocaleTool.autoSync();
return function (proxy, allowedHost) {
const config = configFunction(proxy, allowedHost);
config.proxy = {

View File

@ -10,7 +10,6 @@
"build:prod": "env-cmd -f .env.production react-app-rewired build",
"build": "env-cmd -f .env react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject",
"lint": "eslint . --cache --fix --ext .ts,.tsx",
"prepare": "cd .. && husky install",
"cz": "cz",
@ -74,6 +73,7 @@
"@types/react-helmet": "^6.1.5",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.33.0",
"chokidar": "^3.5.3",
"commitizen": "^4.2.5",
"conventional-changelog-cli": "^2.2.2",
"customize-cra": "^1.0.0",
@ -101,7 +101,8 @@
"sass": "^1.54.4",
"tsconfig-paths-webpack-plugin": "^4.0.0",
"typescript": "*",
"web-vitals": "^2.1.4"
"web-vitals": "^2.1.4",
"yaml-loader": "^0.8.0"
},
"packageManager": "pnpm@7.9.5",
"engines": {

View File

@ -26,6 +26,7 @@ specifiers:
axios: ^0.27.2
bootstrap: ^5.2.0
bootstrap-icons: ^1.9.1
chokidar: ^3.5.3
classnames: ^2.3.1
codemirror: 5.65.0
commitizen: ^4.2.5
@ -77,6 +78,7 @@ specifiers:
tsconfig-paths-webpack-plugin: ^4.0.0
typescript: '*'
web-vitals: ^2.1.4
yaml-loader: ^0.8.0
zustand: ^4.1.1
dependencies:
@ -131,6 +133,7 @@ devDependencies:
'@types/react-helmet': 6.1.5
'@typescript-eslint/eslint-plugin': 5.38.0_wsb62dxj2oqwgas4kadjymcmry
'@typescript-eslint/parser': 5.38.0_irgkl5vooow2ydyo6aokmferha
chokidar: 3.5.3
commitizen: 4.2.5
conventional-changelog-cli: 2.2.2
customize-cra: 1.0.0
@ -159,6 +162,7 @@ devDependencies:
tsconfig-paths-webpack-plugin: 4.0.0
typescript: 4.8.3
web-vitals: 2.1.4
yaml-loader: 0.8.0
packages:
@ -7040,6 +7044,10 @@ packages:
filelist: 1.0.4
minimatch: 3.1.2
/javascript-stringify/2.1.0:
resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==}
dev: true
/jest-changed-files/27.5.1:
resolution: {integrity: sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==}
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
@ -11682,6 +11690,15 @@ packages:
/yallist/4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
/yaml-loader/0.8.0:
resolution: {integrity: sha512-LjeKnTzVBKWiQBeE2L9ssl6WprqaUIxCSNs5tle8PaDydgu3wVFXTbMfsvF2MSErpy9TDVa092n4q6adYwJaWg==}
engines: {node: '>= 12.13'}
dependencies:
javascript-stringify: 2.1.0
loader-utils: 2.0.2
yaml: 2.1.1
dev: true
/yaml/1.10.2:
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
engines: {node: '>= 6'}

View File

@ -0,0 +1,56 @@
/* eslint-disable import/no-extraneous-dependencies */
const path = require('node:path');
const fs = require('node:fs');
const chokidar = require('chokidar');
const SRC_PATH = path.resolve(__dirname, '../../i18n');
const DEST_PATH = path.resolve(__dirname, '../src/i18n/locales');
const PRESET_LANG = ['en_US', 'zh_CN'];
const cleanLocales = () => {
fs.readdirSync(DEST_PATH).forEach((fp) => {
fs.rmSync(path.resolve(DEST_PATH, fp), { force: true, recursive: true });
});
};
const copyLocaleFile = (filePath) => {
const targetFilePath = path.resolve(DEST_PATH, path.basename(filePath));
fs.copyFile(
filePath,
targetFilePath,
fs.constants.COPYFILE_FICLONE,
(err) => {
if (err) {
throw err;
}
},
);
};
const watchAndSync = () => {
chokidar
.watch(path.resolve(SRC_PATH, '*.yaml'), {
awaitWriteFinish: true,
})
.on('all', (evt, filePath) => {
copyLocaleFile(filePath);
});
};
const autoSync = () => {
cleanLocales();
watchAndSync();
};
const resolvePresetLocales = () => {
PRESET_LANG.forEach((lng) => {
const sp = path.resolve(SRC_PATH, `${lng}.yaml`);
copyLocaleFile(sp);
});
};
module.exports = {
autoSync,
resolvePresetLocales,
};

View File

@ -1,5 +1,6 @@
export const DEFAULT_LANG = 'en_US';
export const CURRENT_LANG_STORAGE_KEY = '_a_lang_';
export const LANG_RESOURCE_STORAGE_KEY = '_a_lang_r_';
export const LOGGED_USER_STORAGE_KEY = '_a_lui_';
export const LOGGED_TOKEN_STORAGE_KEY = '_a_ltk_';
export const REDIRECT_PATH_STORAGE_KEY = '_a_rp_';

View File

@ -18,7 +18,7 @@ const PageTitle: FC<IProp> = ({ title = '', suffix = '' }) => {
if (!suffix) {
suffix = `${siteInfo.name}`;
}
title = title ? `${title} - ${suffix}` : suffix;
title = title ? `${title}${suffix ? ` - ${suffix}` : ''}` : suffix;
return <>{setPageTitle(title)}</>;
};

View File

@ -12,6 +12,7 @@ interface Props {
sortKey?: string;
className?: string;
pathname?: string;
wrapClassName?: string;
}
const MAX_BUTTON_COUNT = 3;
const Index: FC<Props> = ({
@ -21,6 +22,7 @@ const Index: FC<Props> = ({
i18nKeyPrefix = '',
className = '',
pathname = '',
wrapClassName = '',
}) => {
const [searchParams, setUrlSearchParams] = useSearchParams();
const navigate = useNavigate();
@ -51,7 +53,7 @@ const Index: FC<Props> = ({
return (typeof btn === 'string' ? btn : btn.name) === currentSort;
});
return (
<ButtonGroup size="sm">
<ButtonGroup size="sm" className={wrapClassName}>
{data.map((btn, index) => {
const key = typeof btn === 'string' ? btn : btn.sort;
const name = typeof btn === 'string' ? btn : btn.name;
@ -62,7 +64,7 @@ const Index: FC<Props> = ({
variant="outline-secondary"
active={currentSort === name}
className={classNames(
'text-capitalize',
'text-capitalize fit-content',
data.length > MAX_BUTTON_COUNT &&
index > MAX_BUTTON_COUNT - 2 &&
'd-none d-md-block',

View File

@ -1,5 +1,5 @@
import { FC } from 'react';
import { Row, Col, ListGroup } from 'react-bootstrap';
import { ListGroup } from 'react-bootstrap';
import { NavLink, useParams, useSearchParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
@ -103,23 +103,19 @@ const QuestionList: FC<Props> = ({ source }) => {
return (
<div>
<Row className="mb-3">
<Col className="d-flex align-items-center">
<h5 className="fs-5 text-nowrap mb-3 mb-md-0">
{source === 'questions'
? t('all_questions')
: t('x_questions', { count })}
</h5>
</Col>
<Col>
<QueryGroup
data={QuestionOrderKeys}
currentSort={curOrder}
pathname={source === 'questions' ? '/questions' : ''}
i18nKeyPrefix="question"
/>
</Col>
</Row>
<div className="mb-3 d-flex flex-wrap justify-content-between">
<h5 className="fs-5 text-nowrap mb-3 mb-md-0">
{source === 'questions'
? t('all_questions')
: t('x_questions', { count })}
</h5>
<QueryGroup
data={QuestionOrderKeys}
currentSort={curOrder}
pathname={source === 'questions' ? '/questions' : ''}
i18nKeyPrefix="question"
/>
</div>
<ListGroup variant="flush" className="border-top border-bottom-0">
{listData?.list?.map((li) => {
return (

View File

View File

@ -4,9 +4,8 @@ import i18next from 'i18next';
import Backend from 'i18next-http-backend';
import { DEFAULT_LANG } from '@/common/constants';
import en from './locales/en.json';
import zh from './locales/zh_CN.json';
import en_US from '@/i18n/locales/en_US.yaml';
import zh_CN from '@/i18n/locales/zh_CN.yaml';
i18next
// load translation using http
@ -16,10 +15,10 @@ i18next
.init({
resources: {
en_US: {
translation: en,
translation: en_US.ui,
},
zh_CN: {
translation: zh,
translation: zh_CN.ui,
},
},
// debug: process.env.NODE_ENV === 'development',

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
# all support language
language_options:
- label: "简体中文(CN)"
value: "zh_CN"
- label: "English(US)"
value: "en_US"

View File

@ -0,0 +1,170 @@
base:
success:
other: "Successo"
unknown:
other: "Errore sconosciuto"
request_format_error:
other: "Il formato della richiesta non è valido"
unauthorized_error:
other: "Non autorizzato"
database_error:
other: "Errore server dati"
email:
other: "email"
password:
other: "password"
email_or_password_wrong_error: &email_or_password_wrong
other: "Email o password errati"
error:
admin:
email_or_password_wrong: *email_or_password_wrong
answer:
not_found:
other: "Risposta non trovata"
comment:
edit_without_permission:
other: "Non si hanno di privilegi sufficienti per modificare il commento"
not_found:
other: "Commento non trovato"
email:
duplicate:
other: "email già esistente"
need_to_be_verified:
other: "email deve essere verificata"
verify_url_expired:
other: "l'url di verifica email è scaduto, si prega di reinviare la email"
lang:
not_found:
other: "lingua non trovata"
object:
captcha_verification_failed:
other: "captcha errato"
disallow_follow:
other: "Non sei autorizzato a seguire"
disallow_vote:
other: "non sei autorizzato a votare"
disallow_vote_your_self:
other: "Non puoi votare un tuo post!"
not_found:
other: "oggetto non trovato"
verification_failed:
other: "verifica fallita"
email_or_password_incorrect:
other: "email o password incorretti"
old_password_verification_failed:
other: "la verifica della vecchia password è fallita"
new_password_same_as_previous_setting:
other: "La nuova password è identica alla precedente"
question:
not_found:
other: "domanda non trovata"
rank:
fail_to_meet_the_condition:
other: "Condizioni non valide per il grado"
report:
handle_failed:
other: "Gestione del report fallita"
not_found:
other: "Report non trovato"
tag:
not_found:
other: "Etichetta non trovata"
theme:
not_found:
other: "tema non trovato"
user:
email_or_password_wrong:
other: *email_or_password_wrong
not_found:
other: "utente non trovato"
suspended:
other: "utente sospeso"
username_invalid:
other: "utente non valido"
username_duplicate:
other: "utente già in uso"
report:
spam:
name:
other: "spam"
description:
other: "Questo articolo è una pubblicità o vandalismo. Non è utile o rilevante all'argomento corrente"
rude:
name:
other: "scortese o violento"
description:
other: "Una persona ragionevole trova questo contenuto inappropriato a un discorso rispettoso"
duplicate:
name:
other: "duplicato"
description:
other: "Questa domanda è già stata posta e ha già una risposta."
not_answer:
name:
other: "non è una risposta"
description:
other: "Questo è stato postato come una risposta, ma non sta cercando di rispondere alla domanda. Dovrebbe essere una modifica, un commento, un'altra domanda o cancellato del tutto."
not_need:
name:
other: "non più necessario"
description:
other: "Questo commento è datato, conversazionale o non rilevante a questo articolo."
other:
name:
other: "altro"
description:
other: "Questo articolo richiede una supervisione dello staff per altre ragioni non listate sopra."
question:
close:
duplicate:
name:
other: "spam"
description:
other: "Questa domanda è già stata chiesta o ha già una risposta."
guideline:
name:
other: "motivo legato alla community"
description:
other: "Questa domanda non soddisfa le linee guida della comunità."
multiple:
name:
other: "richiede maggiori dettagli o chiarezza"
description:
other: "Questa domanda attualmente contiene più domande. Deve concentrarsi solamente su un unico problema."
other:
name:
other: "altro"
description:
other: "Questo articolo richiede un'altro motivo non listato sopra."
notification:
action:
update_question:
other: "domanda aggiornata"
answer_the_question:
other: "domanda risposta"
update_answer:
other: "risposta aggiornata"
adopt_answer:
other: "risposta accettata"
comment_question:
other: "domanda commentata"
comment_answer:
other: "risposta commentata"
reply_to_you:
other: "hai ricevuto risposta"
mention_you:
other: "sei stato menzionato"
your_question_is_closed:
other: "la tua domanda è stata chiusa"
your_question_was_deleted:
other: "la tua domanda è stata rimossa"
your_answer_was_deleted:
other: "la tua risposta è stata rimossa"
your_comment_was_deleted:
other: "il tuo commento è stato rimosso"

View File

@ -1,914 +0,0 @@
{
"how_to_format": {
"title": "如何设定文本格式",
"description": "<ul class=\"mb-0\"><li><p class=\"mb-2\">添加链接:</p><pre class=\"mb-2\"><code>&lt;https://url.com&gt;<br/><br/>[标题](https://url.com)</code></pre></li><li><p class=\"mb-2\">段落之间使用空行分隔</p></li><li><p class=\"mb-2\"><em>_斜体_</em> 或者 **<strong>粗体</strong>**</p></li><li><p class=\"mb-2\">使用 4 个空格缩进代码</p></li><li><p class=\"mb-2\">在行首添加<code>&gt;</code>表示引用</p></li><li><p class=\"mb-2\">反引号进行转义 <code>`像 _这样_`</code></p></li><li><p class=\"mb-2\">使用<code>```</code>创建代码块</p><pre class=\"mb-0\"><code>```<br/>// 这是代码<br/>```</code></pre></li></ul>"
},
"pagination": {
"prev": "上一页",
"next": "下一页"
},
"page_title": {
"question": "问题",
"questions": "问题",
"tag": "标签",
"tags": "标签",
"tag_wiki": "标签 wiki",
"edit_tag": "编辑标签",
"ask_a_question": "提问题",
"edit_question": "编辑问题",
"edit_answer": "编辑回答",
"search": "搜索",
"posts_containing": "包含",
"settings": "设定",
"notifications": "通知",
"login": "登录",
"sign_up": "注册",
"account_recovery": "账号恢复",
"account_activation": "账号激活",
"confirm_email": "确认电子邮件",
"account_suspended": "账号已封禁",
"admin": "后台管理"
},
"notifications": {
"title": "通知",
"inbox": "收件箱",
"achievement": "成就",
"all_read": "全部标记为已读",
"show_more": "显示更多"
},
"suspended": {
"title": "账号已封禁",
"until_time": "你的账号被封禁至{{ time }}。",
"forever": "你的账号已被永久封禁。",
"end": "违反了我们的社区准则。"
},
"editor": {
"blockquote": {
"text": "引用"
},
"bold": {
"text": "粗体"
},
"chart": {
"text": "图表",
"flow_chart": "流程图",
"sequence_diagram": "时序图",
"class_diagram": "类图",
"state_diagram": "状态图",
"entity_relationship_diagram": "ER 图",
"user_defined_diagram": "User defined diagram",
"gantt_chart": "甘特图",
"pie_chart": "饼图"
},
"code": {
"text": "代码块",
"add_code": "添加代码块",
"form": {
"fields": {
"code": {
"label": "代码块",
"msg": {
"empty": "代码块不能为空"
}
},
"language": {
"label": "语言 (可选)",
"placeholder": "自动识别"
}
}
},
"btn_cancel": "取消",
"btn_confirm": "添加"
},
"formula": {
"text": "公式",
"options": {
"inline": "行内公式",
"block": "公式块"
}
},
"heading": {
"text": "标题",
"options": {
"h1": "标题 1",
"h2": "标题 2",
"h3": "标题 3",
"h4": "标题 4",
"h5": "标题 5",
"h6": "标题 6"
}
},
"help": {
"text": "帮助"
},
"hr": {
"text": "水平分割线"
},
"image": {
"text": "图片",
"add_image": "添加图片",
"tab_image": "上传图片",
"form_image": {
"fields": {
"file": {
"label": "图片文件",
"btn": "选择图片",
"msg": {
"empty": "请选择图片文件。",
"only_image": "只能上传图片文件。",
"max_size": "图片文件大小不能超过 4 MB。"
}
},
"description": {
"label": "图片描述(可选)"
}
}
},
"tab_url": "网络图片",
"form_url": {
"fields": {
"url": {
"label": "图片地址",
"msg": {
"empty": "图片地址不能为空"
}
},
"name": {
"label": "图片描述(可选)"
}
}
},
"btn_cancel": "取消",
"btn_confirm": "添加",
"uploading": "上传中..."
},
"indent": {
"text": "添加缩进"
},
"outdent": {
"text": "减少缩进"
},
"italic": {
"text": "斜体"
},
"link": {
"text": "超链接",
"add_link": "添加超链接",
"form": {
"fields": {
"url": {
"label": "链接",
"msg": {
"empty": "链接不能为空。"
}
},
"name": {
"label": "链接描述(可选)"
}
}
},
"btn_cancel": "取消",
"btn_confirm": "添加"
},
"ordered_list": {
"text": "有编号列表"
},
"unordered_list": {
"text": "无编号列表"
},
"table": {
"text": "表格",
"heading": "表头",
"cell": "单元格"
}
},
"close_modal": {
"title": "关闭原因是...",
"btn_cancel": "取消",
"btn_submit": "提交",
"remark": {
"empty": "不能为空。"
},
"msg": {
"empty": "请选择一个原因。"
}
},
"report_modal": {
"flag_title": "举报原因是...",
"close_title": "关闭原因是...",
"review_question_title": "审查问题",
"review_answer_title": "审查回答",
"review_comment_title": "审查评论",
"btn_cancel": "取消",
"btn_submit": "提交",
"remark": {
"empty": "不能为空"
},
"msg": {
"empty": "请选择一个原因。"
}
},
"tag_modal": {
"title": "创建新标签",
"form": {
"fields": {
"display_name": {
"label": "显示名称(别名)",
"msg": {
"empty": "不能为空",
"range": "不能超过 35 个字符"
}
},
"slug_name": {
"label": "URL 固定链接",
"description": "必须由 \"a-z\", \"0-9\", \"+ # - .\" 组成",
"msg": {
"empty": "不能为空",
"range": "不能超过 35 个字符",
"character": "包含非法字符"
}
},
"description": {
"label": "标签描述(可选)"
}
}
},
"btn_cancel": "取消",
"btn_submit": "提交"
},
"tag_info": {
"created_at": "创建于",
"edited_at": "编辑于",
"synonyms": {
"title": "同义词",
"text": "以下标签等同于",
"empty": "此标签目前没有同义词。",
"btn_add": "添加同义词",
"btn_edit": "编辑",
"btn_save": "保存"
},
"synonyms_text": "以下标签等同于",
"delete": {
"title": "删除标签",
"content": "<p>不允许删除有关联问题的标签。</p><p>请先从关联的问题中删除此标签的引用。</p>",
"content2": "确定要删除吗?",
"close": "关闭"
}
},
"edit_tag": {
"title": "编辑标签",
"default_reason": "编辑标签",
"form": {
"fields": {
"revision": {
"label": "编辑历史"
},
"display_name": {
"label": "名称"
},
"slug_name": {
"label": "URL 固定链接",
"info": "必须由 \"a-z\", \"0-9\", \"+ # - .\" 组成"
},
"description": {
"label": "描述"
},
"edit_summary": {
"label": "编辑概要",
"placeholder": "简单描述更改原因 (错别字、文字表达、格式等等)"
}
}
},
"btn_save_edits": "保存更改",
"btn_cancel": "取消"
},
"dates": {
"long_date": "MM月DD日",
"long_date_with_year": "YYYY年MM月DD日",
"long_date_with_time": "YYYY年MM月DD日 HH:mm",
"now": "刚刚",
"x_seconds_ago": "{{count}} 秒前",
"x_minutes_ago": "{{count}} 分钟前",
"x_hours_ago": "{{count}} 小时前"
},
"comment": {
"btn_add_comment": "添加评论",
"reply_to": "回复",
"btn_reply": "回复",
"btn_edit": "编辑",
"btn_delete": "删除",
"btn_flag": "举报",
"btn_save_edits": "保存",
"btn_cancel": "取消",
"show_more": "显示更多评论",
"tip_question": "使用评论提问更多信息或者提出改进意见。尽量避免使用评论功能回答问题。",
"tip_answer": "使用评论对回答者进行回复,或者通知回答者你已更新了问题的内容。如果要补充或者完善问题的内容,请在原问题中更改。"
},
"edit_answer": {
"title": "编辑回答",
"default_reason": "编辑回答",
"form": {
"fields": {
"revision": {
"label": "编辑历史"
},
"answer": {
"label": "回答内容"
},
"edit_summary": {
"label": "编辑概要",
"placeholder": "简单描述更改原因 (错别字、文字表达、格式等等)"
}
}
},
"btn_save_edits": "保存更改",
"btn_cancel": "取消"
},
"tags": {
"title": "标签",
"sort_buttons": {
"popular": "热门",
"name": "名称",
"newest": "最新"
},
"button_follow": "关注",
"button_following": "已关注",
"tag_label": "个问题",
"search_placeholder": "通过标签名过滤",
"no_description": "此标签无描述。",
"more": "更多"
},
"ask": {
"title": "提交新的问题",
"edit_title": "编辑问题",
"default_reason": "编辑问题",
"similar_questions": "相似的问题",
"form": {
"fields": {
"revision": {
"label": "编辑历史"
},
"title": {
"label": "标题",
"placeholder": "请详细描述你的问题",
"msg": {
"empty": "标题不能为空",
"range": "标题最多 150 个字符"
}
},
"body": {
"label": "内容",
"msg": {
"empty": "内容不能为空"
}
},
"tags": {
"label": "标签",
"msg": {
"empty": "必须选择一个标签"
}
},
"answer": {
"label": "回答内容",
"msg": {
"empty": "回答内容不能为空"
}
}
}
},
"btn_post_question": "提交问题",
"btn_save_edits": "保存更改",
"answer_question": "直接发表回答",
"post_question&answer": "提交问题和回答"
},
"tag_selector": {
"add_btn": "添加标签",
"create_btn": "创建新标签",
"search_tag": "搜索标签",
"hint": "选择至少一个与问题相关的标签。",
"no_result": "没有匹配的标签"
},
"header": {
"nav": {
"question": "问题",
"tag": "标签",
"user": "用户",
"profile": "用户主页",
"setting": "账号设置",
"logout": "退出登录",
"admin": "后台管理"
},
"search": {
"placeholder": "搜索"
}
},
"footer": {
"build_on": "Built on <1> Answer </1>- the open-source software that power Q&A communities<br />Made with love © 2022 Answer"
},
"upload_img": {
"name": "更改图片",
"loading": "加载中..."
},
"pic_auth_code": {
"title": "验证码",
"placeholder": "输入图片中的文字",
"msg": {
"empty": "不能为空"
}
},
"inactive": {
"first": "马上就好了!我们发送了一封激活邮件到 <bold>{{mail}}</bold>。请按照邮件中的说明激活您的帐户。",
"info": "如果没有收到,请检查您的垃圾邮件文件夹。",
"another": "我们向您发送了另一封激活电子邮件,地址为 <bold>{{mail}}</bold>。它可能需要几分钟才能到达;请务必检查您的垃圾邮件文件夹。",
"btn_name": "重新发送激活邮件",
"msg": {
"empty": "不能为空"
}
},
"login": {
"page_title": "欢迎来到 Answer",
"info_sign": "没有帐户?<1>注册</1>",
"info_login": "已经有一个帐户?<1>登录</1>",
"forgot_pass": "忘记密码?",
"name": {
"label": "昵称",
"msg": {
"empty": "昵称不能为空",
"range": "昵称最多 30 个字符"
}
},
"email": {
"label": "邮箱",
"msg": {
"empty": "邮箱不能为空"
}
},
"password": {
"label": "密码",
"msg": {
"empty": "密码不能为空",
"different": "两次输入密码不一致"
}
}
},
"account_forgot": {
"page_title": "忘记密码",
"btn_name": "发送恢复邮件",
"send_success": "如无意外,你的邮箱 <strong>{{mail}}</strong> 将会收到一封重置密码的邮件,请根据指引重置你的密码。",
"email": {
"label": "邮箱",
"msg": {
"empty": "邮箱不能为空"
}
}
},
"password_reset": {
"page_title": "密码重置",
"btn_name": "重置我的密码",
"reset_success": "你已经成功更改密码,将返回登录页面",
"link_invalid": "抱歉,此密码重置链接已失效。也许是你已经重置过密码了?",
"to_login": "前往登录页面",
"password": {
"label": "密码",
"msg": {
"empty": "密码不能为空",
"length": "密码长度在8-32个字符之间",
"different": "两次输入密码不一致"
}
},
"password_confirm": {
"label": "确认新密码"
}
},
"settings": {
"page_title": "设置",
"nav": {
"profile": "我的资料",
"notification": "通知",
"account": "账号",
"interface": "界面"
},
"profile": {
"btn_name": "保存更改",
"display_name": {
"label": "昵称",
"msg": "昵称不能为空",
"msg_range": "昵称不能超过 30 个字符"
},
"username": {
"label": "用户名",
"caption": "用户之间可以通过 \"@用户名\" 进行交互。",
"msg": "用户名不能为空",
"msg_range": "用户名不能超过 30 个字符",
"character": "用户名只能由 \"a-z\", \"0-9\", \" - . _\" 组成"
},
"avatar": {
"label": "头像",
"text": "您可以上传图片作为头像,也可以 <1>重置</1> 为"
},
"bio": {
"label": "关于我 (可选)"
},
"website": {
"label": "网站 (可选)",
"placeholder": "https://example.com",
"msg": "格式不正确"
},
"location": {
"label": "位置 (可选)",
"placeholder": "城市, 国家"
}
},
"notification": {
"email": {
"label": "邮件通知",
"radio": "你的提问有新的回答,评论,和其他"
}
},
"account": {
"change_email_btn": "更改邮箱",
"change_pass_btn": "更改密码",
"change_email_info": "邮件已发送。请根据指引完成验证。",
"email": {
"label": "邮箱",
"msg": "邮箱不能为空"
},
"password_title": "密码",
"current_pass": {
"label": "当前密码",
"msg": {
"empty": "当前密码不能为空",
"length": "密码长度必须在 8 至 32 之间",
"different": "两次输入的密码不匹配"
}
},
"new_pass": {
"label": "新密码"
},
"pass_confirm": {
"label": "确认新密码"
}
},
"interface": {
"lang": {
"label": "界面语言",
"text": "设置用户界面语言,在刷新页面后生效。"
}
}
},
"toast": {
"update": "更新成功",
"update_password": "更改密码成功。",
"flag_success": "感谢您的标记,我们会尽快处理。"
},
"related_question": {
"title": "相关问题",
"btn": "我要提问",
"answers": "个回答"
},
"question_detail": {
"Asked": "提问于",
"asked": "提问于",
"update": "修改于",
"edit": "最后编辑于",
"Views": "阅读次数",
"Follow": "关注此问题",
"Following": "已关注",
"answered": "回答于",
"closed_in": "关闭于",
"show_exist": "查看相关问题。",
"answers": {
"title": "个回答",
"score": "评分",
"newest": "最新",
"btn_accept": "采纳",
"btn_accepted": "已被采纳"
},
"write_answer": {
"title": "你的回答",
"btn_name": "提交你的回答",
"confirm_title": "继续回答",
"continue": "继续",
"confirm_info": "<p>您确定要提交一个新的回答吗?</p><p>您可以直接编辑和改善您之前的回答的。</p>",
"empty": "回答内容不能为空。"
}
},
"delete": {
"title": "删除",
"question": "我们不建议<strong>删除有回答的帖子</strong>。因为这样做会使得后来的读者无法从该问题中获得帮助。</p><p>如果删除过多有回答的帖子,你的账号将会被禁止提问。你确定要删除吗?",
"answer_accepted": "<p>我们不建议<strong>删除被采纳的回答</strong>。因为这样做会使得后来的读者无法从该回答中获得帮助。</p>如果删除过多被采纳的回答,你的账号将会被禁止回答任何提问。你确定要删除吗?",
"other": "你确定要删除?",
"tip_question_deleted": "此问题已被删除",
"tip_answer_deleted": "此回答已被删除"
},
"btns": {
"confirm": "确认",
"cancel": "取消",
"save": "保存",
"delete": "删除",
"login": "登录",
"signup": "注册",
"logout": "退出登录",
"verify": "验证",
"add_question": "我要提问"
},
"search": {
"title": "搜索结果",
"keywords": "关键词",
"options": "选项",
"follow": "关注",
"following": "已关注",
"counts": "{{count}} 个结果",
"more": "更多",
"sort_btns": {
"relevance": "相关性",
"newest": "最新的",
"active": "活跃的",
"score": "评分"
},
"tips": {
"title": "高级搜索提示",
"tag": "<1>[tag]</1> 在指定标签中搜索",
"user": "<1>user:username</1> 根据作者搜索",
"answer": "<1>answers:0</1> 搜索未回答的问题",
"score": "<1>score:3</1> 评分 3 分或以上",
"question": "<1>is:question</1> 只搜索问题",
"is_answer": "<1>is:answer</1> 只搜索回答"
},
"empty": "找不到任何相关的内容。<br /> 请尝试其他关键字,或者减少查找内容的长度。"
},
"share": {
"name": "分享",
"copy": "复制链接",
"via": "分享在...",
"copied": "已复制",
"facebook": "分享到 Facebook",
"twitter": "分享到 Twitter"
},
"cannot_vote_for_self": "不能给自己投票",
"modal_confirm": {
"title": "发生错误..."
},
"account_result": {
"page_title": "欢迎来到 Answer",
"success": "你的账号已通过验证,即将返回首页。",
"link": "返回首页",
"invalid": "抱歉,此验证链接已失效。也许是你的账号已经通过验证了?",
"confirm_new_email": "你的电子邮箱已更新",
"confirm_new_email_invalid": "抱歉,此验证链接已失效。也许是你的邮箱已经成功更改了?"
},
"question": {
"following_tags": "已关注的标签",
"edit": "编辑",
"save": "保存",
"follow_tag_tip": "按照标签整理您的问题列表。",
"hot_questions": "热点问题",
"all_questions": "全部问题",
"x_questions": "{{ count }} 个问题",
"x_answers": "{{ count }} 个回答",
"questions": "个问题",
"answers": "回答",
"newest": "最新",
"active": "活跃",
"frequent": "浏览量",
"score": "评分",
"unanswered": "未回答",
"modified": "修改于",
"answered": "回答于",
"asked": "提问于",
"closed": "已关闭",
"follow_a_tag": "关注一个标签",
"more": "更多"
},
"personal": {
"overview": "概览",
"answers": "回答",
"answer": "回答",
"questions": "问题",
"question": "问题",
"bookmarks": "收藏",
"reputation": "声望",
"comments": "评论",
"votes": "得票",
"newest": "最新",
"score": "评分",
"edit_profile": "编辑我的资料",
"visited_x_days": "Visited {{ count }} days",
"viewed": "Viewed",
"joined": "加入于",
"last_login": "上次登录",
"about_me": "关于我",
"about_me_empty": "// Hello, World !",
"top_answers": "热门回答",
"top_questions": "热门问题",
"stats": "状态",
"list_empty": "没有找到相关的内容。<br />试试看其他标签?",
"accepted": "已采纳",
"answered": "回答于",
"asked": "提问于",
"upvote": "赞同",
"downvote": "反对",
"mod_short": "管理员",
"mod_long": "管理员",
"x_reputation": "声望",
"x_votes": "得票",
"x_answers": "个回答",
"x_questions": "个问题"
},
"page_404": {
"description": "页面不存在",
"back_home": "回到主页"
},
"page_50X": {
"description": "服务器遇到了一个错误,无法完成你的请求。",
"back_home": "回到主页"
},
"admin": {
"admin_header": {
"title": "后台管理"
},
"nav_menus": {
"dashboard": "后台管理",
"contents": "内容管理",
"questions": "问题",
"answers": "回答",
"users": "用户管理",
"flags": "举报管理",
"settings": "站点设置",
"general": "一般",
"interface": "界面",
"smtp": "SMTP"
},
"dashboard": {
"title": "后台管理",
"welcome": "欢迎来到 Answer 后台管理!",
"version": "版本"
},
"flags": {
"title": "举报",
"pending": "等待处理",
"completed": "已完成",
"flagged": "被举报内容",
"created": "创建于",
"action": "操作",
"review": "审查"
},
"change_modal": {
"title": "更改用户状态为...",
"btn_cancel": "取消",
"btn_submit": "提交",
"normal_name": "正常",
"normal_description": "正常状态的用户可以提问和回答。",
"suspended_name": "封禁",
"suspended_description": "被封禁的用户将无法登录。",
"deleted_name": "删除",
"deleted_description": "删除用户的个人信息,认证等等。",
"inactive_name": "不活跃",
"inactive_description": "不活跃的用户必须重新验证邮箱。",
"confirm_title": "删除此用户",
"confirm_content": "确定要删除此用户?此操作无法撤销!",
"confirm_btn": "删除",
"msg": {
"empty": "请选择一个原因"
}
},
"status_modal": {
"title": "更改 {{ type }} 状态为...",
"normal_name": "正常",
"normal_description": "所有用户都可以访问",
"closed_name": "关闭",
"closed_description": "不能回答,但仍然可以编辑、投票和评论。",
"deleted_name": "删除",
"deleted_description": "所有获得/损失的声望将会恢复。",
"btn_cancel": "取消",
"btn_submit": "提交",
"btn_next": "下一步"
},
"users": {
"title": "用户",
"name": "名称",
"email": "邮箱",
"reputation": "声望",
"created_at": "创建时间",
"delete_at": "删除时间",
"suspend_at": "封禁时间",
"status": "状态",
"action": "操作",
"change": "更改",
"all": "全部",
"inactive": "不活跃",
"suspended": "已封禁",
"deleted": "已删除",
"normal": "正常"
},
"questions": {
"page_title": "问题",
"normal": "正常",
"closed": "已关闭",
"deleted": "已删除",
"post": "标题",
"votes": "得票数",
"answers": "回答数",
"created": "创建于",
"status": "状态",
"action": "操作",
"change": "更改"
},
"answers": {
"page_title": "回答",
"normal": "正常",
"deleted": "已删除",
"post": "标题",
"votes": "得票数",
"created": "创建于",
"status": "状态",
"action": "操作",
"change": "更改"
},
"general": {
"page_title": "一般",
"name": {
"label": "站点名称",
"msg": "不能为空",
"text": "站点的名称作为站点的标题HTML 的 title 标签)。"
},
"short_description": {
"label": "简短的站点标语 (可选)",
"msg": "不能为空",
"text": "简短的标语作为网站主页的标题HTML 的 title 标签)。"
},
"description": {
"label": "网站描述 (可选)",
"msg": "不能为空",
"text": "使用一句话描述本站作为网站的描述HTML 的 meta 标签)。"
}
},
"interface": {
"page_title": "界面",
"logo": {
"label": "Logo (可选)",
"msg": "不能为空",
"text": "可以上传图片,或者<1>重置</1>为站点标题。"
},
"theme": {
"label": "主题",
"msg": "不能为空",
"text": "选择一个主题"
},
"language": {
"label": "界面语言",
"msg": "不能为空",
"text": "设置用户界面语言,在刷新页面后生效。"
}
},
"smtp": {
"page_title": "SMTP",
"from_email": {
"label": "发件人地址",
"msg": "不能为空",
"text": "用于发送邮件的地址。"
},
"from_name": {
"label": "发件人名称",
"msg": "不能为空",
"text": "发件人的名称"
},
"smtp_host": {
"label": "SMTP 主机",
"msg": "不能为空",
"text": "邮件服务器"
},
"encryption": {
"label": "加密",
"msg": "不能为空",
"text": "对于大多数服务器而言SSL 是推荐开启的。",
"ssl": "SSL",
"none": "无加密"
},
"smtp_port": {
"label": "SMTP 端口",
"msg": "SMTP 端口必须在 1 ~ 65535 之间。",
"text": "邮件服务器的端口号。"
},
"smtp_username": {
"label": "SMTP 用户名",
"msg": "不能为空"
},
"smtp_password": {
"label": "SMTP 密码",
"msg": "不能为空"
},
"test_email_recipient": {
"label": "测试邮件收件人",
"text": "提供用于接收测试邮件的邮箱地址。",
"msg": "地址无效"
},
"smtp_authentication": {
"label": "SMTP 认证",
"msg": "不能为空",
"yes": "是",
"no": "否"
}
}
}
}

View File

@ -0,0 +1,920 @@
base:
success:
other: "成功"
unknown:
other: "未知错误"
request_format_error:
other: "请求格式错误"
unauthorized_error:
other: "未登录"
database_error:
other: "数据服务异常"
email:
other: "邮箱"
password:
other: "密码"
email_or_password_wrong_error: &email_or_password_wrong
other: "邮箱或密码错误"
error:
admin:
email_or_password_wrong: *email_or_password_wrong
answer:
not_found:
other: "答案未找到"
comment:
edit_without_permission:
other: "不允许编辑评论"
not_found:
other: "评论未找到"
email:
duplicate:
other: "邮箱已经存在"
need_to_be_verified:
other: "邮箱需要验证"
verify_url_expired:
other: "邮箱验证的网址已过期,请重新发送邮件"
lang:
not_found:
other: "语言未找到"
object:
captcha_verification_failed:
other: "验证码错误"
disallow_follow:
other: "你不能关注"
disallow_vote:
other: "你不能投票"
disallow_vote_your_self:
other: "你不能为自己的帖子投票!"
not_found:
other: "对象未找到"
verification_failed:
other: "验证失败"
email_or_password_incorrect:
other: "邮箱或密码不正确"
old_password_verification_failed:
other: "旧密码验证失败"
new_password_same_as_previous_setting:
other: "新密码与之前的设置相同"
question:
not_found:
other: "问题未找到"
rank:
fail_to_meet_the_condition:
other: "级别不符合条件"
report:
handle_failed:
other: "报告处理失败"
not_found:
other: "报告未找到"
tag:
not_found:
other: "标签未找到"
theme:
not_found:
other: "主题未找到"
user:
email_or_password_wrong:
other: *email_or_password_wrong
not_found:
other: "用户未找到"
suspended:
other: "用户已被暂停"
username_invalid:
other: "用户名无效"
username_duplicate:
other: "用户名已被使用"
set_avatar:
other: "头像设置错误"
report:
spam:
name:
other: "垃圾信息"
description:
other: "此帖子是一个广告贴,或是破坏性行为。它对当前的主题无用,也不相关。"
rude:
name:
other: "粗鲁或辱骂的"
description:
other: "有理智的人都会发现此内容不适合进行尊重的讨论。"
duplicate:
name:
other: "重复信息"
description:
other: "此问题以前就有人问过,而且已经有了答案。"
not_answer:
name:
other: "不是答案"
description:
other: "此帖子是作为一个答案发布的,但它并没有试图回答这个问题。总之,它可能应该是个编辑,评论,另一个问题或者被删除。"
not_need:
name:
other: "不再需要"
description:
other: "此条评论是过时的,对话性的或与本帖无关。"
other:
name:
other: "其他原因"
description:
other: "此帖子需要工作人员关注,因为是上述所列以外的其他理由。"
question:
close:
duplicate:
name:
other: "垃圾信息"
description:
other: "此问题以前就有人问过,而且已经有了答案。"
guideline:
name:
other: "社区特定原因"
description:
other: "此问题不符合社区准则。"
multiple:
name:
other: "需要细节或澄清"
description:
other: "此问题目前涵盖多个问题。它应该只集中在一个问题上。"
other:
name:
other: "其他原因"
description:
other: "此帖子需要上述所列以外的其他理由。"
notification:
action:
update_question:
other: "更新了问题"
answer_the_question:
other: "回答了问题"
update_answer:
other: "更新了答案"
adopt_answer:
other: "接受了答案"
comment_question:
other: "评论了问题"
comment_answer:
other: "评论了答案"
reply_to_you:
other: "回复了你"
mention_you:
other: "提到了你"
your_question_is_closed:
other: "你的问题已被关闭"
your_question_was_deleted:
other: "你的问题已被删除"
your_answer_was_deleted:
other: "你的答案已被删除"
your_comment_was_deleted:
other: "你的评论已被删除"
# The following fields are used for interface presentation(Front-end)
ui:
how_to_format:
title: 如何设定文本格式
description: >-
<ul class="mb-0"><li><p class="mb-2">添加链接:</p><pre
class="mb-2"><code>&lt;https://url.com&gt;<br/><br/>[标题](https://url.com)</code></pre></li><li><p
class="mb-2">段落之间使用空行分隔</p></li><li><p class="mb-2"><em>_斜体_</em> 或者
**<strong>粗体</strong>**</p></li><li><p class="mb-2">使用 4
个空格缩进代码</p></li><li><p
class="mb-2">在行首添加<code>&gt;</code>表示引用</p></li><li><p class="mb-2">反引号进行转义
<code>`像 _这样_`</code></p></li><li><p
class="mb-2">使用<code>```</code>创建代码块</p><pre class="mb-0"><code>```<br/>//
这是代码<br/>```</code></pre></li></ul>
pagination:
prev: 上一页
next: 下一页
page_title:
question: 问题
questions: 问题
tag: 标签
tags: 标签
tag_wiki: 标签 wiki
edit_tag: 编辑标签
ask_a_question: 提问题
edit_question: 编辑问题
edit_answer: 编辑回答
search: 搜索
posts_containing: 包含
settings: 设定
notifications: 通知
login: 登录
sign_up: 注册
account_recovery: 账号恢复
account_activation: 账号激活
confirm_email: 确认电子邮件
account_suspended: 账号已封禁
admin: 后台管理
notifications:
title: 通知
inbox: 收件箱
achievement: 成就
all_read: 全部标记为已读
show_more: 显示更多
suspended:
title: 账号已封禁
until_time: '你的账号被封禁至{{ time }}。'
forever: 你的账号已被永久封禁。
end: 违反了我们的社区准则。
editor:
blockquote:
text: 引用
bold:
text: 粗体
chart:
text: 图表
flow_chart: 流程图
sequence_diagram: 时序图
class_diagram: 类图
state_diagram: 状态图
entity_relationship_diagram: ER 图
user_defined_diagram: User defined diagram
gantt_chart: 甘特图
pie_chart: 饼图
code:
text: 代码块
add_code: 添加代码块
form:
fields:
code:
label: 代码块
msg:
empty: 代码块不能为空
language:
label: 语言 (可选)
placeholder: 自动识别
btn_cancel: 取消
btn_confirm: 添加
formula:
text: 公式
options:
inline: 行内公式
block: 公式块
heading:
text: 标题
options:
h1: 标题 1
h2: 标题 2
h3: 标题 3
h4: 标题 4
h5: 标题 5
h6: 标题 6
help:
text: 帮助
hr:
text: 水平分割线
image:
text: 图片
add_image: 添加图片
tab_image: 上传图片
form_image:
fields:
file:
label: 图片文件
btn: 选择图片
msg:
empty: 请选择图片文件。
only_image: 只能上传图片文件。
max_size: 图片文件大小不能超过 4 MB。
description:
label: 图片描述(可选)
tab_url: 网络图片
form_url:
fields:
url:
label: 图片地址
msg:
empty: 图片地址不能为空
name:
label: 图片描述(可选)
btn_cancel: 取消
btn_confirm: 添加
uploading: 上传中...
indent:
text: 添加缩进
outdent:
text: 减少缩进
italic:
text: 斜体
link:
text: 超链接
add_link: 添加超链接
form:
fields:
url:
label: 链接
msg:
empty: 链接不能为空。
name:
label: 链接描述(可选)
btn_cancel: 取消
btn_confirm: 添加
ordered_list:
text: 有编号列表
unordered_list:
text: 无编号列表
table:
text: 表格
heading: 表头
cell: 单元格
close_modal:
title: 关闭原因是...
btn_cancel: 取消
btn_submit: 提交
remark:
empty: 不能为空。
msg:
empty: 请选择一个原因。
report_modal:
flag_title: 举报原因是...
close_title: 关闭原因是...
review_question_title: 审查问题
review_answer_title: 审查回答
review_comment_title: 审查评论
btn_cancel: 取消
btn_submit: 提交
remark:
empty: 不能为空
msg:
empty: 请选择一个原因。
tag_modal:
title: 创建新标签
form:
fields:
display_name:
label: 显示名称(别名)
msg:
empty: 不能为空
range: 不能超过 35 个字符
slug_name:
label: URL 固定链接
description: '必须由 "a-z", "0-9", "+ # - ." 组成'
msg:
empty: 不能为空
range: 不能超过 35 个字符
character: 包含非法字符
description:
label: 标签描述(可选)
btn_cancel: 取消
btn_submit: 提交
tag_info:
created_at: 创建于
edited_at: 编辑于
synonyms:
title: 同义词
text: 以下标签等同于
empty: 此标签目前没有同义词。
btn_add: 添加同义词
btn_edit: 编辑
btn_save: 保存
synonyms_text: 以下标签等同于
delete:
title: 删除标签
content: <p>不允许删除有关联问题的标签。</p><p>请先从关联的问题中删除此标签的引用。</p>
content2: 确定要删除吗?
close: 关闭
edit_tag:
title: 编辑标签
default_reason: 编辑标签
form:
fields:
revision:
label: 编辑历史
display_name:
label: 名称
slug_name:
label: URL 固定链接
info: '必须由 "a-z", "0-9", "+ # - ." 组成'
description:
label: 描述
edit_summary:
label: 编辑概要
placeholder: 简单描述更改原因 (错别字、文字表达、格式等等)
btn_save_edits: 保存更改
btn_cancel: 取消
dates:
long_date: MM月DD日
long_date_with_year: YYYY年MM月DD日
long_date_with_time: 'YYYY年MM月DD日 HH:mm'
now: 刚刚
x_seconds_ago: '{{count}} 秒前'
x_minutes_ago: '{{count}} 分钟前'
x_hours_ago: '{{count}} 小时前'
comment:
btn_add_comment: 添加评论
reply_to: 回复
btn_reply: 回复
btn_edit: 编辑
btn_delete: 删除
btn_flag: 举报
btn_save_edits: 保存
btn_cancel: 取消
show_more: 显示更多评论
tip_question: 使用评论提问更多信息或者提出改进意见。尽量避免使用评论功能回答问题。
tip_answer: 使用评论对回答者进行回复,或者通知回答者你已更新了问题的内容。如果要补充或者完善问题的内容,请在原问题中更改。
edit_answer:
title: 编辑回答
default_reason: 编辑回答
form:
fields:
revision:
label: 编辑历史
answer:
label: 回答内容
edit_summary:
label: 编辑概要
placeholder: 简单描述更改原因 (错别字、文字表达、格式等等)
btn_save_edits: 保存更改
btn_cancel: 取消
tags:
title: 标签
sort_buttons:
popular: 热门
name: 名称
newest: 最新
button_follow: 关注
button_following: 已关注
tag_label: 个问题
search_placeholder: 通过标签名过滤
no_description: 此标签无描述。
more: 更多
ask:
title: 提交新的问题
edit_title: 编辑问题
default_reason: 编辑问题
similar_questions: 相似的问题
form:
fields:
revision:
label: 编辑历史
title:
label: 标题
placeholder: 请详细描述你的问题
msg:
empty: 标题不能为空
range: 标题最多 150 个字符
body:
label: 内容
msg:
empty: 内容不能为空
tags:
label: 标签
msg:
empty: 必须选择一个标签
answer:
label: 回答内容
msg:
empty: 回答内容不能为空
btn_post_question: 提交问题
btn_save_edits: 保存更改
answer_question: 直接发表回答
post_question&answer: 提交问题和回答
tag_selector:
add_btn: 添加标签
create_btn: 创建新标签
search_tag: 搜索标签
hint: 选择至少一个与问题相关的标签。
no_result: 没有匹配的标签
header:
nav:
question: 问题
tag: 标签
user: 用户
profile: 用户主页
setting: 账号设置
logout: 退出登录
admin: 后台管理
search:
placeholder: 搜索
footer:
build_on: >-
Built on <1> Answer </1>- the open-source software that power Q&A
communities<br />Made with love © 2022 Answer
upload_img:
name: 更改图片
loading: 加载中...
pic_auth_code:
title: 验证码
placeholder: 输入图片中的文字
msg:
empty: 不能为空
inactive:
first: '马上就好了!我们发送了一封激活邮件到 <bold>{{mail}}</bold>。请按照邮件中的说明激活您的帐户。'
info: 如果没有收到,请检查您的垃圾邮件文件夹。
another: '我们向您发送了另一封激活电子邮件,地址为 <bold>{{mail}}</bold>。它可能需要几分钟才能到达;请务必检查您的垃圾邮件文件夹。'
btn_name: 重新发送激活邮件
msg:
empty: 不能为空
login:
page_title: 欢迎来到 Answer
info_sign: 没有帐户?<1>注册</1>
info_login: 已经有一个帐户?<1>登录</1>
forgot_pass: 忘记密码?
name:
label: 昵称
msg:
empty: 昵称不能为空
range: 昵称最多 30 个字符
email:
label: 邮箱
msg:
empty: 邮箱不能为空
password:
label: 密码
msg:
empty: 密码不能为空
different: 两次输入密码不一致
account_forgot:
page_title: 忘记密码
btn_name: 发送恢复邮件
send_success: '如无意外,你的邮箱 <strong>{{mail}}</strong> 将会收到一封重置密码的邮件,请根据指引重置你的密码。'
email:
label: 邮箱
msg:
empty: 邮箱不能为空
password_reset:
page_title: 密码重置
btn_name: 重置我的密码
reset_success: 你已经成功更改密码,将返回登录页面
link_invalid: 抱歉,此密码重置链接已失效。也许是你已经重置过密码了?
to_login: 前往登录页面
password:
label: 密码
msg:
empty: 密码不能为空
length: 密码长度在8-32个字符之间
different: 两次输入密码不一致
password_confirm:
label: 确认新密码
settings:
page_title: 设置
nav:
profile: 我的资料
notification: 通知
account: 账号
interface: 界面
profile:
btn_name: 保存更改
display_name:
label: 昵称
msg: 昵称不能为空
msg_range: 昵称不能超过 30 个字符
username:
label: 用户名
caption: 用户之间可以通过 "@用户名" 进行交互。
msg: 用户名不能为空
msg_range: 用户名不能超过 30 个字符
character: '用户名只能由 "a-z", "0-9", " - . _" 组成'
avatar:
label: 头像
text: 您可以上传图片作为头像,也可以 <1>重置</1> 为
bio:
label: 关于我 (可选)
website:
label: 网站 (可选)
placeholder: 'https://example.com'
msg: 格式不正确
location:
label: 位置 (可选)
placeholder: '城市, 国家'
notification:
email:
label: 邮件通知
radio: 你的提问有新的回答,评论,和其他
account:
change_email_btn: 更改邮箱
change_pass_btn: 更改密码
change_email_info: 邮件已发送。请根据指引完成验证。
email:
label: 邮箱
msg: 邮箱不能为空
password_title: 密码
current_pass:
label: 当前密码
msg:
empty: 当前密码不能为空
length: 密码长度必须在 8 至 32 之间
different: 两次输入的密码不匹配
new_pass:
label: 新密码
pass_confirm:
label: 确认新密码
interface:
lang:
label: 界面语言
text: 设置用户界面语言,在刷新页面后生效。
toast:
update: 更新成功
update_password: 更改密码成功。
flag_success: 感谢您的标记,我们会尽快处理。
related_question:
title: 相关问题
btn: 我要提问
answers: 个回答
question_detail:
Asked: 提问于
asked: 提问于
update: 修改于
edit: 最后编辑于
Views: 阅读次数
Follow: 关注此问题
Following: 已关注
answered: 回答于
closed_in: 关闭于
show_exist: 查看相关问题。
answers:
title: 个回答
score: 评分
newest: 最新
btn_accept: 采纳
btn_accepted: 已被采纳
write_answer:
title: 你的回答
btn_name: 提交你的回答
confirm_title: 继续回答
continue: 继续
confirm_info: <p>您确定要提交一个新的回答吗?</p><p>您可以直接编辑和改善您之前的回答的。</p>
empty: 回答内容不能为空。
delete:
title: 删除
question: >-
我们不建议<strong>删除有回答的帖子</strong>。因为这样做会使得后来的读者无法从该问题中获得帮助。</p><p>如果删除过多有回答的帖子,你的账号将会被禁止提问。你确定要删除吗?
answer_accepted: >-
<p>我们不建议<strong>删除被采纳的回答</strong>。因为这样做会使得后来的读者无法从该回答中获得帮助。</p>如果删除过多被采纳的回答,你的账号将会被禁止回答任何提问。你确定要删除吗?
other: 你确定要删除?
tip_question_deleted: 此问题已被删除
tip_answer_deleted: 此回答已被删除
btns:
confirm: 确认
cancel: 取消
save: 保存
delete: 删除
login: 登录
signup: 注册
logout: 退出登录
verify: 验证
add_question: 我要提问
search:
title: 搜索结果
keywords: 关键词
options: 选项
follow: 关注
following: 已关注
counts: '{{count}} 个结果'
more: 更多
sort_btns:
relevance: 相关性
newest: 最新的
active: 活跃的
score: 评分
tips:
title: 高级搜索提示
tag: '<1>[tag]</1> 在指定标签中搜索'
user: '<1>user:username</1> 根据作者搜索'
answer: '<1>answers:0</1> 搜索未回答的问题'
score: '<1>score:3</1> 评分 3 分或以上'
question: '<1>is:question</1> 只搜索问题'
is_answer: '<1>is:answer</1> 只搜索回答'
empty: 找不到任何相关的内容。<br /> 请尝试其他关键字,或者减少查找内容的长度。
share:
name: 分享
copy: 复制链接
via: 分享在...
copied: 已复制
facebook: 分享到 Facebook
twitter: 分享到 Twitter
cannot_vote_for_self: 不能给自己投票
modal_confirm:
title: 发生错误...
account_result:
page_title: 欢迎来到 Answer
success: 你的账号已通过验证,即将返回首页。
link: 返回首页
invalid: 抱歉,此验证链接已失效。也许是你的账号已经通过验证了?
confirm_new_email: 你的电子邮箱已更新
confirm_new_email_invalid: 抱歉,此验证链接已失效。也许是你的邮箱已经成功更改了?
question:
following_tags: 已关注的标签
edit: 编辑
save: 保存
follow_tag_tip: 按照标签整理您的问题列表。
hot_questions: 热点问题
all_questions: 全部问题
x_questions: '{{ count }} 个问题'
x_answers: '{{ count }} 个回答'
questions: 个问题
answers: 回答
newest: 最新
active: 活跃
frequent: 浏览量
score: 评分
unanswered: 未回答
modified: 修改于
answered: 回答于
asked: 提问于
closed: 已关闭
follow_a_tag: 关注一个标签
more: 更多
personal:
overview: 概览
answers: 回答
answer: 回答
questions: 问题
question: 问题
bookmarks: 收藏
reputation: 声望
comments: 评论
votes: 得票
newest: 最新
score: 评分
edit_profile: 编辑我的资料
visited_x_days: 'Visited {{ count }} days'
viewed: Viewed
joined: 加入于
last_login: 上次登录
about_me: 关于我
about_me_empty: '// Hello, World !'
top_answers: 热门回答
top_questions: 热门问题
stats: 状态
list_empty: 没有找到相关的内容。<br />试试看其他标签?
accepted: 已采纳
answered: 回答于
asked: 提问于
upvote: 赞同
downvote: 反对
mod_short: 管理员
mod_long: 管理员
x_reputation: 声望
x_votes: 得票
x_answers: 个回答
x_questions: 个问题
page_404:
description: 页面不存在
back_home: 回到主页
page_50X:
description: 服务器遇到了一个错误,无法完成你的请求。
back_home: 回到主页
admin:
admin_header:
title: 后台管理
nav_menus:
dashboard: 后台管理
contents: 内容管理
questions: 问题
answers: 回答
users: 用户管理
flags: 举报管理
settings: 站点设置
general: 一般
interface: 界面
smtp: SMTP
dashboard:
title: 后台管理
welcome: 欢迎来到 Answer 后台管理!
version: 版本
flags:
title: 举报
pending: 等待处理
completed: 已完成
flagged: 被举报内容
created: 创建于
action: 操作
review: 审查
change_modal:
title: 更改用户状态为...
btn_cancel: 取消
btn_submit: 提交
normal_name: 正常
normal_description: 正常状态的用户可以提问和回答。
suspended_name: 封禁
suspended_description: 被封禁的用户将无法登录。
deleted_name: 删除
deleted_description: 删除用户的个人信息,认证等等。
inactive_name: 不活跃
inactive_description: 不活跃的用户必须重新验证邮箱。
confirm_title: 删除此用户
confirm_content: 确定要删除此用户?此操作无法撤销!
confirm_btn: 删除
msg:
empty: 请选择一个原因
status_modal:
title: '更改 {{ type }} 状态为...'
normal_name: 正常
normal_description: 所有用户都可以访问
closed_name: 关闭
closed_description: 不能回答,但仍然可以编辑、投票和评论。
deleted_name: 删除
deleted_description: 所有获得/损失的声望将会恢复。
btn_cancel: 取消
btn_submit: 提交
btn_next: 下一步
users:
title: 用户
name: 名称
email: 邮箱
reputation: 声望
created_at: 创建时间
delete_at: 删除时间
suspend_at: 封禁时间
status: 状态
action: 操作
change: 更改
all: 全部
inactive: 不活跃
suspended: 已封禁
deleted: 已删除
normal: 正常
questions:
page_title: 问题
normal: 正常
closed: 已关闭
deleted: 已删除
post: 标题
votes: 得票数
answers: 回答数
created: 创建于
status: 状态
action: 操作
change: 更改
answers:
page_title: 回答
normal: 正常
deleted: 已删除
post: 标题
votes: 得票数
created: 创建于
status: 状态
action: 操作
change: 更改
general:
page_title: 一般
name:
label: 站点名称
msg: 不能为空
text: 站点的名称作为站点的标题HTML 的 title 标签)。
short_description:
label: 简短的站点标语 (可选)
msg: 不能为空
text: 简短的标语作为网站主页的标题HTML 的 title 标签)。
description:
label: 网站描述 (可选)
msg: 不能为空
text: 使用一句话描述本站作为网站的描述HTML 的 meta 标签)。
interface:
page_title: 界面
logo:
label: Logo (可选)
msg: 不能为空
text: 可以上传图片,或者<1>重置</1>为站点标题。
theme:
label: 主题
msg: 不能为空
text: 选择一个主题
language:
label: 界面语言
msg: 不能为空
text: 设置用户界面语言,在刷新页面后生效。
smtp:
page_title: SMTP
from_email:
label: 发件人地址
msg: 不能为空
text: 用于发送邮件的地址。
from_name:
label: 发件人名称
msg: 不能为空
text: 发件人的名称
smtp_host:
label: SMTP 主机
msg: 不能为空
text: 邮件服务器
encryption:
label: 加密
msg: 不能为空
text: 对于大多数服务器而言SSL 是推荐开启的。
ssl: SSL
none: 无加密
smtp_port:
label: SMTP 端口
msg: SMTP 端口必须在 1 ~ 65535 之间。
text: 邮件服务器的端口号。
smtp_username:
label: SMTP 用户名
msg: 不能为空
smtp_password:
label: SMTP 密码
msg: 不能为空
test_email_recipient:
label: 测试邮件收件人
text: 提供用于接收测试邮件的邮箱地址。
msg: 地址无效
smtp_authentication:
label: SMTP 认证
msg: 不能为空
'yes':
'no':

View File

@ -141,6 +141,11 @@ a {
background-color: #fff3cd80;
}
.fit-content {
height: fit-content;
flex: none;
}
// fix bug for React-Bootstrap Form.Text
.form-text {
display: inline-block;

View File

@ -12,13 +12,16 @@ import { interfaceStore } from '@/stores';
import { UploadImg } from '@/components';
import { TIMEZONES, DEFAULT_TIMEZONE } from '@/common/constants';
import {
getAdminLanguageOptions,
uploadAvatar,
updateInterfaceSetting,
useInterfaceSetting,
useThemeOptions,
} from '@/services';
import { setupAppLanguage, setupAppTimeZone } from '@/utils/localize';
import {
setupAppLanguage,
loadLanguageOptions,
setupAppTimeZone,
} from '@/utils/localize';
const Interface: FC = () => {
const { t } = useTranslation('translation', {
@ -53,7 +56,7 @@ const Interface: FC = () => {
},
});
const getLangs = async () => {
const res: LangsType[] = await getAdminLanguageOptions();
const res: LangsType[] = await loadLanguageOptions(true);
setLangs(res);
};
// set default theme value

View File

@ -148,8 +148,6 @@ const Index: FC<Props> = ({ visible, data, changeCallback, nextCallback }) => {
<Form.Label>{t('db_password.label')}</Form.Label>
<Form.Control
required
type="password"
placeholder={t('db_password.placeholder')}
value={data.db_password.value}
isInvalid={data.db_password.isInvalid}
onChange={(e) => {

View File

@ -43,22 +43,22 @@ const Index: FC = () => {
errorMsg: '',
},
db_username: {
value: '',
value: 'root',
isInvalid: false,
errorMsg: '',
},
db_password: {
value: '',
value: 'root',
isInvalid: false,
errorMsg: '',
},
db_host: {
value: '',
value: 'db:3306',
isInvalid: false,
errorMsg: '',
},
db_name: {
value: '',
value: 'answer',
isInvalid: false,
errorMsg: '',
},

View File

@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
import type { LangsType, FormDataType } from '@/common/interface';
import { useToast } from '@/hooks';
import { getLanguageOptions, updateUserInterface } from '@/services';
import { updateUserInterface } from '@/services';
import { localize } from '@/utils';
import { loggedUserInfoStore } from '@/stores';
@ -24,7 +24,7 @@ const Index = () => {
});
const getLangs = async () => {
const res: LangsType[] = await getLanguageOptions();
const res: LangsType[] = await localize.loadLanguageOptions();
setLangs(res);
};

View File

@ -1 +1,2 @@
/// <reference types="react-scripts" />
declare module '*.yaml';

View File

@ -1,9 +1,7 @@
// import useSWR from 'swr';
import request from '@/utils/request';
import type * as Type from '@/common/interface';
export const loadLang = () => {
export const getLanguageConfig = () => {
return request.get('/answer/api/v1/language/config');
};

View File

@ -185,7 +185,6 @@ export const tryNormalLogged = (canNavigate: boolean = false) => {
export const tryLoggedAndActicevated = () => {
const gr: TGuardResult = { ok: true };
const us = deriveLoginState();
console.log('tryLogged', us);
if (!us.isLogged || !us.isActivated) {
gr.ok = false;
}

View File

@ -4,12 +4,70 @@ import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
import { interfaceStore, loggedUserInfoStore } from '@/stores';
import { DEFAULT_LANG, CURRENT_LANG_STORAGE_KEY } from '@/common/constants';
import {
CURRENT_LANG_STORAGE_KEY,
DEFAULT_LANG,
LANG_RESOURCE_STORAGE_KEY,
} from '@/common/constants';
import { Storage } from '@/utils';
import {
getAdminLanguageOptions,
getLanguageConfig,
getLanguageOptions,
} from '@/services';
export const loadLanguageOptions = async (forAdmin = false) => {
const languageOptions = forAdmin
? await getAdminLanguageOptions()
: await getLanguageOptions();
if (process.env.NODE_ENV === 'development') {
const { default: optConf } = await import('@/i18n/locales/i18n.yaml');
optConf?.language_options.forEach((opt) => {
if (!languageOptions.find((_) => opt.label === _.label)) {
languageOptions.push(opt);
}
});
}
return languageOptions;
};
const addI18nResource = async (langName) => {
const res = { lng: langName, resources: undefined };
if (process.env.NODE_ENV === 'development') {
try {
const { default: resConf } = await import(
`@/i18n/locales/${langName}.yaml`
);
res.resources = resConf.ui;
} catch (ex) {
console.log('ex: ', ex);
}
} else {
const storageResource = Storage.get(LANG_RESOURCE_STORAGE_KEY);
if (storageResource?.lng === res.lng) {
res.resources = storageResource.resources;
} else {
const langConf = await getLanguageConfig();
if (langConf) {
res.resources = langConf;
}
}
}
if (res.resources) {
i18next.addResourceBundle(
res.lng,
'translation',
res.resources,
true,
true,
);
Storage.set(LANG_RESOURCE_STORAGE_KEY, res);
}
};
dayjs.extend(utc);
dayjs.extend(timezone);
const localDayjs = (langName) => {
const localeDayjs = (langName) => {
langName = langName.replace('_', '-').toLowerCase();
dayjs.locale(langName);
};
@ -17,19 +75,22 @@ const localDayjs = (langName) => {
export const getCurrentLang = () => {
const loggedUser = loggedUserInfoStore.getState().user;
const adminInterface = interfaceStore.getState().interface;
const storageLang = Storage.get(CURRENT_LANG_STORAGE_KEY);
const fallbackLang = Storage.get(CURRENT_LANG_STORAGE_KEY) || DEFAULT_LANG;
let currentLang = loggedUser.language;
// `default` mean use language value from admin interface
if (/default/i.test(currentLang) && adminInterface.language) {
if (/default/i.test(currentLang)) {
currentLang = adminInterface.language;
}
currentLang ||= storageLang || DEFAULT_LANG;
currentLang ||= fallbackLang;
return currentLang;
};
export const setupAppLanguage = () => {
export const setupAppLanguage = async () => {
const lang = getCurrentLang();
localDayjs(lang);
if (!i18next.getDataByLanguage(lang)) {
await addI18nResource(lang);
}
localeDayjs(lang);
i18next.changeLanguage(lang);
};

View File

@ -23,5 +23,5 @@
"@/*": ["src/*"]
}
},
"include": ["src", "node_modules/@testing-library/jest-dom"]
"include": ["src", "node_modules/@testing-library/jest-dom", "scripts"]
}