mirror of https://gitee.com/answerdev/answer.git
Merge branch 'github-main' into feature-plugin
This commit is contained in:
commit
9c2d2b1df4
|
@ -12,7 +12,7 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: [self-hosted, linux]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
|
@ -17,7 +17,7 @@ env:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-push:
|
build-and-push:
|
||||||
runs-on: ubuntu-latest
|
runs-on: [self-hosted, linux]
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
|
|
|
@ -9,7 +9,7 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-push:
|
build-and-push:
|
||||||
runs-on: ubuntu-latest
|
runs-on: [self-hosted, linux]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|
|
@ -8,8 +8,7 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-push:
|
build-and-push:
|
||||||
runs-on: ubuntu-latest
|
runs-on: [self-hosted, linux]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
/go.work*
|
/go.work*
|
||||||
/logs
|
/logs
|
||||||
/ui/node_modules
|
/ui/node_modules
|
||||||
|
/ui/build/*/*/*
|
||||||
|
/ui/build/*.json
|
||||||
|
/ui/build/*.html
|
||||||
|
/ui/build/*.txt
|
||||||
/vendor
|
/vendor
|
||||||
Thumbs*.db
|
Thumbs*.db
|
||||||
tmp
|
tmp
|
||||||
|
|
|
@ -16,50 +16,25 @@ builds:
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- amd64
|
- amd64
|
||||||
# linux windows need cgomingw64-gcc
|
|
||||||
- id: build-windows
|
- id: build-windows
|
||||||
main: ./cmd/answer/.
|
main: ./cmd/answer/.
|
||||||
binary: answer
|
binary: answer
|
||||||
ldflags: -s -w -X main.Version={{.Version}} -X main.Revision={{.ShortCommit}} -X main.Time={{.Date}} -X main.BuildUser=goreleaser
|
ldflags: -s -w -X main.Version={{.Version}} -X main.Revision={{.ShortCommit}} -X main.Time={{.Date}} -X main.BuildUser=goreleaser
|
||||||
env:
|
|
||||||
- CC=x86_64-w64-mingw32-gcc
|
|
||||||
- CXX=x86_64-w64-mingw32-g++
|
|
||||||
goos:
|
goos:
|
||||||
- windows
|
- windows
|
||||||
goarch:
|
goarch:
|
||||||
- amd64
|
- amd64
|
||||||
# linux arm64 need cgo arm64
|
|
||||||
- id: build-arm64
|
- id: build-arm64
|
||||||
main: ./cmd/answer/.
|
main: ./cmd/answer/.
|
||||||
binary: answer
|
binary: answer
|
||||||
ldflags: -s -w -X main.Version={{.Version}} -X main.Revision={{.ShortCommit}} -X main.Time={{.Date}} -X main.BuildUser=goreleaser
|
ldflags: -s -w -X main.Version={{.Version}} -X main.Revision={{.ShortCommit}} -X main.Time={{.Date}} -X main.BuildUser=goreleaser
|
||||||
env:
|
|
||||||
- CC=aarch64-linux-gnu-gcc
|
|
||||||
- CXX=aarch64-linux-gnu-g++
|
|
||||||
goos:
|
goos:
|
||||||
- linux
|
- linux
|
||||||
goarch:
|
goarch:
|
||||||
- arm64
|
- arm64
|
||||||
- id: build-arm7
|
|
||||||
main: ./cmd/answer/.
|
|
||||||
binary: answer
|
|
||||||
ldflags: -s -w -X main.Version={{.Version}} -X main.Revision={{.ShortCommit}} -X main.Time={{.Date}} -X main.BuildUser=goreleaser
|
|
||||||
env:
|
|
||||||
- CC=arm-linux-gnueabihf-gcc
|
|
||||||
- CXX=arm-linux-gnueabihf-g++
|
|
||||||
- AR=arm-linux-gnueabihf-ar
|
|
||||||
goos:
|
|
||||||
- linux
|
|
||||||
goarch:
|
|
||||||
- arm
|
|
||||||
goarm:
|
|
||||||
- 7
|
|
||||||
- id: build-darwin-arm64
|
- id: build-darwin-arm64
|
||||||
main: ./cmd/answer/.
|
main: ./cmd/answer/.
|
||||||
binary: answer
|
binary: answer
|
||||||
env:
|
|
||||||
- CC=oa64-clang
|
|
||||||
- CXX=oa64-clang++
|
|
||||||
goos:
|
goos:
|
||||||
- darwin
|
- darwin
|
||||||
goarch:
|
goarch:
|
||||||
|
@ -69,9 +44,6 @@ builds:
|
||||||
- id: build-darwin-amd64
|
- id: build-darwin-amd64
|
||||||
main: ./cmd/answer/.
|
main: ./cmd/answer/.
|
||||||
binary: answer
|
binary: answer
|
||||||
env:
|
|
||||||
- CC=o64-clang
|
|
||||||
- CXX=o64-clang++
|
|
||||||
goos:
|
goos:
|
||||||
- darwin
|
- darwin
|
||||||
goarch:
|
goarch:
|
||||||
|
@ -82,8 +54,10 @@ builds:
|
||||||
|
|
||||||
archives:
|
archives:
|
||||||
- replacements:
|
- replacements:
|
||||||
darwin: Darwin
|
darwin: macOS
|
||||||
amd64: x86_64
|
amd64: x86_64
|
||||||
|
linux: Linux
|
||||||
|
windows: Windows
|
||||||
checksum:
|
checksum:
|
||||||
name_template: 'checksums.txt'
|
name_template: 'checksums.txt'
|
||||||
snapshot:
|
snapshot:
|
||||||
|
@ -95,10 +69,4 @@ changelog:
|
||||||
- '^docs:'
|
- '^docs:'
|
||||||
- '^test:'
|
- '^test:'
|
||||||
|
|
||||||
|
|
||||||
# sudo apt-get install build-essential
|
|
||||||
# sudo apt-get install gcc-multilib g++-multilib
|
|
||||||
# sudo apt-get install gcc-mingw-w64
|
|
||||||
# sudo apt-get -y install gcc-aarch64-linux-gnu gcc-arm-linux-gnueabihf
|
|
||||||
# sudo apt-get install clang llvm
|
|
||||||
# goreleaser release --snapshot --rm-dist
|
# goreleaser release --snapshot --rm-dist
|
||||||
|
|
6
Makefile
6
Makefile
|
@ -1,6 +1,6 @@
|
||||||
.PHONY: build clean ui
|
.PHONY: build clean ui
|
||||||
|
|
||||||
VERSION=1.0.3
|
VERSION=1.0.4
|
||||||
BIN=answer
|
BIN=answer
|
||||||
DIR_SRC=./cmd/answer
|
DIR_SRC=./cmd/answer
|
||||||
DOCKER_CMD=docker
|
DOCKER_CMD=docker
|
||||||
|
@ -23,6 +23,8 @@ universal: generate
|
||||||
generate:
|
generate:
|
||||||
@$(GO) get github.com/google/wire/cmd/wire@v0.5.0
|
@$(GO) get github.com/google/wire/cmd/wire@v0.5.0
|
||||||
@$(GO) get github.com/golang/mock/mockgen@v1.6.0
|
@$(GO) get github.com/golang/mock/mockgen@v1.6.0
|
||||||
|
@$(GO) install github.com/google/wire/cmd/wire@v0.5.0
|
||||||
|
@$(GO) install github.com/golang/mock/mockgen@v1.6.0
|
||||||
@$(GO) generate ./...
|
@$(GO) generate ./...
|
||||||
@$(GO) mod tidy
|
@$(GO) mod tidy
|
||||||
|
|
||||||
|
@ -39,6 +41,6 @@ install-ui-packages:
|
||||||
@corepack prepare pnpm@v7.12.2 --activate
|
@corepack prepare pnpm@v7.12.2 --activate
|
||||||
|
|
||||||
ui:
|
ui:
|
||||||
@cd ui && pnpm install && pnpm build && cd -
|
@cd ui && pnpm install && pnpm build && sed -i 's/%AnswerVersion%/'$(VERSION)'/g' ./build/index.html && cd -
|
||||||
|
|
||||||
all: clean build
|
all: clean build
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
Please report security issues to `security@answer.dev`
|
59
docs/docs.go
59
docs/docs.go
|
@ -5808,8 +5808,7 @@ const docTemplate = `{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"object_id",
|
"object_id",
|
||||||
"original_text",
|
"original_text"
|
||||||
"parsed_text"
|
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"mention_username_list": {
|
"mention_username_list": {
|
||||||
|
@ -5825,11 +5824,9 @@ const docTemplate = `{
|
||||||
},
|
},
|
||||||
"original_text": {
|
"original_text": {
|
||||||
"description": "original comment content",
|
"description": "original comment content",
|
||||||
"type": "string"
|
"type": "string",
|
||||||
},
|
"maxLength": 600,
|
||||||
"parsed_text": {
|
"minLength": 2
|
||||||
"description": "parsed comment content",
|
|
||||||
"type": "string"
|
|
||||||
},
|
},
|
||||||
"reply_comment_id": {
|
"reply_comment_id": {
|
||||||
"description": "reply comment id",
|
"description": "reply comment id",
|
||||||
|
@ -5923,17 +5920,11 @@ const docTemplate = `{
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"content": {
|
"content": {
|
||||||
"description": "content",
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 65535,
|
"maxLength": 65535,
|
||||||
"minLength": 6
|
"minLength": 6
|
||||||
},
|
},
|
||||||
"html": {
|
|
||||||
"description": "html",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"question_id": {
|
"question_id": {
|
||||||
"description": "question_id",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5945,29 +5936,20 @@ const docTemplate = `{
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"content": {
|
"content": {
|
||||||
"description": "content",
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 65535,
|
"maxLength": 65535,
|
||||||
"minLength": 6
|
"minLength": 6
|
||||||
},
|
},
|
||||||
"edit_summary": {
|
"edit_summary": {
|
||||||
"description": "edit_summary",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"html": {
|
|
||||||
"description": "html",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"description": "id",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"question_id": {
|
"question_id": {
|
||||||
"description": "question_id",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"description": "title",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7142,7 +7124,6 @@ const docTemplate = `{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"content",
|
"content",
|
||||||
"html",
|
|
||||||
"tags",
|
"tags",
|
||||||
"title"
|
"title"
|
||||||
],
|
],
|
||||||
|
@ -7153,12 +7134,6 @@ const docTemplate = `{
|
||||||
"maxLength": 65535,
|
"maxLength": 65535,
|
||||||
"minLength": 6
|
"minLength": 6
|
||||||
},
|
},
|
||||||
"html": {
|
|
||||||
"description": "html",
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 65535,
|
|
||||||
"minLength": 6
|
|
||||||
},
|
|
||||||
"tags": {
|
"tags": {
|
||||||
"description": "tags",
|
"description": "tags",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -7291,7 +7266,6 @@ const docTemplate = `{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"content",
|
"content",
|
||||||
"html",
|
|
||||||
"id",
|
"id",
|
||||||
"tags",
|
"tags",
|
||||||
"title"
|
"title"
|
||||||
|
@ -7307,12 +7281,6 @@ const docTemplate = `{
|
||||||
"description": "edit summary",
|
"description": "edit summary",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"html": {
|
|
||||||
"description": "html",
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 65535,
|
|
||||||
"minLength": 6
|
|
||||||
},
|
|
||||||
"id": {
|
"id": {
|
||||||
"description": "question id",
|
"description": "question id",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -7878,10 +7846,6 @@ const docTemplate = `{
|
||||||
"description": "original text",
|
"description": "original text",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"parsed_text": {
|
|
||||||
"description": "parsed text",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"slug_name": {
|
"slug_name": {
|
||||||
"description": "slug_name",
|
"description": "slug_name",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -7979,7 +7943,8 @@ const docTemplate = `{
|
||||||
"schema.UpdateCommentReq": {
|
"schema.UpdateCommentReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"comment_id"
|
"comment_id",
|
||||||
|
"original_text"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"comment_id": {
|
"comment_id": {
|
||||||
|
@ -7988,11 +7953,9 @@ const docTemplate = `{
|
||||||
},
|
},
|
||||||
"original_text": {
|
"original_text": {
|
||||||
"description": "original comment content",
|
"description": "original comment content",
|
||||||
"type": "string"
|
"type": "string",
|
||||||
},
|
"maxLength": 600,
|
||||||
"parsed_text": {
|
"minLength": 2
|
||||||
"description": "parsed comment content",
|
|
||||||
"type": "string"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -8138,10 +8101,6 @@ const docTemplate = `{
|
||||||
"description": "original text",
|
"description": "original text",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"parsed_text": {
|
|
||||||
"description": "parsed text",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"slug_name": {
|
"slug_name": {
|
||||||
"description": "slug_name",
|
"description": "slug_name",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|
|
@ -5796,8 +5796,7 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"object_id",
|
"object_id",
|
||||||
"original_text",
|
"original_text"
|
||||||
"parsed_text"
|
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"mention_username_list": {
|
"mention_username_list": {
|
||||||
|
@ -5813,11 +5812,9 @@
|
||||||
},
|
},
|
||||||
"original_text": {
|
"original_text": {
|
||||||
"description": "original comment content",
|
"description": "original comment content",
|
||||||
"type": "string"
|
"type": "string",
|
||||||
},
|
"maxLength": 600,
|
||||||
"parsed_text": {
|
"minLength": 2
|
||||||
"description": "parsed comment content",
|
|
||||||
"type": "string"
|
|
||||||
},
|
},
|
||||||
"reply_comment_id": {
|
"reply_comment_id": {
|
||||||
"description": "reply comment id",
|
"description": "reply comment id",
|
||||||
|
@ -5911,17 +5908,11 @@
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"content": {
|
"content": {
|
||||||
"description": "content",
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 65535,
|
"maxLength": 65535,
|
||||||
"minLength": 6
|
"minLength": 6
|
||||||
},
|
},
|
||||||
"html": {
|
|
||||||
"description": "html",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"question_id": {
|
"question_id": {
|
||||||
"description": "question_id",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5933,29 +5924,20 @@
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"content": {
|
"content": {
|
||||||
"description": "content",
|
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"maxLength": 65535,
|
"maxLength": 65535,
|
||||||
"minLength": 6
|
"minLength": 6
|
||||||
},
|
},
|
||||||
"edit_summary": {
|
"edit_summary": {
|
||||||
"description": "edit_summary",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"html": {
|
|
||||||
"description": "html",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"description": "id",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"question_id": {
|
"question_id": {
|
||||||
"description": "question_id",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"description": "title",
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7130,7 +7112,6 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"content",
|
"content",
|
||||||
"html",
|
|
||||||
"tags",
|
"tags",
|
||||||
"title"
|
"title"
|
||||||
],
|
],
|
||||||
|
@ -7141,12 +7122,6 @@
|
||||||
"maxLength": 65535,
|
"maxLength": 65535,
|
||||||
"minLength": 6
|
"minLength": 6
|
||||||
},
|
},
|
||||||
"html": {
|
|
||||||
"description": "html",
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 65535,
|
|
||||||
"minLength": 6
|
|
||||||
},
|
|
||||||
"tags": {
|
"tags": {
|
||||||
"description": "tags",
|
"description": "tags",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -7279,7 +7254,6 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"content",
|
"content",
|
||||||
"html",
|
|
||||||
"id",
|
"id",
|
||||||
"tags",
|
"tags",
|
||||||
"title"
|
"title"
|
||||||
|
@ -7295,12 +7269,6 @@
|
||||||
"description": "edit summary",
|
"description": "edit summary",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"html": {
|
|
||||||
"description": "html",
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 65535,
|
|
||||||
"minLength": 6
|
|
||||||
},
|
|
||||||
"id": {
|
"id": {
|
||||||
"description": "question id",
|
"description": "question id",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -7866,10 +7834,6 @@
|
||||||
"description": "original text",
|
"description": "original text",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"parsed_text": {
|
|
||||||
"description": "parsed text",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"slug_name": {
|
"slug_name": {
|
||||||
"description": "slug_name",
|
"description": "slug_name",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -7967,7 +7931,8 @@
|
||||||
"schema.UpdateCommentReq": {
|
"schema.UpdateCommentReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"comment_id"
|
"comment_id",
|
||||||
|
"original_text"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"comment_id": {
|
"comment_id": {
|
||||||
|
@ -7976,11 +7941,9 @@
|
||||||
},
|
},
|
||||||
"original_text": {
|
"original_text": {
|
||||||
"description": "original comment content",
|
"description": "original comment content",
|
||||||
"type": "string"
|
"type": "string",
|
||||||
},
|
"maxLength": 600,
|
||||||
"parsed_text": {
|
"minLength": 2
|
||||||
"description": "parsed comment content",
|
|
||||||
"type": "string"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -8126,10 +8089,6 @@
|
||||||
"description": "original text",
|
"description": "original text",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"parsed_text": {
|
|
||||||
"description": "parsed text",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"slug_name": {
|
"slug_name": {
|
||||||
"description": "slug_name",
|
"description": "slug_name",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|
|
@ -147,9 +147,8 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
original_text:
|
original_text:
|
||||||
description: original comment content
|
description: original comment content
|
||||||
type: string
|
maxLength: 600
|
||||||
parsed_text:
|
minLength: 2
|
||||||
description: parsed comment content
|
|
||||||
type: string
|
type: string
|
||||||
reply_comment_id:
|
reply_comment_id:
|
||||||
description: reply comment id
|
description: reply comment id
|
||||||
|
@ -157,7 +156,6 @@ definitions:
|
||||||
required:
|
required:
|
||||||
- object_id
|
- object_id
|
||||||
- original_text
|
- original_text
|
||||||
- parsed_text
|
|
||||||
type: object
|
type: object
|
||||||
schema.AddReportReq:
|
schema.AddReportReq:
|
||||||
properties:
|
properties:
|
||||||
|
@ -217,15 +215,10 @@ definitions:
|
||||||
schema.AnswerAddReq:
|
schema.AnswerAddReq:
|
||||||
properties:
|
properties:
|
||||||
content:
|
content:
|
||||||
description: content
|
|
||||||
maxLength: 65535
|
maxLength: 65535
|
||||||
minLength: 6
|
minLength: 6
|
||||||
type: string
|
type: string
|
||||||
html:
|
|
||||||
description: html
|
|
||||||
type: string
|
|
||||||
question_id:
|
question_id:
|
||||||
description: question_id
|
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- content
|
- content
|
||||||
|
@ -233,24 +226,16 @@ definitions:
|
||||||
schema.AnswerUpdateReq:
|
schema.AnswerUpdateReq:
|
||||||
properties:
|
properties:
|
||||||
content:
|
content:
|
||||||
description: content
|
|
||||||
maxLength: 65535
|
maxLength: 65535
|
||||||
minLength: 6
|
minLength: 6
|
||||||
type: string
|
type: string
|
||||||
edit_summary:
|
edit_summary:
|
||||||
description: edit_summary
|
|
||||||
type: string
|
|
||||||
html:
|
|
||||||
description: html
|
|
||||||
type: string
|
type: string
|
||||||
id:
|
id:
|
||||||
description: id
|
|
||||||
type: string
|
type: string
|
||||||
question_id:
|
question_id:
|
||||||
description: question_id
|
|
||||||
type: string
|
type: string
|
||||||
title:
|
title:
|
||||||
description: title
|
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- content
|
- content
|
||||||
|
@ -1096,11 +1081,6 @@ definitions:
|
||||||
maxLength: 65535
|
maxLength: 65535
|
||||||
minLength: 6
|
minLength: 6
|
||||||
type: string
|
type: string
|
||||||
html:
|
|
||||||
description: html
|
|
||||||
maxLength: 65535
|
|
||||||
minLength: 6
|
|
||||||
type: string
|
|
||||||
tags:
|
tags:
|
||||||
description: tags
|
description: tags
|
||||||
items:
|
items:
|
||||||
|
@ -1113,7 +1093,6 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- content
|
- content
|
||||||
- html
|
|
||||||
- tags
|
- tags
|
||||||
- title
|
- title
|
||||||
type: object
|
type: object
|
||||||
|
@ -1205,11 +1184,6 @@ definitions:
|
||||||
edit_summary:
|
edit_summary:
|
||||||
description: edit summary
|
description: edit summary
|
||||||
type: string
|
type: string
|
||||||
html:
|
|
||||||
description: html
|
|
||||||
maxLength: 65535
|
|
||||||
minLength: 6
|
|
||||||
type: string
|
|
||||||
id:
|
id:
|
||||||
description: question id
|
description: question id
|
||||||
type: string
|
type: string
|
||||||
|
@ -1225,7 +1199,6 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- content
|
- content
|
||||||
- html
|
|
||||||
- id
|
- id
|
||||||
- tags
|
- tags
|
||||||
- title
|
- title
|
||||||
|
@ -1605,9 +1578,6 @@ definitions:
|
||||||
original_text:
|
original_text:
|
||||||
description: original text
|
description: original text
|
||||||
type: string
|
type: string
|
||||||
parsed_text:
|
|
||||||
description: parsed text
|
|
||||||
type: string
|
|
||||||
slug_name:
|
slug_name:
|
||||||
description: slug_name
|
description: slug_name
|
||||||
maxLength: 35
|
maxLength: 35
|
||||||
|
@ -1680,12 +1650,12 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
original_text:
|
original_text:
|
||||||
description: original comment content
|
description: original comment content
|
||||||
type: string
|
maxLength: 600
|
||||||
parsed_text:
|
minLength: 2
|
||||||
description: parsed comment content
|
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- comment_id
|
- comment_id
|
||||||
|
- original_text
|
||||||
type: object
|
type: object
|
||||||
schema.UpdateFollowTagsReq:
|
schema.UpdateFollowTagsReq:
|
||||||
properties:
|
properties:
|
||||||
|
@ -1787,9 +1757,6 @@ definitions:
|
||||||
original_text:
|
original_text:
|
||||||
description: original text
|
description: original text
|
||||||
type: string
|
type: string
|
||||||
parsed_text:
|
|
||||||
description: parsed text
|
|
||||||
type: string
|
|
||||||
slug_name:
|
slug_name:
|
||||||
description: slug_name
|
description: slug_name
|
||||||
maxLength: 35
|
maxLength: 35
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -585,7 +585,8 @@ ui:
|
||||||
msg:
|
msg:
|
||||||
empty: Cannot be empty.
|
empty: Cannot be empty.
|
||||||
login:
|
login:
|
||||||
page_title: Welcome to Answer
|
page_title: Welcome to {{site_name}}
|
||||||
|
login_to_continue: Log in to continue
|
||||||
info_sign: Don't have an account? <1>Sign up</1>
|
info_sign: Don't have an account? <1>Sign up</1>
|
||||||
info_login: Already have an account? <1>Log in</1>
|
info_login: Already have an account? <1>Log in</1>
|
||||||
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
||||||
|
@ -1222,14 +1223,14 @@ ui:
|
||||||
branding:
|
branding:
|
||||||
page_title: Branding
|
page_title: Branding
|
||||||
logo:
|
logo:
|
||||||
label: Logo
|
label: Logo (optional)
|
||||||
msg: Logo cannot be empty.
|
msg: Logo cannot be empty.
|
||||||
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
||||||
mobile_logo:
|
mobile_logo:
|
||||||
label: Mobile Logo (optional)
|
label: Mobile Logo (optional)
|
||||||
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
||||||
square_icon:
|
square_icon:
|
||||||
label: Square Icon
|
label: Square Icon (optional)
|
||||||
msg: Square icon cannot be empty.
|
msg: Square icon cannot be empty.
|
||||||
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
||||||
favicon:
|
favicon:
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
247
i18n/en_US.yaml
247
i18n/en_US.yaml
|
@ -3,242 +3,244 @@
|
||||||
backend:
|
backend:
|
||||||
base:
|
base:
|
||||||
success:
|
success:
|
||||||
other: "Success."
|
other: Success.
|
||||||
unknown:
|
unknown:
|
||||||
other: "Unknown error."
|
other: Unknown error.
|
||||||
request_format_error:
|
request_format_error:
|
||||||
other: "Request format is not valid."
|
other: Request format is not valid.
|
||||||
unauthorized_error:
|
unauthorized_error:
|
||||||
other: "Unauthorized."
|
other: Unauthorized.
|
||||||
database_error:
|
database_error:
|
||||||
other: "Data server error."
|
other: Data server error.
|
||||||
|
|
||||||
role:
|
role:
|
||||||
name:
|
name:
|
||||||
user:
|
user:
|
||||||
other: "User"
|
other: User
|
||||||
admin:
|
admin:
|
||||||
other: "Admin"
|
other: Admin
|
||||||
moderator:
|
moderator:
|
||||||
other: "Moderator"
|
other: Moderator
|
||||||
description:
|
description:
|
||||||
user:
|
user:
|
||||||
other: "Default with no special access."
|
other: Default with no special access.
|
||||||
admin:
|
admin:
|
||||||
other: "Have the full power to access the site."
|
other: Have the full power to access the site.
|
||||||
moderator:
|
moderator:
|
||||||
other: "Has access to all posts except admin settings."
|
other: Has access to all posts except admin settings.
|
||||||
|
|
||||||
email:
|
email:
|
||||||
other: "Email"
|
other: Email
|
||||||
password:
|
password:
|
||||||
other: "Password"
|
other: Password
|
||||||
|
email_or_password_wrong_error:
|
||||||
email_or_password_wrong_error: &email_or_password_wrong
|
other: Email and password do not match.
|
||||||
other: "Email and password do not match."
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
admin:
|
admin:
|
||||||
email_or_password_wrong: *email_or_password_wrong
|
email_or_password_wrong:
|
||||||
|
other: Email and password do not match.
|
||||||
answer:
|
answer:
|
||||||
not_found:
|
not_found:
|
||||||
other: "Answer do not found."
|
other: Answer do not found.
|
||||||
cannot_deleted:
|
cannot_deleted:
|
||||||
other: "No permission to delete."
|
other: No permission to delete.
|
||||||
cannot_update:
|
cannot_update:
|
||||||
other: "No permission to update."
|
other: No permission to update.
|
||||||
comment:
|
comment:
|
||||||
edit_without_permission:
|
edit_without_permission:
|
||||||
other: "Comment are not allowed to edit."
|
other: Comment are not allowed to edit.
|
||||||
not_found:
|
not_found:
|
||||||
other: "Comment not found."
|
other: Comment not found.
|
||||||
cannot_edit_after_deadline:
|
cannot_edit_after_deadline:
|
||||||
other: "The comment time has been too long to modify."
|
other: The comment time has been too long to modify.
|
||||||
email:
|
email:
|
||||||
duplicate:
|
duplicate:
|
||||||
other: "Email already exists."
|
other: Email already exists.
|
||||||
need_to_be_verified:
|
need_to_be_verified:
|
||||||
other: "Email should be verified."
|
other: Email should be verified.
|
||||||
verify_url_expired:
|
verify_url_expired:
|
||||||
other: "Email verified URL has expired, please resend the email."
|
other: Email verified URL has expired, please resend the email.
|
||||||
lang:
|
lang:
|
||||||
not_found:
|
not_found:
|
||||||
other: "Language file not found."
|
other: Language file not found.
|
||||||
object:
|
object:
|
||||||
captcha_verification_failed:
|
captcha_verification_failed:
|
||||||
other: "Captcha wrong."
|
other: Captcha wrong.
|
||||||
disallow_follow:
|
disallow_follow:
|
||||||
other: "You are not allowed to follow."
|
other: You are not allowed to follow.
|
||||||
disallow_vote:
|
disallow_vote:
|
||||||
other: "You are not allowed to vote."
|
other: You are not allowed to vote.
|
||||||
disallow_vote_your_self:
|
disallow_vote_your_self:
|
||||||
other: "You can't vote for your own post."
|
other: You can't vote for your own post.
|
||||||
not_found:
|
not_found:
|
||||||
other: "Object not found."
|
other: Object not found.
|
||||||
verification_failed:
|
verification_failed:
|
||||||
other: "Verification failed."
|
other: Verification failed.
|
||||||
email_or_password_incorrect:
|
email_or_password_incorrect:
|
||||||
other: "Email and password do not match."
|
other: Email and password do not match.
|
||||||
old_password_verification_failed:
|
old_password_verification_failed:
|
||||||
other: "The old password verification failed"
|
other: The old password verification failed
|
||||||
new_password_same_as_previous_setting:
|
new_password_same_as_previous_setting:
|
||||||
other: "The new password is the same as the previous one."
|
other: The new password is the same as the previous one.
|
||||||
question:
|
question:
|
||||||
not_found:
|
not_found:
|
||||||
other: "Question not found."
|
other: Question not found.
|
||||||
cannot_deleted:
|
cannot_deleted:
|
||||||
other: "No permission to delete."
|
other: No permission to delete.
|
||||||
cannot_close:
|
cannot_close:
|
||||||
other: "No permission to close."
|
other: No permission to close.
|
||||||
cannot_update:
|
cannot_update:
|
||||||
other: "No permission to update."
|
other: No permission to update.
|
||||||
rank:
|
rank:
|
||||||
fail_to_meet_the_condition:
|
fail_to_meet_the_condition:
|
||||||
other: "Rank fail to meet the condition."
|
other: Rank fail to meet the condition.
|
||||||
report:
|
report:
|
||||||
handle_failed:
|
handle_failed:
|
||||||
other: "Report handle failed."
|
other: Report handle failed.
|
||||||
not_found:
|
not_found:
|
||||||
other: "Report not found."
|
other: Report not found.
|
||||||
tag:
|
tag:
|
||||||
not_found:
|
not_found:
|
||||||
other: "Tag not found."
|
other: Tag not found.
|
||||||
recommend_tag_not_found:
|
recommend_tag_not_found:
|
||||||
other: "Recommend Tag is not exist."
|
other: Recommend Tag is not exist.
|
||||||
recommend_tag_enter:
|
recommend_tag_enter:
|
||||||
other: "Please enter at least one required tag."
|
other: Please enter at least one required tag.
|
||||||
not_contain_synonym_tags:
|
not_contain_synonym_tags:
|
||||||
other: "Should not contain synonym tags."
|
other: Should not contain synonym tags.
|
||||||
cannot_update:
|
cannot_update:
|
||||||
other: "No permission to update."
|
other: No permission to update.
|
||||||
cannot_set_synonym_as_itself:
|
cannot_set_synonym_as_itself:
|
||||||
other: "You cannot set the synonym of the current tag as itself."
|
other: You cannot set the synonym of the current tag as itself.
|
||||||
smtp:
|
smtp:
|
||||||
config_from_name_cannot_be_email:
|
config_from_name_cannot_be_email:
|
||||||
other: "The From Name cannot be a email address."
|
other: The From Name cannot be a email address.
|
||||||
theme:
|
theme:
|
||||||
not_found:
|
not_found:
|
||||||
other: "Theme not found."
|
other: Theme not found.
|
||||||
revision:
|
revision:
|
||||||
review_underway:
|
review_underway:
|
||||||
other: "Can't edit currently, there is a version in the review queue."
|
other: Can't edit currently, there is a version in the review queue.
|
||||||
no_permission:
|
no_permission:
|
||||||
other: "No permission to Revision."
|
other: No permission to Revision.
|
||||||
user:
|
user:
|
||||||
email_or_password_wrong:
|
email_or_password_wrong:
|
||||||
other: *email_or_password_wrong
|
other:
|
||||||
|
other: Email and password do not match.
|
||||||
not_found:
|
not_found:
|
||||||
other: "User not found."
|
other: User not found.
|
||||||
suspended:
|
suspended:
|
||||||
other: "User has been suspended."
|
other: User has been suspended.
|
||||||
username_invalid:
|
username_invalid:
|
||||||
other: "Username is invalid."
|
other: Username is invalid.
|
||||||
username_duplicate:
|
username_duplicate:
|
||||||
other: "Username is already in use."
|
other: Username is already in use.
|
||||||
set_avatar:
|
set_avatar:
|
||||||
other: "Avatar set failed."
|
other: Avatar set failed.
|
||||||
cannot_update_your_role:
|
cannot_update_your_role:
|
||||||
other: "You cannot modify your role."
|
other: You cannot modify your role.
|
||||||
not_allowed_registration:
|
not_allowed_registration:
|
||||||
other: "Currently the site is not open for registration"
|
other: Currently the site is not open for registration
|
||||||
config:
|
config:
|
||||||
read_config_failed:
|
read_config_failed:
|
||||||
other: "Read config failed"
|
other: Read config failed
|
||||||
database:
|
database:
|
||||||
connection_failed:
|
connection_failed:
|
||||||
other: "Database connection failed"
|
other: Database connection failed
|
||||||
create_table_failed:
|
create_table_failed:
|
||||||
other: "Create table failed"
|
other: Create table failed
|
||||||
install:
|
install:
|
||||||
create_config_failed:
|
create_config_failed:
|
||||||
other: "Can’t create the config.yaml file."
|
other: Can't create the config.yaml file.
|
||||||
report:
|
report:
|
||||||
spam:
|
spam:
|
||||||
name:
|
name:
|
||||||
other: "spam"
|
other: spam
|
||||||
desc:
|
desc:
|
||||||
other: "This post is an advertisement, or vandalism. It is not useful or relevant to the current topic."
|
other: This post is an advertisement, or vandalism. It is not useful or relevant
|
||||||
|
to the current topic.
|
||||||
rude:
|
rude:
|
||||||
name:
|
name:
|
||||||
other: "rude or abusive"
|
other: rude or abusive
|
||||||
desc:
|
desc:
|
||||||
other: "A reasonable person would find this content inappropriate for respectful discourse."
|
other: A reasonable person would find this content inappropriate for respectful
|
||||||
|
discourse.
|
||||||
duplicate:
|
duplicate:
|
||||||
name:
|
name:
|
||||||
other: "a duplicate"
|
other: a duplicate
|
||||||
desc:
|
desc:
|
||||||
other: "This question has been asked before and already has an answer."
|
other: This question has been asked before and already has an answer.
|
||||||
not_answer:
|
not_answer:
|
||||||
name:
|
name:
|
||||||
other: "not an answer"
|
other: not an answer
|
||||||
desc:
|
desc:
|
||||||
other: "This was posted as an answer, but it does not attempt to answer the question. It should possibly be an edit, a comment, another question, or deleted altogether."
|
other: This was posted as an answer, but it does not attempt to answer the
|
||||||
|
question. It should possibly be an edit, a comment, another question,
|
||||||
|
or deleted altogether.
|
||||||
not_need:
|
not_need:
|
||||||
name:
|
name:
|
||||||
other: "no longer needed"
|
other: no longer needed
|
||||||
desc:
|
desc:
|
||||||
other: "This comment is outdated, conversational or not relevant to this post."
|
other: This comment is outdated, conversational or not relevant to this post.
|
||||||
other:
|
other:
|
||||||
name:
|
name:
|
||||||
other: "something else"
|
other: something else
|
||||||
desc:
|
desc:
|
||||||
other: "This post requires staff attention for another reason not listed above."
|
other: This post requires staff attention for another reason not listed above.
|
||||||
|
|
||||||
question:
|
question:
|
||||||
close:
|
close:
|
||||||
duplicate:
|
duplicate:
|
||||||
name:
|
name:
|
||||||
other: "spam"
|
other: spam
|
||||||
desc:
|
desc:
|
||||||
other: "This question has been asked before and already has an answer."
|
other: This question has been asked before and already has an answer.
|
||||||
guideline:
|
guideline:
|
||||||
name:
|
name:
|
||||||
other: "a community-specific reason"
|
other: a community-specific reason
|
||||||
desc:
|
desc:
|
||||||
other: "This question doesn't meet a community guideline."
|
other: This question doesn't meet a community guideline.
|
||||||
multiple:
|
multiple:
|
||||||
name:
|
name:
|
||||||
other: "needs details or clarity"
|
other: needs details or clarity
|
||||||
desc:
|
desc:
|
||||||
other: "This question currently includes multiple questions in one. It should focus on one problem only."
|
other: This question currently includes multiple questions in one. It should
|
||||||
|
focus on one problem only.
|
||||||
other:
|
other:
|
||||||
name:
|
name:
|
||||||
other: "something else"
|
other: something else
|
||||||
desc:
|
desc:
|
||||||
other: "This post requires another reason not listed above."
|
other: This post requires another reason not listed above.
|
||||||
operation_type:
|
operation_type:
|
||||||
asked:
|
asked:
|
||||||
other: "asked"
|
other: asked
|
||||||
answered:
|
answered:
|
||||||
other: "answered"
|
other: answered
|
||||||
modified:
|
modified:
|
||||||
other: "modified"
|
other: modified
|
||||||
notification:
|
notification:
|
||||||
action:
|
action:
|
||||||
update_question:
|
update_question:
|
||||||
other: "updated question"
|
other: updated question
|
||||||
answer_the_question:
|
answer_the_question:
|
||||||
other: "answered question"
|
other: answered question
|
||||||
update_answer:
|
update_answer:
|
||||||
other: "updated answer"
|
other: updated answer
|
||||||
accept_answer:
|
accept_answer:
|
||||||
other: "accepted answer"
|
other: accepted answer
|
||||||
comment_question:
|
comment_question:
|
||||||
other: "commented question"
|
other: commented question
|
||||||
comment_answer:
|
comment_answer:
|
||||||
other: "commented answer"
|
other: commented answer
|
||||||
reply_to_you:
|
reply_to_you:
|
||||||
other: "replied to you"
|
other: replied to you
|
||||||
mention_you:
|
mention_you:
|
||||||
other: "mentioned you"
|
other: mentioned you
|
||||||
your_question_is_closed:
|
your_question_is_closed:
|
||||||
other: "Your question has been closed"
|
other: Your question has been closed
|
||||||
your_question_was_deleted:
|
your_question_was_deleted:
|
||||||
other: "Your question has been deleted"
|
other: Your question has been deleted
|
||||||
your_answer_was_deleted:
|
your_answer_was_deleted:
|
||||||
other: "Your answer has been deleted"
|
other: Your answer has been deleted
|
||||||
your_comment_was_deleted:
|
your_comment_was_deleted:
|
||||||
other: "Your comment has been deleted"
|
other: Your comment has been deleted
|
||||||
|
|
||||||
# The following fields are used for interface presentation(Front-end)
|
# The following fields are used for interface presentation(Front-end)
|
||||||
ui:
|
ui:
|
||||||
|
@ -494,7 +496,7 @@ ui:
|
||||||
btn_flag: Flag
|
btn_flag: Flag
|
||||||
btn_save_edits: Save edits
|
btn_save_edits: Save edits
|
||||||
btn_cancel: Cancel
|
btn_cancel: Cancel
|
||||||
show_more: Show more comment
|
show_more: Show more comments
|
||||||
tip_question: >-
|
tip_question: >-
|
||||||
Use comments to ask for more information or suggest improvements. Avoid
|
Use comments to ask for more information or suggest improvements. Avoid
|
||||||
answering questions in comments.
|
answering questions in comments.
|
||||||
|
@ -510,6 +512,8 @@ ui:
|
||||||
label: Revision
|
label: Revision
|
||||||
answer:
|
answer:
|
||||||
label: Answer
|
label: Answer
|
||||||
|
feedback:
|
||||||
|
characters: content must be at least 6 characters in length.
|
||||||
edit_summary:
|
edit_summary:
|
||||||
label: Edit Summary
|
label: Edit Summary
|
||||||
placeholder: >-
|
placeholder: >-
|
||||||
|
@ -640,7 +644,7 @@ ui:
|
||||||
msg:
|
msg:
|
||||||
empty: Email cannot be empty.
|
empty: Email cannot be empty.
|
||||||
change_email:
|
change_email:
|
||||||
page_title: Welcome to Answer
|
page_title: Welcome to {{site_name}}
|
||||||
btn_cancel: Cancel
|
btn_cancel: Cancel
|
||||||
btn_update: Update email address
|
btn_update: Update email address
|
||||||
send_success: >-
|
send_success: >-
|
||||||
|
@ -681,12 +685,12 @@ ui:
|
||||||
display_name:
|
display_name:
|
||||||
label: Display Name
|
label: Display Name
|
||||||
msg: Display name cannot be empty.
|
msg: Display name cannot be empty.
|
||||||
msg_range: Display name up to 30 characters
|
msg_range: Display name up to 30 characters.
|
||||||
username:
|
username:
|
||||||
label: Username
|
label: Username
|
||||||
caption: People can mention you as "@username".
|
caption: People can mention you as "@username".
|
||||||
msg: Username cannot be empty.
|
msg: Username cannot be empty.
|
||||||
msg_range: Username up to 30 characters
|
msg_range: Username up to 30 characters.
|
||||||
character: 'Must use the character set "a-z", "0-9", " - . _"'
|
character: 'Must use the character set "a-z", "0-9", " - . _"'
|
||||||
avatar:
|
avatar:
|
||||||
label: Profile Image
|
label: Profile Image
|
||||||
|
@ -774,6 +778,7 @@ ui:
|
||||||
<p>Are you sure you want to add another answer?</p><p>You could use the
|
<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>
|
edit link to refine and improve your existing answer, instead.</p>
|
||||||
empty: Answer cannot be empty.
|
empty: Answer cannot be empty.
|
||||||
|
characters: content must be at least 6 characters in length.
|
||||||
reopen:
|
reopen:
|
||||||
title: Reopen this post
|
title: Reopen this post
|
||||||
content: Are you sure you want to reopen?
|
content: Are you sure you want to reopen?
|
||||||
|
@ -840,7 +845,7 @@ ui:
|
||||||
modal_confirm:
|
modal_confirm:
|
||||||
title: Error...
|
title: Error...
|
||||||
account_result:
|
account_result:
|
||||||
page_title: Welcome to Answer
|
page_title: Welcome to {{site_name}}
|
||||||
success: Your new account is confirmed; you will be redirected to the home page.
|
success: Your new account is confirmed; you will be redirected to the home page.
|
||||||
link: Continue to homepage
|
link: Continue to homepage
|
||||||
invalid: >-
|
invalid: >-
|
||||||
|
@ -853,7 +858,7 @@ ui:
|
||||||
unsubscribe:
|
unsubscribe:
|
||||||
page_title: Unsubscribe
|
page_title: Unsubscribe
|
||||||
success_title: Unsubscribe Successful
|
success_title: Unsubscribe Successful
|
||||||
success_desc: You have been successfully removed from this subscriber list and won’t receive any further emails from us.
|
success_desc: You have been successfully removed from this subscriber list and won't receive any further emails from us.
|
||||||
link: Change settings
|
link: Change settings
|
||||||
question:
|
question:
|
||||||
following_tags: Following Tags
|
following_tags: Following Tags
|
||||||
|
@ -915,7 +920,7 @@ ui:
|
||||||
title: Answer
|
title: Answer
|
||||||
next: Next
|
next: Next
|
||||||
done: Done
|
done: Done
|
||||||
config_yaml_error: Can’t create the config.yaml file.
|
config_yaml_error: Can't create the config.yaml file.
|
||||||
lang:
|
lang:
|
||||||
label: Please Choose a Language
|
label: Please Choose a Language
|
||||||
db_type:
|
db_type:
|
||||||
|
@ -946,7 +951,7 @@ ui:
|
||||||
desc: >-
|
desc: >-
|
||||||
You can create the <1>config.yaml</1> file manually in the
|
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.
|
<1>/var/wwww/xxx/</1> directory and paste the following text into it.
|
||||||
info: "After you’ve done that, click “Next” button."
|
info: After you've done that, click "Next" button.
|
||||||
site_information: Site Information
|
site_information: Site Information
|
||||||
admin_account: Admin Account
|
admin_account: Admin Account
|
||||||
site_name:
|
site_name:
|
||||||
|
@ -996,7 +1001,11 @@ ui:
|
||||||
db_failed: Database connection failed
|
db_failed: Database connection failed
|
||||||
db_failed_desc: >-
|
db_failed_desc: >-
|
||||||
This either means that the database information in your <1>config.yaml</1> file is incorrect or that contact with the database server could not be established. This could mean your host’s database server is down.
|
This either means that the database information in your <1>config.yaml</1> file is incorrect or that contact with the database server could not be established. This could mean your host’s database server is down.
|
||||||
|
counts:
|
||||||
|
views: views
|
||||||
|
votes: votes
|
||||||
|
answers: answers
|
||||||
|
accepted: Accepted
|
||||||
page_404:
|
page_404:
|
||||||
desc: "Unfortunately, this page doesn't exist."
|
desc: "Unfortunately, this page doesn't exist."
|
||||||
back_home: Back to homepage
|
back_home: Back to homepage
|
||||||
|
@ -1004,7 +1013,7 @@ ui:
|
||||||
desc: The server encountered an error and could not complete your request.
|
desc: The server encountered an error and could not complete your request.
|
||||||
back_home: Back to homepage
|
back_home: Back to homepage
|
||||||
page_maintenance:
|
page_maintenance:
|
||||||
desc: "We are under maintenance, we’ll be back soon."
|
desc: "We are under maintenance, we'll be back soon."
|
||||||
nav_menus:
|
nav_menus:
|
||||||
dashboard: Dashboard
|
dashboard: Dashboard
|
||||||
contents: Contents
|
contents: Contents
|
||||||
|
@ -1138,7 +1147,7 @@ ui:
|
||||||
password:
|
password:
|
||||||
label: Password
|
label: Password
|
||||||
text: The user will be logged out and need to login again.
|
text: The user will be logged out and need to login again.
|
||||||
msg: Password must be at 8 - 32 characters in length.
|
msg: Password must be at 8-32 characters in length.
|
||||||
btn_cancel: Cancel
|
btn_cancel: Cancel
|
||||||
btn_submit: Submit
|
btn_submit: Submit
|
||||||
user_modal:
|
user_modal:
|
||||||
|
@ -1147,13 +1156,13 @@ ui:
|
||||||
fields:
|
fields:
|
||||||
display_name:
|
display_name:
|
||||||
label: Display Name
|
label: Display Name
|
||||||
msg: display_name must be at 4 - 30 characters in length.
|
msg: Display Name must be at 3-30 characters in length.
|
||||||
email:
|
email:
|
||||||
label: Email
|
label: Email
|
||||||
msg: Email is not valid.
|
msg: Email is not valid.
|
||||||
password:
|
password:
|
||||||
label: Password
|
label: Password
|
||||||
msg: Password must be at 8 - 32 characters in length.
|
msg: Password must be at 8-32 characters in length.
|
||||||
|
|
||||||
btn_cancel: Cancel
|
btn_cancel: Cancel
|
||||||
btn_submit: Submit
|
btn_submit: Submit
|
||||||
|
@ -1274,14 +1283,14 @@ ui:
|
||||||
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
||||||
mobile_logo:
|
mobile_logo:
|
||||||
label: Mobile Logo (optional)
|
label: Mobile Logo (optional)
|
||||||
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the "logo" setting will be used.
|
||||||
square_icon:
|
square_icon:
|
||||||
label: Square Icon (optional)
|
label: Square Icon (optional)
|
||||||
msg: Square icon cannot be empty.
|
msg: Square icon cannot be empty.
|
||||||
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
||||||
favicon:
|
favicon:
|
||||||
label: Favicon (optional)
|
label: Favicon (optional)
|
||||||
text: A favicon for your site. To work correctly over a CDN it must be a png. Will be resized to 32x32. If left blank, “square icon” will be used.
|
text: A favicon for your site. To work correctly over a CDN it must be a png. Will be resized to 32x32. If left blank, "square icon" will be used.
|
||||||
legal:
|
legal:
|
||||||
page_title: Legal
|
page_title: Legal
|
||||||
terms_of_service:
|
terms_of_service:
|
||||||
|
|
134
i18n/es_ES.yaml
134
i18n/es_ES.yaml
|
@ -2,7 +2,7 @@
|
||||||
backend:
|
backend:
|
||||||
base:
|
base:
|
||||||
success:
|
success:
|
||||||
other: "Success."
|
other: "Completado."
|
||||||
unknown:
|
unknown:
|
||||||
other: "Error desconocido."
|
other: "Error desconocido."
|
||||||
request_format_error:
|
request_format_error:
|
||||||
|
@ -88,17 +88,17 @@ backend:
|
||||||
other: "Sin permiso para actualizar."
|
other: "Sin permiso para actualizar."
|
||||||
rank:
|
rank:
|
||||||
fail_to_meet_the_condition:
|
fail_to_meet_the_condition:
|
||||||
other: "Rank fail to meet the condition."
|
other: "El rango no cumple la condición."
|
||||||
report:
|
report:
|
||||||
handle_failed:
|
handle_failed:
|
||||||
other: "Report handle failed."
|
other: "Error en el manejador del reporte."
|
||||||
not_found:
|
not_found:
|
||||||
other: "Report not found."
|
other: "Informe no encontrado."
|
||||||
tag:
|
tag:
|
||||||
not_found:
|
not_found:
|
||||||
other: "Etiqueta no encontrada."
|
other: "Etiqueta no encontrada."
|
||||||
recommend_tag_not_found:
|
recommend_tag_not_found:
|
||||||
other: "Recommend Tag is not exist."
|
other: "Etiqueta recomendada no existe."
|
||||||
recommend_tag_enter:
|
recommend_tag_enter:
|
||||||
other: "Por favor, introduce al menos una de las etiquetas requeridas."
|
other: "Por favor, introduce al menos una de las etiquetas requeridas."
|
||||||
not_contain_synonym_tags:
|
not_contain_synonym_tags:
|
||||||
|
@ -109,13 +109,13 @@ backend:
|
||||||
other: "No se puede establecer como sinónimo de una etiqueta la propia etiqueta."
|
other: "No se puede establecer como sinónimo de una etiqueta la propia etiqueta."
|
||||||
smtp:
|
smtp:
|
||||||
config_from_name_cannot_be_email:
|
config_from_name_cannot_be_email:
|
||||||
other: "The From Name cannot be a email address."
|
other: "¡Su nombre de usuario no puede ser una dirección de correo electrónico!"
|
||||||
theme:
|
theme:
|
||||||
not_found:
|
not_found:
|
||||||
other: "Tema no encontrado."
|
other: "Tema no encontrado."
|
||||||
revision:
|
revision:
|
||||||
review_underway:
|
review_underway:
|
||||||
other: "Can't edit currently, there is a version in the review queue."
|
other: "No se puede editar actualmente, hay una versión en la cola de revisiones."
|
||||||
no_permission:
|
no_permission:
|
||||||
other: "Sin permiso para revisar."
|
other: "Sin permiso para revisar."
|
||||||
user:
|
user:
|
||||||
|
@ -236,9 +236,30 @@ backend:
|
||||||
#The following fields are used for interface presentation(Front-end)
|
#The following fields are used for interface presentation(Front-end)
|
||||||
ui:
|
ui:
|
||||||
how_to_format:
|
how_to_format:
|
||||||
title: How to Format
|
title: Cómo formatear
|
||||||
desc: >-
|
desc: >-
|
||||||
<ul class="mb-0"><li><p class="mb-2">to make links</p><pre class="mb-2"><code><https://url.com><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>></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>
|
<ul class="mb-0">
|
||||||
|
<li><p class="mb-2">Para hacer enlaces</p>
|
||||||
|
<pre class="mb-2">
|
||||||
|
<code><https://url.com><br/><br/>[Title](https://url.com)
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</li>
|
||||||
|
<li><p class="mb-2">Colocar saltos de línea entre párrafos</p></li>
|
||||||
|
<li><p class="mb-2"><em>_cursiva_</em> o **<strong>negrita</strong>**</p></li>
|
||||||
|
<li><p class="mb-2">Indentar el código con 4 espacios</p></li>
|
||||||
|
<li><p class="mb-2">Citar colocando <code>></code> al inicio de la línea</p></li>
|
||||||
|
<li><p class="mb-2">Escape con backticks <code>`como _esto_`</code></p></li>
|
||||||
|
<li><p class="mb-2">Crear barreras de código con backticks <code>`</code></p>
|
||||||
|
<pre class="mb-0">
|
||||||
|
<code>
|
||||||
|
```<br/>
|
||||||
|
código aquí<br/>
|
||||||
|
```
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
pagination:
|
pagination:
|
||||||
prev: Anterior
|
prev: Anterior
|
||||||
next: Siguiente
|
next: Siguiente
|
||||||
|
@ -287,13 +308,13 @@ ui:
|
||||||
chart:
|
chart:
|
||||||
text: Gráfica
|
text: Gráfica
|
||||||
flow_chart: Diagrama de flujo
|
flow_chart: Diagrama de flujo
|
||||||
sequence_diagram: Sequence diagram
|
sequence_diagram: Diagrama de secuencia
|
||||||
class_diagram: Class diagram
|
class_diagram: Diagrama de clase
|
||||||
state_diagram: State diagram
|
state_diagram: Diagrama de estado
|
||||||
entity_relationship_diagram: Entity relationship diagram
|
entity_relationship_diagram: Diagrama de relación de entidad
|
||||||
user_defined_diagram: User defined diagram
|
user_defined_diagram: Diagrama definido por el usuario
|
||||||
gantt_chart: Diagrama de Gantt
|
gantt_chart: Diagrama de Gantt
|
||||||
pie_chart: Pie chart
|
pie_chart: Grafico de torta
|
||||||
code:
|
code:
|
||||||
text: Código
|
text: Código
|
||||||
add_code: Añadir código
|
add_code: Añadir código
|
||||||
|
@ -381,7 +402,7 @@ ui:
|
||||||
heading: Encabezado
|
heading: Encabezado
|
||||||
cell: Celda
|
cell: Celda
|
||||||
close_modal:
|
close_modal:
|
||||||
title: I am closing this post as...
|
title: Estoy cerrando este post como...
|
||||||
btn_cancel: Cancelar
|
btn_cancel: Cancelar
|
||||||
btn_submit: Enviar
|
btn_submit: Enviar
|
||||||
remark:
|
remark:
|
||||||
|
@ -389,11 +410,11 @@ ui:
|
||||||
msg:
|
msg:
|
||||||
empty: Por favor selecciona una razón.
|
empty: Por favor selecciona una razón.
|
||||||
report_modal:
|
report_modal:
|
||||||
flag_title: I am flagging to report this post as...
|
flag_title: Estoy marcando este post como...
|
||||||
close_title: I am closing this post as...
|
close_title: Estoy cerrando este post como...
|
||||||
review_question_title: Review question
|
review_question_title: Revisar pregunta
|
||||||
review_answer_title: Review answer
|
review_answer_title: Revisar respuesta
|
||||||
review_comment_title: Review comment
|
review_comment_title: Revisar comentario
|
||||||
btn_cancel: Cancelar
|
btn_cancel: Cancelar
|
||||||
btn_submit: Enviar
|
btn_submit: Enviar
|
||||||
remark:
|
remark:
|
||||||
|
@ -408,7 +429,7 @@ ui:
|
||||||
label: Nombre a mostrar
|
label: Nombre a mostrar
|
||||||
msg:
|
msg:
|
||||||
empty: El nombre a mostrar no puede estar vacío.
|
empty: El nombre a mostrar no puede estar vacío.
|
||||||
range: Display name up to 35 characters.
|
range: Nombre a mostrar con un máximo de 35 caracteres.
|
||||||
slug_name:
|
slug_name:
|
||||||
label: URL amigable
|
label: URL amigable
|
||||||
desc: 'Debe usar el conjunto de caracteres "a-z", "0-9", "+ # - ."'
|
desc: 'Debe usar el conjunto de caracteres "a-z", "0-9", "+ # - ."'
|
||||||
|
@ -426,16 +447,16 @@ ui:
|
||||||
history: Historial
|
history: Historial
|
||||||
synonyms:
|
synonyms:
|
||||||
title: Sinónimos
|
title: Sinónimos
|
||||||
text: The following tags will be remapped to
|
text: Las siguientes etiquetas serán reasignadas a
|
||||||
empty: No se encontraron sinónimos.
|
empty: No se encontraron sinónimos.
|
||||||
btn_add: Añadir un sinónimo
|
btn_add: Añadir un sinónimo
|
||||||
btn_edit: Editar
|
btn_edit: Editar
|
||||||
btn_save: Guardar
|
btn_save: Guardar
|
||||||
synonyms_text: The following tags will be remapped to
|
synonyms_text: Las siguientes etiquetas serán reasignadas a
|
||||||
delete:
|
delete:
|
||||||
title: Eliminar esta etiqueta
|
title: Eliminar esta etiqueta
|
||||||
content: >-
|
content: >-
|
||||||
<p>We do not allowed deleting tag with posts.</p><p>Please remove this tag from the posts first.</p>
|
<p>No se permite la eliminación de etiquetas con posts.</p><p>Por favor antes elimina esta etiqueta del post.</p>
|
||||||
content2: '¿Estás seguro de que deseas borrarlo?'
|
content2: '¿Estás seguro de que deseas borrarlo?'
|
||||||
close: Cerrar
|
close: Cerrar
|
||||||
edit_tag:
|
edit_tag:
|
||||||
|
@ -508,16 +529,16 @@ ui:
|
||||||
tag_label: preguntas
|
tag_label: preguntas
|
||||||
search_placeholder: Filtrar por nombre de etiqueta
|
search_placeholder: Filtrar por nombre de etiqueta
|
||||||
no_desc: La etiqueta no tiene descripción.
|
no_desc: La etiqueta no tiene descripción.
|
||||||
more: More
|
more: Mas
|
||||||
ask:
|
ask:
|
||||||
title: Add Question
|
title: Agregar una pregunta
|
||||||
edit_title: Edit Question
|
edit_title: Editar pregunta
|
||||||
default_reason: Edit question
|
default_reason: Editar pregunta
|
||||||
similar_questions: Preguntas similares
|
similar_questions: Preguntas similares
|
||||||
form:
|
form:
|
||||||
fields:
|
fields:
|
||||||
revision:
|
revision:
|
||||||
label: Revision
|
label: Revisión
|
||||||
title:
|
title:
|
||||||
label: Título
|
label: Título
|
||||||
placeholder: Sé preciso e imagina que le estás preguntando esto a una persona
|
placeholder: Sé preciso e imagina que le estás preguntando esto a una persona
|
||||||
|
@ -585,7 +606,8 @@ ui:
|
||||||
msg:
|
msg:
|
||||||
empty: No puede estar en blanco.
|
empty: No puede estar en blanco.
|
||||||
login:
|
login:
|
||||||
page_title: Bienvenido a Answer
|
page_title: Bienvenido a {{site_name}}
|
||||||
|
login_to_continue: Inicia sesión para continuar
|
||||||
info_sign: '¿No tienes cuenta? <1>Regístrate</1>'
|
info_sign: '¿No tienes cuenta? <1>Regístrate</1>'
|
||||||
info_login: '¿Ya tienes una cuenta? <1>Inicia sesión</1>'
|
info_login: '¿Ya tienes una cuenta? <1>Inicia sesión</1>'
|
||||||
agreements: Al registrarte, aceptas la <1>política de privacidad</1> y los <3>términos de servicio</3>.
|
agreements: Al registrarte, aceptas la <1>política de privacidad</1> y los <3>términos de servicio</3>.
|
||||||
|
@ -666,7 +688,7 @@ ui:
|
||||||
custom: Propia
|
custom: Propia
|
||||||
btn_refresh: Actualizar
|
btn_refresh: Actualizar
|
||||||
custom_text: Puedes subir tu propia imagen.
|
custom_text: Puedes subir tu propia imagen.
|
||||||
default: System
|
default: Sistema
|
||||||
msg: Por favor, sube una imagen
|
msg: Por favor, sube una imagen
|
||||||
bio:
|
bio:
|
||||||
label: Sobre mí (opcional)
|
label: Sobre mí (opcional)
|
||||||
|
@ -693,11 +715,11 @@ ui:
|
||||||
msg: El correo electrónico no puede estar vacío.
|
msg: El correo electrónico no puede estar vacío.
|
||||||
password_title: Password
|
password_title: Password
|
||||||
current_pass:
|
current_pass:
|
||||||
label: Current Password
|
label: Contraseña actual
|
||||||
msg:
|
msg:
|
||||||
empty: Current Password cannot be empty.
|
empty: La contraseña actual no puede estar vacía.
|
||||||
length: The length needs to be between 8 and 32.
|
length: El largo necesita estar entre 8 y 32 caracteres.
|
||||||
different: The two entered passwords do not match.
|
different: Las contraseñas no coinciden.
|
||||||
new_pass:
|
new_pass:
|
||||||
label: Nueva Contraseña
|
label: Nueva Contraseña
|
||||||
pass_confirm:
|
pass_confirm:
|
||||||
|
@ -712,7 +734,7 @@ ui:
|
||||||
update_password: Contraseña cambiada con éxito.
|
update_password: Contraseña cambiada con éxito.
|
||||||
flag_success: Gracias por reportar.
|
flag_success: Gracias por reportar.
|
||||||
forbidden_operate_self: No puedes modificar tu propio usuario
|
forbidden_operate_self: No puedes modificar tu propio usuario
|
||||||
review: Your revision will show after review.
|
review: Tu revisión será visible luego de ser aprobada.
|
||||||
related_question:
|
related_question:
|
||||||
title: Preguntas relacionadas
|
title: Preguntas relacionadas
|
||||||
btn: Añadir pregunta
|
btn: Añadir pregunta
|
||||||
|
@ -726,7 +748,7 @@ ui:
|
||||||
Follow: Seguir
|
Follow: Seguir
|
||||||
Following: Siguiendo
|
Following: Siguiendo
|
||||||
answered: respondida
|
answered: respondida
|
||||||
closed_in: Closed in
|
closed_in: Cerrado el
|
||||||
show_exist: Mostrar una pregunta existente.
|
show_exist: Mostrar una pregunta existente.
|
||||||
answers:
|
answers:
|
||||||
title: Respuestas
|
title: Respuestas
|
||||||
|
@ -750,9 +772,13 @@ ui:
|
||||||
delete:
|
delete:
|
||||||
title: Eliminar esta publicación
|
title: Eliminar esta publicación
|
||||||
question: >-
|
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?
|
No recomendamos <strong>borrar preguntas con respuestas</strong> porque esto priva a los lectores futuros de este conocimiento.
|
||||||
|
</p><p>
|
||||||
|
El borrado repetido de preguntas respondidas puede resultar en que tu cuenta se bloquee para hacer preguntas. ¿Estás seguro de que deseas borrarlo?
|
||||||
answer_accepted: >-
|
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?
|
<p>No recomendamos <strong>borrar la respuesta aceptada</strong> porque esto priva a los lectores futuros de este conocimiento.</p>
|
||||||
|
|
||||||
|
El borrado repetido de respuestas aceptadas puede resultar en que tu cuenta se bloquee para responder. ¿Estás seguro de que deseas borrarlo?
|
||||||
other: '¿Estás seguro de que deseas borrarlo?'
|
other: '¿Estás seguro de que deseas borrarlo?'
|
||||||
tip_question_deleted: Esta publicación ha sido eliminada
|
tip_question_deleted: Esta publicación ha sido eliminada
|
||||||
tip_answer_deleted: Esta respuesta ha sido eliminada
|
tip_answer_deleted: Esta respuesta ha sido eliminada
|
||||||
|
@ -782,13 +808,13 @@ ui:
|
||||||
newest: Más reciente
|
newest: Más reciente
|
||||||
active: Activas
|
active: Activas
|
||||||
score: Puntuación
|
score: Puntuación
|
||||||
more: More
|
more: Mas
|
||||||
tips:
|
tips:
|
||||||
title: Advanced Search Tips
|
title: Consejos de búsqueda avanzada
|
||||||
tag: "<1>[tag]</1> search withing a tag"
|
tag: "<1>[tag]</1> búsqueda por etiquetas"
|
||||||
user: "<1>user:username</1> search by author"
|
user: "<1>user:username</1> búsqueda por autor"
|
||||||
answer: "<1>answers:0</1> unanswered questions"
|
answer: "<1>answers:0</1> preguntas sin responder"
|
||||||
score: "<1>score:3</1> posts with a 3+ score"
|
score: "<1>score:3</1> Publicaciones con un puntaje de 3 o más"
|
||||||
question: "<1>is:question</1> buscar preguntas"
|
question: "<1>is:question</1> buscar preguntas"
|
||||||
is_answer: "<1>is:answer</1> buscar respuestas"
|
is_answer: "<1>is:answer</1> buscar respuestas"
|
||||||
empty: No pudimos encontrar nada. <br /> Prueba a buscar con palabras diferentes o menos específicas.
|
empty: No pudimos encontrar nada. <br /> Prueba a buscar con palabras diferentes o menos específicas.
|
||||||
|
@ -810,14 +836,14 @@ ui:
|
||||||
Lo sentimos, este link de confirmación de cuenta ya no es válido. ¿Quizás tu cuenta ya está activa?
|
Lo sentimos, este link de confirmación de cuenta ya no es válido. ¿Quizás tu cuenta ya está activa?
|
||||||
confirm_new_email: Tu email ha sido actualizado.
|
confirm_new_email: Tu email ha sido actualizado.
|
||||||
confirm_new_email_invalid: >-
|
confirm_new_email_invalid: >-
|
||||||
Sorry, this confirmation link is no longer valid. Perhaps your email was already changed?
|
Lo siento, este enlace de confirmación ya no es válido. ¿Quizás ya se haya cambiado tu correo electrónico?
|
||||||
unsubscribe:
|
unsubscribe:
|
||||||
page_title: Desuscribir
|
page_title: Desuscribir
|
||||||
success_title: Desuscrito con éxito
|
success_title: Desuscrito con éxito
|
||||||
success_desc: Has sido eliminado con éxito de esta lista de suscriptores y no recibirás más correos electrónicos nuestros.
|
success_desc: Has sido eliminado con éxito de esta lista de suscriptores y no recibirás más correos electrónicos nuestros.
|
||||||
link: Cambiar ajustes
|
link: Cambiar ajustes
|
||||||
question:
|
question:
|
||||||
following_tags: Following Tags
|
following_tags: Etiquetas seguidas
|
||||||
edit: Editar
|
edit: Editar
|
||||||
save: Guardar
|
save: Guardar
|
||||||
follow_tag_tip: Sigue etiquetas para personalizar tu lista de preguntas.
|
follow_tag_tip: Sigue etiquetas para personalizar tu lista de preguntas.
|
||||||
|
@ -828,8 +854,8 @@ ui:
|
||||||
questions: Preguntas
|
questions: Preguntas
|
||||||
answers: Respuestas
|
answers: Respuestas
|
||||||
newest: Más reciente
|
newest: Más reciente
|
||||||
active: Active
|
active: Activo
|
||||||
frequent: Frequent
|
frequent: Frecuente
|
||||||
score: Puntuación
|
score: Puntuación
|
||||||
unanswered: Sin respuesta
|
unanswered: Sin respuesta
|
||||||
modified: modificada
|
modified: modificada
|
||||||
|
@ -852,8 +878,8 @@ ui:
|
||||||
score: Puntuación
|
score: Puntuación
|
||||||
edit_profile: Editar perfil
|
edit_profile: Editar perfil
|
||||||
visited_x_days: "Visitado {{ count }} días"
|
visited_x_days: "Visitado {{ count }} días"
|
||||||
viewed: Viewed
|
viewed: Visto
|
||||||
joined: Joined
|
joined: Unido
|
||||||
last_login: Seen
|
last_login: Seen
|
||||||
about_me: Sobre mí
|
about_me: Sobre mí
|
||||||
about_me_empty: "// ¡Hola Mundo!"
|
about_me_empty: "// ¡Hola Mundo!"
|
||||||
|
@ -1222,14 +1248,14 @@ ui:
|
||||||
branding:
|
branding:
|
||||||
page_title: Branding
|
page_title: Branding
|
||||||
logo:
|
logo:
|
||||||
label: Logo
|
label: Logo (optional)
|
||||||
msg: Logo cannot be empty.
|
msg: Logo cannot be empty.
|
||||||
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
||||||
mobile_logo:
|
mobile_logo:
|
||||||
label: Mobile Logo (optional)
|
label: Mobile Logo (optional)
|
||||||
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
||||||
square_icon:
|
square_icon:
|
||||||
label: Square Icon
|
label: Square Icon (optional)
|
||||||
msg: Square icon cannot be empty.
|
msg: Square icon cannot be empty.
|
||||||
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
||||||
favicon:
|
favicon:
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
785
i18n/fr_FR.yaml
785
i18n/fr_FR.yaml
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,26 +1,26 @@
|
||||||
# all support language
|
# all support language
|
||||||
language_options:
|
language_options:
|
||||||
|
- label: "English(US)"
|
||||||
|
value: "en_US"
|
||||||
|
- label: "Español(ES)"
|
||||||
|
value: "es_ES"
|
||||||
|
- label: "Português(PT)"
|
||||||
|
value: "pt_PT"
|
||||||
|
- label: "Deutsch(DE)"
|
||||||
|
value: "de_DE"
|
||||||
|
- label: "Français(FR)"
|
||||||
|
value: "fr_FR"
|
||||||
|
- label: "日本語(JA)"
|
||||||
|
value: "ja_JP"
|
||||||
|
- label: "Italiano(IT)"
|
||||||
|
value: "it_IT"
|
||||||
|
- label: "Русский(RU)"
|
||||||
|
value: "ru_RU"
|
||||||
- label: "简体中文(CN)"
|
- label: "简体中文(CN)"
|
||||||
value: "zh_CN"
|
value: "zh_CN"
|
||||||
- label: "繁體中文(CN)"
|
- label: "繁體中文(CN)"
|
||||||
value: "zh_TW"
|
value: "zh_TW"
|
||||||
- label: "English(US)"
|
|
||||||
value: "en_US"
|
|
||||||
- label: "Deutsch(DE)"
|
|
||||||
value: "de_DE"
|
|
||||||
- label: "Español(ES)"
|
|
||||||
value: "es_ES"
|
|
||||||
- label: "Français(FR)"
|
|
||||||
value: "fr_FR"
|
|
||||||
- label: "Italiano(IT)"
|
|
||||||
value: "it_IT"
|
|
||||||
- label: "日本語(JA)"
|
|
||||||
value: "ja_JP"
|
|
||||||
- label: "한국어(KO)"
|
- label: "한국어(KO)"
|
||||||
value: "ko_KR"
|
value: "ko_KR"
|
||||||
- label: "Português(PT)"
|
|
||||||
value: "pt_PT"
|
|
||||||
- label: "Русский(RU)"
|
|
||||||
value: "ru_RU"
|
|
||||||
- label: "Tiếng Việt(VI)"
|
- label: "Tiếng Việt(VI)"
|
||||||
value: "vi_VN"
|
value: "vi_VN"
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -129,7 +129,7 @@ backend:
|
||||||
username_invalid:
|
username_invalid:
|
||||||
other: "utente non valido"
|
other: "utente non valido"
|
||||||
username_duplicate:
|
username_duplicate:
|
||||||
other: "utente già in uso"
|
other: "Nome utente già in uso"
|
||||||
set_avatar:
|
set_avatar:
|
||||||
other: "Inserimento dell'Avatar non riuscito."
|
other: "Inserimento dell'Avatar non riuscito."
|
||||||
cannot_update_your_role:
|
cannot_update_your_role:
|
||||||
|
@ -585,7 +585,8 @@ ui:
|
||||||
msg:
|
msg:
|
||||||
empty: Cannot be empty.
|
empty: Cannot be empty.
|
||||||
login:
|
login:
|
||||||
page_title: Welcome to Answer
|
page_title: Welcome to {{site_name}}
|
||||||
|
login_to_continue: Log in to continue
|
||||||
info_sign: Don't have an account? <1>Sign up</1>
|
info_sign: Don't have an account? <1>Sign up</1>
|
||||||
info_login: Already have an account? <1>Log in</1>
|
info_login: Already have an account? <1>Log in</1>
|
||||||
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
||||||
|
@ -1222,14 +1223,14 @@ ui:
|
||||||
branding:
|
branding:
|
||||||
page_title: Branding
|
page_title: Branding
|
||||||
logo:
|
logo:
|
||||||
label: Logo
|
label: Logo (optional)
|
||||||
msg: Logo cannot be empty.
|
msg: Logo cannot be empty.
|
||||||
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
||||||
mobile_logo:
|
mobile_logo:
|
||||||
label: Mobile Logo (optional)
|
label: Mobile Logo (optional)
|
||||||
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
||||||
square_icon:
|
square_icon:
|
||||||
label: Square Icon
|
label: Square Icon (optional)
|
||||||
msg: Square icon cannot be empty.
|
msg: Square icon cannot be empty.
|
||||||
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
||||||
favicon:
|
favicon:
|
||||||
|
|
|
@ -585,7 +585,8 @@ ui:
|
||||||
msg:
|
msg:
|
||||||
empty: Cannot be empty.
|
empty: Cannot be empty.
|
||||||
login:
|
login:
|
||||||
page_title: Welcome to Answer
|
page_title: Welcome to {{site_name}}
|
||||||
|
login_to_continue: Log in to continue
|
||||||
info_sign: Don't have an account? <1>Sign up</1>
|
info_sign: Don't have an account? <1>Sign up</1>
|
||||||
info_login: Already have an account? <1>Log in</1>
|
info_login: Already have an account? <1>Log in</1>
|
||||||
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
||||||
|
@ -1222,14 +1223,14 @@ ui:
|
||||||
branding:
|
branding:
|
||||||
page_title: Branding
|
page_title: Branding
|
||||||
logo:
|
logo:
|
||||||
label: Logo
|
label: Logo (optional)
|
||||||
msg: Logo cannot be empty.
|
msg: Logo cannot be empty.
|
||||||
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
||||||
mobile_logo:
|
mobile_logo:
|
||||||
label: Mobile Logo (optional)
|
label: Mobile Logo (optional)
|
||||||
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
||||||
square_icon:
|
square_icon:
|
||||||
label: Square Icon
|
label: Square Icon (optional)
|
||||||
msg: Square icon cannot be empty.
|
msg: Square icon cannot be empty.
|
||||||
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
||||||
favicon:
|
favicon:
|
||||||
|
|
|
@ -585,7 +585,8 @@ ui:
|
||||||
msg:
|
msg:
|
||||||
empty: Cannot be empty.
|
empty: Cannot be empty.
|
||||||
login:
|
login:
|
||||||
page_title: Welcome to Answer
|
page_title: Welcome to {{site_name}}
|
||||||
|
login_to_continue: Log in to continue
|
||||||
info_sign: Don't have an account? <1>Sign up</1>
|
info_sign: Don't have an account? <1>Sign up</1>
|
||||||
info_login: Already have an account? <1>Log in</1>
|
info_login: Already have an account? <1>Log in</1>
|
||||||
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
||||||
|
@ -1222,14 +1223,14 @@ ui:
|
||||||
branding:
|
branding:
|
||||||
page_title: Branding
|
page_title: Branding
|
||||||
logo:
|
logo:
|
||||||
label: Logo
|
label: Logo (optional)
|
||||||
msg: Logo cannot be empty.
|
msg: Logo cannot be empty.
|
||||||
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
||||||
mobile_logo:
|
mobile_logo:
|
||||||
label: Mobile Logo (optional)
|
label: Mobile Logo (optional)
|
||||||
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
||||||
square_icon:
|
square_icon:
|
||||||
label: Square Icon
|
label: Square Icon (optional)
|
||||||
msg: Square icon cannot be empty.
|
msg: Square icon cannot be empty.
|
||||||
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
||||||
favicon:
|
favicon:
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -585,7 +585,8 @@ ui:
|
||||||
msg:
|
msg:
|
||||||
empty: Cannot be empty.
|
empty: Cannot be empty.
|
||||||
login:
|
login:
|
||||||
page_title: Welcome to Answer
|
page_title: Welcome to {{site_name}}
|
||||||
|
login_to_continue: Log in to continue
|
||||||
info_sign: Don't have an account? <1>Sign up</1>
|
info_sign: Don't have an account? <1>Sign up</1>
|
||||||
info_login: Already have an account? <1>Log in</1>
|
info_login: Already have an account? <1>Log in</1>
|
||||||
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
||||||
|
@ -1222,14 +1223,14 @@ ui:
|
||||||
branding:
|
branding:
|
||||||
page_title: Branding
|
page_title: Branding
|
||||||
logo:
|
logo:
|
||||||
label: Logo
|
label: Logo (optional)
|
||||||
msg: Logo cannot be empty.
|
msg: Logo cannot be empty.
|
||||||
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
||||||
mobile_logo:
|
mobile_logo:
|
||||||
label: Mobile Logo (optional)
|
label: Mobile Logo (optional)
|
||||||
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
||||||
square_icon:
|
square_icon:
|
||||||
label: Square Icon
|
label: Square Icon (optional)
|
||||||
msg: Square icon cannot be empty.
|
msg: Square icon cannot be empty.
|
||||||
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
||||||
favicon:
|
favicon:
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
303
i18n/ru_RU.yaml
303
i18n/ru_RU.yaml
|
@ -2,122 +2,122 @@
|
||||||
backend:
|
backend:
|
||||||
base:
|
base:
|
||||||
success:
|
success:
|
||||||
other: "Success."
|
other: "Выполнено."
|
||||||
unknown:
|
unknown:
|
||||||
other: "Unknown error."
|
other: "Неизвестная ошибка."
|
||||||
request_format_error:
|
request_format_error:
|
||||||
other: "Request format is not valid."
|
other: "Формат файла не корректен."
|
||||||
unauthorized_error:
|
unauthorized_error:
|
||||||
other: "Unauthorized."
|
other: "Авторизация не выполнена."
|
||||||
database_error:
|
database_error:
|
||||||
other: "Data server error."
|
other: "Ошибка сервера данных."
|
||||||
role:
|
role:
|
||||||
name:
|
name:
|
||||||
user:
|
user:
|
||||||
other: "User"
|
other: "Пользователь"
|
||||||
admin:
|
admin:
|
||||||
other: "Admin"
|
other: "Администратор"
|
||||||
moderator:
|
moderator:
|
||||||
other: "Moderator"
|
other: "Модератор"
|
||||||
description:
|
description:
|
||||||
user:
|
user:
|
||||||
other: "Default with no special access."
|
other: "По умолчанию, без специального доступа."
|
||||||
admin:
|
admin:
|
||||||
other: "Have the full power to access the site."
|
other: "Имейте все полномочия для доступа к сайту."
|
||||||
moderator:
|
moderator:
|
||||||
other: "Has access to all posts except admin settings."
|
other: "Имеет доступ ко всем сообщениям, кроме настроек администратора."
|
||||||
email:
|
email:
|
||||||
other: "Email"
|
other: "Эл. почта"
|
||||||
password:
|
password:
|
||||||
other: "Password"
|
other: "Пароль"
|
||||||
email_or_password_wrong_error:
|
email_or_password_wrong_error:
|
||||||
other: "Email and password do not match."
|
other: "Неверное имя пользователя или пароль."
|
||||||
error:
|
error:
|
||||||
admin:
|
admin:
|
||||||
email_or_password_wrong:
|
email_or_password_wrong:
|
||||||
other: Email and password do not match.
|
other: Неверное имя пользователя или пароль.
|
||||||
answer:
|
answer:
|
||||||
not_found:
|
not_found:
|
||||||
other: "Answer do not found."
|
other: "Ответ не найден."
|
||||||
cannot_deleted:
|
cannot_deleted:
|
||||||
other: "No permission to delete."
|
other: "Недостаточно прав для удаления."
|
||||||
cannot_update:
|
cannot_update:
|
||||||
other: "No permission to update."
|
other: "Нет прав для обновления."
|
||||||
comment:
|
comment:
|
||||||
edit_without_permission:
|
edit_without_permission:
|
||||||
other: "Comment are not allowed to edit."
|
other: "Комментарий не может редактироваться."
|
||||||
not_found:
|
not_found:
|
||||||
other: "Comment not found."
|
other: "Комментарий не найден."
|
||||||
email:
|
email:
|
||||||
duplicate:
|
duplicate:
|
||||||
other: "Email already exists."
|
other: "Адрес электронной почты уже существует."
|
||||||
need_to_be_verified:
|
need_to_be_verified:
|
||||||
other: "Email should be verified."
|
other: "Адрес электронной почты должен быть подтвержден."
|
||||||
verify_url_expired:
|
verify_url_expired:
|
||||||
other: "Email verified URL has expired, please resend the email."
|
other: "Срок действия подтверждённого адреса электронной почты истек, пожалуйста, отправьте письмо повторно."
|
||||||
lang:
|
lang:
|
||||||
not_found:
|
not_found:
|
||||||
other: "Language file not found."
|
other: "Языковой файл не найден."
|
||||||
object:
|
object:
|
||||||
captcha_verification_failed:
|
captcha_verification_failed:
|
||||||
other: "Captcha wrong."
|
other: "Captcha введена неверно."
|
||||||
disallow_follow:
|
disallow_follow:
|
||||||
other: "You are not allowed to follow."
|
other: "Вы не можете подписаться."
|
||||||
disallow_vote:
|
disallow_vote:
|
||||||
other: "You are not allowed to vote."
|
other: "Вы не можете голосовать."
|
||||||
disallow_vote_your_self:
|
disallow_vote_your_self:
|
||||||
other: "You can't vote for your own post."
|
other: "Вы не можете голосовать за собственный отзыв."
|
||||||
not_found:
|
not_found:
|
||||||
other: "Object not found."
|
other: "Объект не найден."
|
||||||
verification_failed:
|
verification_failed:
|
||||||
other: "Verification failed."
|
other: "Проверка не удалась."
|
||||||
email_or_password_incorrect:
|
email_or_password_incorrect:
|
||||||
other: "Email and password do not match."
|
other: "Email или пароль не совпадают."
|
||||||
old_password_verification_failed:
|
old_password_verification_failed:
|
||||||
other: "The old password verification failed"
|
other: "Не удалось подтвердить старый пароль"
|
||||||
new_password_same_as_previous_setting:
|
new_password_same_as_previous_setting:
|
||||||
other: "The new password is the same as the previous one."
|
other: "Пароль не может быть таким же как прежний."
|
||||||
question:
|
question:
|
||||||
not_found:
|
not_found:
|
||||||
other: "Question not found."
|
other: "Вопрос не найден."
|
||||||
cannot_deleted:
|
cannot_deleted:
|
||||||
other: "No permission to delete."
|
other: "Недостаточно прав для удаления."
|
||||||
cannot_close:
|
cannot_close:
|
||||||
other: "No permission to close."
|
other: "Нет разрешения на закрытие."
|
||||||
cannot_update:
|
cannot_update:
|
||||||
other: "No permission to update."
|
other: "Нет разрешения на обновление."
|
||||||
rank:
|
rank:
|
||||||
fail_to_meet_the_condition:
|
fail_to_meet_the_condition:
|
||||||
other: "Rank fail to meet the condition."
|
other: "Ранг не соответствует условию."
|
||||||
report:
|
report:
|
||||||
handle_failed:
|
handle_failed:
|
||||||
other: "Report handle failed."
|
other: "Не удалось обработать отчет."
|
||||||
not_found:
|
not_found:
|
||||||
other: "Report not found."
|
other: "Отчет не найден."
|
||||||
tag:
|
tag:
|
||||||
not_found:
|
not_found:
|
||||||
other: "Tag not found."
|
other: "Тег не найден."
|
||||||
recommend_tag_not_found:
|
recommend_tag_not_found:
|
||||||
other: "Recommend Tag is not exist."
|
other: "Рекомендуемый тег не существует."
|
||||||
recommend_tag_enter:
|
recommend_tag_enter:
|
||||||
other: "Please enter at least one required tag."
|
other: "Пожалуйста, введите хотя бы один тег."
|
||||||
not_contain_synonym_tags:
|
not_contain_synonym_tags:
|
||||||
other: "Should not contain synonym tags."
|
other: "Не должно содержать теги синонимы."
|
||||||
cannot_update:
|
cannot_update:
|
||||||
other: "No permission to update."
|
other: "Нет прав для обновления."
|
||||||
cannot_set_synonym_as_itself:
|
cannot_set_synonym_as_itself:
|
||||||
other: "You cannot set the synonym of the current tag as itself."
|
other: "Вы не можете установить синоним текущего тега."
|
||||||
smtp:
|
smtp:
|
||||||
config_from_name_cannot_be_email:
|
config_from_name_cannot_be_email:
|
||||||
other: "The From Name cannot be a email address."
|
other: "Имя пользователя не может быть адрес электронной почты."
|
||||||
theme:
|
theme:
|
||||||
not_found:
|
not_found:
|
||||||
other: "Theme not found."
|
other: "Тема не найдена."
|
||||||
revision:
|
revision:
|
||||||
review_underway:
|
review_underway:
|
||||||
other: "Can't edit currently, there is a version in the review queue."
|
other: "В настоящее время не удается редактировать версию, в очереди на проверку."
|
||||||
no_permission:
|
no_permission:
|
||||||
other: "No permission to Revision."
|
other: "Нет прав на ревизию."
|
||||||
user:
|
user:
|
||||||
email_or_password_wrong:
|
email_or_password_wrong:
|
||||||
other:
|
other:
|
||||||
|
@ -241,68 +241,68 @@ ui:
|
||||||
<ul class="mb-0"><li><p class="mb-2">to make links</p><pre class="mb-2"><code><https://url.com><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>></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>
|
<ul class="mb-0"><li><p class="mb-2">to make links</p><pre class="mb-2"><code><https://url.com><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>></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:
|
pagination:
|
||||||
prev: Prev
|
prev: Prev
|
||||||
next: Next
|
next: Следующий
|
||||||
page_title:
|
page_title:
|
||||||
question: Question
|
question: Вопрос
|
||||||
questions: Questions
|
questions: Вопросы
|
||||||
tag: Tag
|
tag: Тэг
|
||||||
tags: Tags
|
tags: Теги
|
||||||
tag_wiki: tag wiki
|
tag_wiki: wiki тэг
|
||||||
edit_tag: Edit Tag
|
edit_tag: Изменить тег
|
||||||
ask_a_question: Add Question
|
ask_a_question: Добавить вопрос
|
||||||
edit_question: Edit Question
|
edit_question: Редактировать вопрос
|
||||||
edit_answer: Edit Answer
|
edit_answer: Редактировать ответ
|
||||||
search: Search
|
search: Поиск
|
||||||
posts_containing: Posts containing
|
posts_containing: Посты содержащие
|
||||||
settings: Settings
|
settings: Настройки
|
||||||
notifications: Notifications
|
notifications: Уведомления
|
||||||
login: Log In
|
login: Вход
|
||||||
sign_up: Sign Up
|
sign_up: Регистрация
|
||||||
account_recovery: Account Recovery
|
account_recovery: Восстановление аккаунта
|
||||||
account_activation: Account Activation
|
account_activation: Активация учётной записи
|
||||||
confirm_email: Confirm Email
|
confirm_email: Подтвердить адрес электронной почты
|
||||||
account_suspended: Account Suspended
|
account_suspended: Аккаунт заблокирован
|
||||||
admin: Admin
|
admin: Управление
|
||||||
change_email: Modify Email
|
change_email: Изменить Email
|
||||||
install: Answer Installation
|
install: Установка ответа
|
||||||
upgrade: Answer Upgrade
|
upgrade: Обновить ответ
|
||||||
maintenance: Website Maintenance
|
maintenance: Обслуживание сайта
|
||||||
users: Users
|
users: Пользователи
|
||||||
notifications:
|
notifications:
|
||||||
title: Notifications
|
title: Уведомления
|
||||||
inbox: Inbox
|
inbox: Входящие
|
||||||
achievement: Achievements
|
achievement: Достижения
|
||||||
all_read: Mark all as read
|
all_read: Отметить всё как прочитанное
|
||||||
show_more: Show more
|
show_more: Показать еще
|
||||||
suspended:
|
suspended:
|
||||||
title: Your Account has been Suspended
|
title: Ваш аккаунт заблокирован
|
||||||
until_time: "Your account was suspended until {{ time }}."
|
until_time: "Ваша учетная запись была заблокирована до {{ time }}."
|
||||||
forever: This user was suspended forever.
|
forever: Этот пользователь был навсегда заблокирован.
|
||||||
end: You don't meet a community guideline.
|
end: Вы не соответствуете правилам сообщества.
|
||||||
editor:
|
editor:
|
||||||
blockquote:
|
blockquote:
|
||||||
text: Blockquote
|
text: Цитата
|
||||||
bold:
|
bold:
|
||||||
text: Strong
|
text: Жирный
|
||||||
chart:
|
chart:
|
||||||
text: Chart
|
text: Диаграмма
|
||||||
flow_chart: Flow chart
|
flow_chart: Блок-схема
|
||||||
sequence_diagram: Sequence diagram
|
sequence_diagram: Диаграмма последовательности
|
||||||
class_diagram: Class diagram
|
class_diagram: Диаграмма классов
|
||||||
state_diagram: State diagram
|
state_diagram: Диаграмма состояний
|
||||||
entity_relationship_diagram: Entity relationship diagram
|
entity_relationship_diagram: Диаграмма связей сущностей
|
||||||
user_defined_diagram: User defined diagram
|
user_defined_diagram: Пользовательская диаграмма
|
||||||
gantt_chart: Gantt chart
|
gantt_chart: Диаграмма Гантта
|
||||||
pie_chart: Pie chart
|
pie_chart: Круговая диаграмма
|
||||||
code:
|
code:
|
||||||
text: Code Sample
|
text: Фрагмент кода
|
||||||
add_code: Add code sample
|
add_code: Добавить пример кода
|
||||||
form:
|
form:
|
||||||
fields:
|
fields:
|
||||||
code:
|
code:
|
||||||
label: Code
|
label: Код
|
||||||
msg:
|
msg:
|
||||||
empty: Code cannot be empty.
|
empty: Код не может быть пустым.
|
||||||
language:
|
language:
|
||||||
label: Language (optional)
|
label: Language (optional)
|
||||||
placeholder: Automatic detection
|
placeholder: Automatic detection
|
||||||
|
@ -385,79 +385,79 @@ ui:
|
||||||
btn_cancel: Cancel
|
btn_cancel: Cancel
|
||||||
btn_submit: Submit
|
btn_submit: Submit
|
||||||
remark:
|
remark:
|
||||||
empty: Cannot be empty.
|
empty: Не может быть пустым.
|
||||||
msg:
|
msg:
|
||||||
empty: Please select a reason.
|
empty: Пожалуйста, выбери причину.
|
||||||
report_modal:
|
report_modal:
|
||||||
flag_title: I am flagging to report this post as...
|
flag_title: Я помечаю, чтобы пожаловаться на эту публикацию как...
|
||||||
close_title: I am closing this post as...
|
close_title: Я закрываю этот пост как...
|
||||||
review_question_title: Review question
|
review_question_title: Проверить вопрос
|
||||||
review_answer_title: Review answer
|
review_answer_title: Проверить ответ
|
||||||
review_comment_title: Review comment
|
review_comment_title: Просмотр комментариев
|
||||||
btn_cancel: Cancel
|
btn_cancel: Отмена
|
||||||
btn_submit: Submit
|
btn_submit: Отправить
|
||||||
remark:
|
remark:
|
||||||
empty: Cannot be empty.
|
empty: Не может быть пустым.
|
||||||
msg:
|
msg:
|
||||||
empty: Please select a reason.
|
empty: Пожалуйста, выбери причину.
|
||||||
tag_modal:
|
tag_modal:
|
||||||
title: Create new tag
|
title: Создать новый тег
|
||||||
form:
|
form:
|
||||||
fields:
|
fields:
|
||||||
display_name:
|
display_name:
|
||||||
label: Display Name
|
label: Показывать имя
|
||||||
msg:
|
msg:
|
||||||
empty: Display name cannot be empty.
|
empty: Отображаемое название не может быть пустым.
|
||||||
range: Display name up to 35 characters.
|
range: Отображаемое имя до 35 символов.
|
||||||
slug_name:
|
slug_name:
|
||||||
label: URL Slug
|
label: Идентификатор URL
|
||||||
desc: 'Must use the character set "a-z", "0-9", "+ # - ."'
|
desc: 'Необходимо использовать набор символов "a-z", "0-9", "+ # - ."'
|
||||||
msg:
|
msg:
|
||||||
empty: URL slug cannot be empty.
|
empty: URL не может быть пустым.
|
||||||
range: URL slug up to 35 characters.
|
range: URL slug до 35 символов.
|
||||||
character: URL slug contains unallowed character set.
|
character: URL slug содержит недопустимый набор символов.
|
||||||
desc:
|
desc:
|
||||||
label: Description (optional)
|
label: Описание (опционально)
|
||||||
btn_cancel: Cancel
|
btn_cancel: Отмена
|
||||||
btn_submit: Submit
|
btn_submit: Отправить
|
||||||
tag_info:
|
tag_info:
|
||||||
created_at: Created
|
created_at: Создано
|
||||||
edited_at: Edited
|
edited_at: Отредактировано
|
||||||
history: History
|
history: История
|
||||||
synonyms:
|
synonyms:
|
||||||
title: Synonyms
|
title: Синонимы
|
||||||
text: The following tags will be remapped to
|
text: Следующие теги будут переназначены на
|
||||||
empty: No synonyms found.
|
empty: Синонимы не найдены.
|
||||||
btn_add: Add a synonym
|
btn_add: Добавить синоним
|
||||||
btn_edit: Edit
|
btn_edit: Редактировать
|
||||||
btn_save: Save
|
btn_save: Сохранить
|
||||||
synonyms_text: The following tags will be remapped to
|
synonyms_text: Следующие теги будут переназначены на
|
||||||
delete:
|
delete:
|
||||||
title: Delete this tag
|
title: Удалить этот тег
|
||||||
content: >-
|
content: >-
|
||||||
<p>We do not allowed deleting tag with posts.</p><p>Please remove this tag from the posts first.</p>
|
<p>Мы не разрешаем удалять тег с сообщениями.</p><p>Пожалуйста, сначала удалите этот тег из сообщений</p>
|
||||||
content2: Are you sure you wish to delete?
|
content2: Вы действительно хотите удалить?
|
||||||
close: Close
|
close: Закрыть
|
||||||
edit_tag:
|
edit_tag:
|
||||||
title: Edit Tag
|
title: Изменить тег
|
||||||
default_reason: Edit tag
|
default_reason: Правка тега
|
||||||
form:
|
form:
|
||||||
fields:
|
fields:
|
||||||
revision:
|
revision:
|
||||||
label: Revision
|
label: Редакция
|
||||||
display_name:
|
display_name:
|
||||||
label: Display Name
|
label: Показывать имя
|
||||||
slug_name:
|
slug_name:
|
||||||
label: URL Slug
|
label: Идентификатор URL
|
||||||
info: 'Must use the character set "a-z", "0-9", "+ # - ."'
|
info: 'Необходимо использовать набор символов "a-z", "0-9", "+ # - ."'
|
||||||
desc:
|
desc:
|
||||||
label: Description
|
label: Описание
|
||||||
edit_summary:
|
edit_summary:
|
||||||
label: Edit Summary
|
label: Изменить краткое описание
|
||||||
placeholder: >-
|
placeholder: >-
|
||||||
Briefly explain your changes (corrected spelling, fixed grammar, improved formatting)
|
Кратко опишите ваши изменения (исправленная орфография, исправленная грамматика, улучшенное форматирование)
|
||||||
btn_save_edits: Save edits
|
btn_save_edits: Сохранить изменения
|
||||||
btn_cancel: Cancel
|
btn_cancel: Отмена
|
||||||
dates:
|
dates:
|
||||||
long_date: MMM D
|
long_date: MMM D
|
||||||
long_date_with_year: "MMM D, YYYY"
|
long_date_with_year: "MMM D, YYYY"
|
||||||
|
@ -585,7 +585,8 @@ ui:
|
||||||
msg:
|
msg:
|
||||||
empty: Cannot be empty.
|
empty: Cannot be empty.
|
||||||
login:
|
login:
|
||||||
page_title: Welcome to Answer
|
page_title: Welcome to {{site_name}}
|
||||||
|
login_to_continue: Log in to continue
|
||||||
info_sign: Don't have an account? <1>Sign up</1>
|
info_sign: Don't have an account? <1>Sign up</1>
|
||||||
info_login: Already have an account? <1>Log in</1>
|
info_login: Already have an account? <1>Log in</1>
|
||||||
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
||||||
|
@ -1222,14 +1223,14 @@ ui:
|
||||||
branding:
|
branding:
|
||||||
page_title: Branding
|
page_title: Branding
|
||||||
logo:
|
logo:
|
||||||
label: Logo
|
label: Logo (optional)
|
||||||
msg: Logo cannot be empty.
|
msg: Logo cannot be empty.
|
||||||
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
||||||
mobile_logo:
|
mobile_logo:
|
||||||
label: Mobile Logo (optional)
|
label: Mobile Logo (optional)
|
||||||
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
||||||
square_icon:
|
square_icon:
|
||||||
label: Square Icon
|
label: Square Icon (optional)
|
||||||
msg: Square icon cannot be empty.
|
msg: Square icon cannot be empty.
|
||||||
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
||||||
favicon:
|
favicon:
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -585,7 +585,8 @@ ui:
|
||||||
msg:
|
msg:
|
||||||
empty: Cannot be empty.
|
empty: Cannot be empty.
|
||||||
login:
|
login:
|
||||||
page_title: Welcome to Answer
|
page_title: Welcome to {{site_name}}
|
||||||
|
login_to_continue: Log in to continue
|
||||||
info_sign: Don't have an account? <1>Sign up</1>
|
info_sign: Don't have an account? <1>Sign up</1>
|
||||||
info_login: Already have an account? <1>Log in</1>
|
info_login: Already have an account? <1>Log in</1>
|
||||||
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
||||||
|
@ -1222,14 +1223,14 @@ ui:
|
||||||
branding:
|
branding:
|
||||||
page_title: Branding
|
page_title: Branding
|
||||||
logo:
|
logo:
|
||||||
label: Logo
|
label: Logo (optional)
|
||||||
msg: Logo cannot be empty.
|
msg: Logo cannot be empty.
|
||||||
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
||||||
mobile_logo:
|
mobile_logo:
|
||||||
label: Mobile Logo (optional)
|
label: Mobile Logo (optional)
|
||||||
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
||||||
square_icon:
|
square_icon:
|
||||||
label: Square Icon
|
label: Square Icon (optional)
|
||||||
msg: Square icon cannot be empty.
|
msg: Square icon cannot be empty.
|
||||||
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
||||||
favicon:
|
favicon:
|
||||||
|
|
|
@ -405,17 +405,17 @@ ui:
|
||||||
form:
|
form:
|
||||||
fields:
|
fields:
|
||||||
display_name:
|
display_name:
|
||||||
label: 显示名称(别名)
|
label: 显示名称
|
||||||
msg:
|
msg:
|
||||||
empty: 不能为空
|
empty: 显示名称不能为空。
|
||||||
range: 不能超过 35 个字符
|
range: 显示名称不能超过 35 个字符。
|
||||||
slug_name:
|
slug_name:
|
||||||
label: URL 固定链接
|
label: URL 固定链接
|
||||||
desc: '必须使用字符集 "a-z"、"0-9"、"+ # - ."'
|
desc: '必须由 "a-z", "0-9", "+ # - ." 组成'
|
||||||
msg:
|
msg:
|
||||||
empty: 不能为空
|
empty: URL 固定链接不能为空。
|
||||||
range: 不能超过 35 个字符
|
range: URL 固定链接不能超过 35 个字符。
|
||||||
character: 包含非法字符
|
character: URL 固定链接包含非法字符。
|
||||||
desc:
|
desc:
|
||||||
label: 描述(可选)
|
label: 描述(可选)
|
||||||
btn_cancel: 取消
|
btn_cancel: 取消
|
||||||
|
@ -446,7 +446,7 @@ ui:
|
||||||
revision:
|
revision:
|
||||||
label: 编辑历史
|
label: 编辑历史
|
||||||
display_name:
|
display_name:
|
||||||
label: 名称
|
label: 显示名称
|
||||||
slug_name:
|
slug_name:
|
||||||
label: URL 固定链接
|
label: URL 固定链接
|
||||||
info: '必须由 "a-z", "0-9", "+ # - ." 组成'
|
info: '必须由 "a-z", "0-9", "+ # - ." 组成'
|
||||||
|
@ -585,7 +585,8 @@ ui:
|
||||||
msg:
|
msg:
|
||||||
empty: 不能为空
|
empty: 不能为空
|
||||||
login:
|
login:
|
||||||
page_title: 欢迎来到 Answer
|
page_title: 欢迎来到 {{site_name}}
|
||||||
|
login_to_continue: 登录以继续
|
||||||
info_sign: 没有账户?<1>注册</1>
|
info_sign: 没有账户?<1>注册</1>
|
||||||
info_login: 已经有一个账户?<1>登录</1>
|
info_login: 已经有一个账户?<1>登录</1>
|
||||||
agreements: 登录即表示您同意<1>隐私政策</1>和<3>服务条款</3>。
|
agreements: 登录即表示您同意<1>隐私政策</1>和<3>服务条款</3>。
|
||||||
|
@ -614,7 +615,7 @@ ui:
|
||||||
msg:
|
msg:
|
||||||
empty: 邮箱不能为空
|
empty: 邮箱不能为空
|
||||||
change_email:
|
change_email:
|
||||||
page_title: 欢迎来到 Answer
|
page_title: 欢迎来到 {{site_name}}
|
||||||
btn_cancel: 取消
|
btn_cancel: 取消
|
||||||
btn_update: 更新电子邮件地址
|
btn_update: 更新电子邮件地址
|
||||||
send_success: >-
|
send_success: >-
|
||||||
|
@ -651,8 +652,8 @@ ui:
|
||||||
btn_name: 保存
|
btn_name: 保存
|
||||||
display_name:
|
display_name:
|
||||||
label: 昵称
|
label: 昵称
|
||||||
msg: 昵称不能为空
|
msg: 昵称不能为空。
|
||||||
msg_range: 昵称不能超过 30 个字符
|
msg_range: 昵称不能超过 30 个字符。
|
||||||
username:
|
username:
|
||||||
label: 用户名
|
label: 用户名
|
||||||
caption: 用户之间可以通过 "@用户名" 进行交互。
|
caption: 用户之间可以通过 "@用户名" 进行交互。
|
||||||
|
@ -803,7 +804,7 @@ ui:
|
||||||
modal_confirm:
|
modal_confirm:
|
||||||
title: 发生错误...
|
title: 发生错误...
|
||||||
account_result:
|
account_result:
|
||||||
page_title: 欢迎来到 Answer
|
page_title: 欢迎来到 {{site_name}}
|
||||||
success: 你的账号已通过验证,即将返回首页。
|
success: 你的账号已通过验证,即将返回首页。
|
||||||
link: 返回首页
|
link: 返回首页
|
||||||
invalid: >-
|
invalid: >-
|
||||||
|
@ -1102,7 +1103,7 @@ ui:
|
||||||
fields:
|
fields:
|
||||||
display_name:
|
display_name:
|
||||||
label: 昵称
|
label: 昵称
|
||||||
msg: 昵称的长度必须是4-30个字符。
|
msg: 昵称的长度必须是 3-30 个字符。
|
||||||
email:
|
email:
|
||||||
label: 邮箱
|
label: 邮箱
|
||||||
msg: 电子邮箱无效。
|
msg: 电子邮箱无效。
|
||||||
|
@ -1222,14 +1223,14 @@ ui:
|
||||||
branding:
|
branding:
|
||||||
page_title: 品牌
|
page_title: 品牌
|
||||||
logo:
|
logo:
|
||||||
label: 图标
|
label: Logo (可选)
|
||||||
msg: 图标不能为空。
|
msg: 图标不能为空。
|
||||||
text: 在你的网站左上方的Logo图标。使用一个高度为56,长宽比大于3:1的宽长方形图像。如果留空,将显示网站标题文本。
|
text: 在你的网站左上方的Logo图标。使用一个高度为56,长宽比大于3:1的宽长方形图像。如果留空,将显示网站标题文本。
|
||||||
mobile_logo:
|
mobile_logo:
|
||||||
label: 移动端图标(可选)
|
label: 移动端图标(可选)
|
||||||
text: 在你的网站的移动版上使用的标志。使用一个高度为56的宽矩形图像。如果留空,将使用 "Logo"设置中的图像。
|
text: 在你的网站的移动版上使用的标志。使用一个高度为56的宽矩形图像。如果留空,将使用 "Logo"设置中的图像。
|
||||||
square_icon:
|
square_icon:
|
||||||
label: 方形图标
|
label: 方形图标 (可选)
|
||||||
msg: 方形图标不能为空。
|
msg: 方形图标不能为空。
|
||||||
text: 用作元数据图标的基础的图像。最好是大于512x512。
|
text: 用作元数据图标的基础的图像。最好是大于512x512。
|
||||||
favicon:
|
favicon:
|
||||||
|
@ -1247,7 +1248,7 @@ ui:
|
||||||
page_title: 编辑
|
page_title: 编辑
|
||||||
recommend_tags:
|
recommend_tags:
|
||||||
label: 推荐标签
|
label: 推荐标签
|
||||||
text: "请输入以上标签,每行一个标签。"
|
text: "请在上方输入标签固定链接,每行一个标签。"
|
||||||
required_tag:
|
required_tag:
|
||||||
title: 必需的标签
|
title: 必需的标签
|
||||||
label: 根据需要设置推荐标签
|
label: 根据需要设置推荐标签
|
||||||
|
|
|
@ -10,24 +10,24 @@ backend:
|
||||||
unauthorized_error:
|
unauthorized_error:
|
||||||
other: "未授權。"
|
other: "未授權。"
|
||||||
database_error:
|
database_error:
|
||||||
other: "Data server error."
|
other: "資料庫錯誤。"
|
||||||
role:
|
role:
|
||||||
name:
|
name:
|
||||||
user:
|
user:
|
||||||
other: "User"
|
other: "使用者"
|
||||||
admin:
|
admin:
|
||||||
other: "Admin"
|
other: "管理者"
|
||||||
moderator:
|
moderator:
|
||||||
other: "Moderator"
|
other: "版主"
|
||||||
description:
|
description:
|
||||||
user:
|
user:
|
||||||
other: "Default with no special access."
|
other: "預設沒有特別閱讀權限"
|
||||||
admin:
|
admin:
|
||||||
other: "Have the full power to access the site."
|
other: "擁有所有權限"
|
||||||
moderator:
|
moderator:
|
||||||
other: "Has access to all posts except admin settings."
|
other: "可以訪問除了管理員設定以外的所有貼文"
|
||||||
email:
|
email:
|
||||||
other: "Email"
|
other: "電子郵件"
|
||||||
password:
|
password:
|
||||||
other: "密碼"
|
other: "密碼"
|
||||||
email_or_password_wrong_error:
|
email_or_password_wrong_error:
|
||||||
|
@ -38,37 +38,37 @@ backend:
|
||||||
other: 電子郵箱和密碼不匹配。
|
other: 電子郵箱和密碼不匹配。
|
||||||
answer:
|
answer:
|
||||||
not_found:
|
not_found:
|
||||||
other: "Answer do not found."
|
other: "無答案。"
|
||||||
cannot_deleted:
|
cannot_deleted:
|
||||||
other: "No permission to delete."
|
other: "無刪除權限。"
|
||||||
cannot_update:
|
cannot_update:
|
||||||
other: "No permission to update."
|
other: "無更新權限。"
|
||||||
comment:
|
comment:
|
||||||
edit_without_permission:
|
edit_without_permission:
|
||||||
other: "Comment are not allowed to edit."
|
other: "不允許編輯評論。"
|
||||||
not_found:
|
not_found:
|
||||||
other: "Comment not found."
|
other: "無評論。"
|
||||||
email:
|
email:
|
||||||
duplicate:
|
duplicate:
|
||||||
other: "Email already exists."
|
other: "該電子郵件已被使用"
|
||||||
need_to_be_verified:
|
need_to_be_verified:
|
||||||
other: "Email should be verified."
|
other: "需驗證電子郵件信箱。"
|
||||||
verify_url_expired:
|
verify_url_expired:
|
||||||
other: "Email verified URL has expired, please resend the email."
|
other: "電子郵件驗證網址已過期,請重發確認郵件。"
|
||||||
lang:
|
lang:
|
||||||
not_found:
|
not_found:
|
||||||
other: "Language file not found."
|
other: "無此語系檔。"
|
||||||
object:
|
object:
|
||||||
captcha_verification_failed:
|
captcha_verification_failed:
|
||||||
other: "Captcha wrong."
|
other: "驗證碼錯誤。"
|
||||||
disallow_follow:
|
disallow_follow:
|
||||||
other: "You are not allowed to follow."
|
other: "你不能追蹤"
|
||||||
disallow_vote:
|
disallow_vote:
|
||||||
other: "You are not allowed to vote."
|
other: "你不能投票"
|
||||||
disallow_vote_your_self:
|
disallow_vote_your_self:
|
||||||
other: "You can't vote for your own post."
|
other: "你不能為自己的貼文投票"
|
||||||
not_found:
|
not_found:
|
||||||
other: "Object not found."
|
other: "找不到物件"
|
||||||
verification_failed:
|
verification_failed:
|
||||||
other: "驗證失敗。"
|
other: "驗證失敗。"
|
||||||
email_or_password_incorrect:
|
email_or_password_incorrect:
|
||||||
|
@ -88,7 +88,7 @@ backend:
|
||||||
other: "沒有更新的權限。"
|
other: "沒有更新的權限。"
|
||||||
rank:
|
rank:
|
||||||
fail_to_meet_the_condition:
|
fail_to_meet_the_condition:
|
||||||
other: "Rank fail to meet the condition."
|
other: "無法為條件排序"
|
||||||
report:
|
report:
|
||||||
handle_failed:
|
handle_failed:
|
||||||
other: "Report handle failed."
|
other: "Report handle failed."
|
||||||
|
@ -585,7 +585,8 @@ ui:
|
||||||
msg:
|
msg:
|
||||||
empty: Cannot be empty.
|
empty: Cannot be empty.
|
||||||
login:
|
login:
|
||||||
page_title: Welcome to Answer
|
page_title: Welcome to {{site_name}}
|
||||||
|
login_to_continue: Log in to continue
|
||||||
info_sign: Don't have an account? <1>Sign up</1>
|
info_sign: Don't have an account? <1>Sign up</1>
|
||||||
info_login: Already have an account? <1>Log in</1>
|
info_login: Already have an account? <1>Log in</1>
|
||||||
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
agreements: By registering, you agree to the <1>privacy policy</1> and <3>terms of service</3>.
|
||||||
|
@ -1222,14 +1223,14 @@ ui:
|
||||||
branding:
|
branding:
|
||||||
page_title: Branding
|
page_title: Branding
|
||||||
logo:
|
logo:
|
||||||
label: Logo
|
label: Logo (optional)
|
||||||
msg: Logo cannot be empty.
|
msg: Logo cannot be empty.
|
||||||
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
text: The logo image at the top left of your site. Use a wide rectangular image with a height of 56 and an aspect ratio greater than 3:1. If left blank, the site title text will be shown.
|
||||||
mobile_logo:
|
mobile_logo:
|
||||||
label: Mobile Logo (optional)
|
label: Mobile Logo (optional)
|
||||||
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
text: The logo used on mobile version of your site. Use a wide rectangular image with a height of 56. If left blank, the image from the “logo” setting will be used.
|
||||||
square_icon:
|
square_icon:
|
||||||
label: Square Icon
|
label: Square Icon (optional)
|
||||||
msg: Square icon cannot be empty.
|
msg: Square icon cannot be empty.
|
||||||
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
text: Image used as the base for metadata icons. Should ideally be larger than 512x512.
|
||||||
favicon:
|
favicon:
|
||||||
|
|
|
@ -38,6 +38,7 @@ func NewDB(debug bool, dataConf *Database) (*xorm.Engine, error) {
|
||||||
dataConf.Driver = string(schemas.MYSQL)
|
dataConf.Driver = string(schemas.MYSQL)
|
||||||
}
|
}
|
||||||
if dataConf.Driver == string(schemas.SQLITE) {
|
if dataConf.Driver == string(schemas.SQLITE) {
|
||||||
|
dataConf.Driver = "sqlite"
|
||||||
dbFileDir := filepath.Dir(dataConf.Connection)
|
dbFileDir := filepath.Dir(dataConf.Connection)
|
||||||
log.Debugf("try to create database directory %s", dbFileDir)
|
log.Debugf("try to create database directory %s", dbFileDir)
|
||||||
if err := dir.CreateDirIfNotExist(dbFileDir); err != nil {
|
if err := dir.CreateDirIfNotExist(dbFileDir); err != nil {
|
||||||
|
|
|
@ -23,7 +23,6 @@ import (
|
||||||
chineseTraditional "github.com/go-playground/locales/zh_Hant_TW"
|
chineseTraditional "github.com/go-playground/locales/zh_Hant_TW"
|
||||||
ut "github.com/go-playground/universal-translator"
|
ut "github.com/go-playground/universal-translator"
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"github.com/go-playground/validator/v10/non-standard/validators"
|
|
||||||
"github.com/go-playground/validator/v10/translations/en"
|
"github.com/go-playground/validator/v10/translations/en"
|
||||||
"github.com/go-playground/validator/v10/translations/es"
|
"github.com/go-playground/validator/v10/translations/es"
|
||||||
"github.com/go-playground/validator/v10/translations/fr"
|
"github.com/go-playground/validator/v10/translations/fr"
|
||||||
|
@ -98,9 +97,29 @@ func getTran(lo locales.Translator) ut.Translator {
|
||||||
return tran
|
return tran
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NotBlank(fl validator.FieldLevel) (res bool) {
|
||||||
|
field := fl.Field()
|
||||||
|
switch field.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
trimSpace := strings.TrimSpace(field.String())
|
||||||
|
res := len(trimSpace) > 0
|
||||||
|
if !res {
|
||||||
|
field.SetString(trimSpace)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case reflect.Chan, reflect.Map, reflect.Slice, reflect.Array:
|
||||||
|
return field.Len() > 0
|
||||||
|
case reflect.Ptr, reflect.Interface, reflect.Func:
|
||||||
|
return !field.IsNil()
|
||||||
|
default:
|
||||||
|
return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createDefaultValidator(la i18n.Language) *validator.Validate {
|
func createDefaultValidator(la i18n.Language) *validator.Validate {
|
||||||
validate := validator.New()
|
validate := validator.New()
|
||||||
_ = validate.RegisterValidation("notblank", validators.NotBlank)
|
// _ = validate.RegisterValidation("notblank", validators.NotBlank)
|
||||||
|
_ = validate.RegisterValidation("notblank", NotBlank)
|
||||||
validate.RegisterTagNameFunc(func(fld reflect.StructField) (res string) {
|
validate.RegisterTagNameFunc(func(fld reflect.StructField) (res string) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if len(res) > 0 {
|
if len(res) > 0 {
|
||||||
|
|
|
@ -33,7 +33,7 @@ var (
|
||||||
"`user_id`",
|
"`user_id`",
|
||||||
"`vote_count`",
|
"`vote_count`",
|
||||||
"`answer_count`",
|
"`answer_count`",
|
||||||
"0 as `accepted`",
|
"CASE WHEN `accepted_answer_id` > 0 THEN 2 ELSE 0 END as `accepted`",
|
||||||
"`question`.`status` as `status`",
|
"`question`.`status` as `status`",
|
||||||
"`post_update_time`",
|
"`post_update_time`",
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,10 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type AnswerAddReq struct {
|
type AnswerAddReq struct {
|
||||||
QuestionID string `json:"question_id" ` // question_id
|
QuestionID string `json:"question_id"`
|
||||||
Content string `validate:"required,notblank,gte=6,lte=65535" json:"content" ` // content
|
Content string `validate:"required,notblank,gte=6,lte=65535" json:"content"`
|
||||||
HTML string `json:"html" ` // html
|
HTML string `json:"-"`
|
||||||
UserID string `json:"-" ` // user_id
|
UserID string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (req *AnswerAddReq) Check() (errFields []*validator.FormErrorField, err error) {
|
func (req *AnswerAddReq) Check() (errFields []*validator.FormErrorField, err error) {
|
||||||
|
@ -32,13 +32,13 @@ func (req *AnswerAddReq) Check() (errFields []*validator.FormErrorField, err err
|
||||||
}
|
}
|
||||||
|
|
||||||
type AnswerUpdateReq struct {
|
type AnswerUpdateReq struct {
|
||||||
ID string `json:"id"` // id
|
ID string `json:"id"`
|
||||||
QuestionID string `json:"question_id" ` // question_id
|
QuestionID string `json:"question_id"`
|
||||||
UserID string `json:"-" ` // user_id
|
Title string `json:"title"`
|
||||||
Title string `json:"title" ` // title
|
Content string `validate:"required,notblank,gte=6,lte=65535" json:"content"`
|
||||||
Content string `validate:"required,notblank,gte=6,lte=65535" json:"content"` // content
|
EditSummary string `validate:"omitempty" json:"edit_summary"`
|
||||||
HTML string `json:"html" ` // html
|
HTML string `json:"-"`
|
||||||
EditSummary string `validate:"omitempty" json:"edit_summary"` // edit_summary
|
UserID string `json:"-"`
|
||||||
NoNeedReview bool `json:"-"`
|
NoNeedReview bool `json:"-"`
|
||||||
// whether user can edit it
|
// whether user can edit it
|
||||||
CanEdit bool `json:"-"`
|
CanEdit bool `json:"-"`
|
||||||
|
|
|
@ -14,9 +14,9 @@ type AddCommentReq struct {
|
||||||
// reply comment id
|
// reply comment id
|
||||||
ReplyCommentID string `validate:"omitempty" json:"reply_comment_id"`
|
ReplyCommentID string `validate:"omitempty" json:"reply_comment_id"`
|
||||||
// original comment content
|
// original comment content
|
||||||
OriginalText string `validate:"required" json:"original_text"`
|
OriginalText string `validate:"required,notblank,gte=2,lte=600" json:"original_text"`
|
||||||
// parsed comment content
|
// parsed comment content
|
||||||
ParsedText string `validate:"required" json:"parsed_text"`
|
ParsedText string `json:"-"`
|
||||||
// @ user id list
|
// @ user id list
|
||||||
MentionUsernameList []string `validate:"omitempty" json:"mention_username_list"`
|
MentionUsernameList []string `validate:"omitempty" json:"mention_username_list"`
|
||||||
// user id
|
// user id
|
||||||
|
@ -47,9 +47,9 @@ type UpdateCommentReq struct {
|
||||||
// comment id
|
// comment id
|
||||||
CommentID string `validate:"required" json:"comment_id"`
|
CommentID string `validate:"required" json:"comment_id"`
|
||||||
// original comment content
|
// original comment content
|
||||||
OriginalText string `validate:"omitempty" json:"original_text"`
|
OriginalText string `validate:"required,notblank,gte=2,lte=600" json:"original_text"`
|
||||||
// parsed comment content
|
// parsed comment content
|
||||||
ParsedText string `validate:"omitempty" json:"parsed_text"`
|
ParsedText string `json:"-"`
|
||||||
// user id
|
// user id
|
||||||
UserID string `json:"-"`
|
UserID string `json:"-"`
|
||||||
IsAdmin bool `json:"-"`
|
IsAdmin bool `json:"-"`
|
||||||
|
|
|
@ -41,11 +41,11 @@ type ReopenQuestionReq struct {
|
||||||
|
|
||||||
type QuestionAdd struct {
|
type QuestionAdd struct {
|
||||||
// question title
|
// question title
|
||||||
Title string `validate:"required,gte=6,lte=150" json:"title"`
|
Title string `validate:"required,notblank,gte=6,lte=150" json:"title"`
|
||||||
// content
|
// content
|
||||||
Content string `validate:"required,gte=6,lte=65535" json:"content"`
|
Content string `validate:"required,notblank,gte=6,lte=65535" json:"content"`
|
||||||
// html
|
// html
|
||||||
HTML string `validate:"required,gte=6,lte=65535" json:"html"`
|
HTML string `json:"-"`
|
||||||
// tags
|
// tags
|
||||||
Tags []*TagItem `validate:"required,dive" json:"tags"`
|
Tags []*TagItem `validate:"required,dive" json:"tags"`
|
||||||
// user id
|
// user id
|
||||||
|
@ -90,11 +90,11 @@ type QuestionUpdate struct {
|
||||||
// question id
|
// question id
|
||||||
ID string `validate:"required" json:"id"`
|
ID string `validate:"required" json:"id"`
|
||||||
// question title
|
// question title
|
||||||
Title string `validate:"required,gte=6,lte=150" json:"title"`
|
Title string `validate:"required,notblank,gte=6,lte=150" json:"title"`
|
||||||
// content
|
// content
|
||||||
Content string `validate:"required,gte=6,lte=65535" json:"content"`
|
Content string `validate:"required,notblank,gte=6,lte=65535" json:"content"`
|
||||||
// html
|
// html
|
||||||
HTML string `validate:"required,gte=6,lte=65535" json:"html"`
|
HTML string `json:"-"`
|
||||||
// tags
|
// tags
|
||||||
Tags []*TagItem `validate:"required,dive" json:"tags"`
|
Tags []*TagItem `validate:"required,dive" json:"tags"`
|
||||||
// edit summary
|
// edit summary
|
||||||
|
|
|
@ -144,7 +144,7 @@ type TagItem struct {
|
||||||
// original text
|
// original text
|
||||||
OriginalText string `validate:"omitempty" json:"original_text"`
|
OriginalText string `validate:"omitempty" json:"original_text"`
|
||||||
// parsed text
|
// parsed text
|
||||||
ParsedText string `validate:"omitempty" json:"parsed_text"`
|
ParsedText string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveTagReq delete tag request
|
// RemoveTagReq delete tag request
|
||||||
|
@ -166,7 +166,7 @@ type UpdateTagReq struct {
|
||||||
// original text
|
// original text
|
||||||
OriginalText string `validate:"omitempty" json:"original_text"`
|
OriginalText string `validate:"omitempty" json:"original_text"`
|
||||||
// parsed text
|
// parsed text
|
||||||
ParsedText string `validate:"omitempty" json:"parsed_text"`
|
ParsedText string `json:"-"`
|
||||||
// edit summary
|
// edit summary
|
||||||
EditSummary string `validate:"omitempty" json:"edit_summary"`
|
EditSummary string `validate:"omitempty" json:"edit_summary"`
|
||||||
// user id
|
// user id
|
||||||
|
|
|
@ -10,10 +10,9 @@
|
||||||
|
|
||||||
# production
|
# production
|
||||||
|
|
||||||
|
|
||||||
/build/*/*/*
|
/build/*/*/*
|
||||||
/build/*.json
|
/build/*.json
|
||||||
/build/*.ico
|
/build/*.html
|
||||||
/build/*.txt
|
/build/*.txt
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
|
@ -1 +0,0 @@
|
||||||
<!doctype html><html><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><script defer="defer" src="/static/js/main.cb9bf782.js"></script><link href="/static/css/main.b8d8739f.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"><div id="spin-mask"><noscript><style>#spin-mask{display:none!important}</style></noscript><style>@keyframes _doc-spin{to{transform:rotate(360deg)}}#spin-mask{position:fixed;top:0;right:0;bottom:0;left:0;background-color:#fff;z-index:9999}#spin-container{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}#spin-container .spinner{box-sizing:border-box;display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;border:.25rem solid currentColor;border-right-color:transparent;color:rgba(108,117,125,.75);border-radius:50%;animation:.75s linear infinite _doc-spin}</style><div id="spin-container"><div class="spinner"></div></div></div></div></body></html>
|
|
|
@ -1 +0,0 @@
|
||||||
# Build Static
|
|
|
@ -22,7 +22,9 @@
|
||||||
"copy-to-clipboard": "^3.3.2",
|
"copy-to-clipboard": "^3.3.2",
|
||||||
"dayjs": "^1.11.5",
|
"dayjs": "^1.11.5",
|
||||||
"diff": "^5.1.0",
|
"diff": "^5.1.0",
|
||||||
|
"dompurify": "^2.4.3",
|
||||||
"emoji-regex": "^10.2.1",
|
"emoji-regex": "^10.2.1",
|
||||||
|
"html-react-parser": "^3.0.8",
|
||||||
"i18next": "^21.9.0",
|
"i18next": "^21.9.0",
|
||||||
"katex": "^0.16.2",
|
"katex": "^0.16.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
@ -51,6 +53,7 @@
|
||||||
"@testing-library/react": "^13.3.0",
|
"@testing-library/react": "^13.3.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"@types/color": "^3.0.3",
|
"@types/color": "^3.0.3",
|
||||||
|
"@types/dompurify": "^2.4.0",
|
||||||
"@types/jest": "^27.5.2",
|
"@types/jest": "^27.5.2",
|
||||||
"@types/lodash": "^4.14.184",
|
"@types/lodash": "^4.14.184",
|
||||||
"@types/marked": "^4.0.6",
|
"@types/marked": "^4.0.6",
|
||||||
|
|
1412
ui/pnpm-lock.yaml
1412
ui/pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -4,6 +4,7 @@
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
|
<meta name="generator" content="Answer %AnswerVersion% - https://github.com/answerdev/answer">
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -56,7 +56,7 @@ export interface QuestionParams {
|
||||||
title: string;
|
title: string;
|
||||||
url_title?: string;
|
url_title?: string;
|
||||||
content: string;
|
content: string;
|
||||||
html: string;
|
html?: string;
|
||||||
tags: Tag[];
|
tags: Tag[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +207,7 @@ export interface AnswerItem {
|
||||||
|
|
||||||
export interface PostAnswerReq {
|
export interface PostAnswerReq {
|
||||||
content: string;
|
content: string;
|
||||||
html: string;
|
html?: string;
|
||||||
question_id: string;
|
question_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { useState, useEffect, memo } from 'react';
|
import { useState, useEffect, memo } from 'react';
|
||||||
import { Button } from 'react-bootstrap';
|
import { Button, Form } from 'react-bootstrap';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
@ -7,7 +7,7 @@ import classNames from 'classnames';
|
||||||
import { TextArea, Mentions } from '@/components';
|
import { TextArea, Mentions } from '@/components';
|
||||||
import { usePageUsers } from '@/hooks';
|
import { usePageUsers } from '@/hooks';
|
||||||
|
|
||||||
const Form = ({
|
const Index = ({
|
||||||
className = '',
|
className = '',
|
||||||
value: initialValue = '',
|
value: initialValue = '',
|
||||||
onSendReply,
|
onSendReply,
|
||||||
|
@ -18,7 +18,7 @@ const Form = ({
|
||||||
const [value, setValue] = useState('');
|
const [value, setValue] = useState('');
|
||||||
const pageUsers = usePageUsers();
|
const pageUsers = usePageUsers();
|
||||||
const { t } = useTranslation('translation', { keyPrefix: 'comment' });
|
const { t } = useTranslation('translation', { keyPrefix: 'comment' });
|
||||||
|
const [validationErrorMsg, setValidationErrorMsg] = useState('');
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!initialValue) {
|
if (!initialValue) {
|
||||||
return;
|
return;
|
||||||
|
@ -32,6 +32,13 @@ const Form = ({
|
||||||
const handleSelected = (val) => {
|
const handleSelected = (val) => {
|
||||||
setValue(val);
|
setValue(val);
|
||||||
};
|
};
|
||||||
|
const handleSendReply = () => {
|
||||||
|
onSendReply(value).catch((ex) => {
|
||||||
|
if (ex.isError) {
|
||||||
|
setValidationErrorMsg(ex.msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
@ -39,17 +46,27 @@ const Form = ({
|
||||||
className,
|
className,
|
||||||
)}>
|
)}>
|
||||||
<div>
|
<div>
|
||||||
<Mentions pageUsers={pageUsers.getUsers()} onSelected={handleSelected}>
|
<div
|
||||||
<TextArea size="sm" value={value} onChange={handleChange} />
|
className={classNames('custom-form-control', {
|
||||||
</Mentions>
|
'is-invalid': validationErrorMsg,
|
||||||
<div className="form-text">{t(`tip_${mode}`)}</div>
|
})}>
|
||||||
|
<Mentions
|
||||||
|
pageUsers={pageUsers.getUsers()}
|
||||||
|
onSelected={handleSelected}>
|
||||||
|
<TextArea size="sm" value={value} onChange={handleChange} />
|
||||||
|
</Mentions>
|
||||||
|
<div className="form-text">{t(`tip_${mode}`)}</div>
|
||||||
|
</div>
|
||||||
|
<Form.Control.Feedback type="invalid">
|
||||||
|
{validationErrorMsg}
|
||||||
|
</Form.Control.Feedback>
|
||||||
</div>
|
</div>
|
||||||
{type === 'edit' ? (
|
{type === 'edit' ? (
|
||||||
<div className="d-flex flex-row flex-md-column ms-0 ms-md-2 mt-2 mt-md-0">
|
<div className="d-flex flex-row flex-md-column ms-0 ms-md-2 mt-2 mt-md-0">
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
className="text-nowrap "
|
className="text-nowrap "
|
||||||
onClick={() => onSendReply(value)}>
|
onClick={() => handleSendReply()}>
|
||||||
{t('btn_save_edits')}
|
{t('btn_save_edits')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
|
@ -64,7 +81,7 @@ const Form = ({
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
className="text-nowrap ms-0 ms-md-2 mt-2 mt-md-0"
|
className="text-nowrap ms-0 ms-md-2 mt-2 mt-md-0"
|
||||||
onClick={() => onSendReply(value)}>
|
onClick={() => handleSendReply()}>
|
||||||
{t('btn_add_comment')}
|
{t('btn_add_comment')}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
@ -72,4 +89,4 @@ const Form = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(Form);
|
export default memo(Index);
|
||||||
|
|
|
@ -1,21 +1,30 @@
|
||||||
import { useState, memo } from 'react';
|
import { useState, memo } from 'react';
|
||||||
import { Button } from 'react-bootstrap';
|
import { Button, Form } from 'react-bootstrap';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { TextArea, Mentions } from '@/components';
|
import { TextArea, Mentions } from '@/components';
|
||||||
import { usePageUsers } from '@/hooks';
|
import { usePageUsers } from '@/hooks';
|
||||||
|
|
||||||
const Form = ({ userName, onSendReply, onCancel, mode }) => {
|
const Index = ({ userName, onSendReply, onCancel, mode }) => {
|
||||||
const [value, setValue] = useState('');
|
const [value, setValue] = useState('');
|
||||||
const pageUsers = usePageUsers();
|
const pageUsers = usePageUsers();
|
||||||
const { t } = useTranslation('translation', { keyPrefix: 'comment' });
|
const { t } = useTranslation('translation', { keyPrefix: 'comment' });
|
||||||
|
const [validationErrorMsg, setValidationErrorMsg] = useState('');
|
||||||
const handleChange = (e) => {
|
const handleChange = (e) => {
|
||||||
setValue(e.target.value);
|
setValue(e.target.value);
|
||||||
};
|
};
|
||||||
const handleSelected = (val) => {
|
const handleSelected = (val) => {
|
||||||
setValue(val);
|
setValue(val);
|
||||||
};
|
};
|
||||||
|
const handleSendReply = () => {
|
||||||
|
onSendReply(value).catch((ex) => {
|
||||||
|
if (ex.isError) {
|
||||||
|
setValidationErrorMsg(ex.msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
|
@ -24,18 +33,26 @@ const Form = ({ userName, onSendReply, onCancel, mode }) => {
|
||||||
</div>
|
</div>
|
||||||
<div className="d-flex mb-1 align-items-start flex-column flex-md-row">
|
<div className="d-flex mb-1 align-items-start flex-column flex-md-row">
|
||||||
<div>
|
<div>
|
||||||
<Mentions
|
<div
|
||||||
pageUsers={pageUsers.getUsers()}
|
className={classNames('custom-form-control', {
|
||||||
onSelected={handleSelected}>
|
'is-invalid': validationErrorMsg,
|
||||||
<TextArea size="sm" value={value} onChange={handleChange} />
|
})}>
|
||||||
</Mentions>
|
<Mentions
|
||||||
<div className="form-text">{t(`tip_${mode}`)}</div>
|
pageUsers={pageUsers.getUsers()}
|
||||||
|
onSelected={handleSelected}>
|
||||||
|
<TextArea size="sm" value={value} onChange={handleChange} />
|
||||||
|
</Mentions>
|
||||||
|
<div className="form-text">{t(`tip_${mode}`)}</div>
|
||||||
|
</div>
|
||||||
|
<Form.Control.Feedback type="invalid">
|
||||||
|
{validationErrorMsg}
|
||||||
|
</Form.Control.Feedback>
|
||||||
</div>
|
</div>
|
||||||
<div className="d-flex flex-row flex-md-column ms-0 ms-md-2 mt-2 mt-md-0">
|
<div className="d-flex flex-row flex-md-column ms-0 ms-md-2 mt-2 mt-md-0">
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
className="text-nowrap"
|
className="text-nowrap"
|
||||||
onClick={() => onSendReply(value)}>
|
onClick={() => handleSendReply()}>
|
||||||
{t('btn_add_comment')}
|
{t('btn_add_comment')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
|
@ -51,4 +68,4 @@ const Form = ({ userName, onSendReply, onCancel, mode }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(Form);
|
export default memo(Index);
|
||||||
|
|
|
@ -10,7 +10,12 @@ import { marked } from 'marked';
|
||||||
import * as Types from '@/common/interface';
|
import * as Types from '@/common/interface';
|
||||||
import { Modal } from '@/components';
|
import { Modal } from '@/components';
|
||||||
import { usePageUsers, useReportModal } from '@/hooks';
|
import { usePageUsers, useReportModal } from '@/hooks';
|
||||||
import { matchedUsers, parseUserInfo, scrollTop, bgFadeOut } from '@/utils';
|
import {
|
||||||
|
matchedUsers,
|
||||||
|
parseUserInfo,
|
||||||
|
scrollToElementTop,
|
||||||
|
bgFadeOut,
|
||||||
|
} from '@/utils';
|
||||||
import { tryNormalLogged } from '@/utils/guard';
|
import { tryNormalLogged } from '@/utils/guard';
|
||||||
import {
|
import {
|
||||||
useQueryComments,
|
useQueryComments,
|
||||||
|
@ -43,7 +48,7 @@ const Comment = ({ objectId, mode, commentId }) => {
|
||||||
const scrollCallback = useCallback((el, co) => {
|
const scrollCallback = useCallback((el, co) => {
|
||||||
if (pageIndex === 0 && co.comment_id === commentId) {
|
if (pageIndex === 0 && co.comment_id === commentId) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
scrollTop(el);
|
scrollToElementTop(el);
|
||||||
bgFadeOut(el);
|
bgFadeOut(el);
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
@ -102,13 +107,14 @@ const Comment = ({ objectId, mode, commentId }) => {
|
||||||
const handleSendReply = (item) => {
|
const handleSendReply = (item) => {
|
||||||
const users = matchedUsers(item.value);
|
const users = matchedUsers(item.value);
|
||||||
const userNames = unionBy(users.map((user) => user.userName));
|
const userNames = unionBy(users.map((user) => user.userName));
|
||||||
const html = marked.parse(parseUserInfo(item.value));
|
const commentMarkDown = parseUserInfo(item.value);
|
||||||
if (!item.value || !html) {
|
const html = marked.parse(commentMarkDown);
|
||||||
return;
|
// if (!commentMarkDown || !html) {
|
||||||
}
|
// return;
|
||||||
|
// }
|
||||||
const params = {
|
const params = {
|
||||||
object_id: objectId,
|
object_id: objectId,
|
||||||
original_text: item.value,
|
original_text: commentMarkDown,
|
||||||
mention_username_list: userNames,
|
mention_username_list: userNames,
|
||||||
parsed_text: html,
|
parsed_text: html,
|
||||||
...(item.type === 'reply'
|
...(item.type === 'reply'
|
||||||
|
@ -119,7 +125,7 @@ const Comment = ({ objectId, mode, commentId }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (item.type === 'edit') {
|
if (item.type === 'edit') {
|
||||||
updateComment({
|
return updateComment({
|
||||||
...params,
|
...params,
|
||||||
comment_id: item.comment_id,
|
comment_id: item.comment_id,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
@ -134,30 +140,29 @@ const Comment = ({ objectId, mode, commentId }) => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
addComment(params).then((res) => {
|
|
||||||
if (item.type === 'reply') {
|
|
||||||
const index = comments.findIndex(
|
|
||||||
(comment) => comment.comment_id === item.comment_id,
|
|
||||||
);
|
|
||||||
comments[index].showReply = false;
|
|
||||||
comments.splice(index + 1, 0, res);
|
|
||||||
setComments([...comments]);
|
|
||||||
} else {
|
|
||||||
setComments([
|
|
||||||
...comments.map((comment) => {
|
|
||||||
if (comment.comment_id === item.comment_id) {
|
|
||||||
comment.showReply = false;
|
|
||||||
}
|
|
||||||
return comment;
|
|
||||||
}),
|
|
||||||
res,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
setVisibleComment(false);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return addComment(params).then((res) => {
|
||||||
|
if (item.type === 'reply') {
|
||||||
|
const index = comments.findIndex(
|
||||||
|
(comment) => comment.comment_id === item.comment_id,
|
||||||
|
);
|
||||||
|
comments[index].showReply = false;
|
||||||
|
comments.splice(index + 1, 0, res);
|
||||||
|
setComments([...comments]);
|
||||||
|
} else {
|
||||||
|
setComments([
|
||||||
|
...comments.map((comment) => {
|
||||||
|
if (comment.comment_id === item.comment_id) {
|
||||||
|
comment.showReply = false;
|
||||||
|
}
|
||||||
|
return comment;
|
||||||
|
}),
|
||||||
|
res,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
setVisibleComment(false);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = (id) => {
|
const handleDelete = (id) => {
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
import { FC, memo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import classname from 'classnames';
|
||||||
|
|
||||||
|
import { Icon } from '@/components';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
data: {
|
||||||
|
votes: number;
|
||||||
|
answers: number;
|
||||||
|
views: number;
|
||||||
|
};
|
||||||
|
showVotes?: boolean;
|
||||||
|
showAnswers?: boolean;
|
||||||
|
showViews?: boolean;
|
||||||
|
showAccepted?: boolean;
|
||||||
|
isAccepted?: boolean;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
const Index: FC<Props> = ({
|
||||||
|
data,
|
||||||
|
showVotes = true,
|
||||||
|
showAnswers = true,
|
||||||
|
showViews = true,
|
||||||
|
isAccepted = false,
|
||||||
|
showAccepted = false,
|
||||||
|
className = '',
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation('translation', { keyPrefix: 'counts' });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classname('d-flex align-items-center', className)}>
|
||||||
|
{showVotes && (
|
||||||
|
<div className="d-flex align-items-center">
|
||||||
|
<Icon name="hand-thumbs-up-fill me-1" />
|
||||||
|
<span>
|
||||||
|
{data.votes} {t('votes')}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showAccepted && (
|
||||||
|
<div className="d-flex align-items-center ms-3 text-success">
|
||||||
|
<Icon name="check-circle-fill me-1" />
|
||||||
|
<span>{t('accepted')}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showAnswers && (
|
||||||
|
<div
|
||||||
|
className={`d-flex align-items-center ms-3 ${
|
||||||
|
isAccepted ? 'text-success' : ''
|
||||||
|
}`}>
|
||||||
|
{isAccepted ? (
|
||||||
|
<Icon name="check-circle-fill me-1" />
|
||||||
|
) : (
|
||||||
|
<Icon name="chat-square-text-fill me-1" />
|
||||||
|
)}
|
||||||
|
<span>
|
||||||
|
{data.answers} {t('answers')}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{showViews && (
|
||||||
|
<span className="summary-stat ms-3">
|
||||||
|
<Icon name="eye-fill" />
|
||||||
|
<em className="fst-normal ms-1">
|
||||||
|
{data.views} {t('views')}
|
||||||
|
</em>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(Index);
|
|
@ -8,6 +8,7 @@ import {
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
|
||||||
import { markdownToHtml } from '@/services';
|
import { markdownToHtml } from '@/services';
|
||||||
|
import { htmlToReact } from '@/utils';
|
||||||
|
|
||||||
import { htmlRender } from './utils';
|
import { htmlRender } from './utils';
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ const Index = ({ value }, ref) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
previewRef.current?.scrollTo(0, scrollTop);
|
previewRef.current?.scrollTo(0, scrollTop);
|
||||||
|
|
||||||
htmlRender(previewRef.current);
|
htmlRender(previewRef.current);
|
||||||
}, [html]);
|
}, [html]);
|
||||||
useImperativeHandle(ref, () => {
|
useImperativeHandle(ref, () => {
|
||||||
|
@ -49,9 +51,9 @@ const Index = ({ value }, ref) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={previewRef}
|
ref={previewRef}
|
||||||
className="preview-wrap position-relative p-3 bg-light rounded text-break text-wrap mt-2 fmt"
|
className="preview-wrap position-relative p-3 bg-light rounded text-break text-wrap mt-2 fmt">
|
||||||
dangerouslySetInnerHTML={{ __html: html }}
|
{htmlToReact(html)}
|
||||||
/>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@ import { Pagination } from 'react-bootstrap';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useSearchParams, useNavigate, useLocation } from 'react-router-dom';
|
import { useSearchParams, useNavigate, useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { scrollToDocTop } from '@/utils';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
currentPage: number;
|
currentPage: number;
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
|
@ -49,7 +51,7 @@ const PageItem = ({ page, currentPage, path }: PageItemProps) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
navigate(path);
|
navigate(path);
|
||||||
window.scrollTo(0, 0);
|
scrollToDocTop();
|
||||||
}}>
|
}}>
|
||||||
{page}
|
{page}
|
||||||
</Pagination.Item>
|
</Pagination.Item>
|
||||||
|
@ -91,7 +93,7 @@ const Index: FC<Props> = ({
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
navigate(handleParams(currentPage - 1));
|
navigate(handleParams(currentPage - 1));
|
||||||
window.scrollTo(0, 0);
|
scrollToDocTop();
|
||||||
}}>
|
}}>
|
||||||
{t('prev')}
|
{t('prev')}
|
||||||
</Pagination.Prev>
|
</Pagination.Prev>
|
||||||
|
@ -186,7 +188,7 @@ const Index: FC<Props> = ({
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
navigate(handleParams(currentPage + 1));
|
navigate(handleParams(currentPage + 1));
|
||||||
window.scrollTo(0, 0);
|
scrollToDocTop();
|
||||||
}}>
|
}}>
|
||||||
{t('next')}
|
{t('next')}
|
||||||
</Pagination.Next>
|
</Pagination.Next>
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { useTranslation } from 'react-i18next';
|
||||||
import { pathFactory } from '@/router/pathFactory';
|
import { pathFactory } from '@/router/pathFactory';
|
||||||
import type * as Type from '@/common/interface';
|
import type * as Type from '@/common/interface';
|
||||||
import {
|
import {
|
||||||
Icon,
|
|
||||||
Tag,
|
Tag,
|
||||||
Pagination,
|
Pagination,
|
||||||
FormatTime,
|
FormatTime,
|
||||||
|
@ -14,6 +13,7 @@ import {
|
||||||
BaseUserCard,
|
BaseUserCard,
|
||||||
QueryGroup,
|
QueryGroup,
|
||||||
QuestionListLoader,
|
QuestionListLoader,
|
||||||
|
Counts,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { useQuestionList } from '@/services';
|
import { useQuestionList } from '@/services';
|
||||||
|
|
||||||
|
@ -95,29 +95,15 @@ const QuestionList: FC<Props> = ({ source }) => {
|
||||||
preFix={t(li.operation_type)}
|
preFix={t(li.operation_type)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ms-0 ms-md-3 mt-2 mt-md-0">
|
<Counts
|
||||||
<span>
|
data={{
|
||||||
<Icon name="hand-thumbs-up-fill" />
|
votes: li.vote_count,
|
||||||
<em className="fst-normal ms-1">{li.vote_count}</em>
|
answers: li.answer_count,
|
||||||
</span>
|
views: li.view_count,
|
||||||
<span
|
}}
|
||||||
className={`ms-3 ${
|
isAccepted={li.accepted_answer_id >= 1}
|
||||||
li.accepted_answer_id >= 1 ? 'text-success' : ''
|
className="ms-0 ms-md-3 mt-2 mt-md-0"
|
||||||
}`}>
|
/>
|
||||||
<Icon
|
|
||||||
name={
|
|
||||||
li.accepted_answer_id >= 1
|
|
||||||
? 'check-circle-fill'
|
|
||||||
: 'chat-square-text-fill'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<em className="fst-normal ms-1">{li.answer_count}</em>
|
|
||||||
</span>
|
|
||||||
<span className="summary-stat ms-3">
|
|
||||||
<Icon name="eye-fill" />
|
|
||||||
<em className="fst-normal ms-1">{li.view_count}</em>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="question-tags m-n1">
|
<div className="question-tags m-n1">
|
||||||
{Array.isArray(li.tags)
|
{Array.isArray(li.tags)
|
||||||
|
@ -139,7 +125,7 @@ const QuestionList: FC<Props> = ({ source }) => {
|
||||||
currentPage={curPage}
|
currentPage={curPage}
|
||||||
totalSize={count}
|
totalSize={count}
|
||||||
pageSize={pageSize}
|
pageSize={pageSize}
|
||||||
pathname="/questions"
|
pathname={source === 'questions' ? '/questions' : ''}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -155,6 +155,7 @@ const TagSelector: FC<IProps> = ({
|
||||||
};
|
};
|
||||||
const handleKeyDown = (e) => {
|
const handleKeyDown = (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
if (!tags) {
|
if (!tags) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -166,13 +167,20 @@ const TagSelector: FC<IProps> = ({
|
||||||
if (keyCode === 40 && currentIndex < tags.length - 1) {
|
if (keyCode === 40 && currentIndex < tags.length - 1) {
|
||||||
setCurrentIndex(currentIndex + 1);
|
setCurrentIndex(currentIndex + 1);
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
keyCode === 13 &&
|
if (keyCode === 13 && currentIndex > -1) {
|
||||||
currentIndex > -1 &&
|
|
||||||
currentIndex <= tags.length - 1
|
|
||||||
) {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
handleClick(tags[currentIndex]);
|
|
||||||
|
if (tags.length === 0) {
|
||||||
|
tagModal.onShow(tag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (currentIndex <= tags.length - 1) {
|
||||||
|
handleClick(tags[currentIndex]);
|
||||||
|
if (currentIndex === tags.length - 1 && currentIndex > 0) {
|
||||||
|
setCurrentIndex(currentIndex - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -32,6 +32,7 @@ import CustomizeTheme from './CustomizeTheme';
|
||||||
import PageTags from './PageTags';
|
import PageTags from './PageTags';
|
||||||
import QuestionListLoader from './QuestionListLoader';
|
import QuestionListLoader from './QuestionListLoader';
|
||||||
import TagsLoader from './TagsLoader';
|
import TagsLoader from './TagsLoader';
|
||||||
|
import Counts from './Counts';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Avatar,
|
Avatar,
|
||||||
|
@ -70,5 +71,6 @@ export {
|
||||||
PageTags,
|
PageTags,
|
||||||
QuestionListLoader,
|
QuestionListLoader,
|
||||||
TagsLoader,
|
TagsLoader,
|
||||||
|
Counts,
|
||||||
};
|
};
|
||||||
export type { EditorRef, JSONSchema, UISchema };
|
export type { EditorRef, JSONSchema, UISchema };
|
||||||
|
|
|
@ -143,21 +143,7 @@ const Ask = () => {
|
||||||
const checkValidated = (): boolean => {
|
const checkValidated = (): boolean => {
|
||||||
const bol = true;
|
const bol = true;
|
||||||
const { title, content, tags, answer } = formData;
|
const { title, content, tags, answer } = formData;
|
||||||
if (!title.value) {
|
if (title.value && Array.from(title.value).length <= 150) {
|
||||||
// bol = false;
|
|
||||||
// formData.title = {
|
|
||||||
// value: '',
|
|
||||||
// isInvalid: true,
|
|
||||||
// errorMsg: t('form.fields.title.msg.empty'),
|
|
||||||
// };
|
|
||||||
} else if (Array.from(title.value).length > 150) {
|
|
||||||
// bol = false;
|
|
||||||
// formData.title = {
|
|
||||||
// value: title.value,
|
|
||||||
// isInvalid: true,
|
|
||||||
// errorMsg: t('form.fields.title.msg.range'),
|
|
||||||
// };
|
|
||||||
} else {
|
|
||||||
formData.title = {
|
formData.title = {
|
||||||
value: title.value,
|
value: title.value,
|
||||||
isInvalid: false,
|
isInvalid: false,
|
||||||
|
@ -165,14 +151,7 @@ const Ask = () => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!content.value) {
|
if (content.value) {
|
||||||
// bol = false;
|
|
||||||
// formData.content = {
|
|
||||||
// value: '',
|
|
||||||
// isInvalid: true,
|
|
||||||
// errorMsg: t('form.fields.body.msg.empty'),
|
|
||||||
// };
|
|
||||||
} else {
|
|
||||||
formData.content = {
|
formData.content = {
|
||||||
value: content.value,
|
value: content.value,
|
||||||
isInvalid: false,
|
isInvalid: false,
|
||||||
|
@ -180,29 +159,16 @@ const Ask = () => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tags.value.length === 0) {
|
if (Array.isArray(tags.value) && tags.value.length > 0) {
|
||||||
// bol = false;
|
|
||||||
// formData.tags = {
|
|
||||||
// value: [],
|
|
||||||
// isInvalid: true,
|
|
||||||
// errorMsg: t('form.fields.tags.msg.empty'),
|
|
||||||
// };
|
|
||||||
} else {
|
|
||||||
formData.tags = {
|
formData.tags = {
|
||||||
value: tags.value,
|
value: tags.value,
|
||||||
isInvalid: false,
|
isInvalid: false,
|
||||||
errorMsg: '',
|
errorMsg: '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checked) {
|
if (checked) {
|
||||||
if (!answer.value) {
|
if (answer.value) {
|
||||||
// bol = false;
|
|
||||||
// formData.answer = {
|
|
||||||
// value: '',
|
|
||||||
// isInvalid: true,
|
|
||||||
// errorMsg: t('form.fields.answer.msg.empty'),
|
|
||||||
// };
|
|
||||||
} else {
|
|
||||||
formData.answer = {
|
formData.answer = {
|
||||||
value: answer.value,
|
value: answer.value,
|
||||||
isInvalid: false,
|
isInvalid: false,
|
||||||
|
@ -227,7 +193,6 @@ const Ask = () => {
|
||||||
const params: Type.QuestionParams = {
|
const params: Type.QuestionParams = {
|
||||||
title: formData.title.value,
|
title: formData.title.value,
|
||||||
content: formData.content.value,
|
content: formData.content.value,
|
||||||
html: editorRef.current.getHtml(),
|
|
||||||
tags: formData.tags.value,
|
tags: formData.tags.value,
|
||||||
};
|
};
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
|
@ -261,7 +226,6 @@ const Ask = () => {
|
||||||
postAnswer({
|
postAnswer({
|
||||||
question_id: id,
|
question_id: id,
|
||||||
content: formData.answer.value,
|
content: formData.answer.value,
|
||||||
html: editorRef2.current.getHtml(),
|
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
navigate(pathFactory.questionLanding(id, params.url_title));
|
navigate(pathFactory.questionLanding(id, params.url_title));
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
FormatTime,
|
FormatTime,
|
||||||
htmlRender,
|
htmlRender,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { scrollTop, bgFadeOut } from '@/utils';
|
import { scrollToElementTop, bgFadeOut } from '@/utils';
|
||||||
import { AnswerItem } from '@/common/interface';
|
import { AnswerItem } from '@/common/interface';
|
||||||
import { acceptanceAnswer } from '@/services';
|
import { acceptanceAnswer } from '@/services';
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ const Index: FC<Props> = ({
|
||||||
if (aid === data.id) {
|
if (aid === data.id) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const element = answerRef.current;
|
const element = answerRef.current;
|
||||||
scrollTop(element);
|
scrollToElementTop(element);
|
||||||
if (!searchParams.get('commentId')) {
|
if (!searchParams.get('commentId')) {
|
||||||
bgFadeOut(answerRef.current);
|
bgFadeOut(answerRef.current);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import classNames from 'classnames';
|
||||||
import { Editor, Modal, TextArea } from '@/components';
|
import { Editor, Modal, TextArea } from '@/components';
|
||||||
import { FormDataType } from '@/common/interface';
|
import { FormDataType } from '@/common/interface';
|
||||||
import { postAnswer } from '@/services';
|
import { postAnswer } from '@/services';
|
||||||
import { guard } from '@/utils';
|
import { guard, handleFormError } from '@/utils';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
visible?: boolean;
|
visible?: boolean;
|
||||||
|
@ -35,35 +35,60 @@ const Index: FC<Props> = ({ visible = false, data, callback }) => {
|
||||||
const [focusType, setFocusType] = useState('');
|
const [focusType, setFocusType] = useState('');
|
||||||
const [editorFocusState, setEditorFocusState] = useState(false);
|
const [editorFocusState, setEditorFocusState] = useState(false);
|
||||||
|
|
||||||
|
const checkValidated = (): boolean => {
|
||||||
|
let bol = true;
|
||||||
|
const { content } = formData;
|
||||||
|
|
||||||
|
if (!content.value || Array.from(content.value.trim()).length < 6) {
|
||||||
|
bol = false;
|
||||||
|
formData.content = {
|
||||||
|
value: content.value,
|
||||||
|
isInvalid: true,
|
||||||
|
errorMsg: t('characters'),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
formData.content = {
|
||||||
|
value: content.value,
|
||||||
|
isInvalid: false,
|
||||||
|
errorMsg: '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
setFormData({
|
||||||
|
...formData,
|
||||||
|
});
|
||||||
|
return bol;
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
if (!guard.tryNormalLogged(true)) {
|
if (!guard.tryNormalLogged(true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!formData.content.value) {
|
if (!checkValidated()) {
|
||||||
setFormData({
|
|
||||||
content: {
|
|
||||||
value: '',
|
|
||||||
isInvalid: true,
|
|
||||||
errorMsg: t('empty'),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
postAnswer({
|
postAnswer({
|
||||||
question_id: data?.qid,
|
question_id: data?.qid,
|
||||||
content: formData.content.value,
|
content: formData.content.value,
|
||||||
html: marked.parse(formData.content.value),
|
html: marked.parse(formData.content.value),
|
||||||
}).then((res) => {
|
})
|
||||||
setShowEditor(false);
|
.then((res) => {
|
||||||
setFormData({
|
setShowEditor(false);
|
||||||
content: {
|
setFormData({
|
||||||
value: '',
|
content: {
|
||||||
isInvalid: false,
|
value: '',
|
||||||
errorMsg: '',
|
isInvalid: false,
|
||||||
},
|
errorMsg: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
callback?.(res.info);
|
||||||
|
})
|
||||||
|
.catch((ex) => {
|
||||||
|
if (ex.isError) {
|
||||||
|
const stateData = handleFormError(ex, formData);
|
||||||
|
setFormData({ ...stateData });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
callback?.(res.info);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const clickBtn = () => {
|
const clickBtn = () => {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next';
|
||||||
import Pattern from '@/common/pattern';
|
import Pattern from '@/common/pattern';
|
||||||
import { Pagination } from '@/components';
|
import { Pagination } from '@/components';
|
||||||
import { loggedUserInfoStore, toastStore } from '@/stores';
|
import { loggedUserInfoStore, toastStore } from '@/stores';
|
||||||
import { scrollTop } from '@/utils';
|
import { scrollToElementTop } from '@/utils';
|
||||||
import { usePageTags, usePageUsers } from '@/hooks';
|
import { usePageTags, usePageUsers } from '@/hooks';
|
||||||
import type {
|
import type {
|
||||||
ListResult,
|
ListResult,
|
||||||
|
@ -80,7 +80,7 @@ const Index = () => {
|
||||||
if (page > 0 || order) {
|
if (page > 0 || order) {
|
||||||
// scroll into view;
|
// scroll into view;
|
||||||
const element = document.getElementById('answerHeader');
|
const element = document.getElementById('answerHeader');
|
||||||
scrollTop(element);
|
scrollToElementTop(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
res.list.forEach((item) => {
|
res.list.forEach((item) => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useRef } from 'react';
|
||||||
import { Container, Row, Col, Form, Button, Card } from 'react-bootstrap';
|
import { Container, Row, Col, Form, Button, Card } from 'react-bootstrap';
|
||||||
import { useParams, useNavigate } from 'react-router-dom';
|
import { useParams, useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { handleFormError } from '@/utils';
|
||||||
import { usePageTags } from '@/hooks';
|
import { usePageTags } from '@/hooks';
|
||||||
import { pathFactory } from '@/router/pathFactory';
|
import { pathFactory } from '@/router/pathFactory';
|
||||||
import { Editor, EditorRef, Icon } from '@/components';
|
import { Editor, EditorRef, Icon } from '@/components';
|
||||||
|
@ -19,11 +20,11 @@ import {
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
|
|
||||||
interface FormDataItem {
|
interface FormDataItem {
|
||||||
answer: Type.FormValue<string>;
|
content: Type.FormValue<string>;
|
||||||
description: Type.FormValue<string>;
|
description: Type.FormValue<string>;
|
||||||
}
|
}
|
||||||
const initFormData = {
|
const initFormData = {
|
||||||
answer: {
|
content: {
|
||||||
value: '',
|
value: '',
|
||||||
isInvalid: false,
|
isInvalid: false,
|
||||||
errorMsg: '',
|
errorMsg: '',
|
||||||
|
@ -35,7 +36,6 @@ const initFormData = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const Index = () => {
|
const Index = () => {
|
||||||
const [formData, setFormData] = useState<FormDataItem>(initFormData);
|
|
||||||
const { aid = '', qid = '' } = useParams();
|
const { aid = '', qid = '' } = useParams();
|
||||||
const [focusType, setForceType] = useState('');
|
const [focusType, setForceType] = useState('');
|
||||||
|
|
||||||
|
@ -43,6 +43,10 @@ const Index = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const { data } = useQueryAnswerInfo(aid);
|
const { data } = useQueryAnswerInfo(aid);
|
||||||
|
const [formData, setFormData] = useState<FormDataItem>(initFormData);
|
||||||
|
|
||||||
|
initFormData.content.value = data?.info.content || '';
|
||||||
|
|
||||||
const { data: revisions = [] } = useQueryRevisions(aid);
|
const { data: revisions = [] } = useQueryRevisions(aid);
|
||||||
|
|
||||||
const editorRef = useRef<EditorRef>({
|
const editorRef = useRef<EditorRef>({
|
||||||
|
@ -51,18 +55,10 @@ const Index = () => {
|
||||||
|
|
||||||
const questionContentRef = useRef<HTMLDivElement>(null);
|
const questionContentRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!data) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
formData.answer.value = data.info.content;
|
|
||||||
setFormData({ ...formData });
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
const handleAnswerChange = (value: string) =>
|
const handleAnswerChange = (value: string) =>
|
||||||
setFormData({
|
setFormData({
|
||||||
...formData,
|
...formData,
|
||||||
answer: { ...formData.answer, value },
|
content: { ...formData.content, value },
|
||||||
});
|
});
|
||||||
const handleSummaryChange = (evt) => {
|
const handleSummaryChange = (evt) => {
|
||||||
const v = evt.currentTarget.value;
|
const v = evt.currentTarget.value;
|
||||||
|
@ -74,18 +70,18 @@ const Index = () => {
|
||||||
|
|
||||||
const checkValidated = (): boolean => {
|
const checkValidated = (): boolean => {
|
||||||
let bol = true;
|
let bol = true;
|
||||||
const { answer } = formData;
|
const { content } = formData;
|
||||||
|
|
||||||
if (!answer.value) {
|
if (!content.value || Array.from(content.value.trim()).length < 6) {
|
||||||
bol = false;
|
bol = false;
|
||||||
formData.answer = {
|
formData.content = {
|
||||||
value: '',
|
value: content.value,
|
||||||
isInvalid: true,
|
isInvalid: true,
|
||||||
errorMsg: '标题不能为空',
|
errorMsg: t('form.fields.answer.feedback.characters'),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
formData.answer = {
|
formData.content = {
|
||||||
value: answer.value,
|
value: content.value,
|
||||||
isInvalid: false,
|
isInvalid: false,
|
||||||
errorMsg: '',
|
errorMsg: '',
|
||||||
};
|
};
|
||||||
|
@ -105,29 +101,36 @@ const Index = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const params: Type.AnswerParams = {
|
const params: Type.AnswerParams = {
|
||||||
content: formData.answer.value,
|
content: formData.content.value,
|
||||||
html: editorRef.current.getHtml(),
|
html: editorRef.current.getHtml(),
|
||||||
question_id: qid,
|
question_id: qid,
|
||||||
id: aid,
|
id: aid,
|
||||||
edit_summary: formData.description.value,
|
edit_summary: formData.description.value,
|
||||||
};
|
};
|
||||||
modifyAnswer(params).then((res) => {
|
modifyAnswer(params)
|
||||||
navigate(
|
.then((res) => {
|
||||||
pathFactory.answerLanding({
|
navigate(
|
||||||
questionId: qid,
|
pathFactory.answerLanding({
|
||||||
slugTitle: data?.question?.url_title,
|
questionId: qid,
|
||||||
answerId: aid,
|
slugTitle: data?.question?.url_title,
|
||||||
}),
|
answerId: aid,
|
||||||
{
|
}),
|
||||||
state: { isReview: res?.wait_for_review },
|
{
|
||||||
},
|
state: { isReview: res?.wait_for_review },
|
||||||
);
|
},
|
||||||
});
|
);
|
||||||
|
})
|
||||||
|
.catch((ex) => {
|
||||||
|
if (ex.isError) {
|
||||||
|
const stateData = handleFormError(ex, formData);
|
||||||
|
setFormData({ ...stateData });
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
const handleSelectedRevision = (e) => {
|
const handleSelectedRevision = (e) => {
|
||||||
const index = e.target.value;
|
const index = e.target.value;
|
||||||
const revision = revisions[index];
|
const revision = revisions[index];
|
||||||
formData.answer.value = revision.content.content;
|
formData.content.value = revision.content.content;
|
||||||
setFormData({ ...formData });
|
setFormData({ ...formData });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -190,7 +193,7 @@ const Index = () => {
|
||||||
<Form.Group controlId="answer" className="mt-3">
|
<Form.Group controlId="answer" className="mt-3">
|
||||||
<Form.Label>{t('form.fields.answer.label')}</Form.Label>
|
<Form.Label>{t('form.fields.answer.label')}</Form.Label>
|
||||||
<Editor
|
<Editor
|
||||||
value={formData.answer.value}
|
value={formData.content.value}
|
||||||
onChange={handleAnswerChange}
|
onChange={handleAnswerChange}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'form-control p-0',
|
'form-control p-0',
|
||||||
|
@ -205,14 +208,14 @@ const Index = () => {
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
/>
|
/>
|
||||||
<Form.Control
|
<Form.Control
|
||||||
value={formData.answer.value}
|
value={formData.content.value}
|
||||||
type="text"
|
type="text"
|
||||||
isInvalid={formData.answer.isInvalid}
|
isInvalid={formData.content.isInvalid}
|
||||||
readOnly
|
readOnly
|
||||||
hidden
|
hidden
|
||||||
/>
|
/>
|
||||||
<Form.Control.Feedback type="invalid">
|
<Form.Control.Feedback type="invalid">
|
||||||
{formData.answer.errorMsg}
|
{formData.content.errorMsg}
|
||||||
</Form.Control.Feedback>
|
</Form.Control.Feedback>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
<Form.Group controlId="edit_summary" className="my-3">
|
<Form.Group controlId="edit_summary" className="my-3">
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { ListGroupItem } from 'react-bootstrap';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { pathFactory } from '@/router/pathFactory';
|
import { pathFactory } from '@/router/pathFactory';
|
||||||
import { Icon, Tag, FormatTime, BaseUserCard } from '@/components';
|
import { Tag, FormatTime, BaseUserCard, Counts } from '@/components';
|
||||||
import type { SearchResItem } from '@/common/interface';
|
import type { SearchResItem } from '@/common/interface';
|
||||||
import { escapeRemove } from '@/utils';
|
import { escapeRemove } from '@/utils';
|
||||||
|
|
||||||
|
@ -51,23 +51,17 @@ const Index: FC<Props> = ({ data }) => {
|
||||||
className="me-3"
|
className="me-3"
|
||||||
preFix={data.object_type === 'question' ? 'asked' : 'answered'}
|
preFix={data.object_type === 'question' ? 'asked' : 'answered'}
|
||||||
/>
|
/>
|
||||||
<div className="d-flex align-items-center my-2 my-sm-0">
|
|
||||||
<div className="d-flex align-items-center me-3">
|
<Counts
|
||||||
<Icon name="hand-thumbs-up-fill me-1" />
|
className="my-2 my-sm-0"
|
||||||
<span> {data.object?.vote_count}</span>
|
showViews={false}
|
||||||
</div>
|
isAccepted={data.object?.accepted}
|
||||||
<div
|
data={{
|
||||||
className={`d-flex align-items-center ${
|
votes: data.object?.vote_count,
|
||||||
data.object?.accepted ? 'text-success' : ''
|
answers: data.object?.answer_count,
|
||||||
}`}>
|
views: 0,
|
||||||
{data.object?.accepted ? (
|
}}
|
||||||
<Icon name="check-circle-fill me-1" />
|
/>
|
||||||
) : (
|
|
||||||
<Icon name="chat-square-text-fill me-1" />
|
|
||||||
)}
|
|
||||||
<span>{data.object?.answer_count}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{data.object?.excerpt && (
|
{data.object?.excerpt && (
|
||||||
|
|
|
@ -3,10 +3,12 @@ import { Container, Row, Col } from 'react-bootstrap';
|
||||||
import { Link, useLocation } from 'react-router-dom';
|
import { Link, useLocation } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { siteInfoStore } from '@/stores';
|
||||||
import { usePageTags } from '@/hooks';
|
import { usePageTags } from '@/hooks';
|
||||||
|
|
||||||
const Index: FC = () => {
|
const Index: FC = () => {
|
||||||
const { t } = useTranslation('translation', { keyPrefix: 'account_result' });
|
const { t } = useTranslation('translation', { keyPrefix: 'account_result' });
|
||||||
|
const siteName = siteInfoStore((state) => state.siteInfo.name);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
usePageTags({
|
usePageTags({
|
||||||
title: t('account_activation', { keyPrefix: 'page_title' }),
|
title: t('account_activation', { keyPrefix: 'page_title' }),
|
||||||
|
@ -15,7 +17,9 @@ const Index: FC = () => {
|
||||||
<Container className="pt-4 mt-2 mb-5">
|
<Container className="pt-4 mt-2 mb-5">
|
||||||
<Row className="justify-content-center">
|
<Row className="justify-content-center">
|
||||||
<Col lg={6}>
|
<Col lg={6}>
|
||||||
<h3 className="text-center mt-3 mb-5">{t('page_title')}</h3>
|
<h3 className="text-center mt-3 mb-5">
|
||||||
|
{t('page_title', { site_name: siteName })}
|
||||||
|
</h3>
|
||||||
{location.pathname?.includes('success') && (
|
{location.pathname?.includes('success') && (
|
||||||
<>
|
<>
|
||||||
<p className="text-center">{t('success')}</p>
|
<p className="text-center">{t('success')}</p>
|
||||||
|
|
|
@ -2,18 +2,22 @@ import { FC, memo } from 'react';
|
||||||
import { Container, Col } from 'react-bootstrap';
|
import { Container, Col } from 'react-bootstrap';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { siteInfoStore } from '@/stores';
|
||||||
import { usePageTags } from '@/hooks';
|
import { usePageTags } from '@/hooks';
|
||||||
|
|
||||||
import SendEmail from './components/sendEmail';
|
import SendEmail from './components/sendEmail';
|
||||||
|
|
||||||
const Index: FC = () => {
|
const Index: FC = () => {
|
||||||
const { t } = useTranslation('translation', { keyPrefix: 'change_email' });
|
const { t } = useTranslation('translation', { keyPrefix: 'change_email' });
|
||||||
|
const siteName = siteInfoStore((state) => state.siteInfo.name);
|
||||||
usePageTags({
|
usePageTags({
|
||||||
title: t('change_email', { keyPrefix: 'page_title' }),
|
title: t('change_email', { keyPrefix: 'page_title' }),
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<Container style={{ paddingTop: '4rem', paddingBottom: '6rem' }}>
|
<Container style={{ paddingTop: '4rem', paddingBottom: '6rem' }}>
|
||||||
<h3 className="text-center mb-5">{t('page_title')}</h3>
|
<h3 className="text-center mb-5">
|
||||||
|
{t('page_title', { site_name: siteName })}
|
||||||
|
</h3>
|
||||||
<Col className="mx-auto" md={3}>
|
<Col className="mx-auto" md={3}>
|
||||||
<SendEmail />
|
<SendEmail />
|
||||||
</Col>
|
</Col>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Link, useSearchParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { usePageTags } from '@/hooks';
|
import { usePageTags } from '@/hooks';
|
||||||
import { loggedUserInfoStore } from '@/stores';
|
import { loggedUserInfoStore, siteInfoStore } from '@/stores';
|
||||||
import { changeEmailVerify, getLoggedUserInfo } from '@/services';
|
import { changeEmailVerify, getLoggedUserInfo } from '@/services';
|
||||||
|
|
||||||
const Index: FC = () => {
|
const Index: FC = () => {
|
||||||
|
@ -13,6 +13,7 @@ const Index: FC = () => {
|
||||||
const [step, setStep] = useState('loading');
|
const [step, setStep] = useState('loading');
|
||||||
|
|
||||||
const updateUser = loggedUserInfoStore((state) => state.update);
|
const updateUser = loggedUserInfoStore((state) => state.update);
|
||||||
|
const siteName = siteInfoStore((state) => state.siteInfo.name);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const code = searchParams.get('code');
|
const code = searchParams.get('code');
|
||||||
|
@ -38,7 +39,9 @@ const Index: FC = () => {
|
||||||
<Container className="pt-4 mt-2 mb-5">
|
<Container className="pt-4 mt-2 mb-5">
|
||||||
<Row className="justify-content-center">
|
<Row className="justify-content-center">
|
||||||
<Col lg={6}>
|
<Col lg={6}>
|
||||||
<h3 className="text-center mt-3 mb-5">{t('page_title')}</h3>
|
<h3 className="text-center mt-3 mb-5">
|
||||||
|
{t('page_title', { site_name: siteName })}
|
||||||
|
</h3>
|
||||||
{step === 'success' && (
|
{step === 'success' && (
|
||||||
<>
|
<>
|
||||||
<p className="text-center">{t('confirm_new_email')}</p>
|
<p className="text-center">{t('confirm_new_email')}</p>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { FC, memo } from 'react';
|
||||||
import { ListGroup, ListGroupItem } from 'react-bootstrap';
|
import { ListGroup, ListGroupItem } from 'react-bootstrap';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { Icon, FormatTime, Tag } from '@/components';
|
import { FormatTime, Tag, Counts } from '@/components';
|
||||||
import { pathFactory } from '@/router/pathFactory';
|
import { pathFactory } from '@/router/pathFactory';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -35,21 +35,16 @@ const Index: FC<Props> = ({ visible, data }) => {
|
||||||
<div className="d-flex align-items-center fs-14 text-secondary mb-2">
|
<div className="d-flex align-items-center fs-14 text-secondary mb-2">
|
||||||
<FormatTime
|
<FormatTime
|
||||||
time={item.create_time}
|
time={item.create_time}
|
||||||
className="me-4"
|
className="me-3"
|
||||||
preFix={t('answered')}
|
preFix={t('answered')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="d-flex align-items-center me-3">
|
<Counts
|
||||||
<Icon name="hand-thumbs-up-fill me-1" />
|
data={{ votes: item?.vote_count, views: 0, answers: 0 }}
|
||||||
<span>{item?.vote_count}</span>
|
showAnswers={false}
|
||||||
</div>
|
showViews={false}
|
||||||
|
showAccepted={item.accepted === 2}
|
||||||
{item.accepted === 2 && (
|
/>
|
||||||
<div className="d-flex align-items-center me-3 text-success">
|
|
||||||
<Icon name="check-circle-fill me-1" />
|
|
||||||
<span>{t('accepted')}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{item.question_info?.tags?.map((tag) => {
|
{item.question_info?.tags?.map((tag) => {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { FC, memo } from 'react';
|
||||||
import { ListGroup, ListGroupItem } from 'react-bootstrap';
|
import { ListGroup, ListGroupItem } from 'react-bootstrap';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { Icon, FormatTime, Tag, BaseUserCard } from '@/components';
|
import { FormatTime, Tag, BaseUserCard, Counts } from '@/components';
|
||||||
import { pathFactory } from '@/router/pathFactory';
|
import { pathFactory } from '@/router/pathFactory';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -44,35 +44,23 @@ const Index: FC<Props> = ({ visible, tabName, data }) => {
|
||||||
<span className="split-dot" />
|
<span className="split-dot" />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<FormatTime
|
<FormatTime
|
||||||
time={item.create_time}
|
time={
|
||||||
|
tabName === 'bookmarks' ? item.create_time : item.created_at
|
||||||
|
}
|
||||||
className="me-3"
|
className="me-3"
|
||||||
preFix={t('asked')}
|
preFix={t('asked')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="d-flex align-items-center me-3">
|
<Counts
|
||||||
<Icon name="hand-thumbs-up-fill me-1" />
|
isAccepted={Number(item.accepted_answer_id) > 0}
|
||||||
<span>{item.vote_count}</span>
|
data={{
|
||||||
</div>
|
votes: item.vote_count,
|
||||||
|
answers: item.answer_count,
|
||||||
{tabName !== 'answers' && (
|
views: item.view_count,
|
||||||
<div
|
}}
|
||||||
className={`d-flex align-items-center me-3 ${
|
/>
|
||||||
Number(item.accepted_answer_id) > 0 ? 'text-success' : ''
|
|
||||||
}`}>
|
|
||||||
{Number(item.accepted_answer_id) > 0 ? (
|
|
||||||
<Icon name="check-circle-fill me-1" />
|
|
||||||
) : (
|
|
||||||
<Icon name="chat-square-text-fill me-1" />
|
|
||||||
)}
|
|
||||||
<span>{item.answer_count}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="d-flex align-items-center me-3">
|
|
||||||
<Icon name="eye-fill me-1" />
|
|
||||||
<span>{item.view_count}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{item.tags?.map((tag) => {
|
{item.tags?.map((tag) => {
|
||||||
|
|
|
@ -32,9 +32,12 @@ const Index: FC<Props> = ({ data, type }) => {
|
||||||
}>
|
}>
|
||||||
{type === 'answer' ? item.question_info.title : item.title}
|
{type === 'answer' ? item.question_info.title : item.title}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div className="d-inline-block text-secondary ms-3 fs-14">
|
<div className="d-inline-block text-secondary ms-3 fs-14">
|
||||||
<Icon name="hand-thumbs-up-fill" />
|
<Icon name="hand-thumbs-up-fill me-1" />
|
||||||
<span> {item.vote_count}</span>
|
<span>
|
||||||
|
{item.vote_count} {t('votes', { keyPrefix: 'counts' })}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{type === 'question' && (
|
{type === 'question' && (
|
||||||
<div
|
<div
|
||||||
|
@ -47,7 +50,10 @@ const Index: FC<Props> = ({ data, type }) => {
|
||||||
<Icon name="chat-square-text-fill" />
|
<Icon name="chat-square-text-fill" />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<span> {item.answer_count}</span>
|
<span>
|
||||||
|
{' '}
|
||||||
|
{item.answer_count} {t('answers', { keyPrefix: 'counts' })}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import i18next from 'i18next';
|
import i18next from 'i18next';
|
||||||
|
import parse from 'html-react-parser';
|
||||||
|
import * as DOMPurify from 'dompurify';
|
||||||
|
|
||||||
const Diff = require('diff');
|
const Diff = require('diff');
|
||||||
|
|
||||||
|
@ -21,7 +23,7 @@ function formatCount($num: number): string {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrollTop(element) {
|
function scrollToElementTop(element) {
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -36,6 +38,15 @@ function scrollTop(element) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scrollToDocTop = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
window.scrollTo({
|
||||||
|
top: 0,
|
||||||
|
behavior: 'smooth',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const bgFadeOut = (el) => {
|
const bgFadeOut = (el) => {
|
||||||
if (el && !el.classList.contains('bg-fade-out')) {
|
if (el && !el.classList.contains('bg-fade-out')) {
|
||||||
el.classList.add('bg-fade-out');
|
el.classList.add('bg-fade-out');
|
||||||
|
@ -160,14 +171,17 @@ function handleFormError(
|
||||||
) {
|
) {
|
||||||
if (error.list?.length > 0) {
|
if (error.list?.length > 0) {
|
||||||
error.list.forEach((item) => {
|
error.list.forEach((item) => {
|
||||||
data[item.error_field].isInvalid = true;
|
const errorFieldObject = data[item.error_field];
|
||||||
data[item.error_field].errorMsg = item.error_msg;
|
if (errorFieldObject) {
|
||||||
|
errorFieldObject.isInvalid = true;
|
||||||
|
errorFieldObject.errorMsg = item.error_msg;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function diffText(newText: string, oldText: string): string {
|
function diffText(newText: string, oldText?: string): string {
|
||||||
if (!newText) {
|
if (!newText) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -181,8 +195,6 @@ function diffText(newText: string, oldText: string): string {
|
||||||
?.replace(/<input/gi, '<input');
|
?.replace(/<input/gi, '<input');
|
||||||
}
|
}
|
||||||
const diff = Diff.diffChars(oldText, newText);
|
const diff = Diff.diffChars(oldText, newText);
|
||||||
console.log(diff);
|
|
||||||
|
|
||||||
const result = diff.map((part) => {
|
const result = diff.map((part) => {
|
||||||
if (part.added) {
|
if (part.added) {
|
||||||
if (part.value.replace(/\n/g, '').length <= 0) {
|
if (part.value.replace(/\n/g, '').length <= 0) {
|
||||||
|
@ -214,10 +226,18 @@ function diffText(newText: string, oldText: string): string {
|
||||||
?.replace(/<input/gi, '<input');
|
?.replace(/<input/gi, '<input');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function htmlToReact(html: string) {
|
||||||
|
const cleanedHtml = DOMPurify.sanitize(html, {
|
||||||
|
USE_PROFILES: { html: true },
|
||||||
|
});
|
||||||
|
return parse(cleanedHtml);
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
thousandthDivision,
|
thousandthDivision,
|
||||||
formatCount,
|
formatCount,
|
||||||
scrollTop,
|
scrollToElementTop,
|
||||||
|
scrollToDocTop,
|
||||||
bgFadeOut,
|
bgFadeOut,
|
||||||
matchedUsers,
|
matchedUsers,
|
||||||
parseUserInfo,
|
parseUserInfo,
|
||||||
|
@ -228,4 +248,5 @@ export {
|
||||||
labelStyle,
|
labelStyle,
|
||||||
handleFormError,
|
handleFormError,
|
||||||
diffText,
|
diffText,
|
||||||
|
htmlToReact,
|
||||||
};
|
};
|
||||||
|
|
|
@ -267,7 +267,7 @@ export const initAppSettingsStore = async () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const shouldInitAppFetchData = () => {
|
export const shouldInitAppFetchData = () => {
|
||||||
if (isIgnoredPath('/install')) {
|
if (isIgnoredPath('/install') && window.location.pathname === '/install') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ class Request {
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
const { status, data: respData } = error.response || {};
|
const { status, data: respData } = error.response || {};
|
||||||
const { data = {}, msg = '' } = respData || {};
|
const { data = {}, msg = '', reason = '' } = respData || {};
|
||||||
if (status === 400) {
|
if (status === 400) {
|
||||||
// show error message
|
// show error message
|
||||||
if (data instanceof Object && data.err_type) {
|
if (data instanceof Object && data.err_type) {
|
||||||
|
@ -79,7 +79,13 @@ class Request {
|
||||||
|
|
||||||
if (data instanceof Array && data.length > 0) {
|
if (data instanceof Array && data.length > 0) {
|
||||||
// handle form error
|
// handle form error
|
||||||
return Promise.reject({ isError: true, list: data });
|
return Promise.reject({
|
||||||
|
code: status,
|
||||||
|
msg,
|
||||||
|
reason,
|
||||||
|
isError: true,
|
||||||
|
list: data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data || Object.keys(data).length <= 0) {
|
if (!data || Object.keys(data).length <= 0) {
|
||||||
|
|
Loading…
Reference in New Issue