Просмотр исходного кода

Merge pull request #10306 from growilabs/master

Release v7.3.0
Yuki Takei 6 месяцев назад
Родитель
Сommit
6b654e5003
100 измененных файлов с 4630 добавлено и 1040 удалено
  1. 1 1
      .changeset/config.json
  2. 15 8
      .devcontainer/app/devcontainer.json
  3. 4 0
      .devcontainer/app/postCreateCommand.sh
  4. 2 3
      .devcontainer/compose.extend.template.yml
  5. 6 10
      .devcontainer/compose.yml
  6. 2 0
      .devcontainer/pdf-converter/postCreateCommand.sh
  7. 1 1
      .github/ISSUE_TEMPLATE/bug-report.md
  8. 1 1
      .github/ISSUE_TEMPLATE/config.yml
  9. 5 5
      .github/mergify.yml
  10. 7 7
      .github/workflows/ci-app-prod.yml
  11. 6 4
      .github/workflows/ci-app.yml
  12. 2 2
      .github/workflows/ci-pdf-converter.yml
  13. 3 3
      .github/workflows/ci-slackbot-proxy.yml
  14. 1 1
      .github/workflows/list-unhealthy-branches.yml
  15. 5 5
      .github/workflows/release-pdf-converter.yml
  16. 3 2
      .github/workflows/release-rc-scheduled.yml
  17. 3 2
      .github/workflows/release-rc.yml
  18. 2 2
      .github/workflows/release-slackbot-proxy.yml
  19. 2 2
      .github/workflows/release-subpackages.yml
  20. 51 18
      .github/workflows/release.yml
  21. 1 1
      .github/workflows/reusable-app-build-image.yml
  22. 5 2
      .github/workflows/reusable-app-create-manifests.yml
  23. 13 8
      .github/workflows/reusable-app-prod.yml
  24. 1 1
      .github/workflows/reusable-app-reg-suit.yml
  25. 22 0
      .mcp.json
  26. 4 11
      .roo/mcp.json
  27. 1 0
      .serena/.gitignore
  28. 71 0
      .serena/memories/coding_conventions.md
  29. 45 0
      .serena/memories/development_environment.md
  30. 26 0
      .serena/memories/project_overview.md
  31. 90 0
      .serena/memories/project_structure.md
  32. 94 0
      .serena/memories/suggested_commands.md
  33. 95 0
      .serena/memories/task_completion_checklist.md
  34. 42 0
      .serena/memories/tech_stack.md
  35. 68 0
      .serena/project.yml
  36. 20 0
      .vscode/mcp.json
  37. 2 1
      .vscode/settings.json
  38. 129 116
      CHANGELOG.md
  39. 95 0
      CLAUDE.md
  40. 1 1
      LICENSE
  41. 13 13
      README.md
  42. 13 13
      README_JP.md
  43. 1 1
      THIRD-PARTY-NOTICES.md
  44. 3 2
      apps/app/.env.development
  45. 1 1
      apps/app/.env.production
  46. 26 0
      apps/app/.eslintrc.js
  47. 2 1
      apps/app/bin/openapi/definition-apiv1.js
  48. 3 13
      apps/app/bin/openapi/definition-apiv3.js
  49. 14 10
      apps/app/bin/openapi/generate-operation-ids/cli.spec.ts
  50. 5 4
      apps/app/bin/openapi/generate-operation-ids/cli.ts
  51. 29 31
      apps/app/bin/openapi/generate-operation-ids/generate-operation-ids.spec.ts
  52. 42 16
      apps/app/bin/openapi/generate-operation-ids/generate-operation-ids.ts
  53. 0 1
      apps/app/bin/openapi/generate-spec-apiv3.sh
  54. 8 2
      apps/app/config/cdn.js
  55. 1 1
      apps/app/config/logger/config.dev.js
  56. 2 2
      apps/app/config/migrate-mongo-config.js
  57. 4 8
      apps/app/config/migrate-mongo-config.spec.ts
  58. 6 7
      apps/app/config/next-i18next.config.js
  59. 2 2
      apps/app/docker/Dockerfile
  60. 7 7
      apps/app/docker/README.md
  61. 44 44
      apps/app/docker/codebuild/.terraform.lock.hcl
  62. 1 1
      apps/app/docker/codebuild/buildspec.yml
  63. 1 1
      apps/app/docker/codebuild/codebuild.tf
  64. 1 1
      apps/app/docker/codebuild/main.tf
  65. 1 1
      apps/app/docker/codebuild/oidc.tf
  66. 11 4
      apps/app/jest.config.js
  67. 18 15
      apps/app/next.config.js
  68. 1 4
      apps/app/nodemon.json
  69. 14 10
      apps/app/package.json
  70. 14 14
      apps/app/playwright.config.ts
  71. 0 2
      apps/app/playwright/40-admin/access-to-admin-page.spec.ts
  72. 26 14
      apps/app/playwright/60-home/home.spec.ts
  73. 34 44
      apps/app/public/static/locales/en_US/admin.json
  74. 92 36
      apps/app/public/static/locales/en_US/commons.json
  75. 73 26
      apps/app/public/static/locales/en_US/translation.json
  76. 3 13
      apps/app/public/static/locales/fr_FR/admin.json
  77. 92 23
      apps/app/public/static/locales/fr_FR/commons.json
  78. 74 27
      apps/app/public/static/locales/fr_FR/translation.json
  79. 3 13
      apps/app/public/static/locales/ja_JP/admin.json
  80. 93 35
      apps/app/public/static/locales/ja_JP/commons.json
  81. 74 26
      apps/app/public/static/locales/ja_JP/translation.json
  82. 1142 0
      apps/app/public/static/locales/ko_KR/admin.json
  83. 127 0
      apps/app/public/static/locales/ko_KR/commons.json
  84. 1025 0
      apps/app/public/static/locales/ko_KR/translation.json
  85. 229 239
      apps/app/public/static/locales/zh_CN/admin.json
  86. 116 60
      apps/app/public/static/locales/zh_CN/commons.json
  87. 75 26
      apps/app/public/static/locales/zh_CN/translation.json
  88. 6 8
      apps/app/resource/Contributor.js
  89. 14 0
      apps/app/resource/locales/ko_KR/admin/userInvitation.ejs
  90. 11 0
      apps/app/resource/locales/ko_KR/admin/userResetPassword.ejs
  91. 20 0
      apps/app/resource/locales/ko_KR/admin/userWaitingActivation.ejs
  92. 9 0
      apps/app/resource/locales/ko_KR/notifications/comment.ejs
  93. 5 0
      apps/app/resource/locales/ko_KR/notifications/pageCreate.ejs
  94. 5 0
      apps/app/resource/locales/ko_KR/notifications/pageDelete.ejs
  95. 5 0
      apps/app/resource/locales/ko_KR/notifications/pageEdit.ejs
  96. 5 0
      apps/app/resource/locales/ko_KR/notifications/pageLike.ejs
  97. 5 0
      apps/app/resource/locales/ko_KR/notifications/pageMove.ejs
  98. 12 0
      apps/app/resource/locales/ko_KR/notifications/passwordReset.ejs
  99. 8 0
      apps/app/resource/locales/ko_KR/notifications/passwordResetSuccessful.ejs
  100. 12 0
      apps/app/resource/locales/ko_KR/notifications/userActivation.ejs

+ 1 - 1
.changeset/config.json

@@ -1,6 +1,6 @@
 {
   "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
-  "changelog": ["@changesets/changelog-github", { "repo": "weseek/growi" }],
+  "changelog": ["@changesets/changelog-github", { "repo": "growilabs/growi" }],
   "commit": false,
   "fixed": [],
   "linked": [],

+ 15 - 8
.devcontainer/app/devcontainer.json

@@ -8,7 +8,7 @@
 
   "features": {
     "ghcr.io/devcontainers/features/node:1": {
-      "version": "20.18.3"
+      "version": "22.17.0"
     }
   },
 
@@ -23,21 +23,28 @@
   "customizations": {
     "vscode": {
       "extensions": [
+        // AI
+        "anthropic.claude-code",
+        // linter
         "dbaeumer.vscode-eslint",
         "biomejs.biome",
+        "editorconfig.editorconfig",
+        "shinnn.stylelint",
+        "stylelint.vscode-stylelint",
+        // Test
+        "vitest.explorer",
+        "ms-playwright.playwright",
+        // git/github
+        "github.vscode-pull-request-github",
         "mhutchie.git-graph",
         "eamodio.gitlens",
-        "github.vscode-pull-request-github",
         "cschleiden.vscode-github-actions",
+        // DB
         "cweijan.vscode-database-client2",
         "mongodb.mongodb-vscode",
+        // Debug
         "msjsdiag.debugger-for-chrome",
-        "firefox-devtools.vscode-firefox-debug",
-        "editorconfig.editorconfig",
-        "shinnn.stylelint",
-        "stylelint.vscode-stylelint",
-        "vitest.explorer",
-        "ms-playwright.playwright"
+        "firefox-devtools.vscode-firefox-debug"
       ],
       "settings": {
         "terminal.integrated.defaultProfile.linux": "bash"

+ 4 - 0
.devcontainer/app/postCreateCommand.sh

@@ -17,9 +17,13 @@ curl -LsSf https://astral.sh/uv/install.sh | sh
 # Setup pnpm
 SHELL=bash pnpm setup
 eval "$(cat /home/vscode/.bashrc)"
+pnpm config set store-dir /workspace/.pnpm-store
 
 # Install turbo
 pnpm install turbo --global
 
+# Install Claude Code
+pnpm install @anthropic-ai/claude-code --global
+
 # Install dependencies
 turbo run bootstrap

+ 2 - 3
.devcontainer/compose.extend.template.yml

@@ -3,10 +3,9 @@
 services:
   pdf-converter:
     # enabling devcontainer 'features' was not working for secondary devcontainer (https://github.com/devcontainers/features/issues/1175)
-    image: mcr.microsoft.com/vscode/devcontainers/javascript-node:1-20
+    image: mcr.microsoft.com/vscode/devcontainers/javascript-node:1-22
     volumes:
       - ..:/workspace/growi:delegated
-      - pnpm-store:/workspace/growi/.pnpm-store
-      - node_modules:/workspace/growi/node_modules
+      - pnpm-store:/workspace/.pnpm-store
       - page_bulk_export_tmp:/tmp/page-bulk-export
     tty: true

+ 6 - 10
.devcontainer/compose.yml

@@ -3,9 +3,7 @@ services:
     image: mcr.microsoft.com/devcontainers/base:ubuntu
     volumes:
       - ..:/workspace/growi:delegated
-      - pnpm-store:/workspace/growi/.pnpm-store
-      - node_modules:/workspace/growi/node_modules
-      - buildcache_app:/workspace/growi/apps/app/.next
+      - pnpm-store:/workspace/.pnpm-store
       - ../../growi-docker-compose:/workspace/growi-docker-compose:delegated
       - ../../share:/workspace/share:delegated
       - page_bulk_export_tmp:/tmp/page-bulk-export
@@ -15,7 +13,7 @@ services:
     - opentelemetry-collector-dev-setup_default
 
   mongo:
-    image: mongo:6.0
+    image: mongo:8.0
     restart: unless-stopped
     ports:
       - 27017
@@ -23,13 +21,13 @@ services:
       - /data/db
 
   # This container requires '../../growi-docker-compose' repository
-  #   cloned from https://github.com/weseek/growi-docker-compose.git
+  #   cloned from https://github.com/growilabs/growi-docker-compose.git
   elasticsearch:
     build:
-      context: ../../growi-docker-compose/elasticsearch/v8
+      context: ../../growi-docker-compose/elasticsearch/v9
       dockerfile: ./Dockerfile
       args:
-        - version=8.7.0
+        - version=9.0.3
     restart: unless-stopped
     ports:
       - 9200
@@ -43,12 +41,10 @@ services:
         hard: -1
     volumes:
       - /usr/share/elasticsearch/data
-      - ../../growi-docker-compose/elasticsearch/v8/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
+      - ../../growi-docker-compose/elasticsearch/v9/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
 
 volumes:
   pnpm-store:
-  node_modules:
-  buildcache_app:
   page_bulk_export_tmp:
 
 networks:

+ 2 - 0
.devcontainer/pdf-converter/postCreateCommand.sh

@@ -12,6 +12,8 @@ sudo chmod 700 /tmp/page-bulk-export
 # Setup pnpm
 SHELL=bash pnpm setup
 eval "$(cat /home/node/.bashrc)"
+pnpm config set store-dir /workspace/.pnpm-store
+
 # Update pnpm
 pnpm i -g pnpm
 

+ 1 - 1
.github/ISSUE_TEMPLATE/bug-report.md

@@ -18,7 +18,7 @@ Environment
 |Using Docker|yes/no|
 |Using [growi-docker-compose][growi-docker-compose]|yes/no|
 
-[growi-docker-compose]: https://github.com/weseek/growi-docker-compose
+[growi-docker-compose]: https://github.com/growilabs/growi-docker-compose
 
 *(Accessing https://{GROWI_HOST}/admin helps you to fill in above versions)*
 

+ 1 - 1
.github/ISSUE_TEMPLATE/config.yml

@@ -1,7 +1,7 @@
 blank_issues_enabled: false
 contact_links:
   - name: User request or Suggestions
-    url: https://github.com/weseek/growi/discussions
+    url: https://github.com/growilabs/growi/discussions
     about: If you have feature requests or suggestions, you can create a new discussion and consider it with the community.
   - name: Questions
     url: https://communityinviter.com/apps/wsgrowi/invite/

+ 5 - 5
.github/mergify.yml

@@ -7,17 +7,17 @@ queue_rules:
       - check-success ~= ci-app-launch-dev
       - -check-failure ~= ci-app-
       - -check-failure ~= ci-slackbot-
-      - -check-failure ~= test-prod-node20 /
+      - -check-failure ~= test-prod-node22 /
     merge_conditions:
       - check-success ~= ci-app-lint
       - check-success ~= ci-app-test
       - check-success ~= ci-app-launch-dev
-      - check-success = test-prod-node20 / build-prod
-      - check-success = test-prod-node20 / launch-prod
-      - check-success ~= test-prod-node20 / run-playwright
+      - check-success ~= test-prod-node22 / build-prod
+      - check-success ~= test-prod-node22 / launch-prod
+      - check-success ~= test-prod-node22 / run-playwright
       - -check-failure ~= ci-app-
       - -check-failure ~= ci-slackbot-
-      - -check-failure ~= test-prod-node20 /
+      - -check-failure ~= test-prod-node22 /
 
 pull_request_rules:
   - name: Automatic queue to merge

+ 7 - 7
.github/workflows/ci-app-prod.yml

@@ -39,8 +39,8 @@ concurrency:
 
 jobs:
 
-  test-prod-node18:
-    uses: weseek/growi/.github/workflows/reusable-app-prod.yml@master
+  test-prod-node20:
+    uses: growilabs/growi/.github/workflows/reusable-app-prod.yml@master
     if: |
       ( github.event_name == 'push'
         || github.base_ref == 'master'
@@ -48,14 +48,14 @@ jobs:
         || startsWith( github.base_ref, 'release/' )
         || startsWith( github.head_ref, 'mergify/merge-queue/' ))
     with:
-      node-version: 18.x
+      node-version: 20.x
       skip-e2e-test: true
     secrets:
       SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
 
 
-  test-prod-node20:
-    uses: weseek/growi/.github/workflows/reusable-app-prod.yml@master
+  test-prod-node22:
+    uses: growilabs/growi/.github/workflows/reusable-app-prod.yml@master
     if: |
       ( github.event_name == 'push'
         || github.base_ref == 'master'
@@ -63,7 +63,7 @@ jobs:
         || startsWith( github.base_ref, 'release/' )
         || startsWith( github.head_ref, 'mergify/merge-queue/' ))
     with:
-      node-version: 20.x
+      node-version: 22.x
       skip-e2e-test: ${{ contains( github.event.pull_request.labels.*.name, 'dependencies' ) }}
     secrets:
       SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
@@ -71,7 +71,7 @@ jobs:
   # run-reg-suit-node20:
   #   needs: [test-prod-node20]
 
-  #   uses: weseek/growi/.github/workflows/reusable-app-reg-suit.yml@master
+  #   uses: growilabs/growi/.github/workflows/reusable-app-reg-suit.yml@master
 
   #   if: always()
 

+ 6 - 4
.github/workflows/ci-app.yml

@@ -44,7 +44,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [20.x]
+        node-version: [22.x]
 
     steps:
       - uses: actions/checkout@v4
@@ -93,10 +93,11 @@ jobs:
     strategy:
       matrix:
         node-version: [20.x]
+        mongodb-version: ['6.0', '8.0']
 
     services:
       mongodb:
-        image: mongo:6.0
+        image: mongo:${{ matrix.mongodb-version }}
         ports:
           - 27017/tcp
 
@@ -135,7 +136,7 @@ jobs:
       - name: Upload coverage report as artifact
         uses: actions/upload-artifact@v4
         with:
-          name: Coverage Report
+          name: coverage-mongo${{ matrix.mongodb-version }}
           path: |
             apps/app/coverage
             packages/remark-growi-directive/coverage
@@ -157,10 +158,11 @@ jobs:
     strategy:
       matrix:
         node-version: [20.x]
+        mongodb-version: ['6.0', '8.0']
 
     services:
       mongodb:
-        image: mongo:6.0
+        image: mongo:${{ matrix.mongodb-version }}
         ports:
           - 27017/tcp
 

+ 2 - 2
.github/workflows/ci-pdf-converter.yml

@@ -29,7 +29,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [20.x]
+        node-version: [22.x]
 
     steps:
     - uses: actions/checkout@v4
@@ -104,7 +104,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [20.x]
+        node-version: [22.x]
 
     steps:
     - uses: actions/checkout@v4

+ 3 - 3
.github/workflows/ci-slackbot-proxy.yml

@@ -30,7 +30,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [20.x]
+        node-version: [22.x]
 
     steps:
     - uses: actions/checkout@v4
@@ -85,7 +85,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [20.x]
+        node-version: [22.x]
 
     services:
       mysql:
@@ -163,7 +163,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [20.x]
+        node-version: [22.x]
 
     services:
       mysql:

+ 1 - 1
.github/workflows/list-unhealthy-branches.yml

@@ -16,7 +16,7 @@ jobs:
 
     - uses: actions/setup-node@v4
       with:
-        node-version: '18'
+        node-version: '20'
 
     - name: List branches
       id: list-branches

+ 5 - 5
.github/workflows/release-pdf-converter.yml

@@ -16,14 +16,14 @@ jobs:
         ref: ${{ github.event.pull_request.base.ref }}
 
     - name: Retrieve information from package.json
-      uses: myrotvorets/info-from-package-json-action@2.0.1
+      uses: myrotvorets/info-from-package-json-action@v2.0.2
       id: package-json
       with:
         workingDir: apps/pdf-converter
 
     - name: Docker meta
       id: meta
-      uses: docker/metadata-action@v4
+      uses: docker/metadata-action@v5
       with:
         images: growilabs/pdf-converter
         tags: |
@@ -57,7 +57,7 @@ jobs:
         VERBOSE : true
 
     - name: Update Docker Hub Description
-      uses: peter-evans/dockerhub-description@v3
+      uses: peter-evans/dockerhub-description@v4
       with:
         username: growimoogle
         password: ${{ secrets.DOCKER_REGISTRY_PASSWORD_GROWIMOOGLE }}
@@ -72,7 +72,7 @@ jobs:
 
     strategy:
       matrix:
-        node-version: [20.x]
+        node-version: [22.x]
 
     steps:
     - uses: actions/checkout@v4
@@ -96,7 +96,7 @@ jobs:
         turbo run version:prerelease --filter=@growi/pdf-converter
 
     - name: Retrieve information from package.json
-      uses: myrotvorets/info-from-package-json-action@2.0.1
+      uses: myrotvorets/info-from-package-json-action@v2.0.2
       id: package-json
       with:
         workingDir: apps/pdf-converter

+ 3 - 2
.github/workflows/release-rc-scheduled.yml

@@ -46,7 +46,7 @@ jobs:
 
 
   build-image-rc:
-    uses: weseek/growi/.github/workflows/reusable-app-build-image.yml@master
+    uses: growilabs/growi/.github/workflows/reusable-app-build-image.yml@master
     with:
       image-name: weseek/growi
       tag-temporary: latest-rc
@@ -57,11 +57,12 @@ jobs:
   publish-image-rc:
     needs: [determine-tags, build-image-rc]
 
-    uses: weseek/growi/.github/workflows/reusable-app-create-manifests.yml@master
+    uses: growilabs/growi/.github/workflows/reusable-app-create-manifests.yml@master
     with:
       tags: ${{ needs.determine-tags.outputs.TAGS }}
       registry: docker.io
       image-name: weseek/growi
+      docker-registry-username: wsmoogle
       tag-temporary: latest-rc
     secrets:
       DOCKER_REGISTRY_PASSWORD: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}

+ 3 - 2
.github/workflows/release-rc.yml

@@ -38,7 +38,7 @@ jobs:
 
 
   build-image-rc:
-    uses: weseek/growi/.github/workflows/reusable-app-build-image.yml@master
+    uses: growilabs/growi/.github/workflows/reusable-app-build-image.yml@master
     with:
       image-name: weseek/growi
       tag-temporary: latest-rc
@@ -49,11 +49,12 @@ jobs:
   publish-image-rc:
     needs: [determine-tags, build-image-rc]
 
-    uses: weseek/growi/.github/workflows/reusable-app-create-manifests.yml@master
+    uses: growilabs/growi/.github/workflows/reusable-app-create-manifests.yml@master
     with:
       tags: ${{ needs.determine-tags.outputs.TAGS }}
       registry: docker.io
       image-name: weseek/growi
+      docker-registry-username: wsmoogle
       tag-temporary: latest-rc
     secrets:
       DOCKER_REGISTRY_PASSWORD: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}

+ 2 - 2
.github/workflows/release-slackbot-proxy.yml

@@ -70,7 +70,7 @@ jobs:
         VERBOSE : true
 
     - name: Update Docker Hub Description
-      uses: peter-evans/dockerhub-description@v3
+      uses: peter-evans/dockerhub-description@v4
       with:
         username: wsmoogle
         password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
@@ -92,7 +92,7 @@ jobs:
 
     - uses: actions/setup-node@v4
       with:
-        node-version: '18'
+        node-version: '20'
         cache: 'pnpm'
 
     - name: Install dependencies

+ 2 - 2
.github/workflows/release-subpackages.yml

@@ -32,7 +32,7 @@ jobs:
 
     - uses: actions/setup-node@v4
       with:
-        node-version: '20'
+        node-version: '22'
         cache: 'pnpm'
 
     - name: Install dependencies
@@ -75,7 +75,7 @@ jobs:
 
     - uses: actions/setup-node@v4
       with:
-        node-version: '20'
+        node-version: '22'
         cache: 'pnpm'
 
     - name: Install dependencies

+ 51 - 18
.github/workflows/release.yml

@@ -1,3 +1,4 @@
+# TODO: https://redmine.weseek.co.jp/issues/171293
 name: Release
 
 on:
@@ -26,7 +27,7 @@ jobs:
 
     - uses: actions/setup-node@v4
       with:
-        node-version: '20'
+        node-version: '22'
         cache: 'pnpm'
 
     - name: Install dependencies
@@ -80,7 +81,8 @@ jobs:
     runs-on: ubuntu-latest
 
     outputs:
-      TAGS: ${{ steps.meta.outputs.tags }}
+      TAGS_WESEEK: ${{ steps.meta-weseek.outputs.tags }}
+      TAGS_GROWILABS: ${{ steps.meta-growilabs.outputs.tags }}
 
     steps:
     - uses: actions/checkout@v4
@@ -89,9 +91,9 @@ jobs:
       uses: myrotvorets/info-from-package-json-action@v2.0.2
       id: package-json
 
-    - name: Docker meta for docker.io
+    - name: Docker meta for weseek/growi
       uses: docker/metadata-action@v5
-      id: meta
+      id: meta-weseek
       with:
         images: docker.io/weseek/growi
         sep-tags: ','
@@ -101,47 +103,78 @@ jobs:
           type=semver,value=${{ needs.create-github-release.outputs.RELEASED_VERSION }},pattern={{major}}.{{minor}}
           type=semver,value=${{ needs.create-github-release.outputs.RELEASED_VERSION }},pattern={{major}}.{{minor}}.{{patch}}
 
+    - name: Docker meta for growilabs/growi
+      uses: docker/metadata-action@v5
+      id: meta-growilabs
+      with:
+        images: docker.io/growilabs/growi
+        sep-tags: ','
+        tags: |
+          type=raw,value=latest
+          type=semver,value=${{ needs.create-github-release.outputs.RELEASED_VERSION }},pattern={{major}}
+          type=semver,value=${{ needs.create-github-release.outputs.RELEASED_VERSION }},pattern={{major}}.{{minor}}
+          type=semver,value=${{ needs.create-github-release.outputs.RELEASED_VERSION }},pattern={{major}}.{{minor}}.{{patch}}
 
   build-app-image:
     needs: create-github-release
 
-    uses: weseek/growi/.github/workflows/reusable-app-build-image.yml@master
+    uses: growilabs/growi/.github/workflows/reusable-app-build-image.yml@master
     with:
       source-version: refs/tags/v${{ needs.create-github-release.outputs.RELEASED_VERSION }}
-      image-name: weseek/growi
+      image-name: growilabs/growi
       tag-temporary: latest
     secrets:
       AWS_ROLE_TO_ASSUME_FOR_OIDC: ${{ secrets.AWS_ROLE_TO_ASSUME_FOR_OIDC }}
 
+  publish-app-image-for-growilabs:
+    needs: [determine-tags, build-app-image]
+
+    uses: growilabs/growi/.github/workflows/reusable-app-create-manifests.yml@master
+    with:
+      tags: ${{ needs.determine-tags.outputs.TAGS_GROWILABS }}
+      registry: docker.io
+      image-name: 'growilabs/growi'
+      docker-registry-username: 'growimoogle'
+      tag-temporary: latest
+    secrets:
+      DOCKER_REGISTRY_PASSWORD: ${{ secrets.DOCKER_REGISTRY_PASSWORD_GROWIMOOGLE }}
 
-  publish-app-image:
+  publish-app-image-for-weseek:
     needs: [determine-tags, build-app-image]
 
-    uses: weseek/growi/.github/workflows/reusable-app-create-manifests.yml@master
+    uses: growilabs/growi/.github/workflows/reusable-app-create-manifests.yml@master
     with:
-      tags: ${{ needs.determine-tags.outputs.TAGS }}
+      tags: ${{ needs.determine-tags.outputs.TAGS_WESEEK }}
       registry: docker.io
-      image-name: weseek/growi
+      image-name: 'growilabs/growi'
+      docker-registry-username: 'wsmoogle'
       tag-temporary: latest
     secrets:
       DOCKER_REGISTRY_PASSWORD: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
 
-
   post-publish:
-    needs: [create-github-release, publish-app-image]
+    needs: [create-github-release, publish-app-image-for-growilabs, publish-app-image-for-weseek]
     runs-on: ubuntu-latest
 
+    strategy:
+      matrix:
+        include:
+          - repository: weseek/growi
+            username: wsmoogle
+          - repository: growilabs/growi
+            username: growimoogle
+
     steps:
     - uses: actions/checkout@v4
       with:
         ref: v${{ needs.create-github-release.outputs.RELEASED_VERSION }}
 
     - name: Update Docker Hub Description
-      uses: peter-evans/dockerhub-description@v3
+      uses: peter-evans/dockerhub-description@v4
       with:
-        username: wsmoogle
-        password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
-        repository: weseek/growi
+        username: ${{ matrix.username }}
+        password: ${{ (matrix.repository == 'weseek/growi' && secrets.DOCKER_REGISTRY_PASSWORD) || (matrix.repository == 'growilabs/growi' && secrets.DOCKER_REGISTRY_PASSWORD_GROWIMOOGLE) || 'INVALID_SECRET' }}
+        repository: ${{ matrix.repository }}
         readme-filepath: ./apps/app/docker/README.md
 
     - name: Slack Notification
@@ -153,7 +186,7 @@ jobs:
 
 
   create-pr-for-next-rc:
-    needs: [create-github-release, publish-app-image]
+    needs: [create-github-release, publish-app-image-for-growilabs, publish-app-image-for-weseek]
     runs-on: ubuntu-latest
 
     steps:
@@ -165,7 +198,7 @@ jobs:
 
     - uses: actions/setup-node@v4
       with:
-        node-version: '20'
+        node-version: '22'
         cache: 'pnpm'
 
     - name: Install dependencies

+ 1 - 1
.github/workflows/reusable-app-build-image.yml

@@ -8,7 +8,7 @@ on:
         default: ${{ github.sha }}
       image-name:
         type: string
-        default: weseek/growi
+        default: growilabs/growi
       tag-temporary:
         type: string
         default: latest

+ 5 - 2
.github/workflows/reusable-app-create-manifests.yml

@@ -11,7 +11,10 @@ on:
         default: 'docker.io'
       image-name:
         type: string
-        default: weseek/growi
+        default: growilabs/growi
+      docker-registry-username:
+        type: string
+        default: growimoogle
       tag-temporary:
         type: string
         default: latest
@@ -41,7 +44,7 @@ jobs:
       uses: docker/login-action@v3
       with:
         registry: ${{ inputs.registry }}
-        username: wsmoogle
+        username: ${{ inputs.docker-registry-username }}
         password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}
 
     - name: Create and push manifest images

+ 13 - 8
.github/workflows/reusable-app-prod.yml

@@ -1,4 +1,4 @@
-name: Reusable build app workflow for production
+name: Reusable build and test app for production
 
 on:
   workflow_call:
@@ -16,7 +16,7 @@ on:
       node-version:
         required: true
         type: string
-        default: 20.x
+        default: 22.x
       skip-e2e-test:
         type: boolean
         default: false
@@ -107,13 +107,17 @@ jobs:
     needs: [build-prod]
     runs-on: ubuntu-latest
 
+    strategy:
+      matrix:
+        mongodb-version: ['6.0', '8.0']
+
     services:
       mongodb:
-        image: mongo:6.0
+        image: mongo:${{ matrix.mongodb-version }}
         ports:
         - 27017/tcp
       elasticsearch:
-        image: docker.elastic.co/elasticsearch/elasticsearch:7.17.1
+        image: docker.elastic.co/elasticsearch/elasticsearch:9.0.1
         ports:
         - 9200/tcp
         env:
@@ -182,14 +186,15 @@ jobs:
       matrix:
         browser: [chromium, firefox, webkit]
         shard: [1/2, 2/2]
+        mongodb-version: ['6.0', '8.0']
 
     services:
       mongodb:
-        image: mongo:6.0
+        image: mongo:${{ matrix.mongodb-version }}
         ports:
         - 27017/tcp
       elasticsearch:
-        image: docker.elastic.co/elasticsearch/elasticsearch:7.17.1
+        image: docker.elastic.co/elasticsearch/elasticsearch:9.0.1
         ports:
         - 9200/tcp
         env:
@@ -279,7 +284,7 @@ jobs:
       uses: actions/upload-artifact@v4
       if: always()
       with:
-        name: blob-report-${{ matrix.browser }}-${{ steps.shard-id.outputs.shard_id }}
+        name: blob-report-${{ matrix.browser }}-mongo${{ matrix.mongodb-version }}-${{ steps.shard-id.outputs.shard_id }}
         path: ./apps/app/blob-report
         retention-days: 30
 
@@ -288,7 +293,7 @@ jobs:
       if: failure()
       with:
         type: ${{ job.status }}
-        job_name: '*Node CI for growi - run-playwright*'
+        job_name: '*Node CI for growi - run-playwright (${{ matrix.browser }}, MongoDB ${{ matrix.mongodb-version }})*'
         channel: '#ci'
         isCompactMode: true
         url: ${{ secrets.SLACK_WEBHOOK_URL }}

+ 1 - 1
.github/workflows/reusable-app-reg-suit.yml

@@ -32,7 +32,7 @@ jobs:
 
   run-reg-suit:
     # use secrets for "VRT" environment
-    # https://github.com/weseek/growi/settings/environments/376165508/edit
+    # https://github.com/growilabs/growi/settings/environments/376165508/edit
     environment: VRT
 
     if: ${{ !inputs.skip-reg-suit }}

+ 22 - 0
.mcp.json

@@ -0,0 +1,22 @@
+{
+  "mcpServers": {
+    "context7": {
+      "type": "http",
+      "url": "https://mcp.context7.com/mcp"
+    },
+    "serena": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "--from",
+        "git+https://github.com/oraios/serena",
+        "serena-mcp-server",
+        "--context",
+        "ide-assistant",
+        "--project",
+        "/workspace/growi"
+      ],
+      "env": {}
+    }
+  }
+}

+ 4 - 11
.roo/mcp.json

@@ -2,20 +2,13 @@
   "mcpServers": {
     "fetch": {
       "command": "uvx",
-      "args": [
-        "mcp-server-fetch"
-      ],
-      "alwaysAllow": [
-        "fetch"
-      ]
+      "args": ["mcp-server-fetch"],
+      "alwaysAllow": ["fetch"]
     },
     "context7": {
       "type": "streamable-http",
       "url": "https://mcp.context7.com/mcp",
-      "alwaysAllow": [
-        "resolve-library-id",
-        "get-library-docs"
-      ]
+      "alwaysAllow": ["resolve-library-id", "get-library-docs"]
     }
   }
-}
+}

+ 1 - 0
.serena/.gitignore

@@ -0,0 +1 @@
+/cache

+ 71 - 0
.serena/memories/coding_conventions.md

@@ -0,0 +1,71 @@
+# コーディング規約とスタイルガイド
+
+## Linter・フォーマッター設定
+
+### Biome設定(統一予定)
+- **適用範囲**: 
+  - dist/, node_modules/, coverage/ などは除外
+  - .next/, bin/, config/ などのビルド成果物は除外
+  - package.json, .eslintrc.js などの設定ファイルは除外
+- **推奨**: 新規開発では Biome を使用
+
+### ESLint設定(廃止予定・過渡期)
+- **ベース設定**: weseek ESLint設定を使用
+- **TypeScript**: weseek/typescript 設定を適用
+- **React**: React関連のルールを適用
+- **主要なルール**:
+  - `import/prefer-default-export`: オフ(名前付きエクスポートを推奨)
+  - `import/order`: import文の順序を規定
+    - React を最初に
+    - 内部モジュール(`/**`)をparentグループの前に配置
+
+## TypeScript設定
+- **ターゲット**: ESNext
+- **モジュール**: ESNext  
+- **厳格モード**: 有効(strict: true)
+- **モジュール解決**: Bundler
+- **その他**:
+  - allowJs: true(JSファイルも許可)
+  - skipLibCheck: true(型チェックの最適化)
+  - isolatedModules: true(単独モジュールとしてコンパイル)
+
+## Stylelint設定
+- SCSS/CSSファイルに対して適用
+- recess-order設定を使用(プロパティの順序規定)
+- recommended-scss設定を適用
+
+## ファイル命名規則
+- TypeScript/JavaScriptファイル: キャメルケースまたはケバブケース
+- コンポーネントファイル: PascalCase(Reactコンポーネント)
+- 設定ファイル: ドット記法(.eslintrc.js など)
+
+## テストファイル命名規則(Vitest)
+vitest.workspace.mts の設定に基づく:
+
+### 単体テスト(Unit Test)
+- **ファイル名**: `*.spec.{ts,js}`
+- **環境**: Node.js
+- **例**: `utils.spec.ts`, `helper.spec.js`
+
+### 統合テスト(Integration Test)
+- **ファイル名**: `*.integ.ts`
+- **環境**: Node.js(MongoDB設定あり)
+- **例**: `api.integ.ts`, `service.integ.ts`
+
+### コンポーネントテスト(Component Test)
+- **ファイル名**: `*.spec.{tsx,jsx}`
+- **環境**: happy-dom
+- **例**: `Button.spec.tsx`, `Modal.spec.jsx`
+
+## ディレクトリ構造の規則
+- `src/`: ソースコード
+- `test/`: Jest用の古いテストファイル(廃止予定)
+- `test-with-vite/`: Vitest用の新しいテストファイル
+- `playwright/`: E2Eテストファイル
+- `config/`: 設定ファイル
+- `public/`: 静的ファイル
+- `dist/`: ビルド出力
+
+## 移行ガイドライン
+- 新規開発: Biome + Vitest を使用
+- 既存コード: 段階的に ESLint → Biome、Jest → Vitest に移行

+ 45 - 0
.serena/memories/development_environment.md

@@ -0,0 +1,45 @@
+# 開発環境とツール
+
+## 推奨システム要件
+- **Node.js**: ^20 || ^22
+- **パッケージマネージャー**: pnpm 10.4.1
+- **OS**: Linux(Ubuntuベース)、macOS、Windows
+
+## 利用可能なLinuxコマンド
+基本的なLinuxコマンドが利用可能:
+- `apt`, `dpkg`: パッケージ管理
+- `git`: バージョン管理
+- `curl`, `wget`: HTTP クライアント
+- `ssh`, `scp`, `rsync`: ネットワーク関連
+- `ps`, `lsof`, `netstat`, `top`: プロセス・ネットワーク監視
+- `tree`, `find`, `grep`: ファイル検索・操作
+- `zip`, `unzip`, `tar`, `gzip`, `bzip2`, `xz`: アーカイブ操作
+
+## 開発用ブラウザ
+```bash
+# ローカルサーバーをブラウザで開く
+"$BROWSER" http://localhost:3000
+```
+
+## 環境変数管理
+- **dotenv-flow**: 環境ごとの設定管理
+- 環境ファイル:
+  - `.env.development`: 開発環境
+  - `.env.production`: 本番環境
+  - `.env.test`: テスト環境
+  - `.env.*.local`: ローカル固有設定
+
+## デバッグ
+```bash
+# デバッグモードでサーバー起動
+cd apps/app && pnpm run dev  # --inspectフラグ付きでnodemon起動
+
+# REPL(Read-Eval-Print Loop)
+cd apps/app && pnpm run repl
+```
+
+## VS Code設定
+`.vscode/` ディレクトリに設定ファイルが含まれており、推奨拡張機能や設定が適用される。
+
+## Docker対応
+各アプリケーションにDockerファイルが含まれており、コンテナベースでの開発も可能。

+ 26 - 0
.serena/memories/project_overview.md

@@ -0,0 +1,26 @@
+# GROWIプロジェクト概要
+
+## 目的
+GROWIは、マークダウンを使用したチームコラボレーションソフトウェアです。Wikiとドキュメント作成ツールの機能を持ち、チーム間の情報共有とコラボレーションを促進します。
+
+## プロジェクトの詳細
+- **プロジェクト名**: GROWI
+- **バージョン**: 7.3.0-RC.0
+- **ライセンス**: MIT
+- **作者**: Yuki Takei <yuki@weseek.co.jp>
+- **リポジトリ**: https://github.com/growilabs/growi.git
+- **公式サイト**: https://growi.org
+
+## 主な特徴
+- Markdownベースのドキュメント作成
+- チームコラボレーション機能
+- Wikiのような情報共有プラットフォーム
+- ドキュメント管理とバージョン管理
+
+## アーキテクチャ
+- **モノレポ構成**: pnpm workspace + Turbo.js を使用
+- **主要アプリケーション**: apps/app (メインアプリケーション)
+- **追加アプリケーション**: 
+  - apps/pdf-converter (PDF変換サービス)
+  - apps/slackbot-proxy (Slackボットプロキシ)
+- **パッケージ**: packages/ 配下に複数の共有ライブラリ

+ 90 - 0
.serena/memories/project_structure.md

@@ -0,0 +1,90 @@
+# プロジェクト構造
+
+## ルートディレクトリ構造
+```
+growi/
+├── apps/                    # アプリケーション群
+│   ├── app/                # メインのGROWIアプリケーション
+│   ├── pdf-converter/      # PDF変換サービス
+│   └── slackbot-proxy/     # Slackボットプロキシ
+├── packages/               # 共有パッケージ群
+│   ├── core/              # コアライブラリ
+│   ├── core-styles/       # 共通スタイル
+│   ├── editor/            # エディターコンポーネント
+│   ├── pluginkit/         # プラグインキット
+│   ├── ui/                # UIコンポーネント
+│   ├── presentation/      # プレゼンテーション層
+│   ├── preset-templates/  # テンプレート
+│   ├── preset-themes/     # テーマ
+│   └── remark-*/          # remarkプラグイン群
+├── bin/                   # ユーティリティスクリプト
+└── 設定ファイル群
+```
+
+## メインアプリケーション (apps/app/)
+```
+apps/app/
+├── src/                   # ソースコード
+├── test/                  # 古いJestテストファイル(廃止予定)
+├── test-with-vite/        # 新しいVitestテストファイル
+├── playwright/            # E2Eテスト(Playwright)
+├── config/                # 設定ファイル
+├── public/                # 静的ファイル
+├── docker/                # Docker関連
+├── bin/                   # スクリプト
+└── 設定ファイル群
+```
+
+## テストディレクトリの詳細
+
+### test/ (廃止予定)
+- Jest用の古いテストファイル
+- 段階的にtest-with-vite/に移行予定
+- 新規テストは作成しない
+
+### test-with-vite/
+- Vitest用の新しいテストファイル
+- 新規テストはここに作成
+- セットアップファイル: `setup/mongoms.ts` (MongoDB用)
+
+### playwright/
+- E2Eテスト用ディレクトリ
+- ブラウザ操作を含むテスト
+
+## テストファイルの配置ルール
+
+### Vitestテストファイル
+以下のパターンでソースコードと同じディレクトリまたはtest-with-vite/配下に配置:
+
+- **単体テスト**: `*.spec.{ts,js}`
+- **統合テスト**: `*.integ.ts` 
+- **コンポーネントテスト**: `*.spec.{tsx,jsx}`
+
+例:
+```
+src/
+├── utils/
+│   ├── helper.ts
+│   └── helper.spec.ts       # 単体テスト
+├── components/
+│   ├── Button.tsx
+│   └── Button.spec.tsx      # コンポーネントテスト
+└── services/
+    ├── api.ts
+    └── api.integ.ts         # 統合テスト
+```
+
+## パッケージ(packages/)
+各パッケージは独立したnpmパッケージとして管理され、以下の構造を持つ:
+- `src/`: ソースコード
+- `dist/`: ビルド出力
+- `package.json`: パッケージ設定
+- `tsconfig.json`: TypeScript設定
+
+## 重要な設定ファイル
+- **pnpm-workspace.yaml**: ワークスペース設定
+- **turbo.json**: Turbo.jsビルド設定
+- **tsconfig.base.json**: TypeScript基本設定
+- **biome.json**: Biome linter/formatter設定
+- **.eslintrc.js**: ESLint設定(廃止予定)
+- **vitest.workspace.mts**: Vitestワークスペース設定

+ 94 - 0
.serena/memories/suggested_commands.md

@@ -0,0 +1,94 @@
+# 推奨開発コマンド集
+
+## セットアップ
+```bash
+# 初期セットアップ
+pnpm run bootstrap
+# または
+pnpm install
+```
+
+## 開発サーバー
+```bash
+# メインアプリケーション開発モード
+cd apps/app && pnpm run dev
+
+# ルートから起動(本番用ビルド後)
+pnpm start
+```
+
+## ビルド
+```bash
+# メインアプリケーションのビルド
+pnpm run app:build
+
+# Slackbot Proxyのビルド
+pnpm run slackbot-proxy:build
+
+# 全体ビルド(Turboで並列実行)
+turbo run build
+```
+
+## Lint・フォーマット
+```bash
+# 【推奨】Biome実行(lint + format)
+pnpm run lint:biome
+
+# 【過渡期】ESLint実行(廃止予定)
+pnpm run lint:eslint
+
+# Stylelint実行
+pnpm run lint:styles
+
+# 全てのLint実行(過渡期対応)
+pnpm run lint
+
+# TypeScript型チェック
+pnpm run lint:typecheck
+```
+
+## テスト
+```bash
+# 【推奨】Vitestテスト実行
+pnpm run test:vitest
+
+# 【過渡期】Jest(統合テスト)(廃止予定)
+pnpm run test:jest
+
+# 全てのテスト実行(過渡期対応)
+pnpm run test
+
+# Vitestで特定のファイルに絞って実行
+pnpm run test:vitest {target-file-name}
+
+# E2Eテスト(Playwright)
+npx playwright test
+```
+
+## データベース関連
+```bash
+# マイグレーション実行
+cd apps/app && pnpm run migrate
+
+# 開発環境でのマイグレーション
+cd apps/app && pnpm run dev:migrate
+
+# マイグレーション状態確認
+cd apps/app && pnpm run dev:migrate:status
+```
+
+## その他の便利コマンド
+```bash
+# REPL起動
+cd apps/app && pnpm run repl
+
+# OpenAPI仕様生成
+cd apps/app && pnpm run openapi:generate-spec:apiv3
+
+# クリーンアップ
+cd apps/app && pnpm run clean
+```
+
+## 注意事項
+- ESLintとJestは廃止予定のため、新規開発ではBiomeとVitestを使用してください
+- 既存のコードは段階的に移行中です

+ 95 - 0
.serena/memories/task_completion_checklist.md

@@ -0,0 +1,95 @@
+# タスク完了時のチェックリスト
+
+## コードを書いた後に必ず実行すべきコマンド
+
+### 1. Lint・フォーマットの実行
+```bash
+# 【推奨】Biome実行(新規開発)
+pnpm run lint:biome
+
+# 【過渡期】全てのLint実行(既存コード)
+pnpm run lint
+
+# 個別実行(必要に応じて)
+pnpm run lint:eslint      # ESLint(廃止予定)
+pnpm run lint:styles      # Stylelint
+pnpm run lint:typecheck   # TypeScript型チェック
+```
+
+### 2. テストの実行
+```bash
+# 【推奨】Vitestテスト実行(新規開発)
+pnpm run test:vitest
+
+# 【過渡期】全てのテスト実行(既存コード)
+pnpm run test
+
+# 個別実行
+pnpm run test:jest        # Jest(廃止予定)
+pnpm run test:vitest {target-file-name}     # Vitest
+```
+
+### 3. E2Eテストの実行(重要な機能変更時)
+```bash
+cd apps/app
+npx playwright test
+```
+
+### 4. ビルドの確認
+```bash
+# メインアプリケーションのビルド
+pnpm run app:build
+
+# 関連パッケージのビルド
+turbo run build
+```
+
+### 5. 動作確認
+```bash
+# 開発サーバーでの動作確認
+cd apps/app && pnpm run dev
+
+# または本番ビルドでの確認
+pnpm start
+```
+
+## 特別な確認事項
+
+### OpenAPI仕様の確認(API変更時)
+```bash
+cd apps/app
+pnpm run openapi:generate-spec:apiv3
+pnpm run lint:openapi:apiv3
+```
+
+### データベーススキーマ変更時
+```bash
+cd apps/app
+pnpm run dev:migrate:status  # 現在の状態確認
+pnpm run dev:migrate         # マイグレーション実行
+```
+
+## テストファイル作成時の注意
+
+### 新規テストファイル
+- **単体テスト**: `*.spec.{ts,js}` (Node.js環境)
+- **統合テスト**: `*.integ.ts` (Node.js + MongoDB環境)  
+- **コンポーネントテスト**: `*.spec.{tsx,jsx}` (happy-dom環境)
+- test-with-vite/ または対象ファイルと同じディレクトリに配置
+
+### 既存テストの修正
+- test/ 配下のJestテストは段階的に移行
+- 可能であればtest-with-vite/にVitestテストとして書き直し
+
+## コミット前の最終チェック
+1. Biome(または過渡期はESLint)エラーが解消されているか
+2. Vitestテスト(または過渡期はJest)がパスしているか
+3. 重要な変更はPlaywright E2Eテストも実行
+4. ビルドが成功するか
+5. 変更による既存機能への影響がないか
+6. 適切なコミットメッセージを作成したか
+
+## 移行期間中の注意事項
+- 新規開発: Biome + Vitest を使用
+- 既存コード修正: 可能な限り Biome + Vitest に移行
+- レガシーツールは段階的に廃止予定

+ 42 - 0
.serena/memories/tech_stack.md

@@ -0,0 +1,42 @@
+# 技術スタック
+
+## プログラミング言語
+- **TypeScript**: メイン言語(~5.0.0)
+- **JavaScript**: 一部のコンポーネント
+
+## フロントエンド
+- **Next.js**: Reactベースのフレームワーク
+- **React**: UIライブラリ
+- **Vite**: ビルドツール、開発サーバー
+- **SCSS**: スタイルシート
+- **SWR**: グローバルステート管理、データフェッチ・キャッシュ管理(^2.3.2)
+
+## バックエンド
+- **Node.js**: ランタイム(^20 || ^22)
+- **Express.js**: Webフレームワーク(推測)
+- **MongoDB**: データベース
+- **Mongoose**: MongoDB用ORM(^6.13.6)
+  - mongoose-gridfs: GridFS対応(^1.2.42)
+  - mongoose-paginate-v2: ページネーション(^1.3.9)
+  - mongoose-unique-validator: バリデーション(^2.0.3)
+
+## 開発ツール
+- **pnpm**: パッケージマネージャー(10.4.1)
+- **Turbo**: モノレポビルドシステム(^2.1.3)
+- **ESLint**: Linter(weseek設定を使用)【廃止予定 - 現在は過渡期】
+- **Biome**: 統一予定のLinter/Formatter
+- **Stylelint**: CSS/SCSSのLinter
+- **Jest**: テスティングフレームワーク【廃止予定 - 現在は過渡期】
+- **Vitest**: 高速テスティングフレームワーク【統一予定】
+- **Playwright**: E2Eテスト【統一予定】
+
+## その他のツール
+- **SWC**: TypeScriptコンパイラー(高速)
+- **ts-node**: TypeScript直接実行
+- **nodemon**: 開発時のホットリロード
+- **dotenv-flow**: 環境変数管理
+- **Swagger/OpenAPI**: API仕様
+
+## 移行計画
+- **Linter**: ESLint → Biome に統一予定
+- **テスト**: Jest → Vitest + Playwright に統一予定

+ 68 - 0
.serena/project.yml

@@ -0,0 +1,68 @@
+# language of the project (csharp, python, rust, java, typescript, go, cpp, or ruby)
+#  * For C, use cpp
+#  * For JavaScript, use typescript
+# Special requirements:
+#  * csharp: Requires the presence of a .sln file in the project folder.
+language: typescript
+
+# whether to use the project's gitignore file to ignore files
+# Added on 2025-04-07
+ignore_all_files_in_gitignore: true
+# list of additional paths to ignore
+# same syntax as gitignore, so you can use * and **
+# Was previously called `ignored_dirs`, please update your config if you are using that.
+# Added (renamed) on 2025-04-07
+ignored_paths: []
+
+# whether the project is in read-only mode
+# If set to true, all editing tools will be disabled and attempts to use them will result in an error
+# Added on 2025-04-18
+read_only: false
+
+
+# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
+# Below is the complete list of tools for convenience.
+# To make sure you have the latest list of tools, and to view their descriptions, 
+# execute `uv run scripts/print_tool_overview.py`.
+#
+#  * `activate_project`: Activates a project by name.
+#  * `check_onboarding_performed`: Checks whether project onboarding was already performed.
+#  * `create_text_file`: Creates/overwrites a file in the project directory.
+#  * `delete_lines`: Deletes a range of lines within a file.
+#  * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
+#  * `execute_shell_command`: Executes a shell command.
+#  * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
+#  * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
+#  * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
+#  * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
+#  * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
+#  * `initial_instructions`: Gets the initial instructions for the current project.
+#     Should only be used in settings where the system prompt cannot be set,
+#     e.g. in clients you have no control over, like Claude Desktop.
+#  * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
+#  * `insert_at_line`: Inserts content at a given line in a file.
+#  * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
+#  * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
+#  * `list_memories`: Lists memories in Serena's project-specific memory store.
+#  * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
+#  * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
+#  * `read_file`: Reads a file within the project directory.
+#  * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
+#  * `remove_project`: Removes a project from the Serena configuration.
+#  * `replace_lines`: Replaces a range of lines within a file with new content.
+#  * `replace_symbol_body`: Replaces the full definition of a symbol.
+#  * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
+#  * `search_for_pattern`: Performs a search for a pattern in the project.
+#  * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
+#  * `switch_modes`: Activates modes by providing a list of their names
+#  * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
+#  * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
+#  * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
+#  * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
+excluded_tools: []
+
+# initial prompt for the project. It will always be given to the LLM upon activating the project
+# (contrary to the memories, which are loaded on demand).
+initial_prompt: ""
+
+project_name: "growi"

+ 20 - 0
.vscode/mcp.json

@@ -0,0 +1,20 @@
+{
+  "servers": {
+    "context7": {
+      "type": "http",
+      "url": "https://mcp.context7.com/mcp"
+    },
+    "serena": {
+      "type": "stdio",
+      "command": "uvx",
+      "args": [
+        "--from",
+        "git+https://github.com/oraios/serena",
+        "serena",
+        "start-mcp-server",
+        "--context",
+        "ide-assistant"
+      ]
+    }
+  }
+}

+ 2 - 1
.vscode/settings.json

@@ -96,6 +96,7 @@
     {
       "text": "Always write commit messages in English."
     }
-  ]
+  ],
+  "git-worktree-menu.worktreeDir": "/workspace"
 
 }

Разница между файлами не показана из-за своего большого размера
+ 129 - 116
CHANGELOG.md


+ 95 - 0
CLAUDE.md

@@ -0,0 +1,95 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Language
+
+If it is detected at the start or during a session that the user's primary language is not English, always respond in that language from then on. However, technical terms may remain in English as needed.
+
+## Project Overview
+
+GROWI is a team collaboration software using markdown - a wiki platform with hierarchical page organization. It's built with Next.js, Express, MongoDB, and includes features like real-time collaborative editing, authentication integrations, and plugin support.
+
+## Development Commands
+
+### Core Development
+- `turbo run bootstrap` - Install dependencies for all workspace packages
+- `turbo run dev` - Start development server (automatically runs migrations and pre-builds styles)
+
+### Production Commands
+- `pnpm run app:build` - Build GROWI app client and server for production
+- `pnpm run app:server` - Launch GROWI app server in production mode
+- `pnpm start` - Build and start the application (runs both build and server commands)
+
+### Database Migrations
+- `pnpm run migrate` - Run MongoDB migrations (production)
+- `turbo run dev:migrate @apps/app` - Run migrations in development (or wait for automatic execution with dev)
+- `cd apps/app && pnpm run dev:migrate:status` - Check migration status
+- `cd apps/app && pnpm run dev:migrate:down` - Rollback last migration
+
+### Testing and Quality
+- `turbo run test @apps/app` - Run Jest and Vitest test suites with coverage
+- `turbo run lint @apps/app` - Run all linters (TypeScript, ESLint, Biome, Stylelint, OpenAPI)
+- `cd apps/app && pnpm run lint:typecheck` - TypeScript type checking only
+- `cd apps/app && pnpm run test:vitest` - Run Vitest unit tests
+- `cd apps/app && pnpm run test:jest` - Run Jest integration tests
+
+### Development Utilities  
+- `cd apps/app && pnpm run repl` - Start Node.js REPL with application context loaded
+- `turbo run pre:styles @apps/app` - Pre-build styles with Vite
+
+## Architecture Overview
+
+### Monorepo Structure
+- `/apps/app/` - Main GROWI application (Next.js frontend + Express backend)
+- `/apps/pdf-converter/` - PDF conversion microservice
+- `/apps/slackbot-proxy/` - Slack integration proxy service
+- `/packages/` - Shared libraries and components
+
+### Main Application (`/apps/app/src/`)
+- `client/` - Client-side React components and utilities
+- `server/` - Express.js backend (API routes, models, services)  
+- `components/` - Shared React components and layouts
+- `pages/` - Next.js page components using file-based routing
+- `stores/` - State management (SWR-based stores with React context)
+- `styles/` - SCSS stylesheets with modular architecture
+- `migrations/` - MongoDB database migration scripts
+- `interfaces/` - TypeScript type definitions
+
+### Key Technical Details
+- **Frontend**: Next.js 14 with React 18, TypeScript, SCSS modules
+- **Backend**: Express.js with TypeScript, MongoDB with Mongoose
+- **State Management**: SWR for server state, React Context for client state
+- **Authentication**: Passport.js with multiple strategies (local, LDAP, OAuth, SAML)
+- **Real-time Features**: Socket.io for collaborative editing and notifications
+- **Editor**: Custom markdown editor with collaborative editing using Yjs
+- **Database**: MongoDB 8.0+ with migration system using migrate-mongo
+- **Package Manager**: pnpm with workspace support
+- **Build System**: Turborepo for monorepo orchestration
+
+### Development Dependencies
+- Node.js v20.x or v22.x
+- pnpm 10.x  
+- MongoDB v6.x or v8.x
+- Optional: Redis 3.x, Elasticsearch 7.x/8.x/9.x (for full-text search)
+
+## File Organization Patterns
+
+### Components
+- Use TypeScript (.tsx) for React components
+- Co-locate styles as `.module.scss` files
+- Export components through `index.ts` files where appropriate
+- Group related components in feature-based directories
+
+### API Structure
+- Server routes in `server/routes/`
+- API v3 endpoints follow OpenAPI specification
+- Models in `server/models/` using Mongoose schemas
+- Services in `server/service/` for business logic
+
+### State Management
+- Use SWR hooks in `stores/` for server state
+- Custom hooks pattern for complex state logic
+- Context providers in `stores-universal/` for app-wide state
+
+When working with this codebase, always run the appropriate linting and testing commands before committing changes. The application uses strict TypeScript checking and comprehensive test coverage requirements.

+ 1 - 1
LICENSE

@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2018 WESEEK, Inc.
+Copyright (c) 2018 GROWI, Inc.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 13 - 13
README.md

@@ -6,7 +6,7 @@
   </a>
 </p>
 <p align="center">
-  <a href="https://github.com/weseek/growi/releases/latest"><img src="https://img.shields.io/github/release/weseek/growi.svg" alt="Latest version"></a>
+  <a href="https://github.com/growilabs/growi/releases/latest"><img src="https://img.shields.io/github/release/growilabs/growi.svg" alt="Latest version"></a>
   <a href="https://communityinviter.com/apps/wsgrowi/invite/"><img src="https://img.shields.io/badge/Slack-Join%20Us-4A154B?style=flat&logo=slack&logoColor=white" alt="Slack - Join US"></a>
 </p>
 
@@ -17,9 +17,9 @@
 # GROWI
 
 [![docker pulls](https://img.shields.io/docker/pulls/weseek/growi.svg)](https://hub.docker.com/r/weseek/growi/)
-[![CodeQL](https://github.com/weseek/growi/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/weseek/growi/actions/workflows/codeql-analysis.yml)
-[![Node CI for app development](https://github.com/weseek/growi/actions/workflows/ci-app.yml/badge.svg)](https://github.com/weseek/growi/actions/workflows/ci-app.yml)
-[![Node CI for app production](https://github.com/weseek/growi/actions/workflows/ci-app-prod.yml/badge.svg)](https://github.com/weseek/growi/actions/workflows/ci-app-prod.yml)
+[![CodeQL](https://github.com/growilabs/growi/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/growilabs/growi/actions/workflows/codeql-analysis.yml)
+[![Node CI for app development](https://github.com/growilabs/growi/actions/workflows/ci-app.yml/badge.svg)](https://github.com/growilabs/growi/actions/workflows/ci-app.yml)
+[![Node CI for app production](https://github.com/growilabs/growi/actions/workflows/ci-app-prod.yml/badge.svg)](https://github.com/growilabs/growi/actions/workflows/ci-app-prod.yml)
 
 ## Demonstration
 <video src="https://private-user-images.githubusercontent.com/34241526/333079483-fee540d7-2fa6-46d7-833e-74014c5340e3.mp4?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MTY0NDk2OTEsIm5iZiI6MTcxNjQ0OTM5MSwicGF0aCI6Ii8zNDI0MTUyNi8zMzMwNzk0ODMtZmVlNTQwZDctMmZhNi00NmQ3LTgzM2UtNzQwMTRjNTM0MGUzLm1wND9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA1MjMlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNTIzVDA3Mjk1MVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTBkYWFkMmYyYmIwMTI2YWE3ZmQzZTFiNWU3ZThkMDc5NDA5N2Q3YWE5ZGM1NDgwNjk0OGNjYjZmOTJkM2IzZGQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.FAvLseWBzE62yFA7wt26uERamvEVQdIGRVdBwk0uLhE"></video>
@@ -81,11 +81,11 @@ See [GROWI Docs: Environment Variables](https://docs.growi.org/en/admin-guide/ad
 
 ## Dependencies
 
-- Node.js v18.x or v20.x
-- npm 6.x
-- pnpm 9.x
+- Node.js v20.x or v22.x
+- npm 10.x
+- pnpm 10.x
 - [Turborepo](https://turbo.build/repo)
-- MongoDB 6.0 or above
+- MongoDB v6.x or v8.x
 
 ### Optional Dependencies
 
@@ -138,11 +138,11 @@ If you have questions or suggestions, you can [join our Slack team](https://comm
 # License
 
 - The MIT License (MIT)
-- See [LICENSE](https://github.com/weseek/growi/blob/master/LICENSE) and [THIRD-PARTY-NOTICES.md](https://github.com/weseek/growi/blob/master/THIRD-PARTY-NOTICES.md).
+- See [LICENSE](https://github.com/growilabs/growi/blob/master/LICENSE) and [THIRD-PARTY-NOTICES.md](https://github.com/growilabs/growi/blob/master/THIRD-PARTY-NOTICES.md).
 
 [crowi]: https://github.com/crowi/crowi
-[growi]: https://github.com/weseek/growi
-[issues]: https://github.com/weseek/growi/issues
-[pulls]: https://github.com/weseek/growi/pulls
+[growi]: https://github.com/growilabs/growi
+[issues]: https://github.com/growilabs/growi/issues
+[pulls]: https://github.com/growilabs/growi/pulls
 [dockerhub]: https://hub.docker.com/r/weseek/growi
-[docker-compose]: https://github.com/weseek/growi-docker-compose
+[docker-compose]: https://github.com/growilabs/growi-docker-compose

+ 13 - 13
README_JP.md

@@ -6,7 +6,7 @@
   </a>
 </p>
 <p align="center">
-  <a href="https://github.com/weseek/growi/releases/latest"><img src="https://img.shields.io/github/release/weseek/growi.svg" alt="Latest version"></a>
+  <a href="https://github.com/growilabs/growi/releases/latest"><img src="https://img.shields.io/github/release/growilabs/growi.svg" alt="Latest version"></a>
   <a href="https://communityinviter.com/apps/wsgrowi/invite/"><img src="https://img.shields.io/badge/Slack-Join%20Us-4A154B?style=flat&logo=slack&logoColor=white" alt="Slack - Join US"></a>
 </p>
 
@@ -17,9 +17,9 @@
 # GROWI
 
 [![docker pulls](https://img.shields.io/docker/pulls/weseek/growi.svg)](https://hub.docker.com/r/weseek/growi/)
-[![CodeQL](https://github.com/weseek/growi/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/weseek/growi/actions/workflows/codeql-analysis.yml)
-[![Node CI for app development](https://github.com/weseek/growi/actions/workflows/ci-app.yml/badge.svg)](https://github.com/weseek/growi/actions/workflows/ci-app.yml)
-[![Node CI for app production](https://github.com/weseek/growi/actions/workflows/ci-app-prod.yml/badge.svg)](https://github.com/weseek/growi/actions/workflows/ci-app-prod.yml)
+[![CodeQL](https://github.com/growilabs/growi/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/growilabs/growi/actions/workflows/codeql-analysis.yml)
+[![Node CI for app development](https://github.com/growilabs/growi/actions/workflows/ci-app.yml/badge.svg)](https://github.com/growilabs/growi/actions/workflows/ci-app.yml)
+[![Node CI for app production](https://github.com/growilabs/growi/actions/workflows/ci-app-prod.yml/badge.svg)](https://github.com/growilabs/growi/actions/workflows/ci-app-prod.yml)
 
 ## デモ
 <video src="https://private-user-images.githubusercontent.com/34241526/333079216-cec7f7d8-c3cc-4ee7-bc94-167b056d4ce2.mp4?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MTY0NDk0MDQsIm5iZiI6MTcxNjQ0OTEwNCwicGF0aCI6Ii8zNDI0MTUyNi8zMzMwNzkyMTYtY2VjN2Y3ZDgtYzNjYy00ZWU3LWJjOTQtMTY3YjA1NmQ0Y2UyLm1wND9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA1MjMlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNTIzVDA3MjUwNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWQ2M2IwZjc0ZGNhOWQxNWE4MGIyZTZlMzQ0ZDQ4MGZlNjEzMWE3MTQ1YmMwYzg3MmY1NWMyZWI2NzQ3NGIwMTkmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.qLfu5120JrkdfpghXlLG8wCn0p4JNZ7W8AD3zUJTIYY"></video>
@@ -81,11 +81,11 @@ Crowi からの移行は **[こちら](https://docs.growi.org/en/admin-guide/mig
 
 ## 依存関係
 
-- Node.js v18.x or v20.x
-- npm 6.x
-- pnpm 9.x
+- Node.js v20.x or v22.x
+- npm 10.x
+- pnpm 10.x
 - [Turborepo](https://turbo.build/repo)
-- MongoDB 6.0 以上
+- MongoDB v6.x or v8.x
 
 ### オプションの依存関係
 
@@ -137,11 +137,11 @@ Issue と Pull requests の作成は英語・日本語どちらでも受け付
 # ライセンス
 
 - The MIT License (MIT)
-- [ライセンス](https://github.com/weseek/growi/blob/master/LICENSE) と [THIRD-PARTY-NOTICES.md](https://github.com/weseek/growi/blob/master/THIRD-PARTY-NOTICES.md) をご覧ください。
+- [ライセンス](https://github.com/growilabs/growi/blob/master/LICENSE) と [THIRD-PARTY-NOTICES.md](https://github.com/growilabs/growi/blob/master/THIRD-PARTY-NOTICES.md) をご覧ください。
 
   [crowi]: https://github.com/crowi/crowi
-  [growi]: https://github.com/weseek/growi
-  [issues]: https://github.com/weseek/growi/issues
-  [pulls]: https://github.com/weseek/growi/pulls
+  [growi]: https://github.com/growilabs/growi
+  [issues]: https://github.com/growilabs/growi/issues
+  [pulls]: https://github.com/growilabs/growi/pulls
   [dockerhub]: https://hub.docker.com/r/weseek/growi
-  [docker-compose]: https://github.com/weseek/growi-docker-compose
+  [docker-compose]: https://github.com/growilabs/growi-docker-compose

+ 1 - 1
THIRD-PARTY-NOTICES.md

@@ -9,7 +9,7 @@ please bring it to our attention through any of the ways detailed here :
 The attached notices are provided for information only.
 
 For any licenses that require disclosure of source, sources are available at  
-https://github.com/weseek/growi.
+https://github.com/growilabs/growi.
 
 
 1. Apache License, Version 2.0 Derivative Works

+ 3 - 2
apps/app/.env.development

@@ -14,7 +14,6 @@ ELASTICSEARCH_URI="http://elasticsearch:9200/growi"
 ELASTICSEARCH_REQUEST_TIMEOUT=15000
 ELASTICSEARCH_REJECT_UNAUTHORIZED=true
 OGP_URI="http://ogp:8088"
-QUESTIONNAIRE_SERVER_ORIGIN="http://host.docker.internal:3003"
 # DRAWIO_URI="http://localhost:8080/?offline=1&https=0"
 # S2SMSG_PUBSUB_SERVER_TYPE=nchan
 # PUBLISH_OPEN_API=true
@@ -31,7 +30,9 @@ QUESTIONNAIRE_SERVER_ORIGIN="http://host.docker.internal:3003"
 # AUDIT_LOG_ADDITIONAL_ACTIONS=
 # AUDIT_LOG_EXCLUDE_ACTIONS=
 
-# OpenTelemetry Official Configuration
+SERVICE_TYPE=dev
+
+# OpenTelemetry Official Configuration for dev
 # Environment variables starting with 'OTEL_' are automatically loaded by the OpenTelemetry SDK
 OPENTELEMETRY_ENABLED=false
 OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317

+ 1 - 1
apps/app/.env.production

@@ -7,6 +7,6 @@ MIGRATIONS_DIR=dist/migrations/
 
 # OpenTelemetry Official Configuration
 # Environment variables starting with 'OTEL_' are automatically loaded by the OpenTelemetry SDK
-OTEL_TRACES_SAMPLER_ARG=0.1
+OTEL_TRACES_SAMPLER_ARG=0.01
 OTEL_METRIC_EXPORT_INTERVAL=300000
 OTEL_EXPORTER_OTLP_ENDPOINT="https://telemetry.growi.org"

+ 26 - 0
apps/app/.eslintrc.js

@@ -16,6 +16,32 @@ module.exports = {
     'src/linter-checker/**',
     'tmp/**',
     'next-env.d.ts',
+    'next.config.js',
+    'playwright.config.ts',
+    'test/integration/global-setup.js',
+    'test/integration/global-teardown.js',
+    'test/integration/setup-crowi.ts',
+    'test/integration/crowi/**',
+    'test/integration/middlewares/**',
+    'test/integration/migrations/**',
+    'test/integration/models/**',
+    'test/integration/setup.js',
+    'bin/**',
+    'config/**',
+    'src/linter-checker/**',
+    'src/migrations/**',
+    'src/features/callout/**',
+    'src/features/comment/**',
+    'src/features/templates/**',
+    'src/features/mermaid/**',
+    'src/features/search/**',
+    'src/features/plantuml/**',
+    'src/features/external-user-group/**',
+    'src/features/page-bulk-export/**',
+    'src/features/opentelemetry/**',
+    'src/stores-universal/**',
+    'src/interfaces/**',
+    'src/utils/**',
   ],
   settings: {
     // resolve path aliases by eslint-import-resolver-typescript

+ 2 - 1
apps/app/bin/openapi/definition-apiv1.js

@@ -12,7 +12,8 @@ module.exports = {
       variables: {
         server: {
           default: 'https://demo.growi.org',
-          description: 'The base URL for the GROWI API except for the version path (/_api). This can be set to your GROWI instance URL.',
+          description:
+            'The base URL for the GROWI API except for the version path (/_api). This can be set to your GROWI instance URL.',
         },
       },
     },

+ 3 - 13
apps/app/bin/openapi/definition-apiv3.js

@@ -12,7 +12,8 @@ module.exports = {
       variables: {
         server: {
           default: 'https://demo.growi.org',
-          description: 'The base URL for the GROWI API except for the version path (/_api/v3). This can be set to your GROWI instance URL.',
+          description:
+            'The base URL for the GROWI API except for the version path (/_api/v3). This can be set to your GROWI instance URL.',
         },
       },
     },
@@ -98,8 +99,6 @@ module.exports = {
         'MongoDB',
         'NotificationSetting',
         'Plugins',
-        'Questionnaire',
-        'QuestionnaireSetting',
         'SlackIntegration',
         'SlackIntegrationSettings',
         'SlackIntegrationSettings (with proxy)',
@@ -117,16 +116,7 @@ module.exports = {
     },
     {
       name: 'Public API',
-      tags: [
-        'Healthcheck',
-        'Statistics',
-        '',
-        '',
-        '',
-        '',
-        '',
-        '',
-      ],
+      tags: ['Healthcheck', 'Statistics', '', '', '', '', '', ''],
     },
   ],
 };

+ 14 - 10
apps/app/bin/openapi/generate-operation-ids/cli.spec.ts

@@ -1,8 +1,6 @@
 import { writeFileSync } from 'fs';
 
-import {
-  beforeEach, describe, expect, it, vi,
-} from 'vitest';
+import { beforeEach, describe, expect, it, vi } from 'vitest';
 
 import { generateOperationIds } from './generate-operation-ids';
 
@@ -23,7 +21,7 @@ describe('cli', () => {
     vi.spyOn(console, 'error').mockImplementation(() => {});
   });
 
-  it('processes input file and writes output to specified file', async() => {
+  it('processes input file and writes output to specified file', async () => {
     // Mock generateOperationIds to return success
     vi.mocked(generateOperationIds).mockResolvedValue(mockJsonStrings);
 
@@ -35,13 +33,15 @@ describe('cli', () => {
     await cliModule.main();
 
     // Verify generateOperationIds was called with correct arguments
-    expect(generateOperationIds).toHaveBeenCalledWith('input.json', { overwriteExisting: undefined });
+    expect(generateOperationIds).toHaveBeenCalledWith('input.json', {
+      overwriteExisting: undefined,
+    });
 
     // Verify writeFileSync was called with correct arguments
     expect(writeFileSync).toHaveBeenCalledWith('output.json', mockJsonStrings);
   });
 
-  it('uses input file as output when no output file is specified', async() => {
+  it('uses input file as output when no output file is specified', async () => {
     // Mock generateOperationIds to return success
     vi.mocked(generateOperationIds).mockResolvedValue(mockJsonStrings);
 
@@ -53,13 +53,15 @@ describe('cli', () => {
     await cliModule.main();
 
     // Verify generateOperationIds was called with correct arguments
-    expect(generateOperationIds).toHaveBeenCalledWith('input.json', { overwriteExisting: undefined });
+    expect(generateOperationIds).toHaveBeenCalledWith('input.json', {
+      overwriteExisting: undefined,
+    });
 
     // Verify writeFileSync was called with input file as output
     expect(writeFileSync).toHaveBeenCalledWith('input.json', mockJsonStrings);
   });
 
-  it('handles overwrite-existing option correctly', async() => {
+  it('handles overwrite-existing option correctly', async () => {
     // Mock generateOperationIds to return success
     vi.mocked(generateOperationIds).mockResolvedValue(mockJsonStrings);
 
@@ -71,10 +73,12 @@ describe('cli', () => {
     await cliModule.main();
 
     // Verify generateOperationIds was called with overwriteExisting option
-    expect(generateOperationIds).toHaveBeenCalledWith('input.json', { overwriteExisting: true });
+    expect(generateOperationIds).toHaveBeenCalledWith('input.json', {
+      overwriteExisting: true,
+    });
   });
 
-  it('handles generateOperationIds error correctly', async() => {
+  it('handles generateOperationIds error correctly', async () => {
     // Mock generateOperationIds to throw error
     const error = new Error('Test error');
     vi.mocked(generateOperationIds).mockRejectedValue(error);

+ 5 - 4
apps/app/bin/openapi/generate-operation-ids/cli.ts

@@ -1,10 +1,9 @@
-import { writeFileSync } from 'fs';
-
 import { Command } from 'commander';
+import { writeFileSync } from 'fs';
 
 import { generateOperationIds } from './generate-operation-ids';
 
-export const main = async(): Promise<void> => {
+export const main = async (): Promise<void> => {
   // parse command line arguments
   const program = new Command();
   program
@@ -18,7 +17,9 @@ export const main = async(): Promise<void> => {
   const [inputFile] = program.args;
 
   // eslint-disable-next-line no-console
-  const jsonStrings = await generateOperationIds(inputFile, { overwriteExisting }).catch(console.error);
+  const jsonStrings = await generateOperationIds(inputFile, {
+    overwriteExisting,
+  }).catch(console.error);
   if (jsonStrings != null) {
     writeFileSync(outputFile ?? inputFile, jsonStrings);
   }

+ 29 - 31
apps/app/bin/openapi/generate-operation-ids/generate-operation-ids.spec.ts

@@ -1,13 +1,11 @@
 import fs from 'fs/promises';
+import type { OpenAPI3 } from 'openapi-typescript';
 import { tmpdir } from 'os';
 import path from 'path';
-
-import type { OpenAPI3 } from 'openapi-typescript';
 import { describe, expect, it } from 'vitest';
 
 import { generateOperationIds } from './generate-operation-ids';
 
-
 async function createTempOpenAPIFile(spec: OpenAPI3): Promise<string> {
   const tempDir = await fs.mkdtemp(path.join(tmpdir(), 'openapi-test-'));
   const filePath = path.join(tempDir, 'openapi.json');
@@ -19,15 +17,14 @@ async function cleanup(filePath: string): Promise<void> {
   try {
     await fs.unlink(filePath);
     await fs.rmdir(path.dirname(filePath));
-  }
-  catch (err) {
+  } catch (err) {
     // eslint-disable-next-line no-console
     console.error('Cleanup failed:', err);
   }
 }
 
 describe('generateOperationIds', () => {
-  it('should generate correct operationId for simple paths', async() => {
+  it('should generate correct operationId for simple paths', async () => {
     const spec: OpenAPI3 = {
       openapi: '3.0.0',
       info: { title: 'Test API', version: '1.0.0' },
@@ -46,13 +43,12 @@ describe('generateOperationIds', () => {
 
       expect(parsed.paths['/foo'].get.operationId).toBe('getFoo');
       expect(parsed.paths['/foo'].post.operationId).toBe('postFoo');
-    }
-    finally {
+    } finally {
       await cleanup(filePath);
     }
   });
 
-  it('should generate correct operationId for paths with parameters', async() => {
+  it('should generate correct operationId for paths with parameters', async () => {
     const spec: OpenAPI3 = {
       openapi: '3.0.0',
       info: { title: 'Test API', version: '1.0.0' },
@@ -72,14 +68,15 @@ describe('generateOperationIds', () => {
       const parsed = JSON.parse(result);
 
       expect(parsed.paths['/foo/{id}'].get.operationId).toBe('getFooById');
-      expect(parsed.paths['/foo/{id}/bar/{page}'].get.operationId).toBe('getBarByPageByIdForFoo');
-    }
-    finally {
+      expect(parsed.paths['/foo/{id}/bar/{page}'].get.operationId).toBe(
+        'getBarByPageByIdForFoo',
+      );
+    } finally {
       await cleanup(filePath);
     }
   });
 
-  it('should generate correct operationId for nested resources', async() => {
+  it('should generate correct operationId for nested resources', async () => {
     const spec: OpenAPI3 = {
       openapi: '3.0.0',
       info: { title: 'Test API', version: '1.0.0' },
@@ -96,13 +93,12 @@ describe('generateOperationIds', () => {
       const parsed = JSON.parse(result);
 
       expect(parsed.paths['/foo/bar'].get.operationId).toBe('getBarForFoo');
-    }
-    finally {
+    } finally {
       await cleanup(filePath);
     }
   });
 
-  it('should preserve existing operationId when overwriteExisting is false', async() => {
+  it('should preserve existing operationId when overwriteExisting is false', async () => {
     const existingOperationId = 'existingOperation';
     const spec: OpenAPI3 = {
       openapi: '3.0.0',
@@ -118,17 +114,18 @@ describe('generateOperationIds', () => {
 
     const filePath = await createTempOpenAPIFile(spec);
     try {
-      const result = await generateOperationIds(filePath, { overwriteExisting: false });
+      const result = await generateOperationIds(filePath, {
+        overwriteExisting: false,
+      });
       const parsed = JSON.parse(result);
 
       expect(parsed.paths['/foo'].get.operationId).toBe(existingOperationId);
-    }
-    finally {
+    } finally {
       await cleanup(filePath);
     }
   });
 
-  it('should overwrite existing operationId when overwriteExisting is true', async() => {
+  it('should overwrite existing operationId when overwriteExisting is true', async () => {
     const spec: OpenAPI3 = {
       openapi: '3.0.0',
       info: { title: 'Test API', version: '1.0.0' },
@@ -143,17 +140,18 @@ describe('generateOperationIds', () => {
 
     const filePath = await createTempOpenAPIFile(spec);
     try {
-      const result = await generateOperationIds(filePath, { overwriteExisting: true });
+      const result = await generateOperationIds(filePath, {
+        overwriteExisting: true,
+      });
       const parsed = JSON.parse(result);
 
       expect(parsed.paths['/foo'].get.operationId).toBe('getFoo');
-    }
-    finally {
+    } finally {
       await cleanup(filePath);
     }
   });
 
-  it('should generate correct operationId for root path', async() => {
+  it('should generate correct operationId for root path', async () => {
     const spec: OpenAPI3 = {
       openapi: '3.0.0',
       info: { title: 'Test API', version: '1.0.0' },
@@ -170,13 +168,12 @@ describe('generateOperationIds', () => {
       const parsed = JSON.parse(result);
 
       expect(parsed.paths['/'].get.operationId).toBe('getRoot');
-    }
-    finally {
+    } finally {
       await cleanup(filePath);
     }
   });
 
-  it('should generate operationId for all HTTP methods', async() => {
+  it('should generate operationId for all HTTP methods', async () => {
     const spec: OpenAPI3 = {
       openapi: '3.0.0',
       info: { title: 'Test API', version: '1.0.0' },
@@ -207,13 +204,14 @@ describe('generateOperationIds', () => {
       expect(parsed.paths['/foo'].options.operationId).toBe('optionsFoo');
       expect(parsed.paths['/foo'].head.operationId).toBe('headFoo');
       expect(parsed.paths['/foo'].trace.operationId).toBe('traceFoo');
-    }
-    finally {
+    } finally {
       await cleanup(filePath);
     }
   });
 
-  it('should throw error for non-existent file', async() => {
-    await expect(generateOperationIds('non-existent-file.json')).rejects.toThrow();
+  it('should throw error for non-existent file', async () => {
+    await expect(
+      generateOperationIds('non-existent-file.json'),
+    ).rejects.toThrow();
   });
 });

+ 42 - 16
apps/app/bin/openapi/generate-operation-ids/generate-operation-ids.ts

@@ -1,15 +1,25 @@
 import SwaggerParser from '@apidevtools/swagger-parser';
-import type { OpenAPI3, OperationObject, PathItemObject } from 'openapi-typescript';
+import type {
+  OpenAPI3,
+  OperationObject,
+  PathItemObject,
+} from 'openapi-typescript';
 
-const toPascal = (s: string): string => s.split('-').map(w => w[0]?.toUpperCase() + w.slice(1)).join('');
+const toPascal = (s: string): string =>
+  s
+    .split('-')
+    .map((w) => w[0]?.toUpperCase() + w.slice(1))
+    .join('');
 
 const createParamSuffix = (params: string[]): string => {
   return params.length > 0
-    ? params.reverse().map(param => `By${toPascal(param.slice(1, -1))}`).join('')
+    ? params
+        .reverse()
+        .map((param) => `By${toPascal(param.slice(1, -1))}`)
+        .join('')
     : '';
 };
 
-
 /**
  * Generates a PascalCase operation name based on the HTTP method and path.
  *
@@ -24,8 +34,8 @@ const createParamSuffix = (params: string[]): string => {
  */
 function createOperationId(method: string, path: string): string {
   const segments = path.split('/').filter(Boolean);
-  const params = segments.filter(s => s.startsWith('{'));
-  const paths = segments.filter(s => !s.startsWith('{'));
+  const params = segments.filter((s) => s.startsWith('{'));
+  const paths = segments.filter((s) => !s.startsWith('{'));
 
   const paramSuffix = createParamSuffix(params);
 
@@ -37,19 +47,35 @@ function createOperationId(method: string, path: string): string {
   return `${method.toLowerCase()}${toPascal(resource)}${paramSuffix}For${context.reverse().map(toPascal).join('')}`;
 }
 
-export async function generateOperationIds(inputFile: string, opts?: { overwriteExisting: boolean }): Promise<string> {
-  const api = await SwaggerParser.parse(inputFile) as OpenAPI3;
+export async function generateOperationIds(
+  inputFile: string,
+  opts?: { overwriteExisting: boolean },
+): Promise<string> {
+  const api = (await SwaggerParser.parse(inputFile)) as OpenAPI3;
 
   Object.entries(api.paths || {}).forEach(([path, pathItem]) => {
     const item = pathItem as PathItemObject;
-    (['get', 'post', 'put', 'delete', 'patch', 'options', 'head', 'trace'] as const)
-      .forEach((method) => {
-        const operation = item[method] as OperationObject | undefined;
-        if (operation == null || (operation.operationId != null && !opts?.overwriteExisting)) {
-          return;
-        }
-        operation.operationId = createOperationId(method, path);
-      });
+    (
+      [
+        'get',
+        'post',
+        'put',
+        'delete',
+        'patch',
+        'options',
+        'head',
+        'trace',
+      ] as const
+    ).forEach((method) => {
+      const operation = item[method] as OperationObject | undefined;
+      if (
+        operation == null ||
+        (operation.operationId != null && !opts?.overwriteExisting)
+      ) {
+        return;
+      }
+      operation.operationId = createOperationId(method, path);
+    });
   });
 
   const output = JSON.stringify(api, null, 2);

+ 0 - 1
apps/app/bin/openapi/generate-spec-apiv3.sh

@@ -11,7 +11,6 @@ swagger-jsdoc \
   -o "${OUT}" \
   -d "${APP_PATH}/bin/openapi/definition-apiv3.js" \
   "${APP_PATH}/src/features/external-user-group/server/routes/apiv3/*.ts" \
-  "${APP_PATH}/src/features/questionnaire/server/routes/apiv3/*.ts" \
   "${APP_PATH}/src/features/templates/server/routes/apiv3/*.ts" \
   "${APP_PATH}/src/features/growi-plugin/server/routes/apiv3/**/*.ts" \
   "${APP_PATH}/src/server/routes/apiv3/**/*.{js,ts}" \

+ 8 - 2
apps/app/config/cdn.js

@@ -2,7 +2,13 @@ import path from 'path';
 
 import { projectRoot } from '~/utils/project-dir-utils';
 
-export const cdnLocalScriptRoot = path.join(projectRoot, 'public/static/js/cdn');
+export const cdnLocalScriptRoot = path.join(
+  projectRoot,
+  'public/static/js/cdn',
+);
 export const cdnLocalScriptWebRoot = '/static/js/cdn';
-export const cdnLocalStyleRoot = path.join(projectRoot, 'public/static/styles/cdn');
+export const cdnLocalStyleRoot = path.join(
+  projectRoot,
+  'public/static/styles/cdn',
+);
 export const cdnLocalStyleWebRoot = '/static/styles/cdn';

+ 1 - 1
apps/app/config/logger/config.dev.js

@@ -29,7 +29,6 @@ module.exports = {
   'growi-plugin:*': 'debug',
   'growi:service:search-delegator:elasticsearch': 'debug',
   'growi:service:g2g-transfer': 'debug',
-  'growi:service:questionnaire': 'debug',
 
   'growi:migration:add-installed-date-to-config': 'debug',
 
@@ -44,4 +43,5 @@ module.exports = {
   // 'growi:cli:ItemsTree': 'debug',
   'growi:searchResultList': 'debug',
   'growi:service:openai': 'debug',
+  'growi:middleware:access-token-parser:access-token': 'debug',
 };

+ 2 - 2
apps/app/config/migrate-mongo-config.js

@@ -9,8 +9,8 @@ const isProduction = process.env.NODE_ENV === 'production';
 const { URL } = require('url');
 
 const { getMongoUri, mongoOptions } = isProduction
-  // eslint-disable-next-line import/extensions, import/no-unresolved
-  ? require('../dist/server/util/mongoose-utils')
+  ? // eslint-disable-next-line import/extensions, import/no-unresolved
+    require('../dist/server/util/mongoose-utils')
   : require('../src/server/util/mongoose-utils');
 
 // get migrationsDir from env var

+ 4 - 8
apps/app/config/migrate-mongo-config.spec.ts

@@ -2,11 +2,8 @@ import mockRequire from 'mock-require';
 
 const { reRequire } = mockRequire;
 
-
 describe('config/migrate-mongo-config.js', () => {
-
   test.concurrent('throws an error when MIGRATIONS_DIR is not set', () => {
-
     const getMongoUriMock = vi.fn();
     const mongoOptionsMock = vi.fn();
 
@@ -32,13 +29,11 @@ describe('config/migrate-mongo-config.js', () => {
     ${'mongodb://user:pass@example.com/growi'}        | ${'growi'}
     ${'mongodb://example.com/growi?replicaSet=mySet'} | ${'growi'}
   `('returns', ({ MONGO_URI, expectedDbName }) => {
-
-    beforeEach(async() => {
+    beforeEach(async () => {
       process.env.MIGRATIONS_DIR = 'testdir/migrations';
     });
 
     test(`when 'MONGO_URI' is '${MONGO_URI}`, () => {
-
       const getMongoUriMock = vi.fn(() => MONGO_URI);
       const mongoOptionsMock = vi.fn();
 
@@ -49,7 +44,9 @@ describe('config/migrate-mongo-config.js', () => {
       });
 
       // use reRequire to avoid using module cache
-      const { mongodb, migrationsDir, changelogCollectionName } = reRequire('./migrate-mongo-config');
+      const { mongodb, migrationsDir, changelogCollectionName } = reRequire(
+        './migrate-mongo-config',
+      );
 
       mockRequire.stop('../src/server/util/mongoose-utils');
 
@@ -61,5 +58,4 @@ describe('config/migrate-mongo-config.js', () => {
       expect(changelogCollectionName).toBe('migrations');
     });
   });
-
 });

+ 6 - 7
apps/app/config/next-i18next.config.js

@@ -26,17 +26,17 @@ module.exports = {
     ? isServer()
       ? [new HMRPlugin({ webpack: { server: true } })]
       : [
-        require('i18next-chained-backend').default,
-        new HMRPlugin({ webpack: { client: true } }),
-      ]
+          require('i18next-chained-backend').default,
+          new HMRPlugin({ webpack: { client: true } }),
+        ]
     : [],
   backend: {
     backends: isServer()
       ? []
       : [
-        require('i18next-localstorage-backend').default,
-        require('i18next-http-backend').default,
-      ],
+          require('i18next-localstorage-backend').default,
+          require('i18next-http-backend').default,
+        ],
     backendOptions: [
       // options for i18next-localstorage-backend
       { expirationTime: isDev ? 0 : 24 * 60 * 60 * 1000 }, // 1 day in production
@@ -44,5 +44,4 @@ module.exports = {
       { loadPath: '/static/locales/{{lng}}/{{ns}}.json' },
     ],
   },
-
 };

+ 2 - 2
apps/app/docker/Dockerfile

@@ -6,7 +6,7 @@ ARG PNPM_HOME="/root/.local/share/pnpm"
 ##
 ## base
 ##
-FROM node:20-slim AS base
+FROM node:22-slim AS base
 
 ARG OPT_DIR
 ARG PNPM_HOME
@@ -72,7 +72,7 @@ RUN tar -zcf /tmp/packages.tar.gz \
 ##
 ## release
 ##
-FROM node:20-slim
+FROM node:22-slim
 LABEL maintainer="Yuki Takei <yuki@weseek.co.jp>"
 
 ARG OPT_DIR

+ 7 - 7
apps/app/docker/README.md

@@ -2,7 +2,7 @@
 GROWI Official docker image
 ========================
 
-[![Actions Status](https://github.com/weseek/growi/workflows/Release/badge.svg)](https://github.com/weseek/growi/actions) [![docker-pulls](https://img.shields.io/docker/pulls/weseek/growi.svg)](https://hub.docker.com/r/weseek/growi/) [![](https://images.microbadger.com/badges/image/weseek/growi.svg)](https://microbadger.com/images/weseek/growi)
+[![Actions Status](https://github.com/growilabs/growi/workflows/Release/badge.svg)](https://github.com/growilabs/growi/actions) [![docker-pulls](https://img.shields.io/docker/pulls/weseek/growi.svg)](https://hub.docker.com/r/weseek/growi/) [![](https://images.microbadger.com/badges/image/weseek/growi.svg)](https://microbadger.com/images/weseek/growi)
 
 ![GROWI-x-docker](https://github.com/user-attachments/assets/1a82236d-5a85-4a2e-842a-971b4c1625e6)
 
@@ -10,9 +10,9 @@ GROWI Official docker image
 Supported tags and respective Dockerfile links
 ------------------------------------------------
 
-* [`7.1.0`, `7.1`, `7`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v7.1.0/apps/app/docker/Dockerfile)
-* [`7.0.23`, `7.0` (Dockerfile)](https://github.com/weseek/growi/blob/v7.0.23/apps/app/docker/Dockerfile)
-* [`6.3.2`, `6.3`, `6` (Dockerfile)](https://github.com/weseek/growi/blob/v6.3.2/apps/app/docker/Dockerfile)
+* [`7.1.0`, `7.1`, `7`, `latest` (Dockerfile)](https://github.com/growilabs/growi/blob/v7.1.0/apps/app/docker/Dockerfile)
+* [`7.0.23`, `7.0` (Dockerfile)](https://github.com/growilabs/growi/blob/v7.0.23/apps/app/docker/Dockerfile)
+* [`6.3.2`, `6.3`, `6` (Dockerfile)](https://github.com/growilabs/growi/blob/v6.3.2/apps/app/docker/Dockerfile)
 
 
 What is GROWI?
@@ -20,7 +20,7 @@ What is GROWI?
 
 GROWI is a team collaboration software and it forked from [crowi](https://github.com/weseek/crowi/crowi)
 
-see: [weseek/growi](https://github.com/weseek/growi)
+see: [growilabs/growi](https://github.com/growilabs/growi)
 
 
 Requirements
@@ -60,7 +60,7 @@ docker run -d \
 
 Using docker-compose is the fastest and the most convenient way to boot GROWI.
 
-see: [weseek/growi-docker-compose](https://github.com/weseek/growi-docker-compose)
+see: [weseek/growi-docker-compose](https://github.com/growilabs/growi-docker-compose)
 
 
 Configuration
@@ -76,5 +76,5 @@ See [GROWI Docs: Admin Guide](https://docs.growi.org/en/admin-guide/) ([en](http
 Issues
 ------
 
-If you have any issues or questions about this image, please contact us through  [GitHub issue](https://github.com/weseek/growi-docker/issues).
+If you have any issues or questions about this image, please contact us through  [GitHub issue](https://github.com/growilabs/growi-docker/issues).
 

+ 44 - 44
apps/app/docker/codebuild/.terraform.lock.hcl

@@ -2,64 +2,64 @@
 # Manual edits may be lost in future updates.
 
 provider "registry.terraform.io/hashicorp/aws" {
-  version     = "4.49.0"
-  constraints = "~> 4.16"
+  version     = "6.12.0"
+  constraints = ">= 5.0.0, >= 6.0.0, ~> 6.0"
   hashes = [
-    "h1:oOwWQpvQWd1uVP1axBz/TO6xzzLWoL982AY/MQfeF7I=",
-    "zh:09803937f00fdf2873eccf685eec7854408925cbf183c9b683df7c5825be463f",
-    "zh:2af1575e538fb0b669266f8d1385b17bfdaf17c521b6b6329baa1f2971fc4a4d",
-    "zh:3f71882b438cde3108fe68cfe2637839d3eed08157a9721bd97babf3912247a8",
-    "zh:577af1b38f5da8a9f29eebe5eebec9279d26e757cd03b0c8c59311f9ce8a859b",
-    "zh:60160d39094973beefb9b10cfd6aaa5b63a2e68c32445ecffcd1b101356e6f9b",
-    "zh:762656454722548baeccf35cbaa23b887976337e1ed321682df7390419fdf22d",
-    "zh:7f6d7887821659bf3bef815949077dc91ffcdb0d911644a887b6683b264a5ca6",
-    "zh:8f16a352cc903f8951fa4619c36233b3e66e27d724817b131f2035dd8896f524",
-    "zh:8f768f65e370366c8b91c00d01c9a6264fe26ea9ae1819f14bdcd12c066272bc",
-    "zh:95ad78c689a83c08ef7c3e544c3c9aca93ed528054aa77cc968ddd9efa3a1023",
+    "h1:QiSzB4pjONZ4hek1L8Rcd6S9vtP+yMr5iOfczJg5/JI=",
+    "zh:054bcbf13c6ac9ddd2247876f82f9b56493e2f71d8c88baeec142386a395165d",
+    "zh:195489f16ad5621db2cec80be997d33060462a3b8d442c890bef3eceba34fa4d",
+    "zh:3461ef14904ab7de246296e44d24c042f3190e6bead3d7ce1d9fda63dcb0f047",
+    "zh:44517a0035996431e4127f45db5a84f53ce80730eae35629eda3101709df1e5c",
+    "zh:4b0374abaa6b9a9debed563380cc944873e4f30771dd1da7b9e812a49bf485e3",
+    "zh:531468b99465bd98a89a4ce2f1a30168dfadf6edb57f7836df8a977a2c4f9804",
+    "zh:6a95ed7b4852174aa748d3412bff3d45e4d7420d12659f981c3d9f4a1a59a35f",
+    "zh:88c2d21af1e64eed4a13dbb85590c66a519f3ecc54b72875d4bb6326f3ef84e7",
     "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
-    "zh:a47097ab6a4ca8302da82964303ffdd2310ed65e8f8524bfe4058816cf1addb7",
-    "zh:b66d820c70cd5fd628ffe882d2b97e76b969dca4e6827ac2ba0f8d3bc5d6e9c6",
-    "zh:b80f713a4f3e1355c3dd1600e9d08b9f15ed2370054ec792ad2c01f2541abe02",
-    "zh:ce065bc3962cb71fa7652562226b9d486f3d7fcb88285c1020ebe2f550e28641",
+    "zh:a8b648470bb5df098e56b1ec5c6a39e0bbb7b496b23a19ea9f494bf48d4a122a",
+    "zh:b23fb13efdb527677db546bc92aeb2bdf64ff3f480188841f2bfdfa7d3d907c1",
+    "zh:be5858a1951ae5f5a9c388949c3e3c66a3375f684fb79b06b1d1db7a9703b18e",
+    "zh:c368e03a7c922493daf4c7348faafc45f455225815ef218b5491c46cea5f76b7",
+    "zh:e31e75d5d19b8ac08aa01be7e78207966e1faa3b82ed9fe3acfdc2d806be924c",
+    "zh:ea84182343b5fd9252a6fae41e844eed4fdc3311473a753b09f06e49ec0e7853",
   ]
 }
 
 provider "registry.terraform.io/hashicorp/random" {
-  version     = "3.4.3"
+  version     = "3.7.2"
   constraints = ">= 2.1.0"
   hashes = [
-    "h1:xZGZf18JjMS06pFa4NErzANI98qi59SEcBsOcS2P2yQ=",
-    "zh:41c53ba47085d8261590990f8633c8906696fa0a3c4b384ff6a7ecbf84339752",
-    "zh:59d98081c4475f2ad77d881c4412c5129c56214892f490adf11c7e7a5a47de9b",
-    "zh:686ad1ee40b812b9e016317e7f34c0d63ef837e084dea4a1f578f64a6314ad53",
+    "h1:KG4NuIBl1mRWU0KD/BGfCi1YN/j3F7H4YgeeM7iSdNs=",
+    "zh:14829603a32e4bc4d05062f059e545a91e27ff033756b48afbae6b3c835f508f",
+    "zh:1527fb07d9fea400d70e9e6eb4a2b918d5060d604749b6f1c361518e7da546dc",
+    "zh:1e86bcd7ebec85ba336b423ba1db046aeaa3c0e5f921039b3f1a6fc2f978feab",
+    "zh:24536dec8bde66753f4b4030b8f3ef43c196d69cccbea1c382d01b222478c7a3",
+    "zh:29f1786486759fad9b0ce4fdfbbfece9343ad47cd50119045075e05afe49d212",
+    "zh:4d701e978c2dd8604ba1ce962b047607701e65c078cb22e97171513e9e57491f",
     "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
-    "zh:84103eae7251384c0d995f5a257c72b0096605048f757b749b7b62107a5dccb3",
-    "zh:8ee974b110adb78c7cd18aae82b2729e5124d8f115d484215fd5199451053de5",
-    "zh:9dd4561e3c847e45de603f17fa0c01ae14cae8c4b7b4e6423c9ef3904b308dda",
-    "zh:bb07bb3c2c0296beba0beec629ebc6474c70732387477a65966483b5efabdbc6",
-    "zh:e891339e96c9e5a888727b45b2e1bb3fcbdfe0fd7c5b4396e4695459b38c8cb1",
-    "zh:ea4739860c24dfeaac6c100b2a2e357106a89d18751f7693f3c31ecf6a996f8d",
-    "zh:f0c76ac303fd0ab59146c39bc121c5d7d86f878e9a69294e29444d4c653786f8",
-    "zh:f143a9a5af42b38fed328a161279906759ff39ac428ebcfe55606e05e1518b93",
+    "zh:7b8434212eef0f8c83f5a90c6d76feaf850f6502b61b53c329e85b3b281cba34",
+    "zh:ac8a23c212258b7976e1621275e3af7099e7e4a3d4478cf8d5d2a27f3bc3e967",
+    "zh:b516ca74431f3df4c6cf90ddcdb4042c626e026317a33c53f0b445a3d93b720d",
+    "zh:dc76e4326aec2490c1600d6871a95e78f9050f9ce427c71707ea412a2f2f1a62",
+    "zh:eac7b63e86c749c7d48f527671c7aee5b4e26c10be6ad7232d6860167f99dbb0",
   ]
 }
 
 provider "registry.terraform.io/hashicorp/tls" {
-  version     = "4.0.4"
-  constraints = ">= 3.0.0"
+  version     = "4.1.0"
+  constraints = ">= 4.0.0"
   hashes = [
-    "h1:pe9vq86dZZKCm+8k1RhzARwENslF3SXb9ErHbQfgjXU=",
-    "zh:23671ed83e1fcf79745534841e10291bbf34046b27d6e68a5d0aab77206f4a55",
-    "zh:45292421211ffd9e8e3eb3655677700e3c5047f71d8f7650d2ce30242335f848",
-    "zh:59fedb519f4433c0fdb1d58b27c210b27415fddd0cd73c5312530b4309c088be",
-    "zh:5a8eec2409a9ff7cd0758a9d818c74bcba92a240e6c5e54b99df68fff312bbd5",
-    "zh:5e6a4b39f3171f53292ab88058a59e64825f2b842760a4869e64dc1dc093d1fe",
-    "zh:810547d0bf9311d21c81cc306126d3547e7bd3f194fc295836acf164b9f8424e",
-    "zh:824a5f3617624243bed0259d7dd37d76017097dc3193dac669be342b90b2ab48",
-    "zh:9361ccc7048be5dcbc2fafe2d8216939765b3160bd52734f7a9fd917a39ecbd8",
-    "zh:aa02ea625aaf672e649296bce7580f62d724268189fe9ad7c1b36bb0fa12fa60",
-    "zh:c71b4cd40d6ec7815dfeefd57d88bc592c0c42f5e5858dcc88245d371b4b8b1e",
-    "zh:dabcd52f36b43d250a3d71ad7abfa07b5622c69068d989e60b79b2bb4f220316",
+    "h1:zEv9tY1KR5vaLSyp2lkrucNJ+Vq3c+sTFK9GyQGLtFs=",
+    "zh:14c35d89307988c835a7f8e26f1b83ce771e5f9b41e407f86a644c0152089ac2",
+    "zh:2fb9fe7a8b5afdbd3e903acb6776ef1be3f2e587fb236a8c60f11a9fa165faa8",
+    "zh:35808142ef850c0c60dd93dc06b95c747720ed2c40c89031781165f0c2baa2fc",
+    "zh:35b5dc95bc75f0b3b9c5ce54d4d7600c1ebc96fbb8dfca174536e8bf103c8cdc",
+    "zh:38aa27c6a6c98f1712aa5cc30011884dc4b128b4073a4a27883374bfa3ec9fac",
+    "zh:51fb247e3a2e88f0047cb97bb9df7c228254a3b3021c5534e4563b4007e6f882",
+    "zh:62b981ce491e38d892ba6364d1d0cdaadcee37cc218590e07b310b1dfa34be2d",
+    "zh:bc8e47efc611924a79f947ce072a9ad698f311d4a60d0b4dfff6758c912b7298",
+    "zh:c149508bd131765d1bc085c75a870abb314ff5a6d7f5ac1035a8892d686b6297",
+    "zh:d38d40783503d278b63858978d40e07ac48123a2925e1a6b47e62179c046f87a",
     "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
+    "zh:fb07f708e3316615f6d218cec198504984c0ce7000b9f1eebff7516e384f4b54",
   ]
 }

+ 1 - 1
apps/app/docker/codebuild/buildspec.yml

@@ -11,7 +11,7 @@ phases:
   pre_build:
     commands:
       # login to docker.io
-      - echo ${DOCKER_REGISTRY_PASSWORD} | docker login --username wsmoogle --password-stdin
+      - echo ${DOCKER_REGISTRY_PASSWORD} | docker login --username growimoogle --password-stdin
   build:
     commands:
       - docker build -t ${IMAGE_TAG} -f ./apps/app/docker/Dockerfile .

+ 1 - 1
apps/app/docker/codebuild/codebuild.tf

@@ -7,7 +7,7 @@ module "codebuild" {
   artifact_type       = "NO_ARTIFACTS"
 
   source_type         = "GITHUB"
-  source_location     = "https://github.com/weseek/growi.git"
+  source_location     = "https://github.com/growilabs/growi.git"
   source_version      = "refs/heads/master"
   git_clone_depth     = 1
 

+ 1 - 1
apps/app/docker/codebuild/main.tf

@@ -10,7 +10,7 @@ terraform {
   required_providers {
     aws = {
       source  = "hashicorp/aws"
-      version = "~> 4.16"
+      version = "~> 6.0"
     }
   }
 

+ 1 - 1
apps/app/docker/codebuild/oidc.tf

@@ -7,7 +7,7 @@ module "oidc_github" {
   }
 
   github_repositories = [
-    "weseek/growi",
+    "growilabs/growi",
   ]
 }
 

+ 11 - 4
apps/app/jest.config.js

@@ -22,9 +22,14 @@ module.exports = {
 
       rootDir: '.',
       roots: ['<rootDir>'],
-      testMatch: ['<rootDir>/test/integration/**/*.test.ts', '<rootDir>/test/integration/**/*.test.js'],
+      testMatch: [
+        '<rootDir>/test/integration/**/*.test.ts',
+        '<rootDir>/test/integration/**/*.test.js',
+      ],
       // https://regex101.com/r/jTaxYS/1
-      modulePathIgnorePatterns: ['<rootDir>/test/integration/*.*/v5(..*)*.[t|j]s'],
+      modulePathIgnorePatterns: [
+        '<rootDir>/test/integration/*.*/v5(..*)*.[t|j]s',
+      ],
       testEnvironment: 'node',
       globalSetup: '<rootDir>/test/integration/global-setup.js',
       globalTeardown: '<rootDir>/test/integration/global-teardown.js',
@@ -43,7 +48,10 @@ module.exports = {
 
       rootDir: '.',
       roots: ['<rootDir>'],
-      testMatch: ['<rootDir>/test/integration/**/v5.*.test.ts', '<rootDir>/test/integration/**/v5.*.test.js'],
+      testMatch: [
+        '<rootDir>/test/integration/**/v5.*.test.ts',
+        '<rootDir>/test/integration/**/v5.*.test.js',
+      ],
 
       testEnvironment: 'node',
       globalSetup: '<rootDir>/test/integration/global-setup.js',
@@ -75,5 +83,4 @@ module.exports = {
     '/resource/',
     '/node_modules/',
   ],
-
 };

+ 18 - 15
apps/app/next.config.js

@@ -8,8 +8,10 @@
 const path = require('path');
 
 const { withSuperjson } = require('next-superjson');
-const { PHASE_PRODUCTION_BUILD, PHASE_PRODUCTION_SERVER } = require('next/constants');
-
+const {
+  PHASE_PRODUCTION_BUILD,
+  PHASE_PRODUCTION_SERVER,
+} = require('next/constants');
 
 const getTranspilePackages = () => {
   const { listPrefixedPackages } = require('./src/utils/next.config.utils');
@@ -56,7 +58,14 @@ const getTranspilePackages = () => {
     'github-slugger',
     'html-url-attributes',
     'estree-util-is-identifier-name',
-    ...listPrefixedPackages(['remark-', 'rehype-', 'hast-', 'mdast-', 'micromark-', 'unist-']),
+    ...listPrefixedPackages([
+      'remark-',
+      'rehype-',
+      'hast-',
+      'mdast-',
+      'micromark-',
+      'unist-',
+    ]),
   ];
 
   // const eazyLogger = require('eazy-logger');
@@ -84,13 +93,11 @@ const optimizePackageImports = [
   '@growi/ui',
 ];
 
-module.exports = async(phase, { defaultConfig }) => {
-
+module.exports = async (phase, { defaultConfig }) => {
   const { i18n, localePath } = require('./config/next-i18next.config');
 
   /** @type {import('next').NextConfig} */
   const nextConfig = {
-
     reactStrictMode: true,
     poweredByHeader: false,
     pageExtensions: ['page.tsx', 'page.ts', 'page.jsx', 'page.js'],
@@ -103,9 +110,8 @@ module.exports = async(phase, { defaultConfig }) => {
     typescript: {
       tsconfigPath: 'tsconfig.build.client.json',
     },
-    transpilePackages: phase !== PHASE_PRODUCTION_SERVER
-      ? getTranspilePackages()
-      : undefined,
+    transpilePackages:
+      phase !== PHASE_PRODUCTION_SERVER ? getTranspilePackages() : undefined,
     experimental: {
       optimizePackageImports,
     },
@@ -150,7 +156,6 @@ module.exports = async(phase, { defaultConfig }) => {
 
       return config;
     },
-
   };
 
   // production server
@@ -159,11 +164,9 @@ module.exports = async(phase, { defaultConfig }) => {
   }
 
   const withBundleAnalyzer = require('@next/bundle-analyzer')({
-    enabled: phase === PHASE_PRODUCTION_BUILD
-      && (
-        process.env.ANALYZE === 'true'
-          || process.env.ANALYZE === '1'
-      ),
+    enabled:
+      phase === PHASE_PRODUCTION_BUILD &&
+      (process.env.ANALYZE === 'true' || process.env.ANALYZE === '1'),
   });
 
   return withBundleAnalyzer(withSuperjson()(nextConfig));

+ 1 - 4
apps/app/nodemon.json

@@ -1,9 +1,6 @@
 {
   "ext": "js,ts,json",
-  "watch": [
-    ".",
-    "../../packages/**/dist"
-  ],
+  "watch": [".", "../../packages/**/dist"],
   "ignore": [
     ".next",
     "public/static",

+ 14 - 10
apps/app/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/app",
-  "version": "7.2.9",
+  "version": "7.3.0-RC.0",
   "license": "MIT",
   "private": "true",
   "scripts": {
@@ -28,18 +28,19 @@
     "launch-dev:ci": "cross-env NODE_ENV=development pnpm run dev:migrate && pnpm run ts-node src/server/app.ts --ci",
     "lint:typecheck": "vue-tsc --noEmit",
     "lint:eslint": "eslint --quiet \"**/*.{js,mjs,jsx,ts,mts,tsx}\"",
+    "lint:biome": "biome check",
     "lint:styles": "stylelint \"src/**/*.scss\"",
     "lint:openapi:apiv3": "node node_modules/swagger2openapi/oas-validate tmp/openapi-spec-apiv3.json",
     "lint:openapi:apiv1": "node node_modules/swagger2openapi/oas-validate tmp/openapi-spec-apiv1.json",
     "lint": "run-p lint:**",
     "prelint:openapi:apiv3": "pnpm run openapi:generate-spec:apiv3",
     "prelint:openapi:apiv1": "pnpm run openapi:generate-spec:apiv1",
-    "test": "run-p test:*",
+    "test": "run-p test:jest test:vitest:coverage",
     "test:jest": "cross-env NODE_ENV=test TS_NODE_PROJECT=test/integration/tsconfig.json jest",
-    "test:vitest": "vitest run --coverage",
+    "test:vitest": "vitest run",
+    "test:vitest:coverage": "COLUMNS=200 vitest run --coverage",
     "jest:run": "cross-env NODE_ENV=test TS_NODE_PROJECT=test/integration/tsconfig.json jest --passWithNoTests -- ",
     "reg:run": "reg-suit run",
-    "previtest:run:integ": "vitest run -c test-with-vite/download-mongo-binary/vitest.config.ts test-with-vite/download-mongo-binary",
     "//// misc": "",
     "console": "npm run repl",
     "repl": "cross-env NODE_ENV=development npm run ts-node src/server/repl.ts",
@@ -69,8 +70,9 @@
     "@azure/storage-blob": "^12.16.0",
     "@browser-bunyan/console-formatted-stream": "^1.8.0",
     "@cspell/dynamic-import": "^8.15.4",
-    "@elastic/elasticsearch7": "npm:@elastic/elasticsearch@^7.17.0",
-    "@elastic/elasticsearch8": "npm:@elastic/elasticsearch@^8.7.0",
+    "@elastic/elasticsearch7": "npm:@elastic/elasticsearch@^7.17.4",
+    "@elastic/elasticsearch8": "npm:@elastic/elasticsearch@^8.18.2",
+    "@elastic/elasticsearch9": "npm:@elastic/elasticsearch@^9.0.3",
     "@godaddy/terminus": "^4.9.0",
     "@google-cloud/storage": "^5.8.5",
     "@growi/core": "workspace:^",
@@ -134,7 +136,7 @@
     "express-session": "^1.16.1",
     "express-validator": "^6.14.0",
     "extensible-custom-error": "^0.0.7",
-    "form-data": "^4.0.0",
+    "form-data": "^4.0.4",
     "graceful-fs": "^4.1.11",
     "hast-util-sanitize": "^5.0.1",
     "hast-util-select": "^6.0.2",
@@ -156,7 +158,7 @@
     "mdast-util-from-markdown": "^2.0.1",
     "mdast-util-gfm-table": "^2.0.0",
     "mdast-util-wiki-link": "^0.1.2",
-    "mermaid": "^11.2.0",
+    "mermaid": "^11.10.0",
     "method-override": "^3.0.0",
     "micromark-extension-gfm-table": "^2.1.0",
     "micromark-extension-wiki-link": "^0.0.4",
@@ -170,7 +172,7 @@
     "multer": "~1.4.0",
     "multer-autoreap": "^1.0.3",
     "mustache": "^4.2.0",
-    "next": "^14.2.30",
+    "next": "^14.2.32",
     "next-dynamic-loading-props": "^0.1.1",
     "next-i18next": "^15.3.1",
     "next-superjson": "^0.0.4",
@@ -336,6 +338,8 @@
     "simplebar-react": "^2.3.6",
     "socket.io-client": "^4.7.5",
     "source-map-loader": "^4.0.1",
-    "swagger2openapi": "^7.0.8"
+    "swagger2openapi": "^7.0.8",
+    "unist-util-is": "^6.0.0",
+    "unist-util-visit-parents": "^6.0.0"
   }
 }

+ 14 - 14
apps/app/playwright.config.ts

@@ -10,18 +10,20 @@ const storageState = fs.existsSync(authFile) ? authFile : undefined;
 
 const supportedBrowsers = ['chromium', 'firefox', 'webkit'] as const;
 
-const projects: Array<Project> = supportedBrowsers.map(browser => ({
+const projects: Array<Project> = supportedBrowsers.map((browser) => ({
   name: browser,
   use: { ...devices[`Desktop ${browser}`], storageState },
   testIgnore: /(10-installer|21-basic-features-for-guest)\/.*\.spec\.ts/,
   dependencies: ['setup', 'auth'],
 }));
 
-const projectsForGuestMode: Array<Project> = supportedBrowsers.map(browser => ({
-  name: `${browser}/guest-mode`,
-  use: { ...devices[`Desktop ${browser}`] }, // Do not use storageState
-  testMatch: /21-basic-features-for-guest\/.*\.spec\.ts/,
-}));
+const projectsForGuestMode: Array<Project> = supportedBrowsers.map(
+  (browser) => ({
+    name: `${browser}/guest-mode`,
+    use: { ...devices[`Desktop ${browser}`] }, // Do not use storageState
+    testMatch: /21-basic-features-for-guest\/.*\.spec\.ts/,
+  }),
+);
 
 /**
  * Read environment variables from file.
@@ -48,12 +50,7 @@ export default defineConfig({
   /* Opt out of parallel tests on CI. */
   workers: process.env.CI ? 1 : undefined,
   /* Reporter to use. See https://playwright.dev/docs/test-reporters */
-  reporter: process.env.CI
-    ? [
-      ['github'],
-      ['blob'],
-    ]
-    : 'list',
+  reporter: process.env.CI ? [['github'], ['blob']] : 'list',
 
   webServer: {
     command: 'pnpm run server',
@@ -79,7 +76,11 @@ export default defineConfig({
   /* Configure projects for major browsers */
   projects: [
     // Setup project
-    { name: 'setup', testMatch: /.*\.setup\.ts/, testIgnore: /auth\.setup\.ts/ },
+    {
+      name: 'setup',
+      testMatch: /.*\.setup\.ts/,
+      testIgnore: /auth\.setup\.ts/,
+    },
     { name: 'auth', testMatch: /auth\.setup\.ts/ },
 
     {
@@ -113,5 +114,4 @@ export default defineConfig({
     //   use: { ...devices['Desktop Chrome'], channel: 'chrome' },
     // },
   ],
-
 });

+ 0 - 2
apps/app/playwright/40-admin/access-to-admin-page.spec.ts

@@ -13,8 +13,6 @@ test('admin/app is successfully loaded', async({ page }) => {
   await expect(page.getByTestId('admin-app-settings')).toBeVisible();
   // await expect(page.getByTestId('v5-page-migration')).toBeVisible();
   await expect(page.locator('#cbFileUpload')).toBeChecked();
-  await expect(page.locator('#isQuestionnaireEnabled')).toBeChecked();
-  await expect(page.locator('#isAppSiteUrlHashed')).not.toBeChecked();
 });
 
 test('admin/security is successfully loaded', async({ page }) => {

+ 26 - 14
apps/app/playwright/60-home/home.spec.ts

@@ -25,18 +25,6 @@ test('Vist User settings', async({ page }) => {
   await expect(page.getByTestId('grw-user-settings')).toBeVisible();
 });
 
-test('Open questionnaire modal', async({ page }) => {
-  await page.goto('/dummy');
-
-  // Open PersonalDropdown
-  await page.getByTestId('personal-dropdown-button').click();
-  await expect(page.getByTestId('grw-personal-dropdown-menu-user-home')).toBeVisible();
-
-  // Expect the questionnaire modal to be displayed when the QuestionnaireModalToggleButton is clicked
-  await page.getByTestId('grw-proactive-questionnaire-modal-toggle-btn').click();
-  await expect(page.getByTestId('grw-proactive-questionnaire-modal')).toBeVisible();
-});
-
 test('Access User information', async({ page }) => {
   await page.goto('/me');
 
@@ -97,6 +85,30 @@ test('Access API setting', async({ page }) => {
   await expect(page.locator('.Toastify__toast')).toBeVisible();
 });
 
+test('Access Access Token setting', async({ page }) => {
+  await page.goto('/me');
+
+  // Click ApiSettingTabButton
+  await expect(page.getByTestId('grw-user-settings')).toBeVisible();
+  await page.getByTestId('api-settings-tab-button').first().click();
+
+  // Expect a success toaster to be displayed when new Access Token is generated
+  await page.getByTestId('btn-accesstoken-toggleform').click();
+  await page.getByTestId('grw-accesstoken-textarea-description').fill('dummy');
+  await page.getByTestId('grw-accesstoken-checkbox-read:*').check();
+  await page.getByTestId('grw-accesstoken-create-button').click();
+  await expect(page.locator('.Toastify__toast')).toBeVisible();
+  await expect(page.getByTestId('grw-accesstoken-new-token-display')).toBeVisible();
+
+  // Expect a success toaster to be displayed when the Access Token is deleted
+  await page.getByTestId('grw-accesstoken-delete-button').click();
+  await page.getByTestId('grw-accesstoken-cancel-button-in-modal').click();
+  await page.getByTestId('grw-accesstoken-delete-button').click();
+  await page.getByTestId('grw-accesstoken-delete-button-in-modal').click();
+  await expect(page.locator('.Toastify__toast')).toBeVisible();
+
+});
+
 test('Access In-App Notification setting', async({ page }) => {
   await page.goto('/me');
 
@@ -116,7 +128,7 @@ test('Acccess Other setting', async({ page }) => {
   await expect(page.getByTestId('grw-user-settings')).toBeVisible();
   await page.getByTestId('other-settings-tab-button').first().click();
 
-  // Expect a success toaster to be displayed when the QuestionnaireSettingsUpdateButton is clicked
-  await page.getByTestId('grw-questionnaire-settings-update-btn').click();
+  // Expect a success toaster to be displayed when the updating UI button is clicked
+  await page.getByTestId('grw-ui-settings-update-btn').click();
   await expect(page.locator('.Toastify__toast')).toBeVisible();
 });

+ 34 - 44
apps/app/public/static/locales/en_US/admin.json

@@ -97,9 +97,9 @@
       "closed": "Closed (Invitation Only)"
     },
     "share_link_management": "Share Link Management",
-    "No_share_links":"No share links",
-    "share_link_notice":"remove all share links",
-    "delete_all_share_links":"Delete all share links",
+    "No_share_links": "No share links",
+    "share_link_notice": "remove all share links",
+    "delete_all_share_links": "Delete all share links",
     "share_link_rights": "Share link rights",
     "enable_link_sharing": "Enable link sharing",
     "all_share_links": "All share links",
@@ -229,7 +229,7 @@
     "prioritize_webhook_desc": "Check this option and GROWI use Incoming Webhooks even if Slack App settings are enabled.",
     "slack_app_configuration": "Slack app configuration",
     "slack_app_configuration_desc": "This is the way that compatible with Crowi,<br /> but not recommended in GROWI because it is <strong>too complex</strong>.",
-    "use_instead":"Please use Slack Incoming Webhooks Configuration instead.",
+    "use_instead": "Please use Slack Incoming Webhooks Configuration instead.",
     "how_to": {
       "header": "How to configure Incoming Webhooks?",
       "workspace": "(At Workspace) Add a hook",
@@ -296,7 +296,7 @@
     "rebuild_description_1": "Click the button to rebuild index and add all page datas.",
     "rebuild_description_2": "This may take a while."
   },
-  "mailer_setup_required":"<a href='/admin/app'>Email settings</a> are required to send.",
+  "mailer_setup_required": "<a href='/admin/app'>Email settings</a> are required to send.",
   "admin_top": {
     "management_wiki": "Management Wiki",
     "system_information": "System information",
@@ -305,7 +305,7 @@
     "package_name": "Package name",
     "specified_version": "Specified version",
     "installed_version": "Installed version",
-    "list_of_env_vars":"List of environment variables",
+    "list_of_env_vars": "List of environment variables",
     "env_var_priority": "For environment variables other than security, the value of the database is obtained preferentially.",
     "about_security": "Check <a href='/admin/security'>Security Settings</a> for security environment variables.",
     "copy_prefilled_host_information": {
@@ -313,7 +313,7 @@
       "done": "Copied to clipboard!"
     },
     "bug_report": "Submitting a bug report",
-    "submit_bug_report": "<a href='https://github.com/weseek/growi/issues/new?assignees=&labels=bug&template=bug-report.md&title=Bug%3A' target='_blank' rel='noreferrer'>then submit your issue to GitHub.</a>"
+    "submit_bug_report": "<a href='https://github.com/growilabs/growi/issues/new?assignees=&labels=bug&template=bug-report.md&title=Bug%3A' target='_blank' rel='noreferrer'>then submit your issue to GitHub.</a>"
   },
   "v5_page_migration": {
     "migration_desc": "There are some pages with old v4 compatibility. To take advantage of new features such as page trees and easy renaming, please convert all your pages to v5 compatibility.",
@@ -368,9 +368,9 @@
     "mail_settings": "E-mail Settings",
     "mailer_is_not_set_up": "E-mail setting is not set up.",
     "from_e-mail_address": "From e-mail address",
-    "transmission_method":"Transmission Method",
-    "smtp_label":"SMTP",
-    "ses_label":"SES(AWS)",
+    "transmission_method": "Transmission Method",
+    "smtp_label": "SMTP",
+    "ses_label": "SES(AWS)",
     "send_test_email": "Send a test-email",
     "success_to_send_test_email": "Success to send a test-email",
     "smtp_settings": "SMTP settings",
@@ -380,13 +380,13 @@
     "initialize_mail_settings": "initialize e-mail settings",
     "initialize_mail_modal_header": "Initialize e-mail settings",
     "confirm_to_initialize_mail_settings": "You can't restore to the current settings. Are you sure you want to initialize e-mail settings?",
-    "file_upload_settings":"File Upload Settings",
-    "file_upload_method":"File Upload Method",
-    "file_delivery_method":"File Delivery Method",
-    "file_delivery_method_redirect":"Redirect",
-    "file_delivery_method_relay":"Internal System Relay",
-    "file_delivery_method_redirect_info":"Redirect: It redirects to a signed URL without GROWI server, it gives excellent performance.",
-    "file_delivery_method_relay_info":"Internal System Relay: The GROWI server delivers to clients, it provides complete security.",
+    "file_upload_settings": "File Upload Settings",
+    "file_upload_method": "File Upload Method",
+    "file_delivery_method": "File Delivery Method",
+    "file_delivery_method_redirect": "Redirect",
+    "file_delivery_method_relay": "Internal System Relay",
+    "file_delivery_method_redirect_info": "Redirect: It redirects to a signed URL without GROWI server, it gives excellent performance.",
+    "file_delivery_method_relay_info": "Internal System Relay: The GROWI server delivers to clients, it provides complete security.",
     "fixed_by_env_var": "This is fixed by the env var <code>{{envKey}}={{envVar}}</code>.",
     "gcs_label": "GCP(GCS)",
     "aws_label": "AWS(S3)",
@@ -411,17 +411,7 @@
     "enable": "Enable",
     "disable": "Disable",
     "use_env_var_if_empty": "If the value in the database is empty, the value of the environment variable <code>{{variable}}</code> is used.",
-    "note_for_the_only_env_option": "The GCS Settings is limited by the value of environment variable.<br>To change this setting, please change to false or delete the value of the environment variable <code>{{env}}</code> .",
-    "questionnaire_settings": "Questionnaire settings",
-    "questionnaire_settings_explanation": "This will enable/disable questionnaires on the whole system. When enabled, users can also enable/disable questionnaires individually from \"Other Settings\" in the personal settings page.",
-    "about_data_sent": "About information sent",
-    "docs_link": "https://docs.growi.org/en/admin-guide/management-cookbook/app-settings.html#questionnaire-settings",
-    "learn_more": "Learn more",
-    "other_info_will_be_sent": "Along with the questionnaire answer, information necessary to improve GROWI will be sent. Personal user info will not be included in the data sent.",
-    "we_will_use_the_data_to_improve_growi": "We will use the data to improve GROWI experience as much as possible.",
-    "anonymize_app_site_url": "Anonymize app site URL in data sent",
-    "url_anonymization_explanation": "The app site URL included in the questionnaire answer will be anonymized. By enabling this, the GROWI application that sends the questionnaire answer will not be identified.",
-    "enable_questionnaire": "Enable questionnaire"
+    "note_for_the_only_env_option": "The GCS Settings is limited by the value of environment variable.<br>To change this setting, please change to false or delete the value of the environment variable <code>{{env}}</code> ."
   },
   "markdown_settings": {
     "markdown_settings": "Markdown Settings",
@@ -502,13 +492,13 @@
       "show_page_side_authors": "Always display creators and updaters above the table of contents",
       "show_page_side_authors_desc": "Displays information about the creator and the last updater above the table of contents in the page sidebar."
     },
-      "presentation": "Presentation",
+    "presentation": "Presentation",
     "presentation_options": {
       "enable_marp": "Enable Marp ",
       "enable_marp_desc": "Marp can be used in presentation preview. This option may make you vulnerable to XSS.",
       "marp_official_site": "The Marp Official Site",
       "marp_official_site_link": "https://marp.app",
-      "marp_in_growi" : "GROWI Docs - Create slide using Marp",
+      "marp_in_growi": "GROWI Docs - Create slide using Marp",
       "marp_in_growi_link": "https://docs.growi.org/en/guide/features/marp.html"
     },
     "custom_title": "Custom title",
@@ -525,7 +515,7 @@
     "custom_presentation": "Custom presentation",
     "write_java": "You can write Javascript that is applied to whole system.",
     "reflect_change": "You need to reload the page to reflect the change.",
-    "custom_logo" : "Custom Logo",
+    "custom_logo": "Custom Logo",
     "default_logo": "Default Logo",
     "upload_logo": "Upload Logo",
     "current_logo": "Current Logo",
@@ -599,9 +589,9 @@
     },
     "import": "Import",
     "skip_username_and_email_when_overlapped": "Skip username and email using same username and email in new environment",
-    "prepare_new_account_for_migration":"Prepare new account for migration",
-    "archive_data_import_detail":"More Details? Ckick here.",
-    "admin_archive_data_import_guide_url":"https://docs.growi.org/en/admin-guide/management-cookbook/import.html",
+    "prepare_new_account_for_migration": "Prepare new account for migration",
+    "archive_data_import_detail": "More Details? Ckick here.",
+    "admin_archive_data_import_guide_url": "https://docs.growi.org/en/admin-guide/management-cookbook/import.html",
     "page_skip": "Pages with a name that already exists on GROWI are not imported",
     "Directory_hierarchy_tag": "Directory hierarchy tag"
   },
@@ -671,7 +661,7 @@
     "delete": "Delete",
     "integration_procedure": "Integration Procedure",
     "custom_bot_without_proxy_settings": "Custom Bot without proxy Settings",
-    "integration_failed":"Integration failed",
+    "integration_failed": "Integration failed",
     "reset": "Reset",
     "reset_all_settings": "Reset all settings",
     "delete_slackbot_settings": "Delete Slack Bot settings",
@@ -718,7 +708,7 @@
       "allow_specified_long": "Allow specified (Allowed from only specified channels)",
       "test_connection": "Test Connection",
       "test_connection_by_pressing_button": "Press the button to test the connection",
-      "test_connection_only_public_channel":"Please test connection in a public channel",
+      "test_connection_only_public_channel": "Please test connection in a public channel",
       "error_check_logs_below": "An error has occurred. Please check the logs below.",
       "send_message_to_slack_work_space": "Send message to Slack work space.",
       "add_slack_workspace": "Add a Slack Workspace"
@@ -753,10 +743,10 @@
     "status": "Status",
     "invite_modal": {
       "emails": "Emails (Possible to issue multiple people with new lines)",
-      "description1":"Temporarily issue new users by email addresses.",
-      "description2":"A temporary password will be generated for the first login.",
+      "description1": "Temporarily issue new users by email addresses.",
+      "description2": "A temporary password will be generated for the first login.",
       "invite_thru_email": "Send invitation email",
-      "mail_setting_link":"<span className='material-symbols-outlined me-2'>settings</span><a href='/admin/app'>Email settings</a>",
+      "mail_setting_link": "<span className='material-symbols-outlined me-2'>settings</span><a href='/admin/app'>Email settings</a>",
       "valid_email": "Valid email address is required",
       "temporary_password": "The created user has a temporary password",
       "send_new_password": "Please send the new password to the user.",
@@ -791,10 +781,10 @@
       "new_password": "New Password"
     },
     "external_account": "External Account Management",
-    "external_accounts":"External accounts",
-    "create_external_account":"Create external account",
+    "external_accounts": "External accounts",
+    "create_external_account": "Create external account",
     "external_account_list": "External Account List",
-    "external_account_none":"No External Account",
+    "external_account_none": "No External Account",
     "invite": "Invite",
     "invited": "User was invited",
     "back_to_user_management": "Back to User Management",
@@ -979,7 +969,7 @@
     "ADMIN_SITE_URL_UPDATE": "Update Site URL Settings",
     "ADMIN_MAIL_SMTP_UPDATE": "Update E-mail(SMTP) Settings",
     "ADMIN_MAIL_SES_UPDATE": "Update E-mail(SES) Settings",
-    "ADMIN_MAIL_TEST_SUBMIT" : "Send test mail",
+    "ADMIN_MAIL_TEST_SUBMIT": "Send test mail",
     "ADMIN_FILE_UPLOAD_CONFIG_UPDATE": "Update File Upload Settings",
     "ADMIN_PLUGIN_UPDATE": "Update Plugin Settings",
     "ADMIN_MAINTENANCEMODE_ENABLED": "Enable Maintenance Mode",
@@ -1149,4 +1139,4 @@
     "disable_mode_explanation": "Currently, AI integration is disabled. To enable it, configure the <code>AI_ENABLED</code> environment variable along with the required additional variables.<br><br>For details, please refer to the <a target='blank' rel='noopener noreferrer' href={{documentationUrl}}en/guide/features/ai-knowledge-assistant.html>documentation</a>.",
     "ai_search_management": "AI search management"
   }
-}
+}

+ 92 - 36
apps/app/public/static/locales/en_US/commons.json

@@ -7,7 +7,6 @@
   "Sign out": "Logout",
   "New": "New",
   "Delete": "Delete",
-
   "meta": {
     "display_name": "English"
   },
@@ -30,7 +29,6 @@
   "headers": {
     "app_settings": "App Settings"
   },
-
   "header_search_box": {
     "label": {
       "All pages": "All pages",
@@ -41,20 +39,17 @@
       "This tree": "Only children of this tree"
     }
   },
-
   "search_method_menu_item": {
     "search_in_all": "Search in all",
     "only_children_of_this_tree": "Only children of this tree",
     "exact_mutch": "Exact match"
   },
-
   "share_links": {
     "Share Link": "Share Link",
     "Page Path": "Page Path",
     "expire": "Expiration",
     "description": "Description"
   },
-
   "in_app_notification": {
     "notification_list": "In-App Notification List",
     "see_all": "See All",
@@ -65,7 +60,6 @@
     "no_unread_messages": "no_unread_messages",
     "only_unread": "Only unread"
   },
-
   "personal_dropdown": {
     "home": "Home",
     "settings": "Settings",
@@ -75,7 +69,6 @@
     "use_os_settings": "Use OS settings",
     "feedback": "Feedback"
   },
-
   "create_page_dropdown": {
     "new_page": "Create New Page",
     "open_page_create_modal": "Open new page create modal",
@@ -89,7 +82,6 @@
       "descendants": "Template for descendants"
     }
   },
-
   "copy_to_clipboard": {
     "Copy to clipboard": "Copy to clipboard",
     "Page path": "Page path",
@@ -99,14 +91,12 @@
     "Markdown link": "Markdown link",
     "Append params": "Append params"
   },
-
   "crop_image_modal": {
     "image_crop": "Image Crop",
     "crop": "Crop",
     "save": "Save",
     "cancel": "Cancel"
   },
-
   "handsontable_modal": {
     "title": "Edit Table",
     "data_import": "Data Import",
@@ -122,35 +112,9 @@
       "import": "Import"
     }
   },
-
-  "questionnaire_modal": {
-    "required": "Required",
-    "submit": "Submit",
-    "close": "Close",
-    "title": "GROWI questionnaire for service improvement",
-    "more_satisfied_services": "We hope that GROWI customers will be even more satisfied",
-    "strive_to_improve_services": "once we improve our services based on your feedback.",
-    "length_of_experience": {
-      "more_than_two_years": "More than 2 years",
-      "one_to_two_years": "More than 1 year but less than 2 years",
-      "six_months_to_one_year": "More than 6 months but less than 1 year",
-      "three_months_to_six_months": "More than 3 months but less than 6 months",
-      "one_month_to_three_months": "More than 1 month but less than 3 months",
-      "less_than_one_month": "Less than 1 month"
-    },
-    "satisfaction_with_growi": "Satisfaction with GROWI",
-    "history_of_growi_usage": "History of GROWI usage",
-    "occupation": "Occupation",
-    "position": "Position",
-    "comment_on_growi": "Comment on GROWI",
-    "successfully_submitted": "Your survey has been submitted.",
-    "thanks_for_answering": "Thank you very much for answering."
-  },
-
   "not_found_page": {
     "page_not_exist": "This page does not exist."
   },
-
   "g2g_data_transfer": {
     "tab": "Data transfer",
     "data_transfer": "Data Transfer",
@@ -159,5 +123,97 @@
     "transfer_key_limit": "Transfer keys are valid for 1 hour after issuance.",
     "once_transfer_key_used": "Once the transfer key is used for transfer, it cannot be used for any other transfer.",
     "transfer_to_growi_cloud": "For more details, please click <a href='{{documentationUrl}}en/admin-guide/management-cookbook/g2g-transfer.html'>here.</a>"
+  },
+  "accesstoken_scopes_desc": {
+    "read": {
+      "all": "Grants permission to view all content.",
+      "admin": {
+        "all": "Grants permission to view admin features.",
+        "top": "Grants permission to view Wiki management top.",
+        "app": "Grants permission to view app settings.",
+        "security": "Grants permission to view security settings.",
+        "markdown": "Grants permission to view markdown settings.",
+        "customize": "Grants permission to view customization settings.",
+        "import_data": "Grants permission to view data import settings.",
+        "export_data": "Grants permission to view data archive settings.",
+        "data_transfer": "Grants permission to view data transfer settings.",
+        "external_notification": "Grants permission to view external notification settings.",
+        "slack_integration": "Grants permission to view Slack integration settings.",
+        "legacy_slack_integration": "Grants permission to view legacy Slack integration settings.",
+        "user_management": "Grants permission to view user management.",
+        "user_group_management": "Grants permission to view user group management.",
+        "audit_log": "Grants permission to view audit logs.",
+        "plugin": "Grants permission to view plugin settings.",
+        "ai_integration": "Grants permission to view AI integration settings.",
+        "full_text_search": "Grants permission to view full text search management."
+      },
+      "user_settings": {
+        "all": "Grants permission to view user settings.",
+        "info": "Grants permission to view user information.",
+        "external_account": "Grants permission to view external accounts.",
+        "password": "Grants permission to view password settings.",
+        "api": {
+          "all": "Grants permission to view API settings.",
+          "api_token": "Grants permission to view API token settings.",
+          "access_token": "Grants permission to view access token settings."
+        },
+        "in_app_notification": "Grants permission to view in-app notification settings.",
+        "other": "Grants permission to view other settings."
+      },
+      "features": {
+        "all": "Grants permission to view features.",
+        "ai_assistant": "Grants permission to view AI assistant features.",
+        "page": "Grants permission to view page features.",
+        "share_link": "Grants permission to view share link features.",
+        "bookmark": "Grants permission to view bookmark features.",
+        "attachment": "Grants permission to view attachment features.",
+        "page_bulk_export": "Grants permission to view page bulk export features."
+      }
+    },
+    "write": {
+      "all": "Grants permission to edit all content.",
+      "admin": {
+        "all": "Grants permission to edit admin features.",
+        "top": "Grants permission to edit Wiki management top.",
+        "app": "Grants permission to edit app settings.",
+        "security": "Grants permission to edit security settings.",
+        "markdown": "Grants permission to edit markdown settings.",
+        "customize": "Grants permission to edit customization settings.",
+        "import_data": "Grants permission to edit data import settings.",
+        "export_data": "Grants permission to edit data archive settings.",
+        "data_transfer": "Grants permission to edit data transfer settings.",
+        "external_notification": "Grants permission to edit external notification settings.",
+        "slack_integration": "Grants permission to edit Slack integration settings.",
+        "legacy_slack_integration": "Grants permission to edit legacy Slack integration settings.",
+        "user_management": "Grants permission to edit user management.",
+        "user_group_management": "Grants permission to edit user group management.",
+        "audit_log": "Grants permission to edit audit logs.",
+        "plugin": "Grants permission to edit plugin settings.",
+        "ai_integration": "Grants permission to edit AI integration settings.",
+        "full_text_search": "Grants permission to edit full text search management."
+      },
+      "user_settings": {
+        "all": "Grants permission to edit user settings.",
+        "info": "Grants permission to edit user information.",
+        "external_account": "Grants permission to edit external accounts.",
+        "password": "Grants permission to edit password settings.",
+        "api": {
+          "all": "Grants permission to edit API settings.",
+          "api_token": "Grants permission to edit API token settings.",
+          "access_token": "Grants permission to edit access token settings."
+        },
+        "in_app_notification": "Grants permission to edit in-app notification settings.",
+        "other": "Grants permission to edit other settings."
+      },
+      "features": {
+        "all": "Grants permission to edit features.",
+        "ai_assistant": "Grants permission to edit AI assistant features.",
+        "page": "Grants permission to edit page features.",
+        "share_link": "Grants permission to edit share link features.",
+        "bookmark": "Grants permission to edit bookmark features.",
+        "attachment": "Grants permission to edit attachment features.",
+        "page_bulk_export": "Grants permission to edit page bulk export features."
+      }
+    }
   }
 }

+ 73 - 26
apps/app/public/static/locales/en_US/translation.json

@@ -142,7 +142,6 @@
   "edited this page": "edited this page.",
   "List Drafts": "Drafts",
   "Deleted Pages": "Deleted Pages",
-  "Questionnaire": "Questionnaire",
   "Disassociate": "Disassociate",
   "No bookmarks yet": "No bookmarks yet",
   "add_bookmark": "Add to Bookmarks",
@@ -222,6 +221,9 @@
       "profile_image2": "Set up AWS or enable local uploads."
     }
   },
+  "API Token Settings": "API token settings",
+  "Current API Token": "Current API token",
+  "Update API Token": "Update API token",
   "page_me_apitoken": {
     "api_token": "API Token",
     "notice": {
@@ -231,6 +233,35 @@
     },
     "form_help": {}
   },
+  "Access Token Settings": "Access token settings",
+  "page_me_access_token": {
+    "access_token": "Access token",
+    "expiredAt": "Expiration date",
+    "description": "Description",
+    "scope": "Scope",
+    "scope_read": "Read",
+    "action": "Action",
+    "create_token": "Create Token",
+    "no_tokens_found": "No access tokens found",
+    "new_token": {
+      "title": "New access token",
+      "copy_to_clipboard": "Copy to clipboard",
+      "message": "This token will only be displayed once. Please save it securely."
+    },
+    "modal": {
+      "message": "Are you sure you want to delete this access token?",
+      "alert": "This action cannot be undone.",
+      "delete_token": "Delete Token"
+    },
+    "form": {
+      "title": "Create New Access Token",
+      "expiredAt_desc": "Select when this access token should expire.",
+      "description_desc": "Provide a description to help you identify this token later",
+      "description_max_length": "Description must be less than {{length}} characters",
+      "scope_desc": "Select the scope of the access token."
+    },
+    "copy_to_clipboard": "Copy to clipboard"
+  },
   "Password": "Password",
   "Password Settings": "Password settings",
   "personal_settings": {
@@ -261,9 +292,6 @@
   },
   "API Settings": "API settings",
   "Other Settings": "Other Settings",
-  "API Token Settings": "API token settings",
-  "Current API Token": "Current API token",
-  "Update API Token": "Update API token",
   "in_app_notification_settings": {
     "in_app_notification_settings": "In-App Notification Settings",
     "subscribe_settings": "Settings to automatically subscribe (Receive notifications) to pages",
@@ -479,9 +507,27 @@
       "Search in Editor": "Search in Editor",
       "Move Line": "Move Line",
       "Copy Line": "Copy Line",
-      "Toggle Line": "Toggle Line Comment",
       "Insert Line": "Insert Line",
-      "Post Comment": "(Post Comment)"
+      "Post Comment": "(Post Comment)",
+      "Multiple Cursors": "Multiple Cursors",
+      "Or Alt Click": "or Alt + Click"
+    },
+    "format": {
+      "title": "Format Settings (Editor)",
+      "Bold": "Bold",
+      "Italic": "Italic",
+      "Strikethrough": "Strikethrough",
+      "Code Text": "Code Text",
+      "Hyperlink": "Hyperlink"
+    },
+    "line_settings": {
+      "title": "Line Settings (Editor)",
+      "Bullet List": "Bullet List",
+      "Numbered List": "Numbered List",
+      "Quote": "Quote",
+      "Code Block": "Code Block",
+      "Comment Out": "Comment Out",
+      "Comment Out Desc": "(Hide)"
     }
   },
   "modal_resolve_conflict": {
@@ -497,6 +543,8 @@
   },
   "sidebar_ai_assistant": {
     "reference_pages_label": "Reference pages",
+    "recent_chat": "Recent chat",
+    "no_recent_chat": "No recent chat",
     "placeholder": "Ask me anything.",
     "knowledge_assistant_placeholder": "Ask me anything.",
     "editor_assistant_placeholder": "Can I help you with anything?",
@@ -552,6 +600,17 @@
       "create_failed": "Failed to create assistant",
       "update_failed": "Failed to update assistant"
     },
+    "select_source_pages": "Select pages for the assistant to reference",
+    "search_reference_pages_by_keyword": "Search for pages the assistant will reference by keyword",
+    "search_by_keyword": "Search by keyword",
+    "enter_keywords": "Enter keywords",
+    "max_items_space_separated_hint": "Enter up to 5 items separated by spaces",
+    "select_assistant_reference_pages": "Select pages for the assistant to reference",
+    "reference_pages": "Reference pages",
+    "no_pages_selected": "No pages selected",
+    "can_add_later": "You can add more later",
+    "next": "Next",
+    "select_from_page_tree": "Select from page tree",
     "edit_page_description": "Edit pages that the assistant can reference.<br> The assistant can reference up to {{limitLearnablePageCountPerAssistant}} pages including child pages.",
     "default_instruction": "You are the knowledge assistant for this Wiki.\n\n## Multilingual Support:\nRespond in the same language the user uses in their input.\n",
     "add_page_button": "Add page",
@@ -603,11 +662,12 @@
   "default_ai_assistant": {
     "not_set": "Default assistant is not set"
   },
-  "ai_assistant_tree": {
+  "ai_assistant_substance": {
     "add_assistant": "Add Assistant",
     "my_assistants": "My Assistants",
     "team_assistants": "Team Assistants",
     "thread_does_not_exist": "No threads exist",
+    "recent_threads": "Recent Items",
     "toaster": {
       "ai_assistant_deleted_success": "Assistant deleted",
       "ai_assistant_deleted_failed": "Failed to delete assistant",
@@ -615,6 +675,10 @@
       "thread_deleted_failed": "Failed to delete thread",
       "ai_assistant_set_default_success": "Default assistant set successfully",
       "ai_assistant_set_default_failed": "Failed to set default assistant"
+    },
+    "delete_modal": {
+      "title": "Delete Assistant",
+      "confirm_message": "Are you sure you want to delete this assistant?"
     }
   },
   "link_edit": {
@@ -833,7 +897,7 @@
     "Password field is required": "Password field is required.",
     "Username or E-mail has invalid characters": "Username or E-mail has invalid characters.",
     "user_not_found": "User not found.",
-    "provider_duplicated_username_exception": "<p><strong><span class='material-symbols-outlined me-1'>cancel</span>DuplicatedUsernameException occured</strong></p><p class='mb-0'> Your {{ failedProviderForDuplicatedUsernameException }} authentication was succeeded, but a new user could not be created. See the issue <a href='https://github.com/weseek/growi/issues/193'>#193</a>.</p>"
+    "provider_duplicated_username_exception": "<p><strong><span class='material-symbols-outlined me-1'>cancel</span>DuplicatedUsernameException occured</strong></p><p class='mb-0'> Your {{ failedProviderForDuplicatedUsernameException }} authentication was succeeded, but a new user could not be created. See the issue <a href='https://github.com/growilabs/growi/issues/193'>#193</a>.</p>"
   },
   "grid_edit": {
     "create_bootstrap_4_grid": "Create Bootstrap 4 Grid",
@@ -958,23 +1022,6 @@
     "page_tree_not_avaliable": "Page tree feature is not available yet.",
     "go_to_settings": "Go to settings to enable the feature"
   },
-  "questionnaire": {
-    "give_us_feedback": "Give us feedback for improvements",
-    "thank_you_for_answering": "Thank you for answering",
-    "additional_feedback": "Send us additional feedback from the user icon dropdown.",
-    "dont_show_again": "Don`t show again",
-    "deny": "Don't answer",
-    "agree": "Agree",
-    "disagree": "Disagree",
-    "answer": "Answer",
-    "no_answer": "No answer",
-    "settings": "Questionnaire settings",
-    "failed_to_send": "Failed to send feedback",
-    "denied": "The questionnaire won't be shown again",
-    "personal_settings_explanation": "Questionnaires for improving GROWI will be shown. If you have other feedbacks, you can send them from the user icon dropdown.",
-    "enable_questionnaire": "Enable questionnaire",
-    "disabled_by_admin": "Questionnaire is disabled by admin"
-  },
   "tag_edit_modal": {
     "edit_tags": "Edit Tags",
     "done": "Done",
@@ -1015,4 +1062,4 @@
     "skipped-toaster": "Skipped synchronizing since the editor is not activated. Please open the editor and try again.",
     "error-toaster": "Synchronization of the latest text failed"
   }
-}
+}

+ 3 - 13
apps/app/public/static/locales/fr_FR/admin.json

@@ -313,7 +313,7 @@
       "done": "Copié dans le presse-papier!"
     },
     "bug_report": "Informations de diagnostic",
-    "submit_bug_report": "<a href='https://github.com/weseek/growi/issues/new?assignees=&labels=bug&template=bug-report.md&title=Bug%3A' target='_blank' rel='noreferrer'>soummettre ensuite sur GitHub.</a>"
+    "submit_bug_report": "<a href='https://github.com/growilabs/growi/issues/new?assignees=&labels=bug&template=bug-report.md&title=Bug%3A' target='_blank' rel='noreferrer'>soummettre ensuite sur GitHub.</a>"
   },
   "v5_page_migration": {
     "migration_desc": "Des pages sont encore en V4. Pour profiter des nouvelles fonctionnalitées, convertir toutes les pages vers la V5.",
@@ -411,17 +411,7 @@
     "enable": "Activer",
     "disable": "Désactiver",
     "use_env_var_if_empty": "Si la valeur dans la base de données est vide, la valeur de variable d'environnement <code>{{variable}}</code> est utilisé.",
-    "note_for_the_only_env_option": "Les paramètres sont définis par des variables d'environnement.<br>Pour modifier ce paramètre, supprimer la variable d'environnement <code>{{env}}</code> .",
-    "questionnaire_settings": "Sondages anonymes",
-    "questionnaire_settings_explanation": "Paramètres d'activation des données analytiques. L'utilisateur peut choisir ce paramètre individuellement dans \"Autres paramètres\".",
-    "about_data_sent": "À propos",
-    "docs_link": "https://docs.growi.org/en/admin-guide/management-cookbook/app-settings.html#questionnaire-settings",
-    "learn_more": "En savoir plus",
-    "other_info_will_be_sent": "En plus des données analytiques, des données diagnostiques pour améliorer GROWI sont envoyées. Les données personnelles ne sont pas incluses.",
-    "we_will_use_the_data_to_improve_growi": "Les données seront utilisées pour améliorer au mieux GROWI",
-    "anonymize_app_site_url": "Ne pas inclure l'URL du site",
-    "url_anonymization_explanation": "L'URL du site configurée ne sera pas inclue dans les données envoyées.",
-    "enable_questionnaire": "Activer les données analytiques"
+    "note_for_the_only_env_option": "Les paramètres sont définis par des variables d'environnement.<br>Pour modifier ce paramètre, supprimer la variable d'environnement <code>{{env}}</code> ."
   },
   "markdown_settings": {
     "markdown_settings": "Markdown",
@@ -1148,4 +1138,4 @@
     "disable_mode_explanation": "Actuellement, l'intégration AI est désactivée. Pour l'activer, configurez la variable d'environnement <code>AI_ENABLED</code> ainsi que les autres variables nécessaires.<br><br>Pour plus de détails, veuillez consulter la <a target='blank' rel='noopener noreferrer' href={{documentationUrl}}en/guide/features/ai-knowledge-assistant.html>documentation</a>.",
     "ai_search_management": "Gestion de la recherche par l'IA"
   }
-}
+}

+ 92 - 23
apps/app/public/static/locales/fr_FR/commons.json

@@ -111,29 +111,6 @@
       "import": "Importer"
     }
   },
-  "questionnaire_modal": {
-    "required": "Requis",
-    "submit": "Soumettre",
-    "close": "Fermer",
-    "title": "Sondages aléatoires GROWI pour données anonymisées.",
-    "more_satisfied_services": "Nous espérons satisfaire au mieux les utilisateurs de GROWI",
-    "strive_to_improve_services": "et utilisons les retours d'utilisateurs afin d'améliorer l'expérience d'usage GROWI",
-    "length_of_experience": {
-      "more_than_two_years": "Plus de 2 ans",
-      "one_to_two_years": "Plus d'un an, mais moins de 2 ans",
-      "six_months_to_one_year": "Plus de 6 mois, mais moins d'un an",
-      "three_months_to_six_months": "Plus de 3 mois, mais moins de 6 mois",
-      "one_month_to_three_months": "Plus d'un moins, mais moins de 3 mois",
-      "less_than_one_month": "Moins d'un mois"
-    },
-    "satisfaction_with_growi": "Satisfaction avec GROWI",
-    "history_of_growi_usage": "Historique d'usage de GROWI",
-    "occupation": "Occupation",
-    "position": "Position",
-    "comment_on_growi": "Commentaires sur GROWI",
-    "successfully_submitted": "Questionnaire soumis.",
-    "thanks_for_answering": "Merci pour votre avis."
-  },
   "not_found_page": {
     "page_not_exist": "Cette page est introuvable."
   },
@@ -145,5 +122,97 @@
     "transfer_key_limit": "Les clés de transfert sont valides durant une heure.",
     "once_transfer_key_used": "Les clés de transfert sont à usage unique.",
     "transfer_to_growi_cloud": "Pour plus de détails, veuillez cliquer <a href='{{documentationUrl}}en/admin-guide/management-cookbook/g2g-transfer.html'>ici.</a>"
+  },
+  "accesstoken_scopes_desc": {
+    "read": {
+      "all": "Accorde la permission de voir tout le contenu.",
+      "admin": {
+        "all": "Accorde la permission de voir les fonctionnalités d'administration.",
+        "top": "Accorde la permission de voir la page principale de gestion du Wiki.",
+        "app": "Accorde la permission de voir les paramètres de l'application.",
+        "security": "Accorde la permission de voir les paramètres de sécurité.",
+        "markdown": "Accorde la permission de voir les paramètres markdown.",
+        "customize": "Accorde la permission de voir les paramètres de personnalisation.",
+        "import_data": "Accorde la permission de voir les paramètres d'importation de données.",
+        "export_data": "Accorde la permission de voir les paramètres d'archivage de données.",
+        "data_transfer": "Accorde la permission de voir les paramètres de transfert de données.",
+        "external_notification": "Accorde la permission de voir les paramètres de notification externe.",
+        "slack_integration": "Accorde la permission de voir les paramètres d'intégration Slack.",
+        "legacy_slack_integration": "Accorde la permission de voir les paramètres d'intégration Slack (ancien).",
+        "user_management": "Accorde la permission de voir la gestion des utilisateurs.",
+        "user_group_management": "Accorde la permission de voir la gestion des groupes d'utilisateurs.",
+        "audit_log": "Accorde la permission de voir les journaux d'audit.",
+        "plugin": "Accorde la permission de voir les paramètres des plugins.",
+        "ai_integration": "Accorde la permission de voir les paramètres d'intégration IA.",
+        "full_text_search": "Accorde la permission de voir la gestion de la recherche en texte intégral."
+      },
+      "user_settings": {
+        "all": "Accorde la permission de voir les paramètres utilisateur.",
+        "info": "Accorde la permission de voir les informations utilisateur.",
+        "external_account": "Accorde la permission de voir les comptes externes.",
+        "password": "Accorde la permission de voir les paramètres de mot de passe.",
+        "api": {
+          "all": "Accorde la permission de voir les paramètres API.",
+          "api_token": "Accorde la permission de voir les paramètres de jeton API.",
+          "access_token": "Accorde la permission de voir les paramètres de jeton d'accès."
+        },
+        "in_app_notification": "Accorde la permission de voir les paramètres de notification dans l'application.",
+        "other": "Accorde la permission de voir les autres paramètres."
+      },
+      "features": {
+        "all": "Accorde la permission de voir les fonctionnalités.",
+        "ai_assistant": "Accorde la permission de voir les fonctionnalités d'assistant IA.",
+        "page": "Accorde la permission de voir les fonctionnalités de page.",
+        "share_link": "Accorde la permission de voir les fonctionnalités de lien de partage.",
+        "bookmark": "Accorde la permission de voir les fonctionnalités de signet.",
+        "attachment": "Accorde la permission de voir les fonctionnalités de pièce jointe.",
+        "page_bulk_export": "Accorde la permission de voir les fonctionnalités d'exportation en masse de pages."
+      }
+    },
+    "write": {
+      "all": "Accorde la permission de modifier tout le contenu.",
+      "admin": {
+        "all": "Accorde la permission de modifier les fonctionnalités d'administration.",
+        "top": "Accorde la permission de modifier la page principale de gestion du Wiki.",
+        "app": "Accorde la permission de modifier les paramètres de l'application.",
+        "security": "Accorde la permission de modifier les paramètres de sécurité.",
+        "markdown": "Accorde la permission de modifier les paramètres markdown.",
+        "customize": "Accorde la permission de modifier les paramètres de personnalisation.",
+        "import_data": "Accorde la permission de modifier les paramètres d'importation de données.",
+        "export_data": "Accorde la permission de modifier les paramètres d'archivage de données.",
+        "data_transfer": "Accorde la permission de modifier les paramètres de transfert de données.",
+        "external_notification": "Accorde la permission de modifier les paramètres de notification externe.",
+        "slack_integration": "Accorde la permission de modifier les paramètres d'intégration Slack.",
+        "legacy_slack_integration": "Accorde la permission de modifier les paramètres d'intégration Slack (ancien).",
+        "user_management": "Accorde la permission de modifier la gestion des utilisateurs.",
+        "user_group_management": "Accorde la permission de modifier la gestion des groupes d'utilisateurs.",
+        "audit_log": "Accorde la permission de modifier les journaux d'audit.",
+        "plugin": "Accorde la permission de modifier les paramètres des plugins.",
+        "ai_integration": "Accorde la permission de modifier les paramètres d'intégration IA.",
+        "full_text_search": "Accorde la permission de modifier la gestion de la recherche en texte intégral."
+      },
+      "user_settings": {
+        "all": "Accorde la permission de modifier les paramètres utilisateur.",
+        "info": "Accorde la permission de modifier les informations utilisateur.",
+        "external_account": "Accorde la permission de modifier les comptes externes.",
+        "password": "Accorde la permission de modifier les paramètres de mot de passe.",
+        "api": {
+          "all": "Accorde la permission de modifier les paramètres API.",
+          "api_token": "Accorde la permission de modifier les paramètres de jeton API.",
+          "access_token": "Accorde la permission de modifier les paramètres de jeton d'accès."
+        },
+        "in_app_notification": "Accorde la permission de modifier les paramètres de notification dans l'application.",
+        "other": "Accorde la permission de modifier les autres paramètres."
+      },
+      "features": {
+        "all": "Accorde la permission de modifier les fonctionnalités.",
+        "ai_assistant": "Accorde la permission de modifier les fonctionnalités d'assistant IA.",
+        "page": "Accorde la permission de modifier les fonctionnalités de page.",
+        "share_link": "Accorde la permission de modifier les fonctionnalités de lien de partage.",
+        "bookmark": "Accorde la permission de modifier les fonctionnalités de signet.",
+        "attachment": "Accorde la permission de modifier les fonctionnalités de pièce jointe.",
+        "page_bulk_export": "Accorde la permission de modifier les fonctionnalités d'exportation en masse de pages."
+      }
+    }
   }
 }

+ 74 - 27
apps/app/public/static/locales/fr_FR/translation.json

@@ -143,7 +143,6 @@
   "edited this page": "à modifié cette page.",
   "List Drafts": "Brouillons",
   "Deleted Pages": "Pages supprimées",
-  "Questionnaire": "Questionnaire",
   "Disassociate": "Dissocier",
   "No bookmarks yet": "Aucuns favoris",
   "add_bookmark": "Ajouter aux favoris",
@@ -223,6 +222,9 @@
       "profile_image2": "Configurer AWS ou activer le stockage local."
     }
   },
+  "API Token Settings": "Jetons d'API",
+  "Current API Token": "Mon jeton d'API",
+  "Update API Token": "Regénérer",
   "page_me_apitoken": {
     "api_token": "Jeton API",
     "notice": {
@@ -232,6 +234,35 @@
     },
     "form_help": {}
   },
+  "Access Token Settings": "Jeton d'accès",
+  "page_me_access_token": {
+    "access_token": "Jeton d'accès",
+    "expiredAt": "Date d'expiration",
+    "description": "Description",
+    "scope": "Portée",
+    "scope_read": "Lecture",
+    "action": "Action",
+    "create_token": "Créer un jeton",
+    "no_tokens_found": "Aucun jeton d'accès trouvé",
+    "new_token": {
+      "title": "Nouveau jeton d'accès",
+      "copy_to_clipboard": "Copier dans le presse-papiers",
+      "message": "Ce jeton ne sera affiché qu'une seule fois. Veuillez le sauvegarder en lieu sûr."
+    },
+    "modal": {
+      "message": "Êtes-vous sûr de vouloir supprimer ce jeton d'accès ?",
+      "alert": "Cette action ne peut pas être annulée.",
+      "delete_token": "Supprimer le jeton"
+    },
+    "form": {
+      "title": "Créer un nouveau jeton d'accès",
+      "expiredAt_desc": "Sélectionnez la date d'expiration de ce jeton d'accès.",
+      "description_desc": "Fournissez une description pour vous aider à identifier ce jeton ultérieurement.",
+      "description_max_length": "Veuillez saisir jusqu'à {{length}} caractères.",
+      "scope_desc": "Sélectionnez la portée du jeton d'accès."
+    },
+    "copy_to_clipboard": "Copier dans le presse-papiers"
+  },
   "Password": "Mot de passe",
   "Password Settings": "Sécurité",
   "personal_settings": {
@@ -262,9 +293,6 @@
   },
   "API Settings": "API GROWI",
   "Other Settings": "Autres paramètres",
-  "API Token Settings": "Jetons d'API",
-  "Current API Token": "Mon jeton d'API",
-  "Update API Token": "Regénérer",
   "in_app_notification_settings": {
     "in_app_notification_settings": "Notifications",
     "subscribe_settings": "Paramètres d'abonnement automatique aux notifications de pages",
@@ -460,7 +488,7 @@
       "Create Page": "Créer page",
       "Search": "Rechercher",
       "Show Contributors": "Voir contributeurs",
-      "MirrorMode": "Mode mirroir",
+      "MirrorMode": "Mode miroir",
       "Konami Code": "Code Konami",
       "konami_code_url": "https://fr.wikipedia.org/wiki/Code_Konami"
     },
@@ -474,9 +502,27 @@
       "Search in Editor": "Rechercher dans l'éditeur",
       "Move Line": "Déplacer la ligne",
       "Copy Line": "Copier la ligne",
-      "Toggle Line": "Commenter/Décommenter la ligne",
       "Insert Line": "Insérer une ligne",
-      "Post Comment": "(Publier le commentaire)"
+      "Post Comment": "(Publier le commentaire)",
+      "Multiple Cursors": "Curseurs multiples",
+      "Or Alt Click": "ou Alt + Clic"
+    },
+    "format": {
+      "title": "Paramètres de format (Éditeur)",
+      "Bold": "Gras",
+      "Italic": "Italique",
+      "Strikethrough": "Barré",
+      "Code Text": "Texte de code",
+      "Hyperlink": "Lien hypertexte"
+    },
+    "line_settings": {
+      "title": "Paramètres de ligne (Éditeur)",
+      "Bullet List": "Liste à puces",
+      "Numbered List": "Liste numérotée",
+      "Quote": "Citation",
+      "Code Block": "Bloc de code",
+      "Comment Out": "Masquer",
+      "Comment Out Desc": "(Commenter)"
     }
   },
   "modal_resolve_conflict": {
@@ -492,6 +538,8 @@
   },
   "sidebar_ai_assistant": {
     "reference_pages_label": "Pages de référence",
+    "recent_chat": "Chat récent",
+    "no_recent_chat": "Pas de chat récent",
     "knowledge_assistant_placeholder": "Demandez-moi n'importe quoi.",
     "editor_assistant_placeholder": "Puis-je vous aider ?",
     "summary_mode_label": "Mode résumé",
@@ -546,6 +594,17 @@
       "create_failed": "Échec de la création de l'assistant",
       "update_failed": "Échec de la mise à jour de l'assistant"
     },
+    "select_source_pages": "Sélectionnez les pages que l'assistant doit référencer",
+    "search_reference_pages_by_keyword": "Rechercher les pages de référence de l'assistant par mot-clé",
+    "search_by_keyword": "Rechercher par mot-clé",
+    "max_items_space_separated_hint": "Saisissez jusqu'à 5 éléments séparés par des espaces",
+    "select_assistant_reference_pages": "Sélectionnez les pages de référence pour l'assistant",
+    "enter_keywords": "Entrer des mots-clés",
+    "reference_pages": "Pages de référence",
+    "no_pages_selected": "Aucune page sélectionnée",
+    "can_add_later": "Vous pouvez en ajouter plus tard",
+    "next": "Suivant",
+    "select_from_page_tree": "Sélectionner depuis l'arborescence des pages",
     "edit_page_description": "Modifier les pages que l'assistant peut référencer.<br> L'assistant peut référencer jusqu'à {{limitLearnablePageCountPerAssistant}} pages, y compris les pages enfants.",
     "default_instruction": "Vous êtes l'assistant de connaissances pour ce Wiki.\n\n## Support multilingue :\nRépondez dans la même langue que celle utilisée par l'utilisateur dans sa requête.\n",
     "add_page_button": "Ajouter une page",
@@ -597,11 +656,12 @@
   "default_ai_assistant": {
     "not_set": "L'assistant par défaut n'est pas configuré"
   },
-  "ai_assistant_tree": {
+  "ai_assistant_substance": {
     "add_assistant": "Ajouter un assistant",
     "my_assistants": "Mes assistants",
     "team_assistants": "Assistants d'équipe",
     "thread_does_not_exist": "Aucune discussion",
+    "recent_threads": "Éléments récents",
     "toaster": {
       "ai_assistant_deleted_success": "Assistant supprimé",
       "ai_assistant_deleted_failed": "Échec de la suppression de l'assistant",
@@ -609,6 +669,10 @@
       "thread_deleted_failed": "Échec de la suppression de la discussion",
       "ai_assistant_set_default_success": "Assistant par défaut défini avec succès",
       "ai_assistant_set_default_failed": "Échec de la définition de l'assistant par défaut"
+    },
+    "delete_modal": {
+      "title": "Supprimer l'assistant",
+      "confirm_message": "Êtes-vous sûr de vouloir supprimer cet assistant ?"
     }
   },
   "link_edit": {
@@ -827,7 +891,7 @@
     "Password field is required": "Mot de passe requis.",
     "Username or E-mail has invalid characters": "Le nom d'utilisateur ou l'adresse courriel contient des caractères invalides",
     "user_not_found": "Utilisateur introuvable.",
-    "provider_duplicated_username_exception": "<p><strong><span class='material-symbols-outlined me-1'>cancel</span>DuplicatedUsernameException</strong></p><p class='mb-0'> L'authentification est réussie pour {{ failedProviderForDuplicatedUsernameException }} , mais la création d'un utilisateur a échouée. Voir <a href='https://github.com/weseek/growi/issues/193'>#193</a>.</p>"
+    "provider_duplicated_username_exception": "<p><strong><span class='material-symbols-outlined me-1'>cancel</span>DuplicatedUsernameException</strong></p><p class='mb-0'> L'authentification est réussie pour {{ failedProviderForDuplicatedUsernameException }} , mais la création d'un utilisateur a échouée. Voir <a href='https://github.com/growilabs/growi/issues/193'>#193</a>.</p>"
   },
   "grid_edit": {
     "create_bootstrap_4_grid": "Créer grille Bootstrap 4",
@@ -952,23 +1016,6 @@
     "page_tree_not_avaliable": "Cette fonctionnalité n'est pas encore disponible.",
     "go_to_settings": "Activer cette fonctionnalité dans les paramètres"
   },
-  "questionnaire": {
-    "give_us_feedback": "Faites-nous part de votre avis",
-    "thank_you_for_answering": "Merci pour votre réponse",
-    "additional_feedback": "Envoyez-nous votre avis depuis le menu déroulant sur le menu utilisateur.",
-    "dont_show_again": "Ne plus afficher",
-    "deny": "Ne pas répondre",
-    "agree": "En accord",
-    "disagree": "En désaccord",
-    "answer": "Répondre",
-    "no_answer": "Aucune réponse",
-    "settings": "Sondages anonymes",
-    "failed_to_send": "Échec de l'envoi du sondage",
-    "denied": "Les sondages ne seront plus affichés.",
-    "personal_settings_explanation": "Sondages de satisfaction anonymes.",
-    "enable_questionnaire": "Sondages anonymes",
-    "disabled_by_admin": "Sondages anonymes désactivés par l'administrateur"
-  },
   "tag_edit_modal": {
     "edit_tags": "Étiquettes",
     "done": "Mettre à jour",
@@ -1006,4 +1053,4 @@
     "skipped-toaster": "L'éditeur n'est pas actif. Synchronisation annulée.",
     "error-toaster": "Synchronisation échouée"
   }
-}
+}

+ 3 - 13
apps/app/public/static/locales/ja_JP/admin.json

@@ -322,7 +322,7 @@
       "done": "クリップボードにコピーしました!"
     },
     "bug_report": "バグを報告する",
-    "submit_bug_report": "<a href='https://github.com/weseek/growi/issues/new?assignees=&labels=bug&template=bug-report.md&title=Bug%3A' target='_blank' rel='noreferrer'>次に GitHub で Issue を投稿してください。</a>"
+    "submit_bug_report": "<a href='https://github.com/growilabs/growi/issues/new?assignees=&labels=bug&template=bug-report.md&title=Bug%3A' target='_blank' rel='noreferrer'>次に GitHub で Issue を投稿してください。</a>"
   },
   "v5_page_migration": {
     "migration_desc": "公開されているページに 古い v4 互換形式のものが存在します。ページツリーや簡単なリネームなどの新機能を利用するには、全てのページを v5 互換形式に変換してください。",
@@ -420,17 +420,7 @@
     "enable": "有効",
     "disable": "無効",
     "use_env_var_if_empty": "データベース側の値が空の場合、環境変数 <code>{{variable}}</code> の値を利用します",
-    "note_for_the_only_env_option": "現在GCS設定は環境変数の値によって制限されています<br>この設定を変更する場合は環境変数 <code>{{env}}</code> の値をfalseに変更もしくは削除してください",
-    "questionnaire_settings": "アンケート設定",
-    "questionnaire_settings_explanation": "システム全体でアンケート機能を有効/無効にします。有効の場合、各ユーザーはユーザー設定ページの「その他の設定」から個別にアンケート機能を有効/無効にできます。",
-    "about_data_sent": "送信される情報について",
-    "docs_link": "https://docs.growi.org/ja/admin-guide/management-cookbook/app-settings.html#%E3%82%A2%E3%83%B3%E3%82%B1%E3%83%BC%E3%83%88%E8%A8%AD%E5%AE%9A",
-    "learn_more": "詳細",
-    "other_info_will_be_sent": "アンケートの回答と合わせて、GROWI の改善に必要な情報を送信します。送信されるデータにユーザーの個人情報は含まれません。",
-    "we_will_use_the_data_to_improve_growi": "私たちはそれらを活用し、最大限ユーザーの体験を向上させるよう努めます。",
-    "anonymize_app_site_url": "サイト URL を匿名化して送信する",
-    "url_anonymization_explanation": "アンケート回答データに含まれるサイト URL が匿名化されます。この設定を有効にすることで、アンケート回答データの送信元である GROWI アプリケーションが特定されなくなります。",
-    "enable_questionnaire": "アンケートを有効にする"
+    "note_for_the_only_env_option": "現在GCS設定は環境変数の値によって制限されています<br>この設定を変更する場合は環境変数 <code>{{env}}</code> の値をfalseに変更もしくは削除してください"
   },
   "markdown_settings": {
     "markdown_settings": "マークダウン設定",
@@ -1158,4 +1148,4 @@
     "disable_mode_explanation": "現在、AI 連携は無効になっています。有効にする場合は環境変数 <code>AI_ENABLED</code> の他、必要な環境変数を設定してください。<br><br>詳細は<a target='blank' rel='noopener noreferrer' href={{documentationUrl}}ja/guide/features/ai-knowledge-assistant.html>ドキュメント</a>を参照してください。",
     "ai_search_management": "AI 検索管理"
   }
-}
+}

+ 93 - 35
apps/app/public/static/locales/ja_JP/commons.json

@@ -32,7 +32,6 @@
   "headers": {
     "app_settings": "アプリ設定"
   },
-
   "header_search_box": {
     "label": {
       "All pages": "全てのページ",
@@ -43,20 +42,17 @@
       "This tree": "この階層下の子ページのみ"
     }
   },
-
   "search_method_menu_item": {
     "search_in_all": "全てのページ",
     "only_children_of_this_tree": "この階層下の子ページのみ",
     "exact_mutch": "キーワードに完全一致した文字を含むページのみ"
   },
-
   "share_links": {
     "Share Link": "共有用リンク",
     "Page Path": "ページパス",
     "expire": "有効期限",
     "description": "概要"
   },
-
   "in_app_notification": {
     "notification_list": "アプリ内通知一覧",
     "see_all": "通知一覧を見る",
@@ -67,7 +63,6 @@
     "no_unread_messages": "未読はありません",
     "only_unread": "未読のみ"
   },
-
   "personal_dropdown": {
     "home": "ホーム",
     "settings": "設定",
@@ -77,7 +72,6 @@
     "use_os_settings": "OS設定を利用する",
     "feedback": "ご意見・ご要望"
   },
-
   "create_page_dropdown": {
     "new_page": "新規ページ作成",
     "open_page_create_modal": "新規ページ作成モーダルを表示",
@@ -91,7 +85,6 @@
       "descendants": "下位層テンプレート"
     }
   },
-
   "copy_to_clipboard": {
     "Copy to clipboard": "クリップボードにコピー",
     "Page path": "ページ名",
@@ -101,14 +94,12 @@
     "Markdown link": "マークダウン形式のリンク",
     "Append params": "パラメータの追加"
   },
-
   "crop_image_modal": {
     "image_crop": "画像の切り抜き",
     "crop": "トリミング",
     "save": "保存",
     "cancel": "キャンセル"
   },
-
   "handsontable_modal": {
     "title": "テーブル編集",
     "data_import": "データインポート",
@@ -124,35 +115,9 @@
       "import": "インポート"
     }
   },
-
-  "questionnaire_modal": {
-    "required": "必須",
-    "submit": "送信",
-    "close": "閉じる",
-    "title": "GROWI サービス改善のためのアンケート",
-    "more_satisfied_services": "GROWI をご利用の皆さまに更にご満足いただけるよう",
-    "strive_to_improve_services": "皆さまからのご意見を参考にサービス改善に努めてまいります。",
-    "length_of_experience": {
-      "more_than_two_years": "2年以上",
-      "one_to_two_years": "1年以上2年未満",
-      "six_months_to_one_year": "6ヶ月以上1年未満",
-      "three_months_to_six_months": "3ヶ月以上6ヶ月未満",
-      "one_month_to_three_months": "1ヶ月以上3ヶ月未満",
-      "less_than_one_month": "1ヶ月未満"
-    },
-    "satisfaction_with_growi": "GROWI の満足度",
-    "history_of_growi_usage": "GROWI の利用歴",
-    "occupation": "職種",
-    "position": "役職",
-    "comment_on_growi": "GROWI へのコメント",
-    "successfully_submitted": "アンケートの送信が完了しました。",
-    "thanks_for_answering": "アンケートのご回答誠にありがとうございました。"
-  },
-
   "not_found_page": {
     "page_not_exist": "このページは存在しません。"
   },
-
   "g2g_data_transfer": {
     "tab": "データ移行",
     "data_transfer": "データ移行",
@@ -161,5 +126,98 @@
     "transfer_key_limit": "※ 移行キーの有効期限は発行から1時間となります。",
     "once_transfer_key_used": "※ 移行キーは一度移行に利用するとそれ以降はご利用いただけなくなります。",
     "transfer_to_growi_cloud": "※ 詳しくは <a href='{{documentationUrl}}ja/admin-guide/management-cookbook/g2g-transfer.html'> GROWI お引越し機能</a>をご確認ください。"
+  },
+
+  "accesstoken_scopes_desc": {
+    "read": {
+      "all": "全ての閲覧権限を付与できます。",
+      "admin": {
+        "all": "管理者機能の閲覧権限を付与できます。",
+        "top": "Wiki管理トップの閲覧権限を付与できます。",
+        "app": "アプリ設定の閲覧権限を付与できます。",
+        "security": "セキュリティ設定の閲覧権限を付与できます。",
+        "markdown": "マークダウン設定の閲覧権限を付与できます。",
+        "customize": "カスタマイズの閲覧権限を付与できます。",
+        "import_data": "データインポートの閲覧権限を付与できます。",
+        "export_data": "データアーカイブの閲覧権限を付与できます。",
+        "data_transfer": "データ移行の閲覧権限を付与できます。",
+        "external_notification": "外部ツールへの通知の閲覧権限を付与できます。",
+        "slack_integration": "Slack連携の閲覧権限を付与できます。",
+        "legacy_slack_integration": "Slack連携(レガシー)の閲覧権限を付与できます。",
+        "user_management": "ユーザー管理の閲覧権限を付与できます。",
+        "user_group_management": "ユーザーグループ管理の閲覧権限を付与できます。",
+        "audit_log": "監査ログの閲覧権限を付与できます。",
+        "plugin": "プラグインの閲覧権限を付与できます。",
+        "ai_integration": "AI連携設定の閲覧権限を付与できます。",
+        "full_text_search": "全文検索管理の閲覧権限を付与できます。"
+      },
+      "user_settings": {
+        "all": "ユーザー設定の閲覧権限を付与できます。",
+        "info": "ユーザー情報の閲覧権限を付与できます。",
+        "external_account": "外部アカウントの閲覧権限を付与できます。",
+        "password": "パスワード設定の閲覧権限を付与できます。",
+        "api": {
+          "all": "API 設定の閲覧権限を付与できます。",
+          "api_token": "API トークン設定の閲覧権限を付与できます。",
+          "access_token": "アクセストークン設定の閲覧権限を付与できます。"
+        },
+        "in_app_notification": "アプリ内通知設定の閲覧権限を付与できます。",
+        "other": "その他設定の閲覧権限を付与できます。"
+      },
+      "features": {
+        "all": "機能の閲覧権限を付与できます。",
+        "ai_assistant": "AIアシスタント機能の閲覧権限を付与できます。",
+        "page": "ページ機能の閲覧権限を付与できます。",
+        "share_link": "共有リンク機能の閲覧権限を付与できます。",
+        "bookmark": "ブックマーク機能の閲覧権限を付与できます。",
+        "attachment": "添付ファイル機能の閲覧権限を付与できます。",
+        "page_bulk_export": "ページの一括エクスポート機能の閲覧権限を付与できます。"
+      }
+    },
+    "write": {
+      "all": "全ての編集権限を付与できます。",
+      "admin": {
+        "all": "管理者機能の編集権限を付与できます。",
+        "top": "Wiki管理トップの編集権限を付与できます。",
+        "app": "アプリ設定の編集権限を付与できます。",
+        "security": "セキュリティ設定の編集権限を付与できます。",
+        "markdown": "マークダウン設定の編集権限を付与できます。",
+        "customize": "カスタマイズの編集権限を付与できます。",
+        "import_data": "データインポートの編集権限を付与できます。",
+        "export_data": "データアーカイブの編集権限を付与できます。",
+        "data_transfer": "データ移行の編集権限を付与できます。",
+        "external_notification": "外部ツールへの通知の編集権限を付与できます。",
+        "slack_integration": "Slack連携の編集権限を付与できます。",
+        "legacy_slack_integration": "Slack連携(レガシー)の編集権限を付与できます。",
+        "user_management": "ユーザー管理の編集権限を付与できます。",
+        "user_group_management": "ユーザーグループ管理の編集権限を付与できます。",
+        "audit_log": "監査ログの編集権限を付与できます。",
+        "plugin": "プラグインの編集権限を付与できます。",
+        "ai_integration": "AI連携設定の編集権限を付与できます。",
+        "full_text_search": "全文検索管理の編集権限を付与できます。"
+      },
+      "user_settings": {
+        "all": "ユーザー設定の編集権限を付与できます。",
+        "info": "ユーザー情報の編集権限を付与できます。",
+        "external_account": "外部アカウントの編集権限を付与できます。",
+        "password": "パスワード設定の編集権限を付与できます。",
+        "api": {
+          "all": "API 設定の編集権限を付与できます。",
+          "api_token": "API トークン設定の編集権限を付与できます。",
+          "access_token": "アクセストークン設定の編集権限を付与できます。"
+        },
+        "in_app_notification": "アプリ内通知設定の編集権限を付与できます。",
+        "other": "その他設定の編集権限を付与できます。"
+      },
+      "features": {
+        "all": "機能の編集権限を付与できます。",
+        "ai_assistant": "AIアシスタント機能の編集権限を付与できます。",
+        "page": "ページ機能の編集権限を付与できます。",
+        "share_link": "共有リンク機能の編集権限を付与できます。",
+        "bookmark": "ブックマーク機能の編集権限を付与できます。",
+        "attachment": "添付ファイル機能の編集権限を付与できます。",
+        "page_bulk_export": "ページの一括エクスポート機能の編集権限を付与できます。"
+      }
+    }
   }
 }

+ 74 - 26
apps/app/public/static/locales/ja_JP/translation.json

@@ -223,6 +223,9 @@
       "profile_image2": "アップロードできるようにするには、AWS またはローカルアップロードの設定をしてください。"
     }
   },
+  "API Token Settings": "API Token設定",
+  "Current API Token": "現在のAPI Token",
+  "Update API Token": "API Tokenを更新",
   "page_me_apitoken": {
     "api_token": "API Token",
     "notice": {
@@ -232,6 +235,35 @@
     },
     "form_help": {}
   },
+  "Access Token Settings": "Access token 設定",
+  "page_me_access_token": {
+    "access_token": "Access token",
+    "expiredAt": "有効期限",
+    "description": "説明",
+    "scope": "スコープ",
+    "scope_read": "Read",
+    "action": "アクション",
+    "create_token": "トークンを作成",
+    "no_tokens_found": "アクセストークンが見つかりません",
+    "new_token": {
+      "title": "新しいアクセストークン",
+      "copy_to_clipboard": "クリップボードにコピーしました",
+      "message": "このアクセストークンは一度しか表示されません。安全に保存してください"
+    },
+    "modal": {
+      "message": "このアクセストークンを削除しますか?",
+      "alert": "この操作は取り消せません",
+      "delete_token": "トークンを削除"
+    },
+    "form": {
+      "title": "アクセストークンを作成",
+      "expiredAt_desc": "アクセストークンの有効期限を選択します。",
+      "description_desc": "このトークンを後で識別するための説明を入力します。",
+      "description_max_length": "{{length}}文字以内で入力してください。",
+      "scope_desc": "スコープによって、このトークンで行える操作を制限します。"
+    },
+    "copy_to_clipboard": "Copy to clipboard"
+  },
   "Password": "パスワード",
   "Password Settings": "パスワード設定",
   "personal_settings": {
@@ -262,9 +294,6 @@
   },
   "API Settings": "API設定",
   "Other Settings": "その他の設定",
-  "API Token Settings": "API Token設定",
-  "Current API Token": "現在のAPI Token",
-  "Update API Token": "API Tokenを更新",
   "in_app_notification_settings": {
     "in_app_notification_settings": "アプリ内通知設定",
     "subscribe_settings": "自動でページをサブスクライブする(通知を受け取る)設定",
@@ -512,9 +541,27 @@
       "Search in Editor": "エディター内検索",
       "Move Line": "行の移動",
       "Copy Line": "行のコピー",
-      "Toggle Line": "行の非表示化",
       "Insert Line": "行を挿入",
-      "Post Comment": "(コメント投稿)"
+      "Post Comment": "(コメント投稿)",
+      "Multiple Cursors": "複数カーソル",
+      "Or Alt Click": "もしくは Alt + クリック"
+    },
+    "format": {
+      "title": "書式設定 (エディター)",
+      "Bold": "太字",
+      "Italic": "斜体",
+      "Strikethrough": "取り消し線",
+      "Code Text": "コードテキスト",
+      "Hyperlink": "ハイパーリンク"
+    },
+    "line_settings": {
+      "title": "行の設定 (エディター)",
+      "Bullet List": "箇条書きリスト",
+      "Numbered List": "番号付きリスト",
+      "Quote": "引用",
+      "Code Block": "コードブロック",
+      "Comment Out": "非表示にする",
+      "Comment Out Desc": "(コメントアウト)"
     }
   },
   "modal_resolve_conflict": {
@@ -530,6 +577,8 @@
   },
   "sidebar_ai_assistant": {
     "reference_pages_label": "参照するページ",
+    "recent_chat": "最近のチャット",
+    "no_recent_chat": "チャットがありません",
     "knowledge_assistant_placeholder": "ききたいことを入力してください",
     "editor_assistant_placeholder": "お手伝いできることはありますか?",
     "summary_mode_label": "要約モード",
@@ -584,6 +633,17 @@
       "create_failed": "アシスタントの作成に失敗しました",
       "update_failed": "アシスタントの更新に失敗しました"
     },
+    "select_source_pages": "アシスタントが参照するページを選択します",
+    "search_reference_pages_by_keyword": "アシスタントが参照するページをキーワードで検索",
+    "search_by_keyword": "キーワードで検索",
+    "enter_keywords": "キーワードを入力",
+    "max_items_space_separated_hint": "スペース区切りで最大5つまで入力できます",
+    "select_assistant_reference_pages": "アシスタントが参照するページを選択してください",
+    "reference_pages": "参照するページ",
+    "no_pages_selected": "ページが選択されていません",
+    "can_add_later": "あとからでも追加できます",
+    "next": "次へ",
+    "select_from_page_tree": "ページツリーから選択",
     "edit_page_description": " アシスタントが参照するページを編集します。<br> 参照できるページは配下ページも含めて {{limitLearnablePageCountPerAssistant}} ページまでです。",
     "default_instruction": "あなたはこのWikiの知識アシスタントです。\n\n## 多言語サポート:\nユーザーが入力で使用した言語と同じ言語で応答してください。\n",
     "add_page_button": "ページを追加する",
@@ -635,11 +695,12 @@
   "default_ai_assistant": {
     "not_set": "デフォルトアシスタントが設定されていません"
   },
-  "ai_assistant_tree": {
+  "ai_assistant_substance": {
     "add_assistant": "アシスタントを追加する",
     "my_assistants": "マイアシスタント",
     "team_assistants": "チームアシスタント",
     "thread_does_not_exist": "スレッドが存在しません",
+    "recent_threads": "最近の項目",
     "toaster": {
       "ai_assistant_deleted_success": "アシスタントを削除しました",
       "ai_assistant_deleted_failed": "アシスタントの削除に失敗しました",
@@ -647,6 +708,10 @@
       "thread_deleted_failed": "スレッドの削除に失敗しました",
       "ai_assistant_set_default_success": "デフォルトアシスタントを設定しました",
       "ai_assistant_set_default_failed": "デフォルトアシスタントの設定に失敗しました"
+    },
+    "delete_modal": {
+      "title": "アシスタントを削除する",
+      "confirm_message": "本当にアシスタントを削除しますか?"
     }
   },
   "link_edit": {
@@ -865,7 +930,7 @@
     "Password field is required": "パスワードの欄は必ず入力してください",
     "Username or E-mail has invalid characters": "ユーザー名または、メールアドレスに無効な文字があります",
     "user_not_found": "ユーザーが見つかりません",
-    "provider_duplicated_username_exception": "<p><strong><span class='material-symbols-outlined me-1'>cancel</span>エラー: DuplicatedUsernameException</strong></p><p class='mb-0'> {{ failedProviderForDuplicatedUsernameException }} 認証は成功しましたが、新しいユーザーを作成できませんでした。詳しくは<a href='https://github.com/weseek/growi/issues/193'>こちら: #193</a>.</p>"
+    "provider_duplicated_username_exception": "<p><strong><span class='material-symbols-outlined me-1'>cancel</span>エラー: DuplicatedUsernameException</strong></p><p class='mb-0'> {{ failedProviderForDuplicatedUsernameException }} 認証は成功しましたが、新しいユーザーを作成できませんでした。詳しくは<a href='https://github.com/growilabs/growi/issues/193'>こちら: #193</a>.</p>"
   },
   "grid_edit": {
     "create_bootstrap_4_grid": "Bootstrap 4 グリッドを作成",
@@ -990,23 +1055,6 @@
     "page_tree_not_avaliable": "Page Tree 機能は現在使用できません。",
     "go_to_settings": "設定する"
   },
-  "questionnaire": {
-    "give_us_feedback": "GROWI の改善のために、アンケートにご協力ください",
-    "thank_you_for_answering": "ご回答ありがとうございます",
-    "additional_feedback": "その他ご意見ご要望はユーザーアイコンのドロップダウンからお願い致します。",
-    "dont_show_again": "今後このアンケートを表示しない",
-    "deny": "回答しない",
-    "agree": "そう思う",
-    "disagree": "そう思わない",
-    "answer": "回答する",
-    "no_answer": "わからない",
-    "settings": "アンケート設定",
-    "failed_to_send": "回答送信に失敗しました",
-    "denied": "このアンケートは今後表示されません",
-    "personal_settings_explanation": "GROWI 改善のためのアンケートが表示されるようになります。ご意見ご要望はユーザーアイコンのドロップダウンからお願いいたします。",
-    "enable_questionnaire": "アンケートを有効にする",
-    "disabled_by_admin": "管理者によってアンケートは無効化されています"
-  },
   "tag_edit_modal": {
     "edit_tags": "タグの編集",
     "done": "完了",
@@ -1040,11 +1088,11 @@
     "untitled": "無題のページ"
   },
   "sync-latest-revision-body": {
-    "menuitem": "最新のリビジョンの本文とエディタのテキストを同期",
+    "menuitem": "最新のリビジョンの本文とエディタのテキストを同期",
     "confirm": "エディターに入力中のドラフトデータを削除して最新の本文を同期します。実行しますか?",
     "alert": "最新の本文が同期されていない可能性があります。リロードして再度ご確認ください。",
     "success-toaster": "最新の本文を同期しました",
     "skipped-toaster": "エディターがアクティブではないため、同期をスキップしました。エディターを開いて再度お試しください。",
     "error-toaster": "最新の本文の同期に失敗しました"
   }
-}
+}

+ 1142 - 0
apps/app/public/static/locales/ko_KR/admin.json

@@ -0,0 +1,1142 @@
+{
+  "meta": {
+    "display_name": "한국어"
+  },
+  "last_login": "최종 로그인",
+  "wiki_management_homepage": "위키 관리 홈페이지",
+  "public": "공개",
+  "anyone_with_the_link": "링크를 가진 모든 사람",
+  "specified_users": "지정된 사용자",
+  "only_me": "나만",
+  "only_inside_the_group": "그룹 내에서만",
+  "optional": "선택 사항",
+  "days": "일",
+  "security_settings": {
+    "security_settings": "보안 설정",
+    "scope_of_page_disclosure": "페이지 공개 범위",
+    "set_point": "설정 지점",
+    "Guest Users Access": "게스트 사용자 접근",
+    "readonly_users_access": "읽기 전용 사용자 접근",
+    "always_hidden": "항상 숨김",
+    "always_displayed": "항상 표시",
+    "Fixed by env var": "이것은 환경 변수 <code>{{key}}={{value}}</code>에 의해 고정됩니다.",
+    "register_limitation": "등록 제한",
+    "register_limitation_desc": "새 사용자 등록 제한",
+    "The whitelist of registration permission E-mail address": "등록 허용 이메일 주소 화이트리스트",
+    "users_without_account": "계정 없는 사용자는 접근할 수 없습니다",
+    "example": "예시",
+    "restrict_emails": "이메일 도메인(@로 시작)을 작성하여 위키에 대한 이메일 등록을 제한할 수 있습니다. ",
+    "for_example": " 예를 들어, growi.org 도메인 내의 사용자로 등록을 제한하려면 ",
+    "in_this_case": "를 작성할 수 있습니다. 이 경우 growi.org 도메인 내의 사용자만 등록할 수 있으며, 다른 모든 사용자는 거부됩니다.",
+    "insert_single": "한 줄에 하나의 이메일 주소를 입력하십시오.",
+    "page_list_and_search_results": "페이지 목록 / 검색 결과",
+    "page_listing_1": "'나만'으로 제한된 페이지 목록/검색<br>",
+    "page_listing_1_desc": "목록/검색 시 '나만' 옵션으로 제한된 페이지 표시",
+    "page_listing_2": "사용자 그룹으로 제한된 페이지 목록/검색<br>",
+    "page_listing_2_desc": "목록/검색 시 사용자 그룹으로 제한된 페이지 표시",
+    "page_access_rights": "페이지 접근 권한",
+    "page_delete_rights": "삭제 권한",
+    "page_delete": "페이지 삭제",
+    "page_delete_completely": "페이지 완전 삭제",
+    "comment_manage_rights": "댓글 관리 권한",
+    "other_options": "기타 옵션",
+    "deletion_explanation": "선택한 단일 페이지를 휴지통으로 이동할 수 있는 사용자를 제한합니다.",
+    "complete_deletion_explanation": "선택한 단일 페이지를 완전히 삭제할 수 있는 사용자를 제한합니다.",
+    "recursive_deletion_explanation": "하위 페이지를 포함하여 페이지를 휴지통으로 이동할 수 있는 사용자를 제한합니다.",
+    "recursive_complete_deletion_explanation": "하위 페이지를 포함하여 페이지를 완전히 삭제할 수 있는 사용자를 제한합니다.",
+    "is_all_group_membership_required_for_page_complete_deletion": "관리자 및 페이지 작성자 외의 사용자는 페이지 접근이 허용된 모든 그룹에 속해야 합니다.",
+    "is_all_group_membership_required_for_page_complete_deletion_explanation": "페이지 접근 설정이 '특정 그룹만'으로 설정된 경우에 유효합니다.",
+    "inherit": "상속 (단일 페이지와 동일한 설정 사용)",
+    "admin_only": "관리자만",
+    "admin_and_author": "관리자 및 작성자",
+    "anyone": "모든 사람",
+    "user_homepage_deletion": {
+      "user_homepage_deletion": "사용자 홈페이지 삭제",
+      "enable_user_homepage_deletion": "사용자 홈페이지 삭제 활성화",
+      "enable_force_delete_user_homepage_on_user_deletion": "사용자를 삭제할 때, 사용자의 홈페이지와 모든 하위 페이지가 완전히 삭제됩니다.",
+      "desc": "삭제된 사용자의 홈페이지를 삭제할 수 있습니다."
+    },
+    "session": "세션",
+    "max_age": "최대 수명 (밀리초)",
+    "max_age_desc": "사용자 세션이 만료되는 시간(밀리초)을 지정합니다.<br>기본값: 2592000000 (30일)",
+    "max_age_caution": "이 값을 수정한 후에는 서버를 다시 시작해야 합니다.",
+    "forced_update_desc": "설정이 강제로 변경되었습니다. 이전 설정: ",
+    "page_delete_rights_caution": "삭제 / 모두 삭제 권한(하위 페이지 포함)은 삭제 / 완전 삭제 권한보다 강하게 강제됩니다. <br> <br> 관리자만 > 관리자 및 작성자 > 모든 사람",
+    "Authentication mechanism settings": "인증 메커니즘 설정",
+    "setup_is_not_yet_complete": "설정이 아직 완료되지 않았습니다",
+    "xss_prevent_setting": "XSS(교차 사이트 스크립팅) 방지",
+    "xss_prevent_setting_link": "마크다운 설정으로 이동",
+    "callback_URL": "콜백 URL",
+    "providerName": "제공자 이름",
+    "issuerHost": "발급자 호스트",
+    "scope": "범위",
+    "desc_of_callback_URL": "{{AuthName}} ID 공급자의 설정에서 사용하십시오",
+    "authorization_endpoint": "인증 엔드포인트",
+    "token_endpoint": "토큰 엔드포인트",
+    "revocation_endpoint": "폐기 엔드포인트",
+    "introspection_endpoint": "인트로스펙션 엔드포인트",
+    "userinfo_endpoint": "사용자 정보 엔드포인트",
+    "end_session_endpoint": "세션 종료 엔드포인트",
+    "registration_endpoint": "등록 엔드포인트",
+    "jwks_uri": "JSON 웹 키 세트 URL",
+    "clientID": "클라이언트 ID",
+    "client_secret": "클라이언트 시크릿",
+    "updated_general_security_setting": "보안 설정 업데이트 성공",
+    "setup_not_completed_yet": "설정이 아직 완료되지 않았습니다",
+    "guest_mode": {
+      "deny": "거부 (등록된 사용자만)",
+      "readonly": "허용 (게스트는 읽기만 가능)"
+    },
+    "read_only_users_comment": {
+      "deny": "거부 (읽기 전용 사용자의 댓글 관리 금지)",
+      "accept": "허용 (읽기 전용 사용자는 댓글 관리 가능)"
+    },
+    "registration_mode": {
+      "open": "열림 (누구나 등록 가능)",
+      "restricted": "제한됨 (관리자의 승인 필요)",
+      "closed": "닫힘 (초대 전용)"
+    },
+    "share_link_management": "공유 링크 관리",
+    "No_share_links": "공유 링크 없음",
+    "share_link_notice": "모든 공유 링크 제거",
+    "delete_all_share_links": "모든 공유 링크 삭제",
+    "share_link_rights": "공유 링크 권한",
+    "enable_link_sharing": "링크 공유 활성화",
+    "all_share_links": "모든 공유 링크",
+    "configuration": " 구성",
+    "Treat username matching as identical": "새로 로그인한 외부 계정을 <code>username</code>이 일치할 때 로컬 계정에 자동으로 바인딩",
+    "Treat username matching as identical_warn": "경고: 시스템이 <code>username</code> 일치로 동일한 사용자를 처리하므로 보안에 유의하십시오.",
+    "Treat email matching as identical": "새로 로그인한 외부 계정을 <code>email</code>이 일치할 때 로컬 계정에 자동으로 바인딩",
+    "Treat email matching as identical_warn": "경고: 시스템이 <code>email</code> 일치로 동일한 사용자를 처리하므로 보안에 유의하십시오.",
+    "Use env var if empty": "비어 있으면 환경 변수 <code>{{env}}</code> 사용",
+    "Use default if both are empty": "둘 다 비어 있으면 기본값 <code>{{target}}</code>이 사용됩니다.",
+    "missing mandatory configs": "다음 필수 항목이 데이터베이스 또는 환경 변수에 설정되어 있지 않습니다.",
+    "Local": {
+      "name": "ID/비밀번호",
+      "note for the only env option": "로컬 인증은 환경 변수 값에 의해 제한됩니다.<br>이 설정을 변경하려면 환경 변수 <code>{{env}}</code>의 값을 false로 변경하거나 삭제하십시오.",
+      "enable_local": "ID/비밀번호 활성화",
+      "password_reset_by_users": "사용자에 의한 비밀번호 재설정",
+      "enable_password_reset_by_users": "사용자에 의한 비밀번호 재설정 활성화",
+      "password_reset_desc": "비밀번호를 잊어버린 경우 사용자가 직접 재설정할 수 있습니다.",
+      "email_authentication": "사용자 등록 시 이메일 인증",
+      "enable_email_authentication": "이메일 인증 활성화",
+      "enable_email_authentication_desc": "사용자 등록을 위해 이메일 인증이 수행됩니다."
+    },
+    "ldap": {
+      "enable_ldap": "LDAP 활성화",
+      "server_url_detail": "디렉토리 서비스의 LDAP URL 형식은 <code>ldap://host:port/DN</code> 또는 <code>ldaps://host:port/DN</code>입니다.",
+      "bind_mode": "바인딩 모드",
+      "bind_manager": "관리자 바인딩",
+      "bind_user": "사용자 바인딩",
+      "bind_DN_manager_detail": "디렉토리 서비스를 인증하고 쿼리하는 계정의 DN",
+      "bind_DN_user_detail1": "디렉토리 서비스와 바인딩하는 데 사용되는 쿼리입니다.",
+      "bind_DN_user_detail2": "로그인 페이지에 입력된 사용자 이름을 참조하려면 <code>&#123;&#123;username&#125;&#125;</code>를 사용하십시오.",
+      "bind_DN_password": "바인딩 DN 비밀번호",
+      "bind_DN_password_manager_detail": "바인딩 DN 계정의 비밀번호입니다.",
+      "bind_DN_password_user_detail": "로그인 페이지에 입력된 비밀번호가 바인딩에 사용됩니다.",
+      "search_filter": "검색 필터",
+      "search_filter_detail1": "인증된 사용자를 찾는 데 사용되는 쿼리입니다.",
+      "search_filter_detail2": "로그인 페이지에 입력된 사용자 이름을 참조하려면 <code>&#123;&#123;username&#125;&#125;</code>를 사용하십시오.",
+      "search_filter_detail3": "비어 있으면 필터 <code>(uid=&#123;&#123;username&#125;&#125;)</code>가 사용됩니다.",
+      "search_filter_example1": "'uid' 또는 'mail'과 일치",
+      "search_filter_example2": "Active Directory의 'sAMAccountName'과 일치",
+      "username_detail": "새 사용자 생성 시 <code>username</code> 매핑 사양",
+      "name_detail": "새 사용자 생성 시 전체 이름 매핑 사양",
+      "mail_detail": "새 사용자 생성 시 메일 주소 매핑 사양",
+      "group_search_base_DN": "그룹 검색 기본 DN",
+      "group_search_base_DN_detail": "그룹을 검색할 기본 DN입니다. 정의된 경우 검색이 작동하려면 <code>그룹 검색 필터</code>도 정의되어야 합니다.",
+      "group_search_filter": "그룹 검색 필터",
+      "group_search_filter_detail1": "그룹을 필터링하는 데 사용되는 쿼리입니다.",
+      "group_search_filter_detail2": "이 쿼리가 하나 이상의 그룹을 찾을 때만 LDAP를 통한 로그인이 허용됩니다.",
+      "group_search_filter_detail3": "찾은 사용자 개체를 대체하려면 <code>&#123;&#123;dn&#125;&#125;</code>를 사용하십시오.",
+      "group_search_filter_detail4": "<code>(&(cn=group1)(memberUid=&#123;&#123;dn&#125;&#125;))</code>는 <code>cn=group1</code>을 가지고 <code>memberUid</code>에 사용자의 <code>uid</code>가 포함된 그룹을 찾습니다(<code>그룹 DN 속성</code>이 기본값에서 변경되지 않은 경우).",
+      "group_search_user_DN_property": "사용자 DN 속성",
+      "group_search_user_DN_property_detail": "<code>그룹 검색 필터</code>의 <code>&#123;&#123;dn&#125;&#125;</code> 보간에 사용할 사용자 개체의 속성입니다.",
+      "test_config": "저장된 구성 테스트",
+      "updated_ldap": "LDAP 설정 업데이트 성공"
+    },
+    "SAML": {
+      "name": "SAML",
+      "enable_saml": "SAML 활성화",
+      "id_detail": "SAML ID 공급자에서 사용자를 식별할 수 있는 속성 이름 사양",
+      "username_detail": "새 사용자 생성 시 <code>username</code> 매핑 사양",
+      "mapping_detail": "새 사용자 생성 시 {{target}} 매핑 사양",
+      "cert_detail": "IdP의 응답을 유효성 검사하기 위한 PEM 인코딩된 X.509 서명 인증서",
+      "Use env var if empty": "데이터베이스 값이 비어 있으면 환경 변수 <code>{{env}}</code>의 값이 사용됩니다.",
+      "note for the only env option": "SAML 인증을 활성화 또는 비활성화하는 설정 항목과 강조 표시된 설정 항목은 환경 변수 값만 사용합니다.<br>이 설정을 변경하려면 환경 변수 <code>{{env}}</code>의 값을 false로 변경하거나 삭제하십시오.",
+      "attr_based_login_control_detail": "<code>&lt;saml: Attribute&gt;</code> 요소와 그 하위 요소 <code>&lt;saml: AttributeValue&gt;</code>에 포함된 <code>&lt;saml: AttributeStatement&gt;</code> 요소를 사용하여 가입할 수 있는 사용자를 제한합니다.",
+      "attr_based_login_control_rule_help": "<h5>지원되는 쿼리:</h5><ul><li>용어</li><li>필드</li><li>AND/NOT/OR 연산자</li><li>그룹화</li></ul><h5>지원되지 않는 쿼리:</h5><ul><li>와일드카드, 퍼지, 근접, 범위 및 부스팅</li><li>+/- 연산자</li><li>필드 그룹화</li></ul><h5>특수 문자 이스케이프</h5>다음 특수 문자를 이스케이프해야 합니다:<br><code>+ - && || ! ( ) { } [ ] ^ &quot; &tilde; * ? : &#92;</code> 및 <code>/</code>",
+      "attr_based_login_control_rule_example1": "<h5>조건 예시</h5>규칙이 <code>(Department: A || Department: B) && Position: Leader</code>인 경우, <code>Department: A</code> 또는 <code>Department: B</code>를 가지고 <code>Position: Leader</code>를 가진 사용자는 로그인할 수 있습니다.",
+      "attr_based_login_control_rule_example2": "<h5>이스케이프 예시</h5>쿼리 값으로 URL을 사용하려면 다음을 이스케이프하십시오:<br><code>http&#92;:&#92;/&#92;/schemas.example.com&#92;/ws&#92;/2005&#92;/05&#92;/identity&#92;/claims&#92;/emailaddress: &quot;myname@example.com&quot;</code>",
+      "updated_saml": "SAML 설정 업데이트 성공"
+    },
+    "OAuth": {
+      "enable_oidc": "OIDC 활성화",
+      "register": "%s 등록",
+      "change_redirect_url": "승인된 리디렉션 URI에 <code>%s</code> <br>(여기서 <code>%s</code>는 호스트 이름)를 입력하십시오.",
+      "Google": {
+        "enable_google": "Google OAuth 활성화",
+        "name": "Google OAuth",
+        "register_1": "{{link}}에 접속",
+        "register_2": "프로젝트가 없으면 프로젝트 생성",
+        "register_3": "자격 증명 생성 &rightarrow; OAuth 클라이언트 ID &rightarrow; 웹 애플리케이션 선택",
+        "register_4": "승인된 리디렉션 URI 중 하나로 <code>{{url}}</code>을 사용하여 OAuth 앱 등록",
+        "register_5": "클라이언트 ID와 클라이언트 시크릿을 위에 복사하여 붙여넣기",
+        "updated_google": "Google OAuth 설정 업데이트 성공"
+      },
+      "GitHub": {
+        "enable_github": "GitHub OAuth 활성화",
+        "name": "GitHub OAuth",
+        "register_1": "{{link}}에 접속",
+        "register_2": "인증 콜백 URL로 <code>{{url}}</code>을 사용하여 OAuth 앱 등록",
+        "register_3": "클라이언트 ID와 클라이언트 시크릿을 위에 복사하여 붙여넣기",
+        "updated_github": "GitHub OAuth 설정 업데이트 성공"
+      },
+      "OIDC": {
+        "name": "OpenID Connect",
+        "id_detail": "OIDC 클레임에서 사용자를 식별할 수 있는 속성 이름 사양",
+        "username_detail": "새 사용자 생성 시 <code>username</code> 매핑 사양",
+        "name_detail": "새 사용자 생성 시 <code>name</code> 매핑 사양",
+        "mapping_detail": "새 사용자 생성 시 {{target}} 매핑 사양",
+        "register_1": "OIDC IdP 관리자에게 문의",
+        "register_2": "인증 콜백 URL로 <code>{{url}}</code>을 사용하여 OIDC 앱 등록",
+        "register_3": "클라이언트 ID와 클라이언트 시크릿을 위에 복사하여 붙여넣기",
+        "updated_oidc": "OpenID Connect 업데이트 성공",
+        "Use discovered URL if empty": "비어 있으면 발급자 호스트에서 검색된 URL 사용"
+      },
+      "how_to": {
+        "google": "Google OAuth를 구성하는 방법은?",
+        "github": "GitHub OAuth를 구성하는 방법은?",
+        "oidc": "OIDC를 구성하는 방법은?"
+      }
+    },
+    "form_item_name": {
+      "entryPoint": "진입점",
+      "issuer": "발급자",
+      "cert": "인증서",
+      "attrMapId": "ID",
+      "attrMapUsername": "사용자 이름",
+      "attrMapMail": "메일 주소",
+      "attrMapFirstName": "이름",
+      "attrMapLastName": "성",
+      "ABLCRule": "규칙"
+    }
+  },
+  "notification_settings": {
+    "notification_settings": "알림 설정",
+    "slack_incoming_configuration": "Slack 수신 웹훅 구성",
+    "prioritize_webhook": "Slack 앱보다 수신 웹훅 우선",
+    "prioritize_webhook_desc": "이 옵션을 선택하면 Slack 앱 설정이 활성화되어 있어도 GROWI는 수신 웹훅을 사용합니다.",
+    "slack_app_configuration": "Slack 앱 구성",
+    "slack_app_configuration_desc": "이것은 Crowi와 호환되는 방식이지만,<br /> GROWI에서는 <strong>너무 복잡하므로</strong> 권장하지 않습니다.",
+    "use_instead": "대신 Slack 수신 웹훅 구성을 사용하십시오.",
+    "how_to": {
+      "header": "수신 웹훅을 구성하는 방법은?",
+      "workspace": "(워크스페이스에서) 훅 추가",
+      "workspace_desc1": "<a href='https://slack.com/services/new/incoming-webhook'>수신 웹훅 구성 페이지</a>로 이동하십시오.",
+      "workspace_desc2": "게시할 기본 채널을 선택하십시오.",
+      "workspace_desc3": "추가하십시오.",
+      "at_growi": "(GROWI 관리 페이지에서) 웹훅 URL 설정",
+      "at_growi_desc": "이 페이지에서 &rdquo;웹훅 URL&rdquo;을 입력하고 제출하십시오."
+    },
+    "user_trigger_notification_header": "패턴에 대한 기본 알림 설정",
+    "pattern": "패턴",
+    "channel": "채널",
+    "pattern_desc": "위키의 경로 이름입니다. <code>*</code>를 사용한 패턴 표현식을 사용할 수 있습니다.",
+    "channel_desc": "Slack 채널 이름입니다. <code>#</code> 없이.",
+    "valid_page": "알림 활성화/비활성화",
+    "link_notification_help": "<strong>링크를 아는 사람만 볼 수 있는 페이지('링크를 가진 모든 사람')</strong>는 항상 알림이 전송되지 않습니다.",
+    "just_me_notification_help": "<strong>'나만'으로 제한된 페이지</strong>는 페이지가 편집될 때 알림이 전송됩니다.",
+    "group_notification_help": "<strong>'사용자 그룹'으로 제한된 페이지</strong>는 페이지가 편집될 때 알림이 전송됩니다.",
+    "notification_list": "알림 설정 목록",
+    "add_notification": "새로 추가",
+    "trigger_path": "트리거 경로",
+    "trigger_path_help": "(<code>*</code>를 사용한 표현식 지원)",
+    "trigger_events": "트리거 이벤트",
+    "notify_to": "알림 대상",
+    "back_to_list": "목록으로 돌아가기",
+    "notification_detail": "알림 설정 세부 정보",
+    "event_pageCreate": "새 페이지가 생성될 때",
+    "event_pageEdit": "페이지가 편집될 때",
+    "event_pageDelete": "페이지가 삭제될 때",
+    "event_pageMove": "페이지가 이동될 때 (이름 변경)",
+    "event_pageLike": "누군가 페이지를 좋아할 때",
+    "event_comment": "누군가 페이지에 댓글을 달 때",
+    "email": {
+      "ifttt_link": "이메일 트리거로 새 IFTTT 애플릿 생성"
+    },
+    "updated_slackApp": "Slack 앱 구성 설정 업데이트 성공",
+    "add_notification_pattern": "사용자 트리거 알림 패턴 추가",
+    "delete_notification_pattern": "알림 패턴 삭제",
+    "delete_notification_pattern_desc1": "경로 삭제: {{path}}",
+    "delete_notification_pattern_desc2": "한 번 삭제하면 복구할 수 없습니다",
+    "toggle_notification": "{{path}} 설정 업데이트",
+    "not_found_global_notification_triggerid": "전역 알림 ID를 찾을 수 없습니다"
+  },
+  "full_text_search_management": {
+    "full_text_search_management": "전체 텍스트 검색 관리",
+    "elasticsearch_management": "Elasticsearch 관리",
+    "connection_status": "연결 상태",
+    "connection_status_label_unconfigured": "구성되지 않음",
+    "connection_status_label_connected": "연결됨",
+    "connection_status_label_disconnected": "연결 끊김",
+    "connection_status_label_erroroccured": "검색 서비스에서 오류 발생",
+    "indices_status": "인덱스 상태",
+    "indices_status_label_normalized": "정규화됨",
+    "indices_status_label_unnormalized": "재구축 중 또는 손상됨",
+    "indices_summary": "인덱스 요약",
+    "reconnect": "재연결",
+    "reconnect_button": "Elasticsearch에 다시 연결 시도",
+    "reconnect_description": "버튼을 클릭하여 Elasticsearch에 다시 연결을 시도합니다.",
+    "normalize": "정규화",
+    "normalize_button": "인덱스 정규화",
+    "normalize_description": "버튼을 클릭하여 손상된 인덱스를 복구합니다.",
+    "rebuild": "재구축",
+    "rebuild_button": "인덱스 재구축",
+    "rebuild_description_1": "버튼을 클릭하여 인덱스를 재구축하고 모든 페이지 데이터를 추가합니다.",
+    "rebuild_description_2": "이 작업은 시간이 걸릴 수 있습니다."
+  },
+  "mailer_setup_required": "<a href='/admin/app'>이메일 설정</a>이 전송에 필요합니다.",
+  "admin_top": {
+    "management_wiki": "관리 위키",
+    "system_information": "시스템 정보",
+    "wiki_administrator": "위키 관리자만 이 페이지에 접근할 수 있습니다",
+    "assign_administrator": "사용자 관리 페이지에서 '관리자 권한 부여' 버튼을 사용하여 선택한 사용자에게 위키 관리자 권한을 부여할 수 있습니다.",
+    "package_name": "패키지 이름",
+    "specified_version": "지정된 버전",
+    "installed_version": "설치된 버전",
+    "list_of_env_vars": "환경 변수 목록",
+    "env_var_priority": "보안 외의 환경 변수는 데이터베이스 값이 우선적으로 적용됩니다.",
+    "about_security": "보안 환경 변수에 대해서는 <a href='/admin/security'>보안 설정</a>을 확인하십시오.",
+    "copy_prefilled_host_information": {
+      "default": "미리 채워진 호스트 정보 복사",
+      "done": "클립보드에 복사되었습니다!"
+    },
+    "bug_report": "버그 보고서 제출",
+    "submit_bug_report": "<a href='https://github.com/growilabs/growi/issues/new?assignees=&labels=bug&template=bug-report.md&title=Bug%3A' target='_blank' rel='noreferrer'>그런 다음 GitHub에 문제를 제출하십시오.</a>"
+  },
+  "v5_page_migration": {
+    "migration_desc": "일부 페이지는 이전 v4 호환성을 가지고 있습니다. 페이지 트리 및 쉬운 이름 변경과 같은 새로운 기능을 활용하려면 모든 페이지를 v5 호환성으로 변환하십시오.",
+    "migration_note": "참고: 페이지 경로에서 고유 제약 조건이 손실됩니다.",
+    "upgrade_to_v5": "v5 호환성으로 변환",
+    "modal_migration_warning": "이 프로세스는 시간이 오래 걸릴 수 있습니다. 관리자는 변환 중 사용자가 페이지를 생성, 수정 또는 삭제하지 않도록 권장합니다.",
+    "start_upgrading": "v5 호환성으로 변환 시작",
+    "successfully_started": "변환 시작 성공",
+    "already_upgraded": "이미 v5 호환성으로 변환을 완료했습니다",
+    "header_upgrading_progress": "업그레이드 진행률",
+    "migration_succeeded": "업그레이드가 성공적으로 완료되었습니다! 유지 보수 모드를 종료하면 GROWI를 사용할 수 있습니다.",
+    "migration_failed": "업그레이드 실패. 실패 시 수행할 작업에 대한 정보는 GROWI 문서를 참조하십시오."
+  },
+  "maintenance_mode": {
+    "maintenance_mode": "유지 보수 모드",
+    "under_maintenance_mode": "유지 보수 모드 중",
+    "failed_to_start_maintenance_mode": "유지 보수 모드 시작 실패",
+    "failed_to_end_maintenance_mode": "유지 보수 모드 종료 실패",
+    "successfully_started_maintenance_mode": "유지 보수 모드 시작 성공",
+    "successfully_ended_maintenance_mode": "유지 보수 모드 종료 성공",
+    "warning_message_to_start": "관리 설정 페이지 외에는 접근할 수 없습니다. 일반 사용자는 유지 보수 모드가 수동으로 종료될 때까지 어떤 콘텐츠에도 접근할 수 없습니다.",
+    "warning_message_to_end": "데이터 가져오기 또는 v5로 업그레이드가 이미 완료되었는지 확인하십시오. 완료되지 않은 경우 유지 보수 모드를 유지하는 것이 좋습니다.",
+    "supplymentary_message_to_start": "API의 경우 관리자 API만 작동합니다.",
+    "start_maintenance_mode": "유지 보수 모드 시작",
+    "end_maintenance_mode": "유지 보수 모드 종료",
+    "description": "유지 보수 모드는 모든 사용자 작업을 제한합니다. 데이터 가져오기 및 V5로 업그레이드 전에 항상 유지 보수 모드를 시작하십시오. 종료하려면 보안 설정 > 유지 보수 모드로 이동하십시오."
+  },
+  "app_setting": {
+    "site_name": "사이트 이름",
+    "sitename_change": "헤더 및 HTML 제목에 사용되는 사이트 이름을 변경할 수 있습니다.",
+    "header_content": "여기에 입력된 내용은 헤더 등에 표시됩니다.",
+    "site_url": {
+      "title": "사이트 URL 설정",
+      "desc": "사이트 URL 설정용입니다.",
+      "warn": "사이트 URL이 설정되지 않아 일부 기능이 작동하지 않습니다.",
+      "help": "<code>http://</code> 또는 <code>https://</code>로 시작하는 사이트 전체 URL입니다.",
+      "note_for_the_only_env_option": "사이트 URL은 환경 변수 값으로 고정됩니다.<br>이 설정을 변경하려면 환경 변수 <code>{{env}}</code>의 값을 false로 변경하거나 삭제하십시오."
+    },
+    "confidential_name": "기밀 이름",
+    "confidential_example": "예): 내부 전용",
+    "default_language": "새 사용자를 위한 기본 언어",
+    "default_mail_visibility": "새 사용자를 위한 이메일 공개",
+    "file_uploading": "파일 업로드",
+    "enable_files_except_image": "이 옵션을 활성화하면 모든 파일 형식을 업로드할 수 있습니다. 이 옵션이 없으면 이미지 파일 업로드만 지원됩니다.",
+    "attach_enable": "이 옵션을 활성화하면 이미지 파일 외의 파일을 첨부할 수 있습니다.",
+    "page_bulk_export_settings": "페이지 대량 내보내기 설정",
+    "enable_page_bulk_export": "대량 내보내기 활성화",
+    "page_bulk_export_explanation": "모든 사용자가 메뉴에서 한 번에 페이지와 모든 하위 페이지를 내보낼 수 있는 기능을 활성화합니다. 내보낸 데이터는 저장 기간이 지나면 자동으로 삭제됩니다.",
+    "page_bulk_export_warning": "대량 페이지 내보내기 기능은 모든 사용자에게 제공됩니다. 시스템 리소스 유지를 위해 최소한의 사용을 부탁드립니다. 관리자라면 모든 사용자에게 이 사실을 알려주십시오.",
+    "page_bulk_export_storage_period": "저장 기간",
+    "update": "업데이트",
+    "mail_settings": "이메일 설정",
+    "mailer_is_not_set_up": "이메일 설정이 되어 있지 않습니다.",
+    "from_e-mail_address": "보내는 이메일 주소",
+    "transmission_method": "전송 방식",
+    "smtp_label": "SMTP",
+    "ses_label": "SES(AWS)",
+    "send_test_email": "테스트 이메일 전송",
+    "success_to_send_test_email": "테스트 이메일 전송 성공",
+    "smtp_settings": "SMTP 설정",
+    "host": "호스트",
+    "port": "포트",
+    "user": "사용자",
+    "initialize_mail_settings": "이메일 설정 초기화",
+    "initialize_mail_modal_header": "이메일 설정 초기화",
+    "confirm_to_initialize_mail_settings": "현재 설정으로 복원할 수 없습니다. 이메일 설정을 초기화하시겠습니까?",
+    "file_upload_settings": "파일 업로드 설정",
+    "file_upload_method": "파일 업로드 방식",
+    "file_delivery_method": "파일 전송 방식",
+    "file_delivery_method_redirect": "리디렉션",
+    "file_delivery_method_relay": "내부 시스템 중계",
+    "file_delivery_method_redirect_info": "리디렉션: GROWI 서버 없이 서명된 URL로 리디렉션하여 뛰어난 성능을 제공합니다.",
+    "file_delivery_method_relay_info": "내부 시스템 중계: GROWI 서버가 클라이언트에 전송하여 완벽한 보안을 제공합니다.",
+    "fixed_by_env_var": "이것은 환경 변수 <code>{{envKey}}={{envVar}}</code>에 의해 고정됩니다.",
+    "gcs_label": "GCP(GCS)",
+    "aws_label": "AWS(S3)",
+    "local_label": "로컬",
+    "gridfs_label": "MongoDB(GridFS)",
+    "azure_label": "Azure(Blob)",
+    "azure_tenant_id": "테넌트 ID",
+    "azure_client_id": "클라이언트 ID",
+    "azure_client_secret": "클라이언트 시크릿",
+    "azure_storage_account_name": "스토리지 계정 이름",
+    "azure_storage_container_name": "컨테이너 이름",
+    "azure_note_for_the_only_env_option": "Azure 설정은 환경 변수 값에 의해 제한됩니다.<br>이 설정을 변경하려면 환경 변수 <code>{{env}}</code>의 값을 false로 변경하거나 삭제하십시오.",
+    "file_upload": "파일 업로드 설정용입니다. 파일 업로드 설정을 완료하면 파일 업로드 기능, 프로필 사진 기능 등이 활성화됩니다.",
+    "test_connection": "메일 연결 테스트",
+    "change_setting": "주의: 이 설정을 완료하지 않으면 지금까지 업로드한 파일에 접근할 수 없습니다.",
+    "region": "지역",
+    "bucket_name": "버킷 이름",
+    "custom_endpoint": "사용자 지정 엔드포인트",
+    "custom_endpoint_change": "S3 호환 API를 가진 MinIO와 같은 객체 스토리지 서비스의 엔드포인트 URL을 입력하십시오. 비어 있으면 Amazon S3가 사용됩니다.",
+    "s3_secret_access_key_input_description": "설정 값이 숨겨져 있습니다",
+    "load_plugins": "플러그인 로드",
+    "enable": "활성화",
+    "disable": "비활성화",
+    "use_env_var_if_empty": "데이터베이스 값이 비어 있으면 환경 변수 <code>{{variable}}</code>의 값이 사용됩니다.",
+    "note_for_the_only_env_option": "GCS 설정은 환경 변수 값에 의해 제한됩니다.<br>이 설정을 변경하려면 환경 변수 <code>{{env}}</code>의 값을 false로 변경하거나 삭제하십시오."
+  },
+  "markdown_settings": {
+    "markdown_settings": "마크다운 설정",
+    "lineBreak_header": "줄 바꿈 설정",
+    "lineBreak_desc": "줄 바꿈 설정을 변경할 수 있습니다.",
+    "lineBreak_options": {
+      "enable_lineBreak": "줄 바꿈 활성화",
+      "enable_lineBreak_desc": "텍스트 페이지의 줄 바꿈을 HTML에서 <code>&lt;br&gt;</code>로 변환",
+      "enable_lineBreak_for_comment": "댓글에서 줄 바꿈 활성화",
+      "enable_lineBreak_for_comment_desc": "댓글의 줄 바꿈을 HTML에서 <code>&lt;br&gt;</code>로 변환"
+    },
+    "indent_header": "들여쓰기 설정",
+    "indent_desc": "들여쓰기 설정을 변경할 수 있습니다.",
+    "indent_options": {
+      "indentSize": "기본 들여쓰기 크기",
+      "indentSize_desc": "마크다운 편집기의 기본 들여쓰기 크기 설정",
+      "disallow_indent_change": "사용자에 의한 들여쓰기 크기 변경 금지",
+      "disallow_indent_change_desc": "사용자가 기본 들여쓰기 크기를 강제로 사용하도록 합니다."
+    },
+    "xss_header": "XSS(교차 사이트 스크립팅) 방지 설정",
+    "xss_desc": "마크다운 텍스트의 HTML 태그 처리 방식을 변경할 수 있습니다.",
+    "xss_options": {
+      "enable_xss_prevention": "XSS 방지 활성화",
+      "remove_all_tags": "모든 태그 제거",
+      "remove_all_tags_desc": "모든 HTML 태그 및 속성 제거",
+      "recommended_setting": "권장 설정",
+      "custom_whitelist": "사용자 지정 화이트리스트",
+      "tag_names": "태그 이름",
+      "tag_attributes": "태그 속성",
+      "import_recommended": "권장 {{target}} 가져오기"
+    }
+  },
+  "customize_settings": {
+    "customize_settings": "사용자 지정",
+    "default_sidebar_mode": {
+      "title": "기본 사이드바 모드",
+      "desc": "새 사용자 및 페이지를 방문하는 게스트를 위한 사이드바 모드를 설정할 수 있습니다.",
+      "dock_mode_default_desc": "독 모드가 선택되었을 때 사이드바의 초기 상태를 설정할 수 있습니다.",
+      "dock_mode_default_open": "처음부터 열린 상태로 페이지 열기",
+      "dock_mode_default_close": "처음부터 닫힌 상태로 페이지 열기"
+    },
+    "layout": "레이아웃",
+    "layout_options": {
+      "default": "기본 콘텐츠 너비",
+      "expanded": "콘텐츠 너비 100%"
+    },
+    "theme": "테마",
+    "theme_desc": {
+      "light_and_dark": "밝은 모드 및 어두운 모드",
+      "unique": "하나의 모드만"
+    },
+    "function": "기능",
+    "function_desc": "기능의 유효/무효를 선택할 수 있습니다.",
+    "function_options": {
+      "timeline": "타임라인 기능",
+      "timeline_desc1": "하위 페이지의 타임라인을 표시할 수 있습니다.",
+      "timeline_desc2": "하위 페이지가 많으면 페이지 로딩 중 성능이 저하됩니다.",
+      "timeline_desc3": "비활성화하여 목록 페이지 표시 속도를 높일 수 있습니다.",
+      "tab_switch": "브라우저에서 탭 전환 저장",
+      "tab_switch_desc1": "브라우저에서 편집 탭 및 기록 탭 전환을 저장하고 브라우저의 앞으로/뒤로 명령에 대한 개체로 만듭니다.",
+      "tab_switch_desc2": "비활성화하여 페이지 전환을 브라우저의 앞으로/뒤로 명령에 대한 유일한 개체로 만들 수 있습니다.",
+      "attach_title_header": "새 페이지 생성 시 자동으로 h1 섹션 추가",
+      "attach_title_header_desc": "새 페이지 생성 시 페이지 경로를 h1 섹션으로 첫 줄에 추가합니다.",
+      "list_num_s": "모달에 표시되는 목록 수",
+      "list_num_desc_s": "'페이지 목록', '타임라인', '페이지 기록' 및 '첨부 파일' 페이지와 같은 페이지당 목록 수 설정",
+      "list_num_m": "다른 콘텐츠가 포함된 문서 페이지에 표시되는 목록 수",
+      "list_num_desc_m": "'북마크' 및 '최근 생성됨' 페이지와 같은 페이지당 목록 수 설정",
+      "list_num_l": "'검색' 페이지에 표시되는 목록 수",
+      "list_num_desc_l": "'검색' 페이지와 같은 페이지당 목록 수 설정",
+      "list_num_xl": "문서 페이지에 표시되는 목록 수",
+      "list_num_desc_xl": "'찾을 수 없음' 및 '휴지통' 페이지와 같은 페이지당 목록 수 설정",
+      "stale_notification": "오래된 페이지에 알림 표시",
+      "stale_notification_desc": "마지막 업데이트 이후 1년 이상 된 페이지에 알림을 표시합니다.",
+      "show_all_reply_comments": "모든 답글 댓글 표시",
+      "show_all_reply_comments_desc": "설정 값이 꺼져 있으면 최신 두 개를 제외한 댓글은 생략됩니다.",
+      "select_search_scope_children_as_default": "검색 범위의 기본값으로 '이 트리 내의 하위 항목만' 선택",
+      "select_search_scope_children_as_default_desc": "설정 값이 꺼져 있으면 '모든 페이지'가 검색 범위의 기본값으로 사용됩니다.",
+      "show_page_side_authors": "목차 위에 작성자 및 업데이트자 항상 표시",
+      "show_page_side_authors_desc": "페이지 사이드바의 목차 위에 작성자 및 마지막 업데이트자에 대한 정보를 표시합니다."
+    },
+    "presentation": "프레젠테이션",
+    "presentation_options": {
+      "enable_marp": "Marp 활성화 ",
+      "enable_marp_desc": "Marp는 프레젠테이션 미리보기에서 사용할 수 있습니다. 이 옵션은 XSS에 취약하게 만들 수 있습니다.",
+      "marp_official_site": "Marp 공식 사이트",
+      "marp_official_site_link": "https://marp.app",
+      "marp_in_growi": "GROWI 문서 - Marp를 사용하여 슬라이드 생성",
+      "marp_in_growi_link": "https://docs.growi.org/en/guide/features/marp.html"
+    },
+    "custom_title": "사용자 지정 제목",
+    "custom_title_detail": "<code>&lt;title&gt;</code> 태그를 사용자 지정할 수 있습니다. 다음 자리 표시자는 자동으로 대체됩니다:",
+    "custom_title_detail_placeholder1": "<code>&#123;&#123;sitename&#125;&#125;</code> - 이 위키의 사이트 이름입니다.",
+    "custom_title_detail_placeholder2": "<code>&#123;&#123;pagename&#125;&#125;</code> - 현재 페이지의 페이지 이름입니다.",
+    "custom_title_detail_placeholder3": "<code>&#123;&#123;pagepath&#125;&#125;</code> - 현재 페이지의 페이지 경로입니다.",
+    "custom_noscript": "사용자 지정 Noscript",
+    "custom_noscript_detail": "모든 페이지에 적용되는 Noscript 코드를 사용자 지정할 수 있습니다. 사용자 지정 Noscript는 body의 첫 번째 요소로 위치한 <code>&lt;noscript&gt;</code> 태그 안에 삽입됩니다.<br>변경 사항을 보려면 페이지를 다시 로드하십시오.",
+    "custom_css": "사용자 지정 CSS",
+    "write_css": "전체 시스템에 적용되는 CSS를 작성할 수 있습니다.",
+    "ctrl_space": "Ctrl+Space로 자동 완성",
+    "custom_script": "사용자 지정 스크립트",
+    "custom_presentation": "사용자 지정 프레젠테이션",
+    "write_java": "전체 시스템에 적용되는 Javascript를 작성할 수 있습니다.",
+    "reflect_change": "변경 사항을 반영하려면 페이지를 다시 로드해야 합니다.",
+    "custom_logo": "사용자 지정 로고",
+    "default_logo": "기본 로고",
+    "upload_logo": "로고 업로드",
+    "current_logo": "현재 로고",
+    "upload_new_logo": "새 로고 업로드",
+    "delete_logo": "로고 삭제"
+  },
+  "importer_management": {
+    "import_data": "데이터 가져오기",
+    "article": "문서",
+    "category": "카테고리",
+    "tag": "태그",
+    "page": "페이지",
+    "page_path": "페이지 경로",
+    "beta_warning": "이 기능은 베타입니다.",
+    "import_from": "{{from}}에서 가져오기",
+    "import_growi_archive": "GROWI 아카이브 가져오기",
+    "error": {
+      "only_upsert_available": "페이지 컬렉션에는 'Upsert' 옵션만 사용할 수 있습니다."
+    },
+    "growi_settings": {
+      "description_of_import_mode": {
+        "about": "기존 데이터와 이름이 같은 데이터를 가져올 때 다음 세 가지 모드 중 하나를 선택하십시오.",
+        "insert": "삽입: 데이터 가져오기를 건너뜁니다.",
+        "upsert": "업서트: 기존 데이터를 가져온 데이터로 덮어쓰고 업데이트합니다.",
+        "flash_and_insert": "플래시 및 삽입: 기존 데이터를 완전히 삭제한 후 데이터를 가져옵니다."
+      },
+      "growi_archive_file": "GROWI 아카이브 파일",
+      "uploaded_data": "업로드된 데이터",
+      "extracted_file": "추출된 파일",
+      "collection": "컬렉션",
+      "upload": "업로드",
+      "discard": "업로드된 데이터 버리기",
+      "errors": {
+        "different_versions": "이 GROWI 버전과 업로드된 데이터 버전이 다릅니다",
+        "at_least_one": "하나 이상의 컬렉션을 선택하십시오.",
+        "page_and_revision": "'페이지'와 '리비전'은 모두 가져와야 합니다.",
+        "depends": "'{{condition}}'이 선택된 경우 '{{target}}'을 선택해야 합니다."
+      },
+      "configuration": {
+        "pages": {
+          "overwrite_author": {
+            "label": "페이지 작성자를 현재 사용자로 덮어쓰기",
+            "desc": "사용자도 복원될 경우 이 옵션을 확인하지 않는 것이 좋습니다."
+          },
+          "set_public_to_page": {
+            "label": "'{{from}}'인 페이지를 '공개'로 설정",
+            "desc": "이 구성은 <b>'{{from}}'</b> 페이지를 <span class=\"text-danger\">모든 사용자</span>가 읽을 수 있도록 합니다."
+          },
+          "initialize_meta_datas": {
+            "label": "페이지의 좋아요, 읽은 사용자 및 댓글 수 초기화",
+            "desc": "사용자도 복원될 경우 이 옵션을 확인하지 않는 것이 좋습니다."
+          }
+        },
+        "revisions": {
+          "overwrite_author": {
+            "label": "리비전 작성자를 현재 사용자로 덮어쓰기",
+            "desc": "사용자도 복원될 경우 이 옵션을 확인하지 않는 것이 좋습니다."
+          }
+        }
+      }
+    },
+    "esa_settings": {
+      "team_name": "팀 이름",
+      "access_token": "액세스 토큰",
+      "test_connection": "esa 연결 테스트"
+    },
+    "qiita_settings": {
+      "team_name": "팀 이름",
+      "access_token": "액세스 토큰",
+      "test_connection": "qiita:team 연결 테스트"
+    },
+    "import": "가져오기",
+    "skip_username_and_email_when_overlapped": "새 환경에서 동일한 사용자 이름과 이메일을 사용하는 경우 사용자 이름과 이메일 건너뛰기",
+    "prepare_new_account_for_migration": "마이그레이션을 위한 새 계정 준비",
+    "archive_data_import_detail": "자세한 내용은 여기를 클릭하십시오.",
+    "admin_archive_data_import_guide_url": "https://docs.growi.org/en/admin-guide/management-cookbook/import.html",
+    "page_skip": "GROWI에 이미 존재하는 이름의 페이지는 가져오지 않습니다.",
+    "Directory_hierarchy_tag": "디렉토리 계층 태그"
+  },
+  "export_management": {
+    "export_archive_data": "아카이브 데이터 내보내기",
+    "exporting_collection_list": "내보내는 컬렉션 목록",
+    "exported_data_list": "내보낸 아카이브 데이터 목록",
+    "export_collections": "컬렉션 내보내기",
+    "check_all": "모두 선택",
+    "uncheck_all": "모두 선택 해제",
+    "desc_password_seed": "<p>사용자 데이터를 복원할 때 새 GROWI 시스템에 현재 <code>PASSWORD_SEED</code>를 설정하는 것을 잊지 마십시오. 그렇지 않으면 사용자가 비밀번호로 로그인할 수 없습니다.<br><br><strong>힌트:</strong><br>현재 <code>PASSWORD_SEED</code>는 내보낸 ZIP 파일의 <code>meta.json</code>에 저장됩니다.</p>",
+    "create_new_archive_data": "새 아카이브 데이터 생성",
+    "export": "내보내기",
+    "cancel": "취소",
+    "file": "파일",
+    "growi_version": "GROWI 버전",
+    "collections": "컬렉션",
+    "exported_at": "내보낸 시간",
+    "export_menu": "내보내기 메뉴",
+    "download": "다운로드",
+    "delete": "삭제"
+  },
+  "external_notification": {
+    "external_notification": "외부 알림",
+    "enabled": "활성화됨",
+    "disabled": "비활성화됨",
+    "header_status": "Slack 통합 상태",
+    "caution_enabled": "주의: 현재 이 페이지에서 구성된 알림은 기본으로 설정된 Slack 워크스페이스로만 전송됩니다."
+  },
+  "slack_integration": {
+    "slack_integration": "Slack 통합",
+    "selecting_bot_types": {
+      "slack_bot": "Slack 봇",
+      "official_bot": "공식 봇",
+      "custom_bot": "사용자 지정 봇",
+      "without_proxy": "프록시 없이",
+      "with_proxy": "프록시와 함께",
+      "recommended": "권장",
+      "set_up": "설정",
+      "multiple_workspaces_integration": "다중 워크스페이스 통합",
+      "security_control": "보안 제어",
+      "easy": "쉬움",
+      "normal": "보통",
+      "hard": "어려움",
+      "possible": "가능",
+      "impossible": "불가능"
+    },
+    "bot_reset_successful": "봇 설정이 재설정되었습니다.",
+    "adding_slack_ws_integration_settings_successful": "Slack 워크스페이스 통합 설정이 추가되었습니다.",
+    "bot_all_reset_successful": "모든 봇 설정이 재설정되었습니다.",
+    "copied_to_clipboard": "클립보드에 복사됨",
+    "set_scope": "Slack 설정에서 봇 토큰 범위를 설정하십시오.",
+    "modal": {
+      "warning": "경고",
+      "sure_change_bot_type": "봇 유형을 변경하시겠습니까?",
+      "changes_will_be_deleted": "다른 봇 유형에 대한 설정은 삭제됩니다.",
+      "cancel": "취소",
+      "change": "변경"
+    },
+    "toastr": {
+      "delete_slack_integration_procedure": "Slack 통합 절차 삭제 성공"
+    },
+    "use_env_var_if_empty": "데이터베이스 값이 비어 있으면 환경 변수 <code>{{variable}}</code>의 값이 사용됩니다.",
+    "access_token_settings": {
+      "regenerate": "재생성"
+    },
+    "delete": "삭제",
+    "integration_procedure": "통합 절차",
+    "custom_bot_without_proxy_settings": "프록시 없는 사용자 지정 봇 설정",
+    "integration_failed": "통합 실패",
+    "reset": "재설정",
+    "reset_all_settings": "모든 설정 재설정",
+    "delete_slackbot_settings": "Slack 봇 설정 삭제",
+    "slackbot_settings_notice": "Slack 워크스페이스 통합 절차가 삭제됩니다. <br> 확실합니까?",
+    "all_settings_of_the_bot_will_be_reset": "봇의 모든 설정이 재설정됩니다.<br>확실합니까?",
+    "accordion": {
+      "create_bot": "봇 생성",
+      "how_to_create_a_bot": "봇을 만드는 방법",
+      "how_to_install": "설치 방법",
+      "install_bot_to_slack": "Slack에 봇 설치",
+      "install_now": "지금 설치",
+      "generate_access_token": "액세스 토큰 생성",
+      "register_for_growi_official_bot_proxy_service": "GROWI 공식 봇 프록시 서비스 등록",
+      "register_for_growi_custom_bot_proxy": "GROWI 사용자 지정 봇 프록시 등록",
+      "enter_growi_register_on_slack": "Slack에서 <b>/growi register</b> 입력",
+      "paste_growi_url": "모달이 표시되면 <b>GROWI URL</b>에 다음 URL을 입력하십시오.",
+      "enter_access_token_for_growi_and_proxy": "<b>GROWI에 대한 액세스 토큰 프록시</b> 및 <b>프록시에 대한 GROWI 액세스 토큰</b> 입력",
+      "set_proxy_url_on_growi": "GROWI에 프록시 URL 설정",
+      "copy_proxy_url": "위 단계가 성공적으로 완료되면 선택한 Slack 채널의 모달에 프록시 URL이 표시되므로 복사하십시오.",
+      "enter_proxy_url_and_update": "이 페이지의 <b>사용자 지정 봇 프록시 통합</b>의 <b>프록시 URL</b>에 위 단계에서 복사한 프록시 URL을 입력하고 업데이트하십시오.",
+      "dont_need_update": "※값이 이미 있는 경우 업데이트할 필요가 없습니다.",
+      "select_install_your_app": "\"앱 설치\"를 선택하십시오.",
+      "go-to-manage-distribution": "Slack 앱 페이지에서 \"설정 관리\" > \"배포 관리\"로 이동하십시오.",
+      "activate-public-distribution": "\"다른 워크스페이스와 앱 공유\"에서 모든 항목이 선택되었는지 확인하고 \"공개 배포 활성화\"를 클릭하십시오.",
+      "click-add-to-slack-button": "\"Slack에 추가\" 버튼을 클릭하십시오.",
+      "select_install_to_workspace": "\"워크스페이스에 설치\"를 선택하십시오.",
+      "register_proxy_url": "GROWI에 프록시 URL 등록",
+      "click_allow": "\"허용\"을 선택하십시오.",
+      "install_complete_if_checked": "\"앱 설치\"가 선택되었는지 확인하십시오.",
+      "invite_bot_to_channel": "@example을 호출하여 GROWI 봇을 채널에 초대하십시오.",
+      "register_secret_and_token": "서명 시크릿 및 봇 토큰 설정",
+      "manage_permission": "권한 관리",
+      "growi_commands": "GROWI 명령",
+      "multiple_growi_command": "여러 GROWI 인스턴스에 한 번에 보낼 수 있는 명령",
+      "single_growi_command": "한 번에 단일 GROWI 인스턴스에 보낼 수 있는 명령",
+      "allowed_channels_description": "\"{{keyName}}\" 명령에 허용된 채널을 입력하십시오. 각 채널을 \",\"로 구분하십시오. 사용자는 여기에 작성된 채널에서 \"{{keyName}}\" 명령을 사용할 수 있습니다.",
+      "unfurl_description": "Slack에서 페이지 링크가 공유되었을 때 GROWI 페이지 콘텐츠 표시",
+      "unfurl_allowed_channels_description": "\"언퍼링\"에 허용된 채널 ID를 입력하십시오. 각 채널을 \",\"로 구분하십시오. 지정된 채널에서 전송된 GROWI 공개 페이지 링크 또는 영구 링크는 메시지에 콘텐츠를 표시합니다.",
+      "allow_all": "모두 허용",
+      "deny_all": "모두 거부",
+      "allow_specified": "지정된 항목 허용",
+      "allow_all_long": "모두 허용 (모든 채널에서 허용)",
+      "deny_all_long": "모두 거부 (모든 채널에서 거부)",
+      "allow_specified_long": "지정된 항목 허용 (지정된 채널에서만 허용)",
+      "test_connection": "연결 테스트",
+      "test_connection_by_pressing_button": "버튼을 눌러 연결 테스트",
+      "test_connection_only_public_channel": "공개 채널에서만 연결 테스트를 해주세요",
+      "error_check_logs_below": "오류가 발생했습니다. 아래 로그를 확인하십시오.",
+      "send_message_to_slack_work_space": "Slack 워크스페이스로 메시지 전송",
+      "add_slack_workspace": "Slack 워크스페이스 추가"
+    },
+    "custom_bot_without_proxy_integration": "프록시 없는 사용자 지정 봇 통합",
+    "integration_sentence": {
+      "integration_is_not_complete": "통합이 완료되지 않았습니다.<br>다음 통합 절차를 진행하십시오.",
+      "integration_successful": "통합 성공",
+      "integration_some_ws_is_not_complete": "일부 워크스페이스가 연결되지 않았습니다."
+    },
+    "custom_bot_with_proxy_integration": "프록시 있는 사용자 지정 봇 통합",
+    "official_bot_integration": "공식 봇 통합",
+    "docs_url": {
+      "slack_integration": "https://docs.growi.org/en/admin-guide/management-cookbook/slack-integration/",
+      "official_bot": "https://docs.growi.org/en/admin-guide/management-cookbook/slack-integration/#official-bot-%E3%80%90recommended%E3%80%91",
+      "custom_bot_without_proxy": "https://docs.growi.org/en/admin-guide/management-cookbook/slack-integration/#custom-bot-without-proxy",
+      "custom_bot_with_proxy": "https://docs.growi.org/en/admin-guide/management-cookbook/slack-integration/#custom-bot-with-proxy",
+      "official_bot_setting": "https://docs.growi.org/en/admin-guide/management-cookbook/slack-integration/official-bot-settings.html",
+      "custom_bot_without_proxy_setting": "https://docs.growi.org/en/admin-guide/management-cookbook/slack-integration/custom-bot-without-proxy-settings.html",
+      "custom_bot_with_proxy_setting": "https://docs.growi.org/en/admin-guide/management-cookbook/slack-integration/custom-bot-with-proxy-settings.html"
+    }
+  },
+  "slack_integration_legacy": {
+    "slack_integration_legacy": "레거시 Slack 통합",
+    "alert_disabled": "이 'Slack 레거시 통합'은 <a href='/admin/slack-integration'>새 설정</a>이 활성화되어 현재 비활성화되었습니다.",
+    "alert_deplicated": "이 '레거시 Slack 통합'은 오래되었으며 향후 중단될 예정입니다. 대신 <a href='/admin/slack-integration'>새 설정</a>을 사용하십시오."
+  },
+  "user_management": {
+    "user_management": "사용자 관리",
+    "invite_users": "새 사용자 임시 발급",
+    "click_twice_same_checkbox": "최소한 하나의 확인란을 선택해야 합니다.",
+    "status": "상태",
+    "invite_modal": {
+      "emails": "이메일 (새 줄로 여러 명 발급 가능)",
+      "description1": "이메일 주소로 새 사용자를 임시 발급합니다.",
+      "description2": "첫 로그인 시 임시 비밀번호가 생성됩니다.",
+      "invite_thru_email": "초대 이메일 전송",
+      "mail_setting_link": "<span className='material-symbols-outlined me-2'>settings</span><a href='/admin/app'>이메일 설정</a>",
+      "valid_email": "유효한 이메일 주소가 필요합니다.",
+      "temporary_password": "생성된 사용자에게는 임시 비밀번호가 있습니다.",
+      "send_new_password": "새 비밀번호를 사용자에게 보내주십시오.",
+      "send_temporary_password": "초대 이메일을 보내지 않은 경우, 이 화면에서 임시 비밀번호를 복사하여 초대자에게 연락하십시오.",
+      "send_email": "사용자 테이블의 드롭다운에서 초대 이메일을 보내거나 다시 보낼 수도 있습니다.",
+      "existing_email": "다음 이메일은 이미 존재합니다.",
+      "issue": "발급"
+    },
+    "user_table": {
+      "administrator": "관리자",
+      "read_only": "읽기 전용",
+      "edit_menu": "편집 메뉴",
+      "reset_password": "비밀번호 재설정",
+      "administrator_menu": "관리자 메뉴",
+      "accept": "수락",
+      "deactivate_account": "계정 비활성화",
+      "your_own": "자신의 계정을 비활성화할 수 없습니다.",
+      "revoke_admin_access": "관리자 권한 취소",
+      "cannot_revoke": "자신에게서 관리자 권한을 취소할 수 없습니다.",
+      "grant_admin_access": "관리자 권한 부여",
+      "revoke_read_only_access": "읽기 전용 권한 취소",
+      "grant_read_only_access": "읽기 전용 권한 부여",
+      "send_invitation_email": "초대 이메일 전송",
+      "resend_invitation_email": "초대 이메일 재전송"
+    },
+    "reset_password": "비밀번호 재설정",
+    "reset_password_modal": {
+      "password_never_seen": "이 화면이 닫히면 임시 비밀번호는 다시 검색할 수 없습니다.",
+      "password_reset_message": "아래의 새 비밀번호를 사용자에게 알리고 즉시 다른 비밀번호로 변경하도록 강력히 권장하십시오.",
+      "send_new_password": "새 비밀번호를 사용자에게 보내주십시오.",
+      "target_user": "대상 사용자",
+      "new_password": "새 비밀번호"
+    },
+    "external_account": "외부 계정 관리",
+    "external_accounts": "외부 계정",
+    "create_external_account": "외부 계정 생성",
+    "external_account_list": "외부 계정 목록",
+    "external_account_none": "외부 계정 없음",
+    "invite": "초대",
+    "invited": "사용자가 초대되었습니다.",
+    "back_to_user_management": "사용자 관리로 돌아가기",
+    "authentication_provider": "인증 제공자",
+    "manage": "관리",
+    "password_setting": "비밀번호 설정",
+    "password_setting_help": "비밀번호가 설정되었습니까?",
+    "set": "예",
+    "unset": "아니요",
+    "related_username": "관련 사용자 ",
+    "cannot_invite_maximum_users": "최대 사용자 수 이상을 초대할 수 없습니다.",
+    "current_users": "현재 사용자:"
+  },
+  "user_group_management": {
+    "user_group_management": "사용자 그룹 관리",
+    "create_group": "새 그룹 생성",
+    "add_child_group": "하위 그룹 추가",
+    "remove_child_group": "제거",
+    "deny_create_group": "현재 설정으로는 새 그룹을 생성할 수 없습니다.",
+    "group_name": "그룹 이름",
+    "group_example": "예: 그룹1",
+    "child_user_group": "하위 사용자 그룹",
+    "parent_group": "상위 그룹",
+    "select_parent_group": "상위 그룹 선택",
+    "release_parent_group": "상위 그룹 해제",
+    "add_modal": {
+      "description": "추가된 사용자는 모든 상위 그룹에도 추가됩니다.",
+      "add_user": "생성된 그룹에 사용자 추가",
+      "search_option": "검색 옵션",
+      "enable_option": "{{option}} 활성화",
+      "forward_match": "정방향 일치",
+      "partial_match": "부분 일치",
+      "backward_match": "역방향 일치"
+    },
+    "group_list": "그룹 목록",
+    "child_group_list": "하위 그룹 목록",
+    "back_to_list": "그룹 목록으로 돌아가기",
+    "basic_info": "기본 정보",
+    "user_list": "사용자 목록",
+    "created_group": "그룹이 생성되었습니다.",
+    "is_loading_data": "데이터 가져오는 중...",
+    "no_pages": "그룹에 보기 권한이 있는 페이지가 없습니다.",
+    "remove_from_group": "이 사용자 제거",
+    "delete_modal": {
+      "header": "그룹 삭제",
+      "desc": "그룹 아래의 모든 하위 그룹도 삭제됩니다. 한 번 삭제되면 삭제된 그룹과 해당 비공개 페이지는 검색할 수 없습니다.",
+      "dropdown_desc": "비공개 페이지에 대한 작업 선택",
+      "select_group": "그룹 선택",
+      "no_groups": "선택할 그룹 없음",
+      "publish_pages": "게시 가능한 페이지 게시",
+      "delete_pages": "모두 삭제",
+      "transfer_pages": "다른 그룹으로 전송",
+      "option_explanation": "\"게시 가능한\" 페이지는 삭제하려는 그룹에만 보이는 페이지입니다. 다른 그룹이 볼 수 있는 페이지는 게시되지 않습니다."
+    },
+    "update_parent_confirm_modal": {
+      "header": "그룹의 상위가 변경됩니다.",
+      "caution_change_parent": "이 작업은 그룹 \"{{groupName}}\"의 상위를 변경합니다.",
+      "danger_message": "이것이 이 그룹과 관련된 모든 페이지의 보기 권한에 영향을 미친다는 점에 유의하십시오.",
+      "force_update_parents_label": "누락된 사용자 강제 추가",
+      "force_update_parents_description": "상위 그룹을 변경한 후 누락된 사용자가 존재하는 경우 상위 그룹에 강제로 추가하려면 이 옵션을 활성화하십시오."
+    }
+  },
+  "audit_log_management": {
+    "audit_log": "감사 로그",
+    "audit_log_settings": "감사 로그 설정",
+    "user": "사용자",
+    "username": "사용자 이름",
+    "date": "날짜",
+    "action": "작업",
+    "ip": "IP 주소",
+    "url": "URL",
+    "settings": "설정",
+    "return": "돌아가기",
+    "clear": "지우기",
+    "activity_expiration_date": "감사 로그 만료일",
+    "activity_expiration_date_explanation": "생성된 감사 로그는 환경 변수에 설정된 시간(초)이 지나면 생성 시간부터 자동으로 삭제됩니다.",
+    "fixed_by_env_var": "이것은 환경 변수 <code>{{key}}={{value}}</code>에 의해 고정됩니다.",
+    "available_action_list": "모든 사용 가능한 작업 검색 / 보기",
+    "available_action_list_explanation": "현재 설정에서 검색/볼 수 있는 작업 목록",
+    "action_list": "작업 목록",
+    "disable_mode_explanation": "감사 로그가 현재 비활성화되어 있습니다. 활성화하려면 환경 변수 <code>AUDIT_LOG_ENABLED</code>를 true로 설정하십시오.",
+    "docs_url": {
+      "log_type": "https://docs.growi.org/en/admin-guide/admin-cookbook/audit-log-setup.html#log-types"
+    }
+  },
+  "g2g_data_transfer": {
+    "transfer_data_to_another_growi": "이 GROWI에서 다른 GROWI로 데이터 전송",
+    "advanced_options": "고급 옵션",
+    "start_transfer": "전송 시작",
+    "paste_transfer_key": "여기에 전송 키 붙여넣기"
+  },
+  "plugins": {
+    "plugins": "플러그인",
+    "plugin_installer": "플러그인 설치 프로그램",
+    "form": {
+      "label_url": "저장소 URL",
+      "desc_url": "URL을 입력하여 플러그인을 설치할 수 있습니다.",
+      "label_branch": "저장소 브랜치 이름",
+      "desc_branch": "설치할 브랜치 이름을 지정할 수 있습니다. 기본값: `main`"
+    },
+    "plugin_card": "플러그인 카드",
+    "plugin_is_not_installed": "플러그인이 설치되지 않았습니다.",
+    "install": "설치",
+    "confirm": "플러그인 삭제?"
+  },
+  "cloud_setting_management": {
+    "to_cloud_settings": "GROWI.cloud 설정 열기"
+  },
+  "audit_log_action_category": {
+    "Page": "페이지",
+    "Comment": "댓글",
+    "Tag": "태그",
+    "Attachment": "첨부 파일",
+    "ShareLink": "공유 링크",
+    "Search": "검색",
+    "User": "사용자",
+    "Admin": "관리자"
+  },
+  "audit_log_action": {
+    "USER_REGISTRATION_SUCCESS": "사용자 생성",
+    "USER_LOGIN_WITH_LOCAL": "ID/비밀번호로 로그인",
+    "USER_LOGIN_WITH_LDAP": "LDAP으로 로그인",
+    "USER_LOGIN_WITH_GOOGLE": "Google로 로그인",
+    "USER_LOGIN_WITH_GITHUB": "GitHub으로 로그인",
+    "USER_LOGIN_WITH_OIDC": "OIDC로 로그인",
+    "USER_LOGIN_WITH_SAML": "SAML로 로그인",
+    "USER_LOGIN_FAILURE": "로그인 실패",
+    "USER_LOGOUT": "로그아웃",
+    "USER_FOGOT_PASSWORD": "비밀번호 재설정 요청",
+    "USER_RESET_PASSWORD": "비밀번호 재설정",
+    "USER_PERSONAL_SETTINGS_UPDATE": "사용자 개인 설정 업데이트",
+    "USER_IMAGE_TYPE_UPDATE": "사용자 이미지 유형 업데이트",
+    "USER_LDAP_ACCOUNT_ASSOCIATE": "LDAP 계정 연결",
+    "USER_LDAP_ACCOUNT_DISCONNECT": "LDAP 계정 연결 해제",
+    "USER_PASSWORD_UPDATE": "비밀번호 업데이트",
+    "USER_API_TOKEN_UPDATE": "API 토큰 업데이트",
+    "USER_EDITOR_SETTINGS_UPDATE": "편집기 설정 업데이트",
+    "USER_IN_APP_NOTIFICATION_SETTINGS_UPDATE": "앱 내 알림 설정 업데이트",
+    "USER_REGISTRATION_APPROVAL_REQUEST": "ID/비밀번호 인증을 위한 사용자 등록 요청",
+    "PAGE_VIEW": "페이지 보기",
+    "PAGE_USER_HOME_VIEW": "페이지 보기 (사용자 홈)",
+    "PAGE_FORBIDDEN": "페이지 보기 (금지된 페이지)",
+    "PAGE_NOT_FOUND": "페이지 보기 (찾을 수 없는 페이지)",
+    "PAGE_NOT_CREATABLE": "페이지 보기 (생성할 수 없는 페이지)",
+    "PAGE_LIKE": "좋아요",
+    "PAGE_UNLIKE": "좋아요 취소",
+    "PAGE_BOOKMARK": "북마크",
+    "PAGE_UNBOOKMARK": "북마크 해제",
+    "PAGE_CREATE": "페이지 생성",
+    "PAGE_UPDATE": "페이지 업데이트",
+    "PAGE_RENAME": "페이지 이름 변경",
+    "PAGE_DUPLICATE": "페이지 복제",
+    "PAGE_DELETE": "페이지 삭제",
+    "PAGE_DELETE_COMPLETELY": "페이지 완전 삭제",
+    "PAGE_REVERT": "페이지 되돌리기",
+    "PAGE_EMPTY_TRASH": "휴지통 비우기",
+    "PAGE_RECURSIVELY_RENAME": "재귀적 페이지 이름 변경",
+    "PAGE_RECURSIVELY_DELETE": "재귀적 페이지 삭제",
+    "PAGE_RECURSIVELY_DELETE_COMPLETELY": "재귀적 페이지 완전 삭제",
+    "PAGE_RECURSIVELY_REVERT": "재귀적 페이지 되돌리기",
+    "PAGE_SUBSCRIBE": "페이지 구독",
+    "PAGE_UNSUBSCRIBE": "페이지 구독 취소",
+    "PAGE_EXPORT": "페이지 내보내기",
+    "TAG_UPDATE": "태그 업데이트",
+    "IN_APP_NOTIFICATION_ALL_STATUSES_OPEN": "모든 앱 내 알림 읽음",
+    "COMMENT_CREATE": "댓글 생성",
+    "COMMENT_UPDATE": "댓글 업데이트",
+    "COMMENT_REMOVE": "댓글 제거",
+    "SHARE_LINK_CREATE": "공유 링크 생성",
+    "SHARE_LINK_DELETE": "공유 링크 삭제",
+    "SHARE_LINK_DELETE_BY_PAGE": "페이지의 모든 공유 링크 제거",
+    "SHARE_LINK_ALL_DELETE": "모든 공유 링크 삭제",
+    "SHARE_LINK_PAGE_VIEW": "페이지 보기(공유 링크)",
+    "SHARE_LINK_EXPIRED_PAGE_VIEW": "페이지 보기(만료된 공유 링크)",
+    "SHARE_LINK_NOT_FOUND": "페이지 보기 (공유 링크를 찾을 수 없음)",
+    "ATTACHMENT_ADD": "첨부 파일 추가",
+    "ATTACHMENT_REMOVE": "첨부 파일 제거",
+    "ATTACHMENT_DOWNLOAD": "첨부 파일 다운로드",
+    "SEARCH_PAGE": "페이지 검색",
+    "SEARCH_PAGE_VIEW": "페이지 보기(검색 결과 페이지)",
+    "ADMIN_APP_SETTING_UPDATE": "앱 설정 업데이트",
+    "ADMIN_SITE_URL_UPDATE": "사이트 URL 설정 업데이트",
+    "ADMIN_MAIL_SMTP_UPDATE": "이메일(SMTP) 설정 업데이트",
+    "ADMIN_MAIL_SES_UPDATE": "이메일(SES) 설정 업데이트",
+    "ADMIN_MAIL_TEST_SUBMIT": "테스트 메일 전송",
+    "ADMIN_FILE_UPLOAD_CONFIG_UPDATE": "파일 업로드 설정 업데이트",
+    "ADMIN_PLUGIN_UPDATE": "플러그인 설정 업데이트",
+    "ADMIN_MAINTENANCEMODE_ENABLED": "유지 보수 모드 활성화",
+    "ADMIN_MAINTENANCEMODE_DISABLED": "유지 보수 모드 비활성화",
+    "ADMIN_SECURITY_SETTINGS_UPDATE": "보안 설정 업데이트",
+    "ADMIN_PERMIT_SHARE_LINK": "공유 링크 활성화",
+    "ADMIN_REJECT_SHARE_LINK": "공유 링크 비활성화",
+    "ADMIN_AUTH_ID_PASS_ENABLED": "ID/비밀번호 인증 활성화",
+    "ADMIN_AUTH_ID_PASS_DISABLED": "ID/비밀번호 인증 비활성화",
+    "ADMIN_AUTH_ID_PASS_UPDATE": "ID/비밀번호 인증 설정 업데이트",
+    "ADMIN_AUTH_LDAP_ENABLED": "LDAP 인증 활성화",
+    "ADMIN_AUTH_LDAP_DISABLED": "LDAP 인증 비활성화",
+    "ADMIN_AUTH_LDAP_UPDATE": "LDAP 인증 설정 업데이트",
+    "ADMIN_AUTH_SAML_ENABLED": "SAML 인증 활성화",
+    "ADMIN_AUTH_SAML_DISABLED": "SAML 인증 비활성화",
+    "ADMIN_AUTH_SAML_UPDATE": "SAML 인증 설정 업데이트",
+    "ADMIN_AUTH_OIDC_ENABLED": "OIDC 인증 활성화",
+    "ADMIN_AUTH_OIDC_DISABLED": "OIDC 인증 비활성화",
+    "ADMIN_AUTH_OIDC_UPDATE": "OIDC 설정 업데이트",
+    "ADMIN_AUTH_GOOGLE_ENABLED": "Google 인증 활성화",
+    "ADMIN_AUTH_GOOGLE_DISABLED": "Google 인증 비활성화",
+    "ADMIN_AUTH_GOOGLE_UPDATE": "Google 인증 설정 업데이트",
+    "ADMIN_AUTH_GITHUB_ENABLED": "GitHub 인증 활성화",
+    "ADMIN_AUTH_GITHUB_DISABLED": "GitHub 인증 비활성화",
+    "ADMIN_AUTH_GITHUB_UPDATE": "GitHub 인증 설정 업데이트",
+    "ADMIN_MARKDOWN_LINE_BREAK_UPDATE": "줄 바꿈 설정 업데이트",
+    "ADMIN_MARKDOWN_INDENT_UPDATE": "들여쓰기 설정 업데이트",
+    "ADMIN_MARKDOWN_PRESENTATION_UPDATE": "프레젠테이션 설정 업데이트",
+    "ADMIN_MARKDOWN_XSS_UPDATE": "XSS 방지 설정 업데이트",
+    "ADMIN_LAYOUT_UPDATE": "레이아웃 업데이트",
+    "ADMIN_THEME_UPDATE": "테마 업데이트",
+    "ADMIN_SIDEBAR_UPDATE": "기본 사이드바 모드 업데이트",
+    "ADMIN_FUNCTION_UPDATE": "기능 업데이트",
+    "ADMIN_CODE_HIGHLIGHT_UPDATE": "코드 하이라이트 업데이트",
+    "ADMIN_CUSTOM_TITLE_UPDATE": "사용자 지정 제목 업데이트",
+    "ADMIN_CUSTOM_NOSCRIPT_UPDATE": "사용자 지정 noscript 업데이트",
+    "ADMIN_CUSTOM_CSS_UPDATE": "사용자 지정 CSS 업데이트",
+    "ADMIN_CUSTOM_SCRIPT_UPDATE": "사용자 지정 스크립트 업데이트",
+    "ADMIN_ARCHIVE_DATA_UPLOAD": "아카이브 데이터 업로드",
+    "ADMIN_GROWI_DATA_IMPORTED": "아카이브 데이터 가져오기",
+    "ADMIN_UPLOADED_GROWI_DATA_DISCARDED": "업로드된 GROWI 데이터 버리기",
+    "ADMIN_ESA_DATA_IMPORTED": "esa.io에서 가져오기",
+    "ADMIN_ESA_DATA_UPDATED": "esa.io 가져오기 설정 업데이트",
+    "ADMIN_CONNECTION_TEST_OF_ESA_DATA": "esa 연결 테스트",
+    "ADMIN_QIITA_DATA_IMPORTED": "Qiita:Team에서 가져오기",
+    "ADMIN_QIITA_DATA_UPDATED": "Qiita:Team 가져오기 설정 업데이트",
+    "ADMIN_CONNECTION_TEST_OF_QIITA_DATA": "Qiita:Team 연결 테스트",
+    "ADMIN_ARCHIVE_DATA_CREATE": "아카이브 데이터 생성",
+    "ADMIN_ARCHIVE_DATA_DOWNLOAD": "아카이브 데이터 다운로드",
+    "ADMIN_ARCHIVE_DATA_DELETE": "아카이브 데이터 삭제",
+    "ADMIN_USER_NOTIFICATION_SETTINGS_ADD": "사용자 트리거 알림 설정 추가",
+    "ADMIN_USER_NOTIFICATION_SETTINGS_DELETE": "사용자 트리거 알림 설정 삭제",
+    "ADMIN_GLOBAL_NOTIFICATION_SETTINGS_ADD": "전역 알림 설정 추가",
+    "ADMIN_GLOBAL_NOTIFICATION_SETTINGS_UPDATE": "전역 알림 설정 업데이트",
+    "ADMIN_NOTIFICATION_GRANT_SETTINGS_UPDATE": "전역 알림 권한 업데이트",
+    "ADMIN_GLOBAL_NOTIFICATION_SETTINGS_ENABLED": "전역 알림 설정 활성화",
+    "ADMIN_GLOBAL_NOTIFICATION_SETTINGS_DISABLED": "전역 알림 설정 비활성화",
+    "ADMIN_GLOBAL_NOTIFICATION_SETTINGS_DELETE": "전역 알림 설정 삭제",
+    "ADMIN_SLACK_WORKSPACE_CREATE": "Slack 워크스페이스 추가",
+    "ADMIN_SLACK_WORKSPACE_DELETE": "Slack 워크스페이스 삭제",
+    "ADMIN_SLACK_BOT_TYPE_UPDATE": "Slack 봇 유형 변경",
+    "ADMIN_SLACK_BOT_TYPE_DELETE": "Slack 봇 유형 삭제",
+    "ADMIN_SLACK_ACCESS_TOKEN_REGENERATE": "Slack 액세스 토큰 재생성",
+    "ADMIN_SLACK_MAKE_APP_PRIMARY": "Slack 봇을 기본으로 설정",
+    "ADMIN_SLACK_PERMISSION_UPDATE": "Slack 봇 권한 업데이트",
+    "ADMIN_SLACK_PROXY_URI_UPDATE": "프록시 있는 사용자 지정 봇의 프록시 URL 업데이트",
+    "ADMIN_SLACK_RELATION_TEST": "Slack 봇 연결 테스트",
+    "ADMIN_SLACK_WITHOUT_PROXY_SETTINGS_UPDATE": "프록시 없는 Slack 봇 설정 업데이트",
+    "ADMIN_SLACK_WITHOUT_PROXY_PERMISSION_UPDATE": "프록시 없는 Slack 봇 권한 업데이트",
+    "ADMIN_SLACK_WITHOUT_PROXY_TEST": "프록시 없는 Slack 봇 연결 테스트",
+    "ADMIN_SLACK_CONFIGURATION_SETTING_UPDATE": "Slack 수신 웹훅 구성 설정 업데이트",
+    "ADMIN_USERS_INVITE": "사용자 초대",
+    "ADMIN_USERS_PASSWORD_RESET": "사용자 비밀번호 재설정",
+    "ADMIN_USERS_ACTIVATE": "사용자 활성화",
+    "ADMIN_USERS_DEACTIVATE": "사용자 비활성화",
+    "ADMIN_USERS_GRANT_ADMIN": "관리자 권한 부여",
+    "ADMIN_USERS_REVOKE_ADMIN": "관리자 권한 취소",
+    "ADMIN_USERS_GRANT_READ_ONLY": "읽기 전용 권한 부여",
+    "ADMIN_USERS_REVOKE_READ_ONLY": "읽기 전용 권한 취소",
+    "ADMIN_USERS_SEND_INVITATION_EMAIL": "초대 이메일 재전송",
+    "ADMIN_USERS_REMOVE": "사용자 제거",
+    "ADMIN_USER_GROUP_CREATE": "사용자 그룹 생성",
+    "ADMIN_USER_GROUP_UPDATE": "사용자 그룹 업데이트",
+    "ADMIN_USER_GROUP_DELETE": "사용자 그룹 삭제",
+    "ADMIN_USER_GROUP_ADD_USER": "사용자 그룹에 사용자 추가",
+    "ADMIN_SEARCH_CONNECTION": "Elasticsearch에 다시 연결 시도",
+    "ADMIN_SEARCH_INDICES_NORMALIZE": "Elasticsearch 인덱스 정규화",
+    "ADMIN_SEARCH_INDICES_REBUILD": "Elasticsearch 인덱스 재구축",
+    "ADMIN_PAGE_BULK_EXPORT_SETTINGS_UPDATE": "페이지 대량 내보내기 설정 업데이트"
+  },
+  "g2g": {
+    "transfer_success": "GROWI 간 전송 성공",
+    "error_generate_growi_archive": "GROWI 아카이브 파일 생성 실패",
+    "error_send_growi_archive": "대상 GROWI로 GROWI 아카이브 파일 전송 실패"
+  },
+  "external_user_group": {
+    "management": "외부 그룹 관리",
+    "execute_sync": "동기화 실행",
+    "sync": "동기화",
+    "invalid_sync_settings": "잘못된 동기화 설정",
+    "update_sync_settings_failed": "동기화 설정 업데이트 실패",
+    "description_form_detail": "설명 매퍼가 동기화 설정에 설정된 경우 다음 동기화 시 편집된 값이 덮어쓰여질 수 있으므로 유의하십시오.",
+    "only_description_edit_allowed": "외부 사용자 그룹의 설명만 편집할 수 있습니다.",
+    "sync_being_executed": "사용자 또는 다른 사용자가 시작한 외부 그룹 동기화 프로세스가 실행 중입니다. 이 프로세스가 완료될 때까지 다음 동기화를 실행할 수 없습니다.",
+    "sync_succeeded": "외부 그룹 동기화 성공",
+    "sync_failed": "외부 그룹 동기화 실패",
+    "provider": "제공자",
+    "confirmation_before_sync": "동기화 전 확인",
+    "execution_time_warning": "그룹 또는 사용자 수가 많으면 동기화가 완료될 때까지 시간이 걸릴 수 있습니다.",
+    "parallel_sync_forbidden": "동기화가 실행 중인 동안에는 다른 외부 그룹 동기화를 실행할 수 없습니다.",
+    "ldap": {
+      "group_sync_settings": "LDAP 그룹 동기화 설정",
+      "group_search_base_DN": "그룹 검색 기본 DN",
+      "group_search_base_dn_detail": "그룹 검색을 위한 기본 DN입니다. 여기에 설정되지 않으면 보안 설정에 설정된 값이 사용됩니다.",
+      "membership_attribute": "멤버십 속성",
+      "membership_attribute_detail": "사용자 멤버십 정보를 나타내는 그룹 개체의 속성",
+      "membership_attribute_type": "멤버십 속성 유형",
+      "membership_attribute_type_detail": "멤버십 속성 값이 DN 또는 UID 유형인지 여부",
+      "child_group_attribute": "하위 그룹 속성",
+      "child_group_attribute_detail": "하위 그룹 정보를 나타내는 그룹 개체의 속성입니다. 속성 값은 하위 그룹의 DN이어야 합니다.",
+      "preserve_deleted_ldap_groups": "삭제된 LDAP 그룹 유지",
+      "name_mapper_detail": "그룹 이름으로 매핑할 속성",
+      "updated_group_sync_settings": "LDAP 그룹 동기화 설정 업데이트",
+      "password": "비밀번호",
+      "password_detail": "바인딩 유형이 사용자 바인딩으로 설정되어 있으므로 로그인 비밀번호가 필요합니다.",
+      "auth_not_set": "동기화 전에 보안 설정에서 LDAP 인증을 활성화하고 구성하십시오."
+    },
+    "keycloak": {
+      "group_sync_settings": "Keycloak 그룹 동기화 설정",
+      "host": "호스트",
+      "host_detail": "Keycloak 호스트 URL",
+      "group_realm": "그룹 영역",
+      "group_realm_detail": "동기화할 그룹을 포함하는 영역",
+      "group_sync_client_realm": "관리 API 요청에 사용되는 클라이언트 영역",
+      "group_sync_client_realm_detail": "Keycloak 관리 API에 요청을 인증하는 데 사용되는 클라이언트를 포함하는 영역",
+      "group_sync_client_id": "클라이언트 ID",
+      "group_sync_client_id_detail": "Keycloak 관리 API에 요청을 인증하는 데 사용되는 클라이언트 ID",
+      "group_sync_client_secret": "클라이언트 시크릿",
+      "group_sync_client_secret_detail": "Keycloak 관리 API에 요청을 인증하는 데 사용되는 시크릿 ID",
+      "updated_group_sync_settings": "Keycloak 그룹 동기화 설정 업데이트",
+      "preserve_deleted_keycloak_groups": "삭제된 Keycloak 그룹 유지",
+      "auth_not_set": "그룹 동기화 설정의 '호스트' 및 '그룹 영역'을 포함하는 OIDC 또는 SAML 호스트를 활성화하십시오."
+    },
+    "auto_generate_user_on_sync": "동기화 시 사용자 자동 생성",
+    "description_mapper_detail": "그룹 설명으로 매핑할 속성입니다. 설명은 동기화 후 편집할 수 있습니다. 그러나 매퍼가 설정된 경우 편집된 값이 다음 동기화 시 덮어쓰여질 수 있습니다."
+  },
+  "toaster": {
+    "grant_user_admin": "{{username}}에게 관리자 권한 부여 성공",
+    "revoke_user_admin": "{{username}}의 관리자 권한 취소 성공",
+    "grant_user_read_only": "{{username}}에게 읽기 전용 권한 부여 성공",
+    "revoke_user_read_only": "{{username}}의 읽기 전용 권한 취소 성공",
+    "activate_user_success": "{{username}} 활성화 성공",
+    "deactivate_user_success": "{{username}} 비활성화 성공",
+    "remove_user_success": "{{username}} 제거 성공",
+    "remove_external_user_success": "{{accountId}} 제거 성공",
+    "switch_disable_link_sharing_success": "공유 링크 설정 업데이트 성공",
+    "install_plugin_success": "{{pluginName}} 설치 성공",
+    "activate_plugin_success": "{{pluginName}} 활성화 성공",
+    "deactivate_plugin_success": "{{pluginName}} 비활성화 성공",
+    "remove_plugin_success": "{{pluginName}} 제거 성공"
+  },
+  "forbidden_page": {
+    "do_not_have_admin_permission": "관리자 권한이 없는 사용자는 관리 화면에 접근할 수 없습니다."
+  },
+  "ai_integration": {
+    "ai_integration": "AI 통합",
+    "disable_mode_explanation": "현재 AI 통합이 비활성화되어 있습니다. 활성화하려면 <code>AI_ENABLED</code> 환경 변수와 필요한 추가 변수를 구성하십시오.<br><br>자세한 내용은 <a target='blank' rel='noopener noreferrer' href={{documentationUrl}}en/guide/features/ai-knowledge-assistant.html>문서</a>를 참조하십시오.",
+    "ai_search_management": "AI 검색 관리"
+  }
+}

+ 127 - 0
apps/app/public/static/locales/ko_KR/commons.json

@@ -0,0 +1,127 @@
+{
+  "Show": "표시",
+  "Hide": "숨기기",
+  "Add": "추가",
+  "Insert": "삽입",
+  "Reset": "재설정",
+  "Sign out": "로그아웃",
+  "New": "새로 만들기",
+  "Delete": "삭제",
+  "meta": {
+    "display_name": "한국어"
+  },
+  "toaster": {
+    "add_succeeded": "{{target}} 추가 성공",
+    "create_failed": "{{target}} 생성 실패",
+    "create_succeeded": "{{target}} 생성 성공",
+    "delete_succeeded": "{{target}} 삭제 성공",
+    "remove_share_link": "{{count}}개 공유 링크 제거 성공",
+    "remove_share_link_success": "{{shareLinkId}} 제거 성공",
+    "update_failed": "{{target}} 업데이트 실패",
+    "update_successed": "{{target}} 업데이트 성공"
+  },
+  "alert": {
+    "siteUrl_is_not_set": "'사이트 URL'이 설정되지 않았습니다. {{link}}에서 설정하십시오.",
+    "please_enable_mailer": "먼저 메일러를 설정하십시오.",
+    "password_reset_please_enable_mailer": "먼저 메일러를 설정하십시오.",
+    "email_is_already_in_use": "이 이메일 주소는 이미 사용 중입니다."
+  },
+  "headers": {
+    "app_settings": "앱 설정"
+  },
+  "header_search_box": {
+    "label": {
+      "All pages": "모든 페이지",
+      "This tree": "이 트리"
+    },
+    "item_label": {
+      "All pages": "모든 페이지",
+      "This tree": "이 트리의 하위 항목만"
+    }
+  },
+  "search_method_menu_item": {
+    "search_in_all": "모두 검색",
+    "only_children_of_this_tree": "이 트리의 하위 항목만",
+    "exact_mutch": "정확히 일치"
+  },
+  "share_links": {
+    "Share Link": "공유 링크",
+    "Page Path": "페이지 경로",
+    "expire": "만료",
+    "description": "설명"
+  },
+  "in_app_notification": {
+    "notification_list": "앱 내 알림 목록",
+    "see_all": "모두 보기",
+    "no_notification": "알림이 없습니다.",
+    "all": "모두",
+    "unopend": "읽지 않음",
+    "mark_all_as_read": "모두 읽음으로 표시",
+    "no_unread_messages": "읽지 않은 메시지 없음",
+    "only_unread": "읽지 않은 메시지만"
+  },
+  "personal_dropdown": {
+    "home": "홈",
+    "settings": "설정",
+    "color_mode": "색상 모드",
+    "sidebar_mode": "사이드바 모드",
+    "sidebar_mode_editor": "편집기 사이드바 모드",
+    "use_os_settings": "OS 설정 사용",
+    "feedback": "피드백"
+  },
+  "create_page_dropdown": {
+    "new_page": "새 페이지 생성",
+    "open_page_create_modal": "새 페이지 생성 모달 열기",
+    "todays": {
+      "desc": "오늘의 메모 생성",
+      "memo": "메모"
+    },
+    "template": {
+      "desc": "템플릿 페이지 생성/편집",
+      "children": "하위 항목용 템플릿",
+      "descendants": "하위 항목용 템플릿"
+    }
+  },
+  "copy_to_clipboard": {
+    "Copy to clipboard": "클립보드에 복사",
+    "Page path": "페이지 경로",
+    "Page URL": "페이지 URL",
+    "Permanent link": "영구 링크",
+    "Page path and permanent link": "페이지 경로 및 영구 링크",
+    "Markdown link": "마크다운 링크",
+    "Append params": "매개변수 추가"
+  },
+  "crop_image_modal": {
+    "image_crop": "이미지 자르기",
+    "crop": "자르기",
+    "save": "저장",
+    "cancel": "취소"
+  },
+  "handsontable_modal": {
+    "title": "테이블 편집",
+    "data_import": "데이터 가져오기",
+    "save": "저장",
+    "cancel": "취소",
+    "done": "완료",
+    "data_import_form": {
+      "select_data_format": "데이터 형식 선택",
+      "import_data": "데이터 가져오기",
+      "paste_table_data": "테이블 데이터 붙여넣기",
+      "parse_error": "구문 분석 오류",
+      "cancel": "취소",
+      "import": "가져오기"
+    }
+  },
+  "not_found_page": {
+    "page_not_exist": "이 페이지는 존재하지 않습니다."
+  },
+  "g2g_data_transfer": {
+    "tab": "데이터 전송",
+    "data_transfer": "데이터 전송",
+    "transfer_data_to_this_growi": "다른 GROWI에서 이 GROWI로 데이터 전송",
+    "publish_transfer_key": "전송 키 게시",
+    "transfer_key_limit": "전송 키는 발급 후 1시간 동안 유효합니다.",
+    "once_transfer_key_used": "전송 키가 전송에 사용되면 다른 전송에는 사용할 수 없습니다.",
+    "transfer_to_growi_cloud": "자세한 내용은 <a href='{{documentationUrl}}en/admin-guide/management-cookbook/g2g-transfer.html'>여기를 클릭하십시오.</a>"
+  }
+}

+ 1025 - 0
apps/app/public/static/locales/ko_KR/translation.json

@@ -0,0 +1,1025 @@
+{
+  "meta": {
+    "display_name": "한국어"
+  },
+  "Help": "도움말",
+  "view": "보기",
+  "Edit": "편집",
+  "Delete": "삭제",
+  "delete_all": "모두 삭제",
+  "Duplicate": "복제",
+  "PathRecovery": "경로 복구",
+  "Copy": "복사",
+  "preview": "미리보기",
+  "desktop": "데스크톱",
+  "phone": "스마트폰",
+  "tablet": "태블릿",
+  "Click to copy": "클릭하여 복사",
+  "Rename": "이름 변경",
+  "Move/Rename": "이동/이름 변경",
+  "Redirected": "리디렉션됨",
+  "Unlinked": "연결 해제됨",
+  "unlink_redirection": "리디렉션 연결 해제",
+  "Done": "완료",
+  "Cancel": "취소",
+  "Create": "생성",
+  "Description": "설명",
+  "Admin": "관리자",
+  "administrator": "관리자",
+  "Tag": "태그",
+  "Tags": "태그",
+  "Close": "닫기",
+  "Shortcuts": "단축키",
+  "Custom Sidebar": "사용자 지정 사이드바",
+  "eg": "예:",
+  "add": "추가",
+  "Undo": "실행 취소",
+  "Article": "문서",
+  "Page Path": "페이지 경로",
+  "Category": "카테고리",
+  "User": "사용자",
+  "account_id": "계정 ID",
+  "Update": "업데이트",
+  "Update Page": "페이지 업데이트",
+  "Error": "오류",
+  "Warning": "경고",
+  "Sign in": "로그인",
+  "Sign in with External auth": "{{signin}}으로 로그인",
+  "Sign up is here": "회원가입",
+  "Sign in is here": "로그인",
+  "Sign up": "회원가입",
+  "or": "또는",
+  "Sign up with Google Account": "Google 계정으로 회원가입",
+  "Sign in with Google Account": "Google 계정으로 로그인",
+  "Sign up with this Google Account": "이 Google 계정으로 회원가입",
+  "Select": "선택",
+  "Required": "필수",
+  "Example": "예시",
+  "Taro Yamada": "홍길동",
+  "List View": "목록 보기",
+  "Timeline View": "타임라인 보기",
+  "History": "기록",
+  "attachment_data": "첨부 파일 데이터",
+  "No_attachments_yet": "아직 첨부 파일이 없습니다.",
+  "Presentation Mode": "프레젠테이션 모드",
+  "Not available for guest": "게스트는 사용할 수 없습니다.",
+  "Not available in this version": "이 버전에서는 사용할 수 없습니다.",
+  "Not available when \"anyone with the link\" is selected": "'링크를 가진 모든 사람'이 선택된 경우 범위를 재정의할 수 없습니다.",
+  "No users have liked this yet": "아직 이 페이지를 좋아한 사용자가 없습니다.",
+  "No users have liked this yet.": "아직 이 페이지를 좋아한 사용자가 없습니다.",
+  "No users have bookmarked yet": "아직 북마크한 사용자가 없습니다.",
+  "Create Archive Page": "아카이브 페이지 생성",
+  "Create Sidebar Page": "<strong>/Sidebar</strong> 페이지 생성",
+  "File type": "파일 형식",
+  "Target page": "대상 페이지",
+  "Include Attachment File": "첨부 파일 포함",
+  "Include Comment": "댓글 포함",
+  "Include Subordinated Page": "하위 페이지 포함",
+  "Include Subordinated Target Page": "{{target}} 포함",
+  "All Subordinated Page": "모든 하위 페이지",
+  "Specify Hierarchy": "계층 지정",
+  "Submitted the request to create the archive": "아카이브 생성 요청 제출됨",
+  "username": "사용자 이름",
+  "Created": "생성됨",
+  "Last updated": "업데이트됨",
+  "Share": "공유",
+  "Markdown Link": "마크다운 링크",
+  "Create/Edit Template": "템플릿 페이지 생성/편집",
+  "Go to this version": "이 버전 보기",
+  "View diff": "차이점 보기",
+  "No diff": "차이점 없음",
+  "Latest": "최신",
+  "User ID": "사용자 ID",
+  "User Information": "사용자 정보",
+  "User Activation": "사용자 활성화",
+  "Basic Info": "기본 정보",
+  "Name": "이름",
+  "Email": "이메일",
+  "Language": "언어",
+  "English": "영어",
+  "Japanese": "일본어",
+  "Set Profile Image": "프로필 이미지 설정",
+  "Upload Image": "이미지 업로드",
+  "Current Image": "현재 이미지",
+  "Delete Image": "이미지 삭제",
+  "Delete this image?": "이 이미지를 삭제하시겠습니까?",
+  "Updated": "업데이트됨",
+  "Upload new image": "새 이미지 업로드",
+  "Connected": "연결됨",
+  "Loading": "로딩 중...",
+  "Disclose E-mail": "이메일 공개",
+  "page exists": "이 페이지는 이미 존재합니다.",
+  "Error occurred": "오류 발생",
+  "Input page name": "페이지 이름 입력",
+  "Input page name (optional)": "페이지 이름 입력 (선택 사항)",
+  "Input parent page path": "상위 페이지 경로 입력",
+  "New Page": "새 페이지",
+  "Create under": "아래에 페이지 생성:",
+  "V5 Page Migration": "V5 호환성으로 변환",
+  "GROWI.5.0_new_schema": "GROWI.5.0 새 스키마",
+  "See_more_detail_on_new_schema": "<a href='https://docs.growi.org/en/admin-guide/upgrading/50x.html#about-the-new-v5-compatible-format' target='_blank'>{{title}}</a>에서 자세한 내용 확인 <span class='growi-custom-icons'>external_link</span> ",
+  "external_account_management": "외부 계정 관리",
+  "UserGroup": "사용자 그룹",
+  "Basic Settings": "기본 설정",
+  "The contents entered here will be shown in the header etc": "여기에 입력된 내용은 헤더 등에 표시됩니다.",
+  "Public": "공개",
+  "Anyone with the link": "링크를 가진 모든 사람",
+  "Specified users only": "지정된 사용자만",
+  "Only me": "나만",
+  "Only inside the group": "그룹 내에서만",
+  "page_list": "페이지 목록",
+  "comments": "댓글",
+  "Reselect the group": "그룹 재선택",
+  "Shareable link": "공유 가능한 링크",
+  "The whitelist of registration permission E-mail address": "등록 허용 이메일 주소 화이트리스트",
+  "Add tags for this page": "이 페이지에 태그 추가",
+  "tag_list": "태그 목록",
+  "popular_tags": "인기 태그",
+  "Check All tags": "모든 태그 확인",
+  "You have no tag, You can set tags on pages": "태그가 없습니다. 페이지에 태그를 설정할 수 있습니다.",
+  "Show latest": "최신 보기",
+  "Load latest": "최신 로드",
+  "edited this page": "이 페이지를 편집했습니다.",
+  "List Drafts": "초안 목록",
+  "Deleted Pages": "삭제된 페이지",
+  "Disassociate": "연결 해제",
+  "No bookmarks yet": "아직 북마크가 없습니다.",
+  "add_bookmark": "북마크에 추가",
+  "remove_bookmark": "북마크에서 제거",
+  "wide_view": "넓은 보기",
+  "Recent Changes": "최근 변경 사항",
+  "Page Tree": "페이지 트리",
+  "Bookmarks": "북마크",
+  "In-App Notification": "알림",
+  "AI Assistant": "AI 어시스턴트",
+  "Knowledge Assistant": "지식 어시스턴트 (베타)",
+  "Editor Assistant": "편집기 어시스턴트 (베타)",
+  "original_path": "원본 경로",
+  "new_path": "새 경로",
+  "duplicated_path": "중복된 경로",
+  "Link sharing is disabled": "링크 공유가 비활성화되었습니다.",
+  "successfully_saved_the_page": "페이지가 성공적으로 저장되었습니다.",
+  "you_can_not_create_page_with_this_name_or_hierarchy": "이 이름 또는 페이지 계층으로 페이지를 생성할 수 없습니다.",
+  "not_allowed_to_see_this_page": "이 페이지를 볼 수 없습니다.",
+  "Confirm": "확인",
+  "Successfully requested": "성공적으로 요청되었습니다.",
+  "source": "소스",
+  "input_validation": {
+    "target": {
+      "page_name": "페이지 이름",
+      "folder_name": "폴더 이름",
+      "field": "필드"
+    },
+    "message": {
+      "error_message": "일부 값이 올바르지 않습니다.",
+      "required": "'{{param}}'은 필수입니다.",
+      "invalid_syntax": "{{syntax}}의 구문이 유효하지 않습니다.",
+      "title_required": "제목은 필수입니다.",
+      "field_required": "{{target}}은 필수입니다."
+    }
+  },
+  "not_creatable_page": {
+    "message": "이 경로에는 페이지 콘텐츠를 생성할 수 없습니다."
+  },
+  "custom_navigation": {
+    "no_pages_under_this_page": "이 페이지 아래에 페이지가 없습니다."
+  },
+  "author_info": {
+    "created_at": "생성일",
+    "created_by": "생성자",
+    "last_revision_posted_at": "마지막 수정 게시일",
+    "updated_by": "업데이트자"
+  },
+  "installer": {
+    "tab": "계정 생성",
+    "title": "설치 프로그램",
+    "setup": "설정",
+    "create_initial_account": "초기 계정 생성",
+    "initial_account_will_be_administrator_automatically": "초기 계정은 자동으로 관리자가 됩니다.",
+    "unavaliable_user_id": "이 '사용자 ID'는 사용할 수 없습니다.",
+    "failed_to_install": "GROWI 설치 실패. 다시 시도하십시오.",
+    "failed_to_login_after_install": "설치 후 로그인 실패. 로그인 양식으로 리디렉션 중..."
+  },
+  "breaking_changes": {
+    "v346_using_basic_auth": "현재 사용 중인 기본 인증은 가까운 시일 내에 <strong>더 이상 사용할 수 없습니다</strong>. %s에서 설정을 제거하십시오."
+  },
+  "page_register": {
+    "send_email": "이메일 전송",
+    "notice": {
+      "restricted": "관리자 승인 필요.",
+      "restricted_defail": "관리자가 회원가입을 승인하면 이 위키에 접근할 수 있습니다."
+    },
+    "form_help": {
+      "email": "이 위키에 가입하려면 아래에 나열된 이메일 주소가 있어야 합니다.",
+      "password": "비밀번호는 최소 {{target}}자 이상이어야 합니다.",
+      "user_id": "생성하는 페이지의 URL에는 사용자 ID가 포함됩니다. 사용자 ID는 문자, 숫자 및 일부 기호로 구성될 수 있습니다."
+    }
+  },
+  "page_me": {
+    "form_help": {
+      "profile_image1": "이미지 업로드 설정이 완료되지 않았습니다.",
+      "profile_image2": "AWS를 설정하거나 로컬 업로드를 활성화하십시오."
+    }
+  },
+  "page_me_apitoken": {
+    "api_token": "API 토큰",
+    "notice": {
+      "apitoken_issued": "API 토큰이 발급되지 않았습니다.",
+      "update_token1": "새 API 토큰을 생성하도록 업데이트할 수 있습니다.",
+      "update_token2": "기존 프로세스에서 API 토큰을 업데이트해야 합니다."
+    },
+    "form_help": {}
+  },
+  "Password": "비밀번호",
+  "Password Settings": "비밀번호 설정",
+  "personal_settings": {
+    "disassociate_external_account": "외부 계정 연결 해제",
+    "disassociate_external_account_desc": "<strong>{{providerType}}</strong> 계정 <strong>{{accountId}}</strong>의 연결을 해제하시겠습니까?",
+    "set_new_password": "새 비밀번호 설정",
+    "update_password": "비밀번호 업데이트",
+    "current_password": "현재 비밀번호",
+    "new_password": "새 비밀번호",
+    "new_password_confirm": "새 비밀번호 다시 입력",
+    "password_is_not_set": "비밀번호가 설정되지 않았습니다."
+  },
+  "share_links": {
+    "Shere this page link to public": "이 페이지 링크를 공개적으로 공유",
+    "share_link_list": "공유 링크 목록",
+    "share_link_management": "공유 링크 관리",
+    "delete_all_share_links": "모든 공유 링크 삭제",
+    "expire": "만료",
+    "Days": "일",
+    "Custom": "사용자 지정",
+    "description": "설명",
+    "enter_desc": "설명 입력",
+    "Unlimited": "무제한",
+    "Issue": "발급",
+    "share_settings": "공유 설정",
+    "Invalid_Number_of_Date": "유효하지 않은 값을 입력했습니다.",
+    "link_sharing_is_disabled": "링크 공유가 비활성화되었습니다."
+  },
+  "API Settings": "API 설정",
+  "Other Settings": "기타 설정",
+  "API Token Settings": "API 토큰 설정",
+  "Current API Token": "현재 API 토큰",
+  "Update API Token": "API 토큰 업데이트",
+  "in_app_notification_settings": {
+    "in_app_notification_settings": "앱 내 알림 설정",
+    "subscribe_settings": "페이지 자동 구독 (알림 수신) 설정",
+    "default_subscribe_rules": {
+      "page_create": "페이지 생성 시 구독."
+    }
+  },
+  "ui_settings": {
+    "ui_settings": "UI 설정",
+    "side_bar_mode": {
+      "settings": "사이드바 모드 설정",
+      "side_bar_mode_setting": "사이드바 모드 설정",
+      "description": "화면 너비가 클 때 사이드바를 항상 열어둘지 여부를 설정할 수 있습니다. 화면 너비가 작으면 사이드바는 항상 닫힙니다."
+    }
+  },
+  "color_mode_settings": {
+    "light": "밝게",
+    "dark": "어둡게",
+    "system": "시스템",
+    "settings": "색상 모드 설정",
+    "description": "밝은 모드, 어두운 모드 또는 시스템별 표시 중 선택합니다.<br>지원되는 테마만 전환할 수 있습니다."
+  },
+  "editor_settings": {
+    "editor_settings": "편집기 설정"
+  },
+  "search_help": {
+    "title": "검색 도움말",
+    "and": {
+      "syntax help": "공백으로 구분",
+      "desc": "제목 또는 본문에 {{word1}}, {{word2}}를 모두 포함하는 페이지 검색"
+    },
+    "exclude": {
+      "desc": "제목 또는 본문에 {{word}}를 포함하는 페이지 제외"
+    },
+    "phrase": {
+      "syntax help": "큰따옴표로 묶음",
+      "desc": "\"{{phrase}}\" 구문을 포함하는 페이지 검색"
+    },
+    "prefix": {
+      "desc": "제목이 {{path}}로 시작하는 페이지만 검색"
+    },
+    "exclude_prefix": {
+      "desc": "제목이 {{path}}로 시작하는 페이지 제외"
+    },
+    "tag": {
+      "desc": "{{tag}} 태그가 있는 페이지 검색"
+    },
+    "exclude_tag": {
+      "desc": "{{tag}} 태그가 있는 페이지 제외"
+    }
+  },
+  "search": {
+    "search page bodies": "전체 텍스트 검색을 위해 [Enter] 키를 누르십시오."
+  },
+  "page_page": {
+    "notice": {
+      "version": "현재 버전이 아닙니다.",
+      "redirected": "다음에서 리디렉션되었습니다.",
+      "redirected_period": ".",
+      "unlinked": "이 페이지로 리디렉션된 페이지가 삭제되었습니다.",
+      "restricted": "이 페이지에 대한 접근이 제한되었습니다.",
+      "stale": "마지막 업데이트 이후 {{count}}년 이상 경과했습니다.",
+      "stale_plural": "마지막 업데이트 이후 {{count}}년 이상 경과했습니다.",
+      "expiration": "이 공유 링크는 <strong>{{expiredAt}}</strong>에 만료됩니다.",
+      "no_deadline": "이 페이지는 만료일이 없습니다.",
+      "not_indexed1": "이 페이지는 전체 텍스트 검색 엔진에 의해 인덱싱되지 않을 수 있습니다.",
+      "not_indexed2": "페이지 본문이 {{threshold}}로 지정된 임계값을 초과합니다."
+    }
+  },
+  "page_edit": {
+    "input_channels": "Slack 채널 이름...",
+    "theme": "테마",
+    "keymap": "키맵",
+    "indent": "들여쓰기",
+    "paste": {
+      "title": "붙여넣기 동작",
+      "both": "둘 다",
+      "text": "텍스트만",
+      "file": "파일만"
+    },
+    "editor_config": "편집기 구성",
+    "editor_assistant": "편집기 어시스턴트",
+    "Show active line": "활성 줄 표시",
+    "auto_format_table": "테이블 자동 서식",
+    "overwrite_scopes": "{{operation}} 및 모든 하위 항목의 범위 덮어쓰기",
+    "notice": {
+      "conflict": "다른 사람이 이 페이지를 편집 중이어서 변경 사항을 저장할 수 없습니다. 페이지를 다시 로드한 후 영향을 받는 섹션을 다시 편집하십시오."
+    },
+    "changes_not_saved": "변경 사항이 저장되지 않을 수 있습니다. 이동하시겠습니까?"
+  },
+  "page_comment": {
+    "comments": "댓글",
+    "comment": "댓글",
+    "preview": "미리보기",
+    "write": "작성",
+    "add_a_comment": "댓글 추가",
+    "display_the_page_when_posting_this_comment": "이 댓글을 게시할 때 페이지 표시",
+    "no_user_found": "사용자를 찾을 수 없습니다.",
+    "reply": "답글",
+    "delete_comment": "댓글 삭제?",
+    "comment_management_is_not_allowed": "댓글 관리가 허용되지 않습니다."
+  },
+  "page_api_error": {
+    "notfound_or_forbidden": "원본 페이지를 찾을 수 없거나 접근이 금지되었습니다.",
+    "already_exists": "경로가 있는 페이지가 이미 존재합니다.",
+    "outdated": "페이지가 업데이트되어 현재 오래되었습니다.",
+    "user_not_admin": "관리자만 삭제할 수 있습니다.",
+    "single_deletion_empty_pages": "빈 페이지는 단일 삭제할 수 없습니다.",
+    "complete_deletion_not_allowed_for_user": "이 페이지를 완전히 삭제할 권한이 없습니다."
+  },
+  "page_history": {
+    "revision_list": "수정 목록",
+    "revision": "버전",
+    "comparing_source": "원본",
+    "comparing_target": "대상",
+    "comparing_revisions": "차이점 비교",
+    "compare_latest": "최신 수정 비교",
+    "compare_previous": "이전 수정 비교"
+  },
+  "modal_rename": {
+    "label": {
+      "Move/Rename page": "페이지 이동/이름 변경",
+      "New page name": "새 페이지 이름",
+      "Failed to get subordinated pages": "하위 페이지를 가져오는 데 실패했습니다.",
+      "Failed to get exist path": "기존 경로를 가져오는 데 실패했습니다.",
+      "Current page name": "현재 페이지 이름",
+      "Rename this page only": "이 페이지만 이름 변경",
+      "Force rename all child pages": "모든 하위 페이지 강제 이름 변경",
+      "Other options": "기타 옵션",
+      "Do not update metadata": "메타데이터 업데이트 안 함",
+      "Redirect": "리디렉션"
+    },
+    "help": {
+      "redirect": "누군가 이 경로로 접근하면 새 페이지로 리디렉션",
+      "metadata": "마지막 업데이트 사용자 및 업데이트 날짜는 동일하게 유지됩니다.",
+      "recursive": "이 경로 아래의 하위 항목을 재귀적으로 이동/이름 변경"
+    }
+  },
+  "Put Back": "되돌리기",
+  "Delete Completely": "완전 삭제",
+  "page_has_been_reverted": "{{path}}가 되돌려졌습니다.",
+  "modal_delete": {
+    "delete_page": "페이지 삭제",
+    "deleting_page": "페이지 삭제 중",
+    "delete_recursively": "하위 페이지 재귀적으로 삭제.",
+    "delete_completely": "완전 삭제",
+    "delete_completely_restriction": "페이지를 완전히 삭제할 권한이 없습니다.",
+    "recursively": "이 경로 아래의 페이지를 재귀적으로 삭제.",
+    "completely": "휴지통에 넣지 않고 완전히 삭제."
+  },
+  "deleted_page": "휴지통으로 이동됨",
+  "deleted_pages": "{{path}}가 삭제되었습니다.",
+  "deleted_pages_completely": "{{path}}가 완전히 삭제되었습니다.",
+  "renamed_pages": "{{path}}가 이름 변경되었습니다.",
+  "empty_trash": "휴지통이 비워졌습니다.",
+  "modal_empty": {
+    "empty_the_trash": "휴지통 비우기",
+    "empty_the_trash_button": "휴지통 비우기",
+    "not_deletable_notice": "일부 페이지는 권한 부족으로 제거할 수 없습니다.",
+    "notice": "완전히 삭제된 페이지는 복구할 수 없습니다."
+  },
+  "modal_duplicate": {
+    "label": {
+      "Duplicate page": "페이지 복제",
+      "New page name": "새 페이지 이름",
+      "Failed to get subordinated pages": "하위 페이지를 가져오는 데 실패했습니다.",
+      "Current page name": "현재 페이지 이름",
+      "Recursively": "재귀적으로",
+      "Duplicate without exist path": "기존 경로 없이 복제",
+      "Same page already exists": "동일한 페이지가 이미 존재합니다.",
+      "Only duplicate user related pages": "사용자 관련 페이지만 복제"
+    },
+    "help": {
+      "recursive": "이 경로 아래의 하위 항목을 재귀적으로 복제",
+      "only_inherit_user_related_groups": "페이지 권한이 \"그룹 내에서만\"으로 설정된 경우, 속하지 않은 그룹은 복제된 페이지에 대한 접근 권한을 잃게 됩니다."
+    }
+  },
+  "duplicated_pages": "{{fromPath}}가 복제되었습니다.",
+  "modal_granted_groups_inheritance_select": {
+    "select_granted_groups": "페이지에 접근할 수 있는 그룹 선택",
+    "inherit_all_granted_groups_from_parent": "상위에서 페이지에 접근할 수 있는 모든 그룹 상속",
+    "only_inherit_related_groups": "상위에서 속한 그룹만 상속",
+    "create_page": "페이지 생성"
+  },
+  "modal_putback": {
+    "label": {
+      "Put Back Page": "페이지 되돌리기",
+      "recursively": "재귀적으로 되돌리기"
+    },
+    "help": {
+      "recursively": "이 경로 아래의 페이지를 재귀적으로 되돌리기"
+    }
+  },
+  "modal_shortcuts": {
+    "global": {
+      "title": "전역 단축키",
+      "Open/Close shortcut help": "단축키 도움말 열기/닫기",
+      "Edit Page": "페이지 편집",
+      "Create Page": "페이지 생성",
+      "Search": "검색",
+      "Show Contributors": "기여자 표시",
+      "MirrorMode": "미러 모드",
+      "Konami Code": "코나미 코드",
+      "konami_code_url": "https://ko.wikipedia.org/wiki/%EC%BD%94%EB%82%98%EB%AF%B8_%EC%BD%94%EB%93%9C"
+    },
+    "editor": {
+      "title": "편집기 단축키",
+      "Indent": "들여쓰기",
+      "Outdent": "내어쓰기",
+      "Save Page": "페이지 저장",
+      "Only Editor": "(편집기 전용)",
+      "Delete Line": "줄 삭제",
+      "Search in Editor": "편집기에서 검색",
+      "Move Line": "줄 이동",
+      "Copy Line": "줄 복사",
+      "Insert Line": "줄 삽입",
+      "Post Comment": "(댓글 게시)",
+      "Multiple Cursors": "다중 커서",
+      "Or Alt Click": "또는 Alt + 클릭"
+    },
+    "format": {
+      "title": "서식 설정 (편집기)",
+      "Bold": "굵게",
+      "Italic": "기울임꼴",
+      "Strikethrough": "취소선",
+      "Code Text": "코드 텍스트",
+      "Hyperlink": "하이퍼링크"
+    },
+    "line_settings": {
+      "title": "줄 설정 (편집기)",
+      "Bullet List": "글머리 기호 목록",
+      "Numbered List": "번호 매기기 목록",
+      "Quote": "인용",
+      "Code Block": "코드 블록",
+      "Comment Out": "주석 처리",
+      "Comment Out Desc": "(숨기기)"
+    }
+  },
+  "modal_resolve_conflict": {
+    "conflicts_with_new_body_on_server_side": "서버 측의 새 본문과 충돌합니다. 충돌을 해결하려면 페이지 본문을 선택하거나 편집하십시오.",
+    "file_conflicting_with_newer_remote": "이 파일은 더 새로운 원격 파일과 충돌합니다.",
+    "resolve_conflict_message": "페이지 본문을 선택하십시오.",
+    "resolve_conflict": "충돌 해결",
+    "resolve_and_save": "해결 및 저장",
+    "select_revision": "{{revision}} 선택",
+    "requested_revision": "내 것",
+    "latest_revision": "그들의 것",
+    "selected_editable_revision": "선택된 편집 가능한 페이지 본문"
+  },
+  "sidebar_ai_assistant": {
+    "reference_pages_label": "참조 페이지",
+    "recent_chat": "최근 채팅",
+    "no_recent_chat": "최근 채팅 없음",
+    "placeholder": "무엇이든 물어보세요.",
+    "knowledge_assistant_placeholder": "무엇이든 물어보세요.",
+    "editor_assistant_placeholder": "도와드릴까요?",
+    "summary_mode_label": "요약 모드",
+    "summary_mode_help": "2-3문장으로 간결한 답변",
+    "extended_thinking_mode_label": "확장 사고 모드",
+    "extended_thinking_mode_help": "활성화하면 AI가 더 많은 시간을 들여 생각하고 더 포괄적인 답변을 제공합니다.",
+    "caution_against_hallucination": "정보를 확인하고 출처를 확인하십시오.",
+    "progress_label": "답변 생성 중",
+    "failed_to_create_or_retrieve_thread": "스레드를 생성하거나 검색하는 데 실패했습니다.",
+    "budget_exceeded": "OpenAI API 사용 한도에 도달했습니다. 지식 어시스턴트를 다시 사용하려면 OpenAI 결제 페이지에서 크레딧을 추가하십시오.",
+    "budget_exceeded_for_growi_cloud": "OpenAI API 사용 한도에 도달했습니다. 지식 어시스턴트를 다시 사용하려면 호스팅 사용자의 경우 GROWI.cloud 관리 페이지에서, 소유 사용자의 경우 OpenAI 결제 페이지에서 크레딧을 추가하십시오.",
+    "error_message": "오류가 발생했습니다.",
+    "show_error_detail": "오류 세부 정보 표시",
+    "editor_assistant_long_context_warn_with_unit_line": "텍스트가 너무 길어서 편집기 어시스턴트는 응답을 위해 약 {{startPosition}}줄에서 {{endPosition}}줄을 참조합니다.",
+    "editor_assistant_long_context_warn_with_unit_char": "텍스트가 너무 길어서 편집기 어시스턴트는 응답을 위해 {{startPosition}}자에서 {{endPosition}}자를 참조합니다.",
+    "discard": "버리기",
+    "accept": "수락",
+    "use_assistant": "어시스턴트 사용",
+    "remove_assistant": "선택된 어시스턴트 선택 해제",
+    "text_generation_by_editor_assistant_label": "편집기 어시스턴트가 텍스트를 생성 중입니다.",
+    "preset_menu": {
+      "summarize": {
+        "title": "이 문서 요약",
+        "prompt": "마크다운 콘텐츠를 요약해 주세요."
+      },
+      "correct": {
+        "title": "텍스트의 오류 수정",
+        "prompt": "마크다운 텍스트의 오류를 수정해 주세요."
+      }
+    }
+  },
+  "modal_ai_assistant": {
+    "header": {
+      "update_assistant": "어시스턴트 업데이트",
+      "add_new_assistant": "새 어시스턴트 추가"
+    },
+    "assistant_name_placeholder": "어시스턴트 이름 입력",
+    "page_count": "{{count}} 페이지",
+    "memo": {
+      "title": "어시스턴트 메모",
+      "optional": "선택 사항",
+      "placeholder": "콘텐츠 및 사용법에 대한 메모를 표시할 수 있습니다.",
+      "description": "메모 내용은 어시스턴트 처리에 영향을 미치지 않습니다."
+    },
+    "submit_button": {
+      "update_assistant": "어시스턴트 업데이트",
+      "create_assistant": "어시스턴트 생성"
+    },
+    "toaster": {
+      "create_success": "어시스턴트가 생성되었습니다.",
+      "update_success": "어시스턴트가 업데이트되었습니다.",
+      "create_failed": "어시스턴트 생성 실패",
+      "update_failed": "어시스턴트 업데이트 실패"
+    },
+    "edit_page_description": "어시스턴트가 참조할 수 있는 페이지를 편집합니다.<br>어시스턴트는 하위 페이지를 포함하여 최대 {{limitLearnablePageCountPerAssistant}}개의 페이지를 참조할 수 있습니다.",
+    "default_instruction": "당신은 이 위키의 지식 어시스턴트입니다.\n\n## 다국어 지원:\n사용자가 입력한 언어와 동일한 언어로 응답하십시오.\n",
+    "add_page_button": "페이지 추가",
+    "page_mode_title": {
+      "share": "어시스턴트 공유",
+      "pages": "참조 페이지",
+      "instruction": "어시스턴트 지침"
+    },
+    "share_assistant": "어시스턴트 공유",
+    "page_access_permission": "페이지 접근 권한",
+    "access_scope": {
+      "owner": "{{username}}이 접근할 수 있는 모든 페이지",
+      "groups": "그룹 지정",
+      "publicOnly": "공개 페이지만"
+    },
+    "share_scope": {
+      "title": "어시스턴트 공유 범위",
+      "owner": {
+        "label": "{{username}}만"
+      },
+      "publicOnly": {
+        "label": "공개",
+        "desc": "모든 사용자와 공유됨"
+      },
+      "groups": {
+        "label": "그룹 지정",
+        "desc": "선택된 그룹의 구성원과만 공유됨"
+      },
+      "sameAsAccessScope": {
+        "label": "페이지 접근 범위와 동일",
+        "desc": "페이지 접근과 동일한 범위로 공유됨"
+      }
+    },
+    "instructions": {
+      "description": "어시스턴트의 동작 방식을 결정하는 지침을 설정할 수 있습니다.<br>어시스턴트는 이 지침을 기반으로 답변하고 분석합니다.",
+      "reset_to_default": "기본값으로 재설정"
+    }
+  },
+  "share_scope_warning_modal": {
+    "header_title": "공유 범위 확인",
+    "warning_message": "이 어시스턴트에는 접근이 제한된 페이지가 포함되어 있습니다.<br>현재 설정으로는 이 페이지의 정보가 어시스턴트의 공개 범위를 통해 원래 접근 권한을 넘어 공유될 수 있습니다.",
+    "selected_pages_label": "선택된 페이지 경로",
+    "confirmation_message": "진행하면 이 페이지의 내용이 어시스턴트의 공개 범위 내에서 공유될 수 있음을 이해했는지 확인하십시오.",
+    "button": {
+      "review": "설정 검토",
+      "proceed": "이해하고 진행"
+    }
+  },
+  "default_ai_assistant": {
+    "not_set": "기본 어시스턴트가 설정되지 않았습니다."
+  },
+  "ai_assistant_substance": {
+    "add_assistant": "어시스턴트 추가",
+    "my_assistants": "내 어시스턴트",
+    "team_assistants": "팀 어시스턴트",
+    "thread_does_not_exist": "스레드가 존재하지 않습니다.",
+    "recent_threads": "최근 항목",
+    "toaster": {
+      "ai_assistant_deleted_success": "어시스턴트 삭제됨",
+      "ai_assistant_deleted_failed": "어시스턴트 삭제 실패",
+      "thread_deleted_success": "스레드 삭제됨",
+      "thread_deleted_failed": "스레드 삭제 실패",
+      "ai_assistant_set_default_success": "기본 어시스턴트 설정 성공",
+      "ai_assistant_set_default_failed": "기본 어시스턴트 설정 실패"
+    },
+    "delete_modal": {
+      "title": "어시스턴트 삭제",
+      "confirm_message": "정말로 이 어시스턴트를 삭제하시겠습니까?"
+    }
+  },
+  "link_edit": {
+    "edit_link": "링크 편집",
+    "set_link_and_label": "링크 및 레이블 설정",
+    "link": "링크",
+    "placeholder_of_link_input": "페이지 경로 또는 URL 입력",
+    "label": "레이블",
+    "path_format": "경로 형식",
+    "use_relative_path": "상대 경로 사용",
+    "use_permanent_link": "영구 링크 사용",
+    "notation": "표기법",
+    "markdown": "마크다운",
+    "GROWI_original": "GROWI 원본",
+    "pukiwiki": "Pukiwiki",
+    "preview": "미리보기",
+    "page_not_found_in_preview": "\"{{path}}\"은 GROWI 페이지가 아닙니다."
+  },
+  "toaster": {
+    "file_upload_failed": "파일 업로드 실패.",
+    "initialize_successed": "{{target}} 초기화 성공",
+    "remove_share_link_success": "{{shareLinkId}} 제거 성공",
+    "issue_share_link": "새 공유 링크 발급 성공",
+    "remove_share_link": "{{count}}개 공유 링크 제거 성공",
+    "switch_disable_link_sharing_success": "공유 링크 설정 업데이트 성공",
+    "failed_to_reset_password": "비밀번호 재설정 실패",
+    "save_succeeded": "저장 성공"
+  },
+  "template": {
+    "modal_label": {
+      "Select template": "템플릿 선택",
+      "Create/Edit Template Page": "템플릿 페이지 생성/편집",
+      "Create template under": "이 페이지 아래에 템플릿 페이지 생성"
+    },
+    "option_label": {
+      "create/edit": "템플릿 페이지 생성/편집..",
+      "select": "템플릿 페이지 유형 선택"
+    },
+    "children": {
+      "label": "하위 항목용 템플릿",
+      "desc": "템플릿이 존재하는 동일 레벨 페이지에만 적용됩니다."
+    },
+    "descendants": {
+      "label": "하위 항목용 템플릿",
+      "desc": "모든 하위 페이지에 적용됩니다."
+    }
+  },
+  "sandbox": {
+    "header": "헤더",
+    "header_x": "헤더 {{index}}",
+    "block": "단락",
+    "block_detail": "단락을 만듭니다.",
+    "empty_line": "빈 줄",
+    "line_break": "줄 바꿈",
+    "line_break_detail": "(2칸 공백) 줄 바꿈을 만듭니다.",
+    "typography": "타이포그래피",
+    "italics": "기울임꼴",
+    "bold": "굵게",
+    "italic_bold": "기울임꼴 굵게",
+    "strikethrough": "취소선",
+    "link": "링크",
+    "code_highlight": "코드 하이라이트",
+    "list": "목록",
+    "unordered_list_x": "순서 없는 목록 {{index}}",
+    "ordered_list_x": "순서 있는 목록 {{index}}",
+    "task": "작업",
+    "task_checked": "체크됨",
+    "task_unchecked": "체크 해제됨",
+    "quote": "인용",
+    "quote1": "작성할 수 있습니다.",
+    "quote2": "여러 줄 인용",
+    "quote_nested": "중첩 인용",
+    "table": "테이블",
+    "image": "이미지",
+    "alt_text": "대체 텍스트",
+    "insert_image": "이미지 삽입",
+    "open_sandbox": "샌드박스 열기"
+  },
+  "slack_notification": {
+    "popover_title": "Slack 알림",
+    "popover_desc": "채널 이름을 입력하십시오. 쉼표로 구분된 목록을 입력하여 여러 채널에 알릴 수 있습니다.",
+    "input_channels": "채널 입력"
+  },
+  "search_result": {
+    "title": "검색",
+    "result_meta": "검색 결과:",
+    "deletion_mode_btn_lavel": "페이지 선택 및 삭제",
+    "cancel": "취소",
+    "delete": "삭제",
+    "check_all": "모두 선택",
+    "deletion_modal_header": "페이지 삭제",
+    "delete_completely": "완전 삭제",
+    "include_certain_path": "{{pathToInclude}} 경로 포함 ",
+    "delete_all_selected_page": "모두 삭제",
+    "select_all": "모두 선택",
+    "delete_selected_pages": "선택된 페이지 삭제",
+    "currently_not_implemented": "현재 구현되지 않았습니다.",
+    "search_again": "다시 검색",
+    "number_of_list_to_display": "표시",
+    "page_number_unit": "페이지",
+    "hit_number_unit": "개",
+    "sort_axis": {
+      "relationScore": "관련성별 정렬",
+      "createdAt": "생성일",
+      "updatedAt": "마지막 업데이트일"
+    }
+  },
+  "private_legacy_pages": {
+    "title": "비공개 레거시 페이지",
+    "bulk_operation": "대량 작업",
+    "convert_all_selected_pages": "모두 새 v5 호환 형식으로 변환",
+    "input_path_to_convert": "페이지를 변환할 경로 입력",
+    "alert_title": "이전 v4 호환 형식 비공개 페이지가 존재합니다.",
+    "alert_desc1": "이 페이지에서 확인란으로 페이지를 선택하고 화면 상단의 \"대량 작업\" 버튼에서 새 v5 호환 형식으로 일괄 변환할 수 있습니다.",
+    "nopages_title": "축하합니다. GROWI v5를 사용할 준비가 되었습니다!",
+    "nopages_desc1": "이제 관리할 수 있는 모든 페이지가 v5 호환 형식인 것 같습니다.",
+    "detail_info": "<a href='https://docs.growi.org/en/admin-guide/upgrading/50x.html' target='_blank' class='alert-link'>GROWI를 v5.0.x로 업그레이드 <span class='growi-custom-icons'>external_link</span></a>에서 자세한 정보를 확인하십시오.",
+    "modal": {
+      "title": "새 v5 호환 형식으로 변환",
+      "converting_pages": "페이지 변환 중",
+      "convert_recursively_label": "하위 페이지 재귀적으로 변환.",
+      "convert_recursively_desc": "이 경로 아래의 페이지를 재귀적으로 변환.",
+      "button_label": "변환"
+    },
+    "toaster": {
+      "page_migration_succeeded": "선택된 페이지의 v5 변환이 성공적으로 완료되었습니다.",
+      "page_migration_failed_with_paths": "{{paths}}의 v5 변환이 실패했습니다.",
+      "page_migration_failed": "페이지의 v5 변환이 실패했습니다."
+    },
+    "by_path_modal": {
+      "title": "새 v5 호환 형식으로 변환",
+      "alert": "이 작업은 되돌릴 수 없으며, 사용자가 볼 수 없는 페이지도 처리 대상이 됩니다.",
+      "checkbox_label": "이해함",
+      "description": "경로를 입력하면 해당 경로 아래의 모든 페이지가 v5 호환 형식으로 변환됩니다.",
+      "button_label": "변환",
+      "success": "변환 요청 성공.",
+      "error": "변환 요청 실패.",
+      "error_grant_invalid": "페이지 권한이 올바르지 않습니다. 수정하고 다시 시도하십시오.",
+      "error_page_not_found": "페이지를 찾을 수 없습니다.",
+      "error_duplicate_pages_found": "동일한 경로 이름의 페이지가 여러 개 발견되었습니다. 이름을 변경하거나 삭제하고 다시 시도하십시오."
+    }
+  },
+  "login": {
+    "title": "로그인",
+    "sign_in_error": "로그인 오류",
+    "registration_successful": "등록 성공. 관리자 승인을 기다리십시오.",
+    "Setup": "설정",
+    "enabled_ldap_has_configuration_problem": "LDAP이 활성화되었지만 구성에 문제가 있습니다.",
+    "set_env_var_for_logs": "(로그를 얻으려면 환경 변수 <code>DEBUG=crowi:service:PassportService</code>를 설정하십시오.)"
+  },
+  "invited": {
+    "title": "초대됨",
+    "discription_heading": "계정 생성",
+    "discription": "초대된 이메일 주소로 계정을 생성하십시오."
+  },
+  "page_export": {
+    "failed_to_export": "내보내기 실패",
+    "failed_to_count_pages": "페이지 수 계산 실패",
+    "export_page_markdown": "페이지를 마크다운으로 내보내기",
+    "export_page_pdf": "페이지를 PDF로 내보내기",
+    "bulk_export": "페이지 및 모든 하위 페이지 내보내기",
+    "bulk_export_download_explanation": "내보내기가 완료되면 알림이 전송됩니다. 내보낸 파일을 다운로드하려면 알림을 클릭하십시오.",
+    "bulk_export_exec_time_warning": "페이지 수가 많으면 내보내기에 시간이 걸릴 수 있습니다.",
+    "large_bulk_export_warning": "시스템 리소스 절약을 위해 대량의 페이지를 연속으로 내보내지 마십시오.",
+    "markdown": "마크다운",
+    "choose_export_format": "내보내기 형식 선택",
+    "bulk_export_started": "잠시 기다려 주십시오...",
+    "bulk_export_download_expired": "다운로드 기간이 만료되었습니다.",
+    "bulk_export_job_expired": "내보내기 프로세스가 너무 오래 걸려 취소되었습니다.",
+    "export_in_progress": "내보내기 진행 중",
+    "export_in_progress_explanation": "동일한 형식의 내보내기가 이미 진행 중입니다. 최신 페이지 콘텐츠를 내보내기 위해 다시 시작하시겠습니까?",
+    "export_cancel_warning": "다음 진행 중인 내보내기가 취소됩니다.",
+    "restart": "다시 시작",
+    "format": "형식",
+    "started_on": "시작일",
+    "file_upload_not_configured": "파일 업로드 설정이 구성되지 않았습니다."
+  },
+  "message": {
+    "successfully_connected": "성공적으로 연결되었습니다!",
+    "fail_to_save_access_token": "액세스 토큰 저장 실패. 다시 시도하십시오.",
+    "fail_to_fetch_access_token": "액세스 토큰 가져오기 실패. 다시 연결하십시오.",
+    "successfully_disconnected": "성공적으로 연결 해제되었습니다!",
+    "strategy_has_not_been_set_up": "{{strategy}}가 설정되지 않았습니다.",
+    "ldap_user_not_valid": "LDAP 사용자가 유효하지 않습니다.",
+    "external_account_not_exist": "외부 계정을 찾거나 생성하는 데 실패했습니다.",
+    "maximum_number_of_users": "최대 사용자 수 이상을 등록할 수 없습니다.",
+    "sign_in_failure": "로그인 실패.",
+    "aws_sttings_required": "이 기능을 사용하려면 AWS 설정이 필요합니다. 관리자에게 문의하십시오.",
+    "application_already_installed": "애플리케이션이 이미 설치되었습니다.",
+    "email_address_could_not_be_used": "이 이메일 주소는 사용할 수 없습니다. (허용된 이메일 주소를 확인하십시오.)",
+    "user_id_is_not_available": "이 사용자 ID는 사용할 수 없습니다.",
+    "username_should_not_be_null": "사용자 이름은 null이 아니어야 합니다. 관리 페이지에서 인증 메커니즘 설정을 확인하십시오.",
+    "email_address_is_already_registered": "이 이메일 주소는 이미 등록되었습니다.",
+    "can_not_register_maximum_number_of_users": "최대 사용자 수 이상을 등록할 수 없습니다.",
+    "email_settings_is_not_setup": "이메일 설정이 설정되지 않았습니다. 관리자에게 문의하십시오.",
+    "email_authentication_is_not_enabled": "이메일 인증이 활성화되지 않았습니다. 관리자에게 문의하십시오.",
+    "failed_to_register": "등록 실패.",
+    "successfully_created": "사용자 {{username}}이 성공적으로 생성되었습니다.",
+    "can_not_activate_maximum_number_of_users": "최대 사용자 수 이상을 활성화할 수 없습니다.",
+    "failed_to_activate": "활성화 실패.",
+    "unable_to_use_this_user": "이 사용자를 사용할 수 없습니다.",
+    "complete_to_install1": "GROWI 설치 완료! 관리자 계정으로 로그인하십시오.",
+    "complete_to_install2": "GROWI 설치 완료! 먼저 이 페이지의 각 설정을 확인하십시오.",
+    "failed_to_create_admin_user": "관리자 사용자 생성 실패. {{errMessage}}",
+    "successfully_send_email_auth": "{{email}}로 이메일을 보냈습니다. 이메일의 URL을 클릭하여 등록을 완료하십시오.",
+    "incorrect_token_or_expired_url": "토큰이 올바르지 않거나 URL이 만료되었습니다.",
+    "user_already_logged_in": "로그인 상태에서는 새 계정을 생성할 수 없습니다.",
+    "registration_closed": "새 계정을 생성할 권한이 없습니다.",
+    "Username has invalid characters": "사용자 이름에 유효하지 않은 문자가 있습니다.",
+    "Username field is required": "사용자 ID 필드는 필수입니다.",
+    "Name field is required": "이름 필드는 필수입니다.",
+    "Email format is invalid": "이메일 형식이 유효하지 않습니다.",
+    "Email field is required": "이메일 필드는 필수입니다.",
+    "Password has invalid character": "비밀번호에 유효하지 않은 문자가 있습니다.",
+    "Password minimum character should be more than n characters": "비밀번호는 최소 {{number}}자 이상이어야 합니다.",
+    "Password field is required": "비밀번호 필드는 필수입니다.",
+    "Username or E-mail has invalid characters": "사용자 이름 또는 이메일에 유효하지 않은 문자가 있습니다.",
+    "user_not_found": "사용자를 찾을 수 없습니다.",
+    "provider_duplicated_username_exception": "<p><strong><span class='material-symbols-outlined me-1'>cancel</span>DuplicatedUsernameException 발생</strong></p><p class='mb-0'> {{ failedProviderForDuplicatedUsernameException }} 인증은 성공했지만 새 사용자를 생성할 수 없습니다. <a href='https://github.com/growilabs/growi/issues/193'>#193</a> 문제를 참조하십시오.</p>"
+  },
+  "grid_edit": {
+    "create_bootstrap_4_grid": "Bootstrap 4 그리드 생성",
+    "grid_settings": "그리드 설정",
+    "grid_pattern": "그리드 패턴",
+    "division": "분할",
+    "smart_no": "스마트폰 / 줄 바꿈 없음",
+    "break_point": "디스플레이 크기별 줄 바꿈 지점"
+  },
+  "validation": {
+    "aws_region": "지역에는 AWS 지역 이름을 입력하십시오. 예):us-east-1",
+    "aws_custom_endpoint": "사용자 지정 엔드포인트에는 http(s)://로 시작하는 URL을 지정하십시오. 또한 후행 슬래시는 필요하지 않습니다.",
+    "failed_to_send_a_test_email": "SMTP를 사용하여 테스트 이메일을 보내는 데 실패했습니다. 설정을 확인하십시오."
+  },
+  "forgot_password": {
+    "forgot_password": "비밀번호를 잊으셨습니까?",
+    "send": "전송",
+    "return_to_login": "로그인으로 돌아가기",
+    "reset_password": "비밀번호 재설정",
+    "sign_in_instead": "대신 로그인",
+    "password_reset_request_desc": "여기에서 비밀번호를 재설정할 수 있습니다.",
+    "password_reset_excecution_desc": "새 비밀번호 입력",
+    "new_password": "새 비밀번호",
+    "confirm_new_password": "새 비밀번호 확인",
+    "email_is_required": "이메일은 필수입니다.",
+    "success_to_send_email": "이메일 전송 성공",
+    "feature_is_unavailable": "이 기능은 사용할 수 없습니다.",
+    "incorrect_token_or_expired_url": "토큰이 올바르지 않거나 URL이 만료되었습니다. 아래 링크를 통해 비밀번호 재설정 요청을 다시 보내십시오.",
+    "password_and_confirm_password_does_not_match": "비밀번호와 비밀번호 확인이 일치하지 않습니다.",
+    "please_enable_mailer_alert": "이메일 설정이 완료되지 않아 비밀번호 재설정 기능이 비활성화되었습니다. 관리자에게 이메일 설정을 완료하도록 요청하십시오."
+  },
+  "maintenance_mode": {
+    "maintenance_mode": "유지 보수 모드",
+    "growi_is_under_maintenance": "GROWI가 유지 보수 중입니다. 완료될 때까지 기다려 주십시오.",
+    "admin_page": "관리자 페이지",
+    "login": "로그인",
+    "logout": "로그아웃"
+  },
+  "pagetree": {
+    "cannot_rename_a_title_that_contains_slash": "'/'를 포함하는 제목은 이름 변경할 수 없습니다.",
+    "you_cannot_move_this_page_now": "지금은 이 페이지를 이동할 수 없습니다.",
+    "something_went_wrong_with_moving_page": "페이지 이동 중 문제가 발생했습니다.",
+    "error_retrieving_the_pagetree": "페이지 트리를 검색하는 동안 오류가 발생했습니다."
+  },
+  "duplicated_page_alert": {
+    "same_page_name_exists": "'{{pageName}}'과(와) 동일한 페이지 이름이 존재합니다.",
+    "same_page_name_exists_at_path": "{{path}}에 {{pageName}}과(와) 동일한 페이지 이름이 존재합니다.",
+    "select_page_to_see": "볼 페이지 선택"
+  },
+  "user_group": {
+    "select_group": "그룹 선택",
+    "belonging_to_no_group": "속한 그룹을 찾을 수 없습니다.",
+    "manage_user_groups": "사용자 그룹 관리"
+  },
+  "fix_page_grant": {
+    "modal": {
+      "no_grant_available": "선택 가능한 권한 목록을 찾을 수 없습니다. 먼저 상위 페이지의 권한을 수정하고 다시 시도하십시오.",
+      "need_to_fix_grant": "이 기능을 올바르게 사용하려면 이 페이지와 관련된 권한을 수정해야 합니다.<br>변경하려면 아래 옵션에서 선택하십시오.",
+      "grant_label": {
+        "public": "공개",
+        "isForbidden": "볼 수 없는 권한",
+        "currentPageGrantLabel": "이 페이지의 권한: ",
+        "parentPageGrantLabel": "상위 페이지의 권한: ",
+        "docLink": "권한 수정에 대한 자세한 내용은 <a href='https://docs.growi.org/en/guide/features/authority.html#permissions-for-subordinate-pages'>이 링크</a>를 참조하십시오."
+      },
+      "radio_btn": {
+        "restrected": "링크를 아는 사람만",
+        "only_me": "나만",
+        "grant_group": "특정 그룹만"
+      },
+      "select_group_default_text": "그룹 선택",
+      "alert_message_select_group": "선택된 그룹 없음",
+      "btn_label": "변환",
+      "title": "권한 수정"
+    },
+    "alert": {
+      "description": "이 페이지의 권한 설정을 수정해야 합니다.",
+      "btn_label": "수정"
+    }
+  },
+  "tooltip": {
+    "like": "좋아요!",
+    "cancel_like": "좋아요 취소",
+    "bookmark": "북마크",
+    "cancel_bookmark": "북마크 취소",
+    "receive_notifications": "알림 받기",
+    "stop_notification": "알림 중지",
+    "footprints": "발자취",
+    "login_required": "로그인 필요",
+    "operation": {
+      "attention": {
+        "rename": "하위 페이지의 경로 이름 변경이 성공적이지 않았습니다. 3점 리더에서 메뉴를 열고 '경로 복구'를 선택하십시오."
+      }
+    }
+  },
+  "page_operation": {
+    "paths_recovered": "경로 복구 성공",
+    "path_recovery_failed": "경로 복구 실패"
+  },
+  "user_home_page": {
+    "bookmarks": "북마크",
+    "recently_created": "최근 생성됨"
+  },
+  "bookmark_folder": {
+    "bookmark_folder": "북마크 폴더",
+    "bookmark": "북마크",
+    "delete_modal": {
+      "modal_header_label": "북마크 폴더 삭제",
+      "modal_body_description": "이 북마크 폴더와 내용을 삭제합니다.",
+      "modal_body_alert": "삭제된 폴더와 내용은 복구할 수 없습니다.",
+      "modal_footer_button": "폴더 삭제"
+    },
+    "input_placeholder": "폴더 이름 입력",
+    "new_folder": "새 폴더",
+    "delete": "폴더 삭제",
+    "drop_item_here": "여기에 항목 끌어다 놓기",
+    "cancel_bookmark": "이 페이지 북마크 해제",
+    "move_to_root": "루트로 이동",
+    "root": "루트 (기본값)"
+  },
+  "v5_page_migration": {
+    "page_tree_not_avaliable": "페이지 트리 기능은 아직 사용할 수 없습니다.",
+    "go_to_settings": "기능을 활성화하려면 설정으로 이동"
+  },
+  "tag_edit_modal": {
+    "edit_tags": "태그 편집",
+    "done": "완료",
+    "tags_input": {
+      "tag_name": "태그 이름"
+    }
+  },
+  "delete_attachment_modal": {
+    "confirm_delete_attachment": "첨부 파일 삭제?"
+  },
+  "rich_attachment": {
+    "attachment_not_be_found": "첨부 파일을 찾을 수 없습니다."
+  },
+  "page_select_modal": {
+    "select_page_location": "페이지 위치 선택"
+  },
+  "wip_page": {
+    "save_as_wip": "WIP로 저장 (작성 중)",
+    "success_save_as_wip": "WIP 페이지로 성공적으로 저장됨",
+    "fail_save_as_wip": "WIP 페이지로 저장 실패",
+    "alert": "이 페이지는 아직 작성 중입니다.",
+    "publish_page": "페이지 게시",
+    "success_publish_page": "페이지가 게시되었습니다.",
+    "fail_publish_page": "페이지 게시 실패"
+  },
+  "sidebar_header": {
+    "show_wip_page": "WIP 표시",
+    "compact_view": "간략 보기"
+  },
+  "create_page": {
+    "untitled": "제목 없음"
+  },
+  "sync-latest-revision-body": {
+    "menuitem": "편집기 텍스트를 최신 수정 본문과 동기화",
+    "confirm": "편집기에 입력된 초안 데이터를 삭제하고 최신 텍스트를 동기화합니다. 실행하시겠습니까?",
+    "alert": "최신 텍스트가 동기화되지 않았을 수 있습니다. 다시 로드하고 다시 확인하십시오.",
+    "success-toaster": "최신 텍스트 동기화됨",
+    "skipped-toaster": "편집기가 활성화되지 않아 동기화 건너뜀. 편집기를 열고 다시 시도하십시오.",
+    "error-toaster": "최신 텍스트 동기화 실패"
+  }
+}

+ 229 - 239
apps/app/public/static/locales/zh_CN/admin.json

@@ -28,21 +28,21 @@
     "always_hidden": "总是隐藏",
     "Guest Users Access": "来宾用户访问",
     "readonly_users_access": "只浏览用户的访问",
-		"Fixed by env var": "这是由env var<code>%s=%s</code>修复的。",
-		"register_limitation": "注册限制",
-		"register_limitation_desc": "限制新用户注册",
-		"The whitelist of registration permission E-mail address": "注册许可电子邮件地址的白名单",
-		"users_without_account": "无法访问没有帐户的用户",
-		"example": "例子",
-		"restrict_emails": "您可以通过编写电子邮件域(以@开头)将电子邮件注册限制为wiki。",
-		"for_example": " 例如,如果要将注册限制为growi.org网站域,你可以写",
-		"in_this_case": ";在这种情况下,只有growi.org网站域将能够注册,所有其他用户将被拒绝。",
-		"insert_single": "请每行插入一个电子邮件地址。",
+    "Fixed by env var": "这是由env var<code>%s=%s</code>修复的。",
+    "register_limitation": "注册限制",
+    "register_limitation_desc": "限制新用户注册",
+    "The whitelist of registration permission E-mail address": "注册许可电子邮件地址的白名单",
+    "users_without_account": "无法访问没有帐户的用户",
+    "example": "例子",
+    "restrict_emails": "您可以通过编写电子邮件域(以@开头)将电子邮件注册限制为wiki。",
+    "for_example": " 例如,如果要将注册限制为growi.org网站域,你可以写",
+    "in_this_case": ";在这种情况下,只有growi.org网站域将能够注册,所有其他用户将被拒绝。",
+    "insert_single": "请每行插入一个电子邮件地址。",
     "page_list_and_search_results": "页面列表/搜索结果",
-		"page_listing_1": "页面列表/搜索<br>受“仅限我”限制",
-		"page_listing_1_desc": "列出/搜索时显示受“仅限我”选项限制的页面",
-		"page_listing_2": "页面列表/搜索<br>受用户组限制",
-		"page_listing_2_desc": "显示列出/搜索时受用户组限制的页面",
+    "page_listing_1": "页面列表/搜索<br>受“仅限我”限制",
+    "page_listing_1_desc": "列出/搜索时显示受“仅限我”选项限制的页面",
+    "page_listing_2": "页面列表/搜索<br>受用户组限制",
+    "page_listing_2_desc": "显示列出/搜索时受用户组限制的页面",
     "page_access_rights": "页面访问",
     "page_delete_rights": "删除权限",
     "page_delete": "删除",
@@ -56,9 +56,9 @@
     "is_all_group_membership_required_for_page_complete_deletion": "除管理员和页面作者之外的用户必须属于被授予页面访问权限的所有组",
     "is_all_group_membership_required_for_page_complete_deletion_explanation": "如果页面权限设置为\"仅限特定群体\",则会启用此功能。",
     "inherit": "继承(使用与单页相同的设置)。",
-		"admin_only": "仅管理员",
-		"admin_and_author": "管理员|作者",
-		"anyone": "任何人",
+    "admin_only": "仅管理员",
+    "admin_and_author": "管理员|作者",
+    "anyone": "任何人",
     "user_homepage_deletion": {
       "user_homepage_deletion": "删除用户主页",
       "enable_user_homepage_deletion": "启用用户主页删除功能",
@@ -71,15 +71,15 @@
     "max_age_caution": "修改该值后需要重启服务器。",
     "forced_update_desc": "设置已被强行更改。以前的设置: ",
     "page_delete_rights_caution": "\"删除/全部删除\"权限(包括后代页面)被强制强于\"删除/完全删除\"权限。 <br> <br> 仅管理员 > 管理员|作者 > 何人",
-		"Authentication mechanism settings": "身份验证机制设置",
-		"setup_is_not_yet_complete": "安装尚未完成",
-		"xss_prevent_setting": "阻止XSS(跨站点脚本)",
-		"xss_prevent_setting_link": "转到Markdown设置",
-		"callback_URL": "回调URL",
-		"providerName": "提供程序名称",
-		"issuerHost": "发行者主机",
-		"scope": "Scope",
-		"desc_of_callback_URL": "在{{AuthName}}身份提供程序的设置中使用它",
+    "Authentication mechanism settings": "身份验证机制设置",
+    "setup_is_not_yet_complete": "安装尚未完成",
+    "xss_prevent_setting": "阻止XSS(跨站点脚本)",
+    "xss_prevent_setting_link": "转到Markdown设置",
+    "callback_URL": "回调URL",
+    "providerName": "提供程序名称",
+    "issuerHost": "发行者主机",
+    "scope": "Scope",
+    "desc_of_callback_URL": "在{{AuthName}}身份提供程序的设置中使用它",
     "authorization_endpoint": "Authorization Endpoint",
     "token_endpoint": "Token Endpoint",
     "revocation_endpoint": "Revocation Endpoint",
@@ -88,41 +88,41 @@
     "end_session_endpoint": "EndSessioin Endpoint",
     "registration_endpoint": "Registration Endpoint",
     "jwks_uri": "JSON Web Key Set URL",
-		"clientID": "Client ID",
-		"client_secret": "客户机密",
-		"updated_general_security_setting": "更新安全设置成功",
-		"setup_not_completed_yet": "安装尚未完成",
+    "clientID": "Client ID",
+    "client_secret": "客户机密",
+    "updated_general_security_setting": "更新安全设置成功",
+    "setup_not_completed_yet": "安装尚未完成",
     "guest_mode": {
-			"deny": "拒绝(仅限注册用户)",
-			"readonly": "接受(来宾可以只读)"
-		},
+      "deny": "拒绝(仅限注册用户)",
+      "readonly": "接受(来宾可以只读)"
+    },
     "read_only_users_comment": {
       "deny": "拒绝 (禁止只浏览用户操作评论)",
       "accept": "允许 (只浏览用户可以管理评论)"
     },
-		"registration_mode": {
-			"open": "打开(任何人都可以注册)",
-			"restricted": "受限(需要管理员批准)",
-			"closed": "已关闭(仅限邀请)"
-		},
+    "registration_mode": {
+      "open": "打开(任何人都可以注册)",
+      "restricted": "受限(需要管理员批准)",
+      "closed": "已关闭(仅限邀请)"
+    },
     "share_link_management": "Share Link Management",
-    "No_share_links":"No share links",
-    "share_link_notice":"remove all share links",
-    "delete_all_share_links":"Delete all share links",
+    "No_share_links": "No share links",
+    "share_link_notice": "remove all share links",
+    "delete_all_share_links": "Delete all share links",
     "share_link_rights": "分享链接权",
     "enable_link_sharing": "启用链接共享",
     "all_share_links": "所有共享链接",
-		"configuration": " 配置",
-		"Treat username matching as identical": "Automatically bind external accounts newly logged in to local accounts when <code>username</code> match",
-		"Treat username matching as identical_warn": "WARNING: Be aware of security because the system treats the same user as a match of <code>username</code>.",
-		"Treat email matching as identical": "Automatically bind external accounts newly logged in to local accounts when <code>email</code> match",
-		"Treat email matching as identical_warn": "WARNING: Be aware of security because the system treats the same user as a match of <code>email</code>.",
-		"Use env var if empty": "Use env var <code>{{env}}</code> if empty",
-		"Use default if both are empty": "If both ​​are empty, the default value <code>{{target}}</code> is used.",
-		"missing mandatory configs": "The following mandatory items are not set in either database nor environment variables.",
-		"Local": {
-			"name": "ID/Password",
-			"note for the only env option": "The LOCAL authentication is limited by the value of environment variable.<br>To change this setting, please change to false or delete the value of the environment variable <code>{{env}}</code> .",
+    "configuration": " 配置",
+    "Treat username matching as identical": "Automatically bind external accounts newly logged in to local accounts when <code>username</code> match",
+    "Treat username matching as identical_warn": "WARNING: Be aware of security because the system treats the same user as a match of <code>username</code>.",
+    "Treat email matching as identical": "Automatically bind external accounts newly logged in to local accounts when <code>email</code> match",
+    "Treat email matching as identical_warn": "WARNING: Be aware of security because the system treats the same user as a match of <code>email</code>.",
+    "Use env var if empty": "Use env var <code>{{env}}</code> if empty",
+    "Use default if both are empty": "If both ​​are empty, the default value <code>{{target}}</code> is used.",
+    "missing mandatory configs": "The following mandatory items are not set in either database nor environment variables.",
+    "Local": {
+      "name": "ID/Password",
+      "note for the only env option": "The LOCAL authentication is limited by the value of environment variable.<br>To change this setting, please change to false or delete the value of the environment variable <code>{{env}}</code> .",
       "enable_local": "Enable ID/Password",
       "password_reset_by_users": "用户重置密码",
       "enable_password_reset_by_users": "启用用户重置密码",
@@ -130,181 +130,181 @@
       "email_authentication": "用户注册时的电子邮件身份验证",
       "enable_email_authentication": "启用电子邮件身份验证",
       "enable_email_authentication_desc": "用户注册将执行电子邮件身份验证。"
-		},
-		"ldap": {
-			"enable_ldap": "Enable LDAP",
-			"server_url_detail": "The LDAP URL of the directory service in the format <code>ldap://host:port/DN</code> or <code>ldaps://host:port/DN</code>.",
-			"bind_mode": "Binding Mode",
-			"bind_manager": "Manager Bind",
-			"bind_user": "User Bind",
-			"bind_DN_manager_detail": "The DN of the account that authenticates and queries the directory service",
-			"bind_DN_user_detail1": "The query used to bind with the directory service.",
-			"bind_DN_user_detail2": "Use <code>&#123;&#123;username&#125;&#125;</code> to reference the username entered in the login page.",
-			"bind_DN_password": "Bind DN Password",
-			"bind_DN_password_manager_detail": "The password for the Bind DN account.",
-			"bind_DN_password_user_detail": "The password that is entered in the login page will be used to bind.",
-			"search_filter": "Search Filter",
-			"search_filter_detail1": "The query used to locate the authenticated user.",
-			"search_filter_detail2": "Use <code>&#123;&#123;username&#125;&#125;</code> to reference the username entered in the login page.",
-			"search_filter_detail3": "If empty, the filter <code>(uid=&#123;&#123;username&#125;&#125;)</code> is used.",
-			"search_filter_example1": "Match with 'uid' or 'mail'",
-			"search_filter_example2": "Match with 'sAMAccountName' for Active Directory",
-			"username_detail": "Specification of mappings for <code>username</code> when creating new users",
-			"name_detail": "Specification of mappings for full name when creating new users",
-			"mail_detail": "Specification of mappings for mail address when creating new users",
-			"group_search_base_DN": "Group Search Base DN",
-			"group_search_base_DN_detail": "The base DN from which to search for groups. If defined, also <code>Group Search Filter</code> must be defined for the search to work.",
-			"group_search_filter": "Group Search Filter",
-			"group_search_filter_detail1": "The query used to filter for groups.",
-			"group_search_filter_detail2": "Login via LDAP is accepted only when this query hits one or more groups.",
-			"group_search_filter_detail3": "Use <code>&#123;&#123;dn&#125;&#125;</code> to have it replaced of the found user object.",
-			"group_search_filter_detail4": "<code>(&(cn=group1)(memberUid=&#123;&#123;dn&#125;&#125;))</code> hits the groups which has <code>cn=group1</code> and <code>memberUid</code> includes the user's <code>uid</code>(when <code>Group DN Property</code> is not changed from the default value.)",
-			"group_search_user_DN_property": "User DN Property",
-			"group_search_user_DN_property_detail": "The property of user object to use in <code>&#123;&#123;dn&#125;&#125;</code> interpolation of <code>Group Search Filter</code>.",
-			"test_config": "Test Saved Configuration",
-			"updated_ldap": "Succeeded to update LDAP setting"
-		},
-		"SAML": {
-			"name": "SAML",
-			"enable_saml": "Enable SAML",
-			"id_detail": "Specification of the name of attribute which can identify the user in SAML Identity Provider",
-			"username_detail": "Specification of mappings for <code>username</code> when creating new users",
-			"mapping_detail": "Specification of mappings for {{target}} when creating new users",
-			"cert_detail": "PEM-encoded X.509 signing certificate to validate the response from IdP",
-			"Use env var if empty": "If the value in the database is empty, the value of the environment variable <code>{{env}}</code> is used.",
-			"note for the only env option": "The setting item that enables or disables the SAML authentication and the highlighted setting items use only the value of environment variables.<br>To change this setting, please change to false or delete the value of the environment variable <code>{{env}}</code> .",
-			"attr_based_login_control_detail": "Limit who can sign up by using <code>&lt;saml: Attribute&gt;</code> element included in <code>&lt;saml: AttributeStatement&gt;</code> element and its child element <code>&lt;saml: AttributeValue&gt;</code>.",
-			"attr_based_login_control_rule_help": "<h5>Supported Queries:</h5><ul><li>Terms</li><li>Fields</li><li>AND/NOT/OR Operator</li><li>Grouping</li></ul><h5>Unsupported Queries:</h5><ul><li>Wildcard, Fuzzy, Proximity, Range and Boosting</li><li>+/- Operator</li><li>Field Grouping</li></ul><h5>Escaping special characters</h5>It is needed to escape following special characters:<br><code>+ - && || ! ( ) { } [ ] ^ &quot; &tilde; * ? : &#92;</code> and <code>/</code>",
-			"attr_based_login_control_rule_example1": "<h5>Example for conditions</h5>If a rule is <code>(Department: A || Department: B) && Position: Leader</code>, users who have either <code>Department: A</code> or <code>Department: B</code> and have <code>Position: Leader</code> <strong>can</strong> sign in.",
+    },
+    "ldap": {
+      "enable_ldap": "Enable LDAP",
+      "server_url_detail": "The LDAP URL of the directory service in the format <code>ldap://host:port/DN</code> or <code>ldaps://host:port/DN</code>.",
+      "bind_mode": "Binding Mode",
+      "bind_manager": "Manager Bind",
+      "bind_user": "User Bind",
+      "bind_DN_manager_detail": "The DN of the account that authenticates and queries the directory service",
+      "bind_DN_user_detail1": "The query used to bind with the directory service.",
+      "bind_DN_user_detail2": "Use <code>&#123;&#123;username&#125;&#125;</code> to reference the username entered in the login page.",
+      "bind_DN_password": "Bind DN Password",
+      "bind_DN_password_manager_detail": "The password for the Bind DN account.",
+      "bind_DN_password_user_detail": "The password that is entered in the login page will be used to bind.",
+      "search_filter": "Search Filter",
+      "search_filter_detail1": "The query used to locate the authenticated user.",
+      "search_filter_detail2": "Use <code>&#123;&#123;username&#125;&#125;</code> to reference the username entered in the login page.",
+      "search_filter_detail3": "If empty, the filter <code>(uid=&#123;&#123;username&#125;&#125;)</code> is used.",
+      "search_filter_example1": "Match with 'uid' or 'mail'",
+      "search_filter_example2": "Match with 'sAMAccountName' for Active Directory",
+      "username_detail": "Specification of mappings for <code>username</code> when creating new users",
+      "name_detail": "Specification of mappings for full name when creating new users",
+      "mail_detail": "Specification of mappings for mail address when creating new users",
+      "group_search_base_DN": "Group Search Base DN",
+      "group_search_base_DN_detail": "The base DN from which to search for groups. If defined, also <code>Group Search Filter</code> must be defined for the search to work.",
+      "group_search_filter": "Group Search Filter",
+      "group_search_filter_detail1": "The query used to filter for groups.",
+      "group_search_filter_detail2": "Login via LDAP is accepted only when this query hits one or more groups.",
+      "group_search_filter_detail3": "Use <code>&#123;&#123;dn&#125;&#125;</code> to have it replaced of the found user object.",
+      "group_search_filter_detail4": "<code>(&(cn=group1)(memberUid=&#123;&#123;dn&#125;&#125;))</code> hits the groups which has <code>cn=group1</code> and <code>memberUid</code> includes the user's <code>uid</code>(when <code>Group DN Property</code> is not changed from the default value.)",
+      "group_search_user_DN_property": "User DN Property",
+      "group_search_user_DN_property_detail": "The property of user object to use in <code>&#123;&#123;dn&#125;&#125;</code> interpolation of <code>Group Search Filter</code>.",
+      "test_config": "Test Saved Configuration",
+      "updated_ldap": "Succeeded to update LDAP setting"
+    },
+    "SAML": {
+      "name": "SAML",
+      "enable_saml": "Enable SAML",
+      "id_detail": "Specification of the name of attribute which can identify the user in SAML Identity Provider",
+      "username_detail": "Specification of mappings for <code>username</code> when creating new users",
+      "mapping_detail": "Specification of mappings for {{target}} when creating new users",
+      "cert_detail": "PEM-encoded X.509 signing certificate to validate the response from IdP",
+      "Use env var if empty": "If the value in the database is empty, the value of the environment variable <code>{{env}}</code> is used.",
+      "note for the only env option": "The setting item that enables or disables the SAML authentication and the highlighted setting items use only the value of environment variables.<br>To change this setting, please change to false or delete the value of the environment variable <code>{{env}}</code> .",
+      "attr_based_login_control_detail": "Limit who can sign up by using <code>&lt;saml: Attribute&gt;</code> element included in <code>&lt;saml: AttributeStatement&gt;</code> element and its child element <code>&lt;saml: AttributeValue&gt;</code>.",
+      "attr_based_login_control_rule_help": "<h5>Supported Queries:</h5><ul><li>Terms</li><li>Fields</li><li>AND/NOT/OR Operator</li><li>Grouping</li></ul><h5>Unsupported Queries:</h5><ul><li>Wildcard, Fuzzy, Proximity, Range and Boosting</li><li>+/- Operator</li><li>Field Grouping</li></ul><h5>Escaping special characters</h5>It is needed to escape following special characters:<br><code>+ - && || ! ( ) { } [ ] ^ &quot; &tilde; * ? : &#92;</code> and <code>/</code>",
+      "attr_based_login_control_rule_example1": "<h5>Example for conditions</h5>If a rule is <code>(Department: A || Department: B) && Position: Leader</code>, users who have either <code>Department: A</code> or <code>Department: B</code> and have <code>Position: Leader</code> <strong>can</strong> sign in.",
       "attr_based_login_control_rule_example2": "<h5>Example for escaping</h5>If you would like to use URL as a query value, escape the following:<br><code>http&#92;:&#92;/&#92;/schemas.example.com&#92;/ws&#92;/2005&#92;/05&#92;/identity&#92;/claims&#92;/emailaddress: &quot;myname@example.com&quot;</code>",
       "updated_saml": "Succeeded to update SAML setting"
-		},
-		"OAuth": {
-			"enable_oidc": "Enable OIDC",
-			"register": "Register for %s",
-			"change_redirect_url": "Enter <code>%s</code> <br>(where <code>%s</code> is your host name) for \"Authorized redirect URIs\".",
-			"Google": {
-				"enable_google": "Enable Google OAuth",
-				"name": "Google OAuth",
-				"register_1": "Access {{link}}",
-				"register_2": "Create Project if no projects exist",
-				"register_3": "Create Credentials &rightarrow; OAuth client ID &rightarrow; Select \"Web application\"",
-				"register_4": "Register your OAuth App with one of Authorized redirect URIs as <code>{{url}}</code>",
-				"register_5": "Copy and paste your ClientID and Client Secret above",
-				"updated_google": "Succeeded to update Google OAuth setting"
-			},
-			"GitHub": {
-				"enable_github": "Enable GitHub OAuth",
-				"name": "GitHub OAuth",
-				"register_1": "Access {{link}}",
-				"register_2": "Register your OAuth App with \"Authorization callback URL\" as <code>{{url}}</code>",
-				"register_3": "Copy and paste your ClientID and Client Secret above",
-				"updated_github": "Succeeded to update GitHub OAuth setting"
-			},
-			"OIDC": {
-				"name": "OpenID Connect",
-				"id_detail": "Specification of the name of attribute which can identify the user in OIDC claims",
-				"username_detail": "Specification of mappings for <code>username</code> when creating new users",
-				"name_detail": "Specification of mappings for <code>name</code> when creating new users",
-				"mapping_detail": "Specification of mappings for {{target}} when creating new users",
-				"register_1": "Contact to OIDC IdP Administrator",
-				"register_2": "Register your OIDC App with \"Authorization callback URL\" as <code>{{url}}</code>",
-				"register_3": "Copy and paste your ClientID and Client Secret above",
-				"updated_oidc": "Succeeded to update OpenID Connect",
+    },
+    "OAuth": {
+      "enable_oidc": "Enable OIDC",
+      "register": "Register for %s",
+      "change_redirect_url": "Enter <code>%s</code> <br>(where <code>%s</code> is your host name) for \"Authorized redirect URIs\".",
+      "Google": {
+        "enable_google": "Enable Google OAuth",
+        "name": "Google OAuth",
+        "register_1": "Access {{link}}",
+        "register_2": "Create Project if no projects exist",
+        "register_3": "Create Credentials &rightarrow; OAuth client ID &rightarrow; Select \"Web application\"",
+        "register_4": "Register your OAuth App with one of Authorized redirect URIs as <code>{{url}}</code>",
+        "register_5": "Copy and paste your ClientID and Client Secret above",
+        "updated_google": "Succeeded to update Google OAuth setting"
+      },
+      "GitHub": {
+        "enable_github": "Enable GitHub OAuth",
+        "name": "GitHub OAuth",
+        "register_1": "Access {{link}}",
+        "register_2": "Register your OAuth App with \"Authorization callback URL\" as <code>{{url}}</code>",
+        "register_3": "Copy and paste your ClientID and Client Secret above",
+        "updated_github": "Succeeded to update GitHub OAuth setting"
+      },
+      "OIDC": {
+        "name": "OpenID Connect",
+        "id_detail": "Specification of the name of attribute which can identify the user in OIDC claims",
+        "username_detail": "Specification of mappings for <code>username</code> when creating new users",
+        "name_detail": "Specification of mappings for <code>name</code> when creating new users",
+        "mapping_detail": "Specification of mappings for {{target}} when creating new users",
+        "register_1": "Contact to OIDC IdP Administrator",
+        "register_2": "Register your OIDC App with \"Authorization callback URL\" as <code>{{url}}</code>",
+        "register_3": "Copy and paste your ClientID and Client Secret above",
+        "updated_oidc": "Succeeded to update OpenID Connect",
         "Use discovered URL if empty": "Use discovered URL from \"Issuer Host\" if empty"
-			},
-			"how_to": {
-				"google": "How to configure Google OAuth?",
-				"github": "How to configure GitHub OAuth?",
-				"oidc": "How to configure OIDC?"
-			}
-		},
-		"form_item_name": {
-			"entryPoint": "Entry point",
-			"issuer": "Issuer",
-			"cert": "Certificate",
-			"attrMapId": "ID",
-			"attrMapUsername": "Username",
-			"attrMapMail": "Mail Address",
-			"attrMapFirstName": "First Name",
-			"attrMapLastName": "Last Name",
-			"ABLCRule": "Rule"
-		}
+      },
+      "how_to": {
+        "google": "How to configure Google OAuth?",
+        "github": "How to configure GitHub OAuth?",
+        "oidc": "How to configure OIDC?"
+      }
+    },
+    "form_item_name": {
+      "entryPoint": "Entry point",
+      "issuer": "Issuer",
+      "cert": "Certificate",
+      "attrMapId": "ID",
+      "attrMapUsername": "Username",
+      "attrMapMail": "Mail Address",
+      "attrMapFirstName": "First Name",
+      "attrMapLastName": "Last Name",
+      "ABLCRule": "Rule"
+    }
   },
   "notification_settings": {
     "notification_settings": "通知设置",
-		"slack_incoming_configuration": "Slack Incoming Webhooks configuration",
-		"prioritize_webhook": "Prioritize incoming webhook than Slack App",
-		"prioritize_webhook_desc": "Check this option and GROWI use Incoming Webhooks even if Slack App settings are enabled.",
-		"slack_app_configuration": "Slack app configuration",
-		"slack_app_configuration_desc": "This is the way that compatible with Crowi,<br /> but not recommended in GROWI because it is <strong>too complex</strong>.",
-		"use_instead": "Please use Slack Incoming Webhooks Configuration instead.",
-		"how_to": {
-			"header": "How to configure Incoming Webhooks?",
-			"workspace": "(At Workspace) Add a hook",
-			"workspace_desc1": "Go to <a href='https://slack.com/services/new/incoming-webhook'>Incoming Webhooks configuration page</a>.",
-			"workspace_desc2": "Choose the default channel to post.",
-			"workspace_desc3": "Add.",
-			"at_growi": "(At GROWI admin page) Set Webhook URL",
-			"at_growi_desc": "Input &rdquo;Webhook URL&rdquo; and submit on this page."
-		},
-		"user_trigger_notification_header": "Default notification settings for patterns",
-		"pattern": "Pattern",
-		"channel": "Channel",
-		"pattern_desc": "Path name of wiki. Pattern expression with <code>*</code> can be used.",
-		"channel_desc": "Slack channel name. Without <code>#</code>.",
-		"valid_page": "启用/禁用通知",
-		"link_notification_help": "<strong>只有那些知道“链接的任何人”链接的人才能查看的页面并不总是得到通知。</strong> ",
-		"just_me_notification_help": "<strong>被“仅限我”限制的页在编辑时被通知。</strong>",
-		"group_notification_help": "<strong>被“用户组”限制的页面在编辑时被通知。</strong>",
-		"notification_list": "List of notification settings",
-		"add_notification": "Add new",
-		"trigger_path": "Trigger path",
-		"trigger_path_help": "(expression with <code>*</code> is supported)",
-		"trigger_events": "Trigger events",
-		"notify_to": "Notify to",
-		"back_to_list": "Go back to list",
-		"notification_detail": "Notification Setting Details",
-		"event_pageCreate": "When new page is \"CREATED\"",
-		"event_pageEdit": "When page is \"EDITED\"",
-		"event_pageDelete": "When page is \"DELETED\"",
-		"event_pageMove": "When page is \"MOVED\" (renamed)",
-		"event_pageLike": "When someone \"LIKES\" page",
-		"event_comment": "When someone \"COMMENTS\" on page",
-		"email": {
-			"ifttt_link": "Create a new IFTTT applet with Email trigger"
-		},
-		"updated_slackApp": "Succeeded to update Slack App Configuration setting",
-		"add_notification_pattern": "Add user trigger notification patterns",
-		"delete_notification_pattern": "Delete notification pattern",
-		"delete_notification_pattern_desc1": "Delete Path: {{path}}",
-		"delete_notification_pattern_desc2": "Once deleted, it cannot be recovered",
-		"toggle_notification": "Updated setting of {{path}}",
+    "slack_incoming_configuration": "Slack Incoming Webhooks configuration",
+    "prioritize_webhook": "Prioritize incoming webhook than Slack App",
+    "prioritize_webhook_desc": "Check this option and GROWI use Incoming Webhooks even if Slack App settings are enabled.",
+    "slack_app_configuration": "Slack app configuration",
+    "slack_app_configuration_desc": "This is the way that compatible with Crowi,<br /> but not recommended in GROWI because it is <strong>too complex</strong>.",
+    "use_instead": "Please use Slack Incoming Webhooks Configuration instead.",
+    "how_to": {
+      "header": "How to configure Incoming Webhooks?",
+      "workspace": "(At Workspace) Add a hook",
+      "workspace_desc1": "Go to <a href='https://slack.com/services/new/incoming-webhook'>Incoming Webhooks configuration page</a>.",
+      "workspace_desc2": "Choose the default channel to post.",
+      "workspace_desc3": "Add.",
+      "at_growi": "(At GROWI admin page) Set Webhook URL",
+      "at_growi_desc": "Input &rdquo;Webhook URL&rdquo; and submit on this page."
+    },
+    "user_trigger_notification_header": "Default notification settings for patterns",
+    "pattern": "Pattern",
+    "channel": "Channel",
+    "pattern_desc": "Path name of wiki. Pattern expression with <code>*</code> can be used.",
+    "channel_desc": "Slack channel name. Without <code>#</code>.",
+    "valid_page": "启用/禁用通知",
+    "link_notification_help": "<strong>只有那些知道“链接的任何人”链接的人才能查看的页面并不总是得到通知。</strong> ",
+    "just_me_notification_help": "<strong>被“仅限我”限制的页在编辑时被通知。</strong>",
+    "group_notification_help": "<strong>被“用户组”限制的页面在编辑时被通知。</strong>",
+    "notification_list": "List of notification settings",
+    "add_notification": "Add new",
+    "trigger_path": "Trigger path",
+    "trigger_path_help": "(expression with <code>*</code> is supported)",
+    "trigger_events": "Trigger events",
+    "notify_to": "Notify to",
+    "back_to_list": "Go back to list",
+    "notification_detail": "Notification Setting Details",
+    "event_pageCreate": "When new page is \"CREATED\"",
+    "event_pageEdit": "When page is \"EDITED\"",
+    "event_pageDelete": "When page is \"DELETED\"",
+    "event_pageMove": "When page is \"MOVED\" (renamed)",
+    "event_pageLike": "When someone \"LIKES\" page",
+    "event_comment": "When someone \"COMMENTS\" on page",
+    "email": {
+      "ifttt_link": "Create a new IFTTT applet with Email trigger"
+    },
+    "updated_slackApp": "Succeeded to update Slack App Configuration setting",
+    "add_notification_pattern": "Add user trigger notification patterns",
+    "delete_notification_pattern": "Delete notification pattern",
+    "delete_notification_pattern_desc1": "Delete Path: {{path}}",
+    "delete_notification_pattern_desc2": "Once deleted, it cannot be recovered",
+    "toggle_notification": "Updated setting of {{path}}",
     "not_found_global_notification_triggerid": "未找到全局通知 ID"
-	},
+  },
   "full_text_search_management": {
     "full_text_search_management": "全文搜索管理",
-		"elasticsearch_management": "Elasticsearch管理",
-		"connection_status": "连接状态",
-		"connection_status_label_unconfigured": "未配置",
-		"connection_status_label_connected": "已连接",
-		"connection_status_label_disconnected": "断开的",
-		"connection_status_label_erroroccured": "搜索服务出错",
-		"indices_status": "索引状态",
-		"indices_status_label_normalized": "标准化",
-		"indices_status_label_unnormalized": "重建或损坏",
-		"indices_summary": "索引摘要",
-		"reconnect": "重新连接",
-		"reconnect_button": "尝试重新连接",
-		"reconnect_description": "单击按钮尝试重新连接到Elasticsearch。",
-		"normalize": "规范化",
-		"normalize_button": "规范化索引",
-		"normalize_description": "单击按钮修复损坏的索引。",
-		"rebuild": "重建",
-		"rebuild_button": "重建索引",
-		"rebuild_description_1": "单击按钮以重新生成索引并添加所有页面数据。",
-		"rebuild_description_2": "这可能需要一段时间。"
-	},
+    "elasticsearch_management": "Elasticsearch管理",
+    "connection_status": "连接状态",
+    "connection_status_label_unconfigured": "未配置",
+    "connection_status_label_connected": "已连接",
+    "connection_status_label_disconnected": "断开的",
+    "connection_status_label_erroroccured": "搜索服务出错",
+    "indices_status": "索引状态",
+    "indices_status_label_normalized": "标准化",
+    "indices_status_label_unnormalized": "重建或损坏",
+    "indices_summary": "索引摘要",
+    "reconnect": "重新连接",
+    "reconnect_button": "尝试重新连接",
+    "reconnect_description": "单击按钮尝试重新连接到Elasticsearch。",
+    "normalize": "规范化",
+    "normalize_button": "规范化索引",
+    "normalize_description": "单击按钮修复损坏的索引。",
+    "rebuild": "重建",
+    "rebuild_button": "重建索引",
+    "rebuild_description_1": "单击按钮以重新生成索引并添加所有页面数据。",
+    "rebuild_description_2": "这可能需要一段时间。"
+  },
   "mailer_setup_required": "<a href='/admin/app'>Email settings</a> are required to send.",
   "admin_top": {
     "management_wiki": "管理Wiki",
@@ -322,7 +322,7 @@
       "done": "复制到剪贴板!"
     },
     "bug_report": "提交一个错误报告",
-    "submit_bug_report": "<a href='https://github.com/weseek/growi/issues/new?assignees=&labels=bug&template=bug-report.md&title=Bug%3A' target='_blank' rel='noreferrer'>然后提交你的问题到GitHub。</a>"
+    "submit_bug_report": "<a href='https://github.com/growilabs/growi/issues/new?assignees=&labels=bug&template=bug-report.md&title=Bug%3A' target='_blank' rel='noreferrer'>然后提交你的问题到GitHub。</a>"
   },
   "v5_page_migration": {
     "migration_desc": "有一些页面具有旧的v4兼容性。为了利用新的功能,如页面树和容易重命名,请将您的所有页面转换为v5兼容性。",
@@ -420,17 +420,7 @@
     "enable": "启用",
     "disable": "停用",
     "use_env_var_if_empty": "如果数据库中的值为空,则环境变量的值 <cod>{{variable}}</code> 启用。",
-    "note_for_the_only_env_option": "The GCS settings is limited by the value of environment variable.<br>To change this setting, please change to false or delete the value of the environment variable <code>{{env}}</code> .",
-    "questionnaire_settings": "问卷设置",
-    "questionnaire_settings_explanation": "这将在整个系统上启用/禁用问卷。 启用后,用户还可以在个人设置页面的“其他设置”中单独启用/禁用问卷调查。",
-    "about_data_sent": "关于发送的信息",
-    "docs_link": "https://docs.growi.org/en/admin-guide/management-cookbook/app-settings.html#questionnaire-settings",
-    "learn_more": "细节",
-    "other_info_will_be_sent": "与问卷回答一起,将发送改进 GROWI 所需的信息。个人用户信息将不包含在发送的数据中。",
-    "we_will_use_the_data_to_improve_growi": "我们将使用这些数据尽可能地改善 GROWI 体验。",
-    "anonymize_app_site_url": "在发送的数据中匿名应用程序站点 URL",
-    "url_anonymization_explanation": "问卷答案中包含的应用站点URL将被匿名化,启用后将不会识别发送问卷答案的GROWI应用。",
-    "enable_questionnaire": "启用问卷"
+    "note_for_the_only_env_option": "The GCS settings is limited by the value of environment variable.<br>To change this setting, please change to false or delete the value of the environment variable <code>{{env}}</code> ."
   },
   "markdown_settings": {
     "markdown_settings": "Markdown设置",
@@ -511,13 +501,13 @@
       "show_page_side_authors": "在目录上方始终显示创建者和更新者",
       "show_page_side_authors_desc": "在页面侧边栏的目录上方显示创建者和最后更新者的信息。"
     },
-      "presentation": "表达",
-      "presentation_options": {
+    "presentation": "表达",
+    "presentation_options": {
       "enable_marp": "启用 Marp",
       "enable_marp_desc": "Marp 可在演示视图中使用。该选项可能会使您受到 XSS 的攻击。",
       "marp_official_site": "参考资料:Marp 官方网站",
       "marp_official_site_link": "https://marp.app",
-      "marp_in_growi" : "参考资料:GROWI Docs - Create slide using Marp",
+      "marp_in_growi": "参考资料:GROWI Docs - Create slide using Marp",
       "marp_in_growi_link": "https://docs.growi.org/en/guide/features/marp.html"
     },
     "custom_title": "自定义标题",
@@ -531,7 +521,7 @@
     "write_css": "您可以编写应用于整个系统的CSS。",
     "ctrl_space": "Ctrl+Space 自动完成",
     "custom_script": "定制纸条",
-    "custom_presentation":"表达",
+    "custom_presentation": "表达",
     "write_java": "您可以编写应用于整个系统的Javascript。",
     "reflect_change": "您需要重新加载页面以反映更改。",
     "custom_logo": "自定义徽标",
@@ -727,7 +717,7 @@
       "allow_specified_long": "允许指定(只允许来自指定的渠道)",
       "test_connection": "测试连接",
       "test_connection_by_pressing_button": "按下按钮以测试连接",
-      "test_connection_only_public_channel":"请在一个公共频道中测试连接",
+      "test_connection_only_public_channel": "请在一个公共频道中测试连接",
       "error_check_logs_below": "发生了错误。请检查以下日志。",
       "send_message_to_slack_work_space": "发送到 Slack 工作区。",
       "add_slack_workspace": "添加Slack Workspace"
@@ -988,7 +978,7 @@
     "ADMIN_SITE_URL_UPDATE": "更新站点 URL 设置",
     "ADMIN_MAIL_SMTP_UPDATE": "更新电子邮件(SMTP)设置",
     "ADMIN_MAIL_SES_UPDATE": "更新电子邮件(SES)设置",
-    "ADMIN_MAIL_TEST_SUBMIT" : "发送测试邮件",
+    "ADMIN_MAIL_TEST_SUBMIT": "发送测试邮件",
     "ADMIN_FILE_UPLOAD_CONFIG_UPDATE": "更新文件上传设置",
     "ADMIN_PLUGIN_UPDATE": "更新插件设置",
     "ADMIN_MAINTENANCEMODE_ENABLED": "启用维护模式",
@@ -1140,8 +1130,8 @@
     "revoke_user_admin": "Succeeded to revoke {{username}} admin",
     "grant_user_read_only": "Succeeded to grant {{username}} read only",
     "revoke_user_read_only": "Succeeded to revoke {{username}} read only",
-		"activate_user_success": "Succeeded to activating {{username}}",
-		"deactivate_user_success": "Succeeded to deactivate {{username}}",
+    "activate_user_success": "Succeeded to activating {{username}}",
+    "deactivate_user_success": "Succeeded to deactivate {{username}}",
     "remove_user_success": "Succeeded to removing {{username}}",
     "remove_external_user_success": "Succeeded to remove {{accountId}}",
     "switch_disable_link_sharing_success": "成功更新分享链接设置",
@@ -1158,4 +1148,4 @@
     "disable_mode_explanation": "目前,AI 集成已被禁用。若要启用,请配置 <code>AI_ENABLED</code> 环境变量以及其他必要的变量。<br><br>详细信息请参考<a target='blank' rel='noopener noreferrer' href={{documentationUrl}}en/guide/features/ai-knowledge-assistant.html>文档</a>。",
     "ai_search_management": "AI 搜索管理"
   }
-}
+}

+ 116 - 60
apps/app/public/static/locales/zh_CN/commons.json

@@ -1,16 +1,15 @@
 {
-	"Show": "显示",
-	"Hide": "隐藏",
+  "Show": "显示",
+  "Hide": "隐藏",
   "Add": "添加",
   "Insert": "插入",
   "Reset": "重启",
-	"Sign out": "退出",
+  "Sign out": "退出",
   "New": "新建",
   "Send": "发送",
   "Close": "关闭",
   "Done": "完成",
   "Delete": "删除",
-
   "meta": {
     "display_name": "简体中文"
   },
@@ -33,52 +32,46 @@
   "headers": {
     "app_settings": "系统设置"
   },
-
   "header_search_box": {
-		"label": {
-			"All pages": "所有页面",
-			"This tree": "当前分支"
-		},
-		"item_label": {
-			"All pages": "所有页面",
-			"This tree": "当前分支以下内容"
-		}
+    "label": {
+      "All pages": "所有页面",
+      "This tree": "当前分支"
+    },
+    "item_label": {
+      "All pages": "所有页面",
+      "This tree": "当前分支以下内容"
+    }
   },
-
   "search_method_menu_item": {
     "search_in_all": "所有页面",
     "only_children_of_this_tree": "当前分支以下内容",
     "exact_mutch": "完全匹配"
   },
-
   "share_links": {
     "Share Link": "Share Link",
     "Page Path": "Page Path",
     "expire": "Expiration",
     "description": "Description"
   },
-
   "in_app_notification": {
     "notification_list": "应用内通知列表",
     "see_all": "查看通知列表",
     "no_notification": "您没有任何通知",
     "all": "全部",
     "unopend": "未读",
-    "mark_all_as_read" : "标记为已读",
+    "mark_all_as_read": "标记为已读",
     "no_unread_messages": "no_unread_messages",
     "only_unread": "Only unread"
   },
-
   "personal_dropdown": {
     "home": "家",
     "settings": "设置",
-		"color_mode": "颜色模式",
-		"sidebar_mode": "边栏模式",
-		"sidebar_mode_editor": "编辑器上的边栏模式",
-		"use_os_settings": "使用操作系统设置",
+    "color_mode": "颜色模式",
+    "sidebar_mode": "边栏模式",
+    "sidebar_mode_editor": "编辑器上的边栏模式",
+    "use_os_settings": "使用操作系统设置",
     "feedback": "意见和要求"
   },
-
   "create_page_dropdown": {
     "new_page": "新页面",
     "open_page_create_modal": "打开新页面创建模式",
@@ -92,24 +85,21 @@
       "descendants": "子代模板"
     }
   },
-
-	"copy_to_clipboard": {
-		"Copy to clipboard": "复制到剪贴板",
-		"Page path": "页面路径",
-		"Page URL": "页面Url",
-		"Parmanent link": "参数化链接",
-		"Page path and parmanent link": "页面路径及参数化链接",
-		"Markdown link": "Markdown链接",
+  "copy_to_clipboard": {
+    "Copy to clipboard": "复制到剪贴板",
+    "Page path": "页面路径",
+    "Page URL": "页面Url",
+    "Parmanent link": "参数化链接",
+    "Page path and parmanent link": "页面路径及参数化链接",
+    "Markdown link": "Markdown链接",
     "Append params": "Append params"
-	},
-
+  },
   "crop_image_modal": {
     "image_crop": "图像裁剪",
     "crop": "修剪",
     "save": "节省",
     "cancel": "取消"
   },
-
   "handsontable_modal": {
     "title": "编辑表格",
     "data_import": "数据导入",
@@ -125,35 +115,9 @@
       "import": "导入"
     }
   },
-
-  "questionnaire_modal": {
-    "required": "必需的",
-    "submit": "发送",
-    "close": "Close",
-    "title": "改善服务的GROWI调查表",
-    "more_satisfied_services": "我们希望让使用GROWI的人更加满意",
-    "strive_to_improve_services": "我们将利用你的反馈来改善我们的服务。",
-    "length_of_experience": {
-      "more_than_two_years": "2年以上",
-      "one_to_two_years": "超过1年但少于2年",
-      "six_months_to_one_year": "超过6个月但少于1年",
-      "three_months_to_six_months": "超过3个月但少于6个月",
-      "one_month_to_three_months": "超过1个月但少于3个月",
-      "less_than_one_month": "不到1个月"
-    },
-    "satisfaction_with_growi": "对GROWI的满意程度",
-    "history_of_growi_usage": "GROWI的使用历史",
-    "occupation": "职位",
-    "position": "职业类型",
-    "comment_on_growi": "关于GROWI的评论",
-    "successfully_submitted": "问卷已经发出。",
-    "thanks_for_answering": "非常感谢您完成问卷调查。"
-  },
-
   "not_found_page": {
     "page_not_exist": "该页面不存在"
   },
-
   "g2g_data_transfer": {
     "tab": "数据迁移",
     "data_transfer": "数据迁移",
@@ -162,5 +126,97 @@
     "transfer_key_limit": "迁移密钥在签发后一小时内有效。",
     "once_transfer_key_used": "一旦迁移密钥被用于迁移,它将不再可用于进一步的迁移。",
     "transfer_to_growi_cloud": "有关更多详情,请点击<a href='{{documentationUrl}}en/admin-guide/management-cookbook/g2g-transfer.html'>此处</a>。"
+  },
+  "accesstoken_scopes_desc": {
+    "read": {
+      "all": "授予查看所有内容的权限。",
+      "admin": {
+        "all": "授予查看管理功能的权限。",
+        "top": "授予查看Wiki管理顶部的权限。",
+        "app": "授予查看应用程序设置的权限。",
+        "security": "授予查看安全设置的权限。",
+        "markdown": "授予查看markdown设置的权限。",
+        "customize": "授予查看自定义设置的权限。",
+        "import_data": "授予查看数据导入设置的权限。",
+        "export_data": "授予查看数据归档设置的权限。",
+        "data_transfer": "授予查看数据迁移设置的权限。",
+        "external_notification": "授予查看外部通知设置的权限。",
+        "slack_integration": "授予查看Slack集成设置的权限。",
+        "legacy_slack_integration": "授予查看旧版Slack集成设置的权限。",
+        "user_management": "授予查看用户管理的权限。",
+        "user_group_management": "授予查看用户组管理的权限。",
+        "audit_log": "授予查看审计日志的权限。",
+        "plugin": "授予查看插件设置的权限。",
+        "ai_integration": "授予查看AI集成设置的权限。",
+        "full_text_search": "授予查看全文搜索管理的权限。"
+      },
+      "user_settings": {
+        "all": "授予查看用户设置的权限。",
+        "info": "授予查看用户信息的权限。",
+        "external_account": "授予查看外部账户的权限。",
+        "password": "授予查看密码设置的权限。",
+        "api": {
+          "all": "授予查看API设置的权限。",
+          "api_token": "授予查看API令牌设置的权限。",
+          "access_token": "授予查看访问令牌设置的权限。"
+        },
+        "in_app_notification": "授予查看应用内通知设置的权限。",
+        "other": "授予查看其他设置的权限。"
+      },
+      "features": {
+        "all": "授予查看功能的权限。",
+        "ai_assistant": "授予查看AI助手功能的权限。",
+        "page": "授予查看页面功能的权限。",
+        "share_link": "授予查看共享链接功能的权限。",
+        "bookmark": "授予查看书签功能的权限。",
+        "attachment": "授予查看附件功能的权限。",
+        "page_bulk_export": "授予查看页面批量导出功能的权限。"
+      }
+    },
+    "write": {
+      "all": "授予编辑所有内容的权限。",
+      "admin": {
+        "all": "授予编辑管理功能的权限。",
+        "top": "授予编辑Wiki管理顶部的权限。",
+        "app": "授予编辑应用程序设置的权限。",
+        "security": "授予编辑安全设置的权限。",
+        "markdown": "授予编辑markdown设置的权限。",
+        "customize": "授予编辑自定义设置的权限。",
+        "import_data": "授予编辑数据导入设置的权限。",
+        "export_data": "授予编辑数据归档设置的权限。",
+        "data_transfer": "授予编辑数据迁移设置的权限。",
+        "external_notification": "授予编辑外部通知设置的权限。",
+        "slack_integration": "授予编辑Slack集成设置的权限。",
+        "legacy_slack_integration": "授予编辑旧版Slack集成设置的权限。",
+        "user_management": "授予编辑用户管理的权限。",
+        "user_group_management": "授予编辑用户组管理的权限。",
+        "audit_log": "授予编辑审计日志的权限。",
+        "plugin": "授予编辑插件设置的权限。",
+        "ai_integration": "授予编辑AI集成设置的权限。",
+        "full_text_search": "授予编辑全文搜索管理的权限。"
+      },
+      "user_settings": {
+        "all": "授予编辑用户设置的权限。",
+        "info": "授予编辑用户信息的权限。",
+        "external_account": "授予编辑外部账户的权限。",
+        "password": "授予编辑密码设置的权限。",
+        "api": {
+          "all": "授予编辑API设置的权限。",
+          "api_token": "授予编辑API令牌设置的权限。",
+          "access_token": "授予编辑访问令牌设置的权限。"
+        },
+        "in_app_notification": "授予编辑应用内通知设置的权限。",
+        "other": "授予编辑其他设置的权限。"
+      },
+      "features": {
+        "all": "授予编辑功能的权限。",
+        "ai_assistant": "授予编辑AI助手功能的权限。",
+        "page": "授予编辑页面功能的权限。",
+        "share_link": "授予编辑共享链接功能的权限。",
+        "bookmark": "授予编辑书签功能的权限。",
+        "attachment": "授予编辑附件功能的权限。",
+        "page_bulk_export": "授予编辑页面批量导出功能的权限。"
+      }
+    }
   }
 }

+ 75 - 26
apps/app/public/static/locales/zh_CN/translation.json

@@ -230,13 +230,46 @@
       "profile_image2": "设置AWS或启用本地上传。"
     }
   },
+  "API Token Settings": "API token 设置",
+  "Current API Token": "当前 API token",
+  "Update API Token": "更新 API token",
   "page_me_apitoken": {
     "api_token": "API Token",
     "notice": {
       "apitoken_issued": "API token 未发布。",
       "update_token1": "您可以更新以生成新的API令牌。",
       "update_token2": "您需要更新任何现有进程中的API令牌。"
-    }
+    },
+    "form_help": {}
+  },
+  "Access Token Settings": "Access token 设置",
+  "page_me_access_token": {
+    "access_token": "访问令牌",
+    "expiredAt": "过期日期",
+    "description": "描述",
+    "scope": "范围",
+    "scope_read": "读取",
+    "action": "操作",
+    "create_token": "创建令牌",
+    "no_tokens_found": "未找到访问令牌",
+    "new_token": {
+      "title": "新访问令牌",
+      "copy_to_clipboard": "复制到剪贴板",
+      "message": "此令牌仅显示一次。请安全保存。"
+    },
+    "modal": {
+      "message": "确定要删除此访问令牌吗?",
+      "alert": "此操作无法撤消。",
+      "delete_token": "删除令牌"
+    },
+    "form": {
+      "title": "创建新访问令牌",
+      "expiredAt_desc": "选择此访问令牌的过期时间。",
+      "description_desc": "提供描述以帮助您稍后识别此令牌。",
+      "description_max_length": "请输入最多 {{length}} 个字符",
+      "scope_desc": "选择访问令牌的范围。"
+    },
+    "copy_to_clipboard": "复制到剪贴板"
   },
   "Password": "密码",
   "Password Settings": "密码设置",
@@ -252,9 +285,6 @@
   },
   "API Settings": "API设置",
   "Other Settings": "其他设置",
-  "API Token Settings": "API token 设置",
-  "Current API Token": "当前 API token",
-  "Update API Token": "更新 API token",
   "in_app_notification_settings": {
     "in_app_notification_settings": "在应用程序通知设置",
     "subscribe_settings": "自动订阅(接收通知)页面的设置",
@@ -469,9 +499,27 @@
       "Search in Editor": "编辑器内搜索",
       "Move Line": "移动行",
       "Copy Line": "复制行",
-      "Toggle Line": "注释/取消注释行",
       "Insert Line": "插入行",
-      "Post Comment": "(发表评论)"
+      "Post Comment": "(发表评论)",
+      "Multiple Cursors": "多光标",
+      "Or Alt Click": "或 Alt + 点击"
+    },
+    "format": {
+      "title": "格式设置(编辑器)",
+      "Bold": "粗体",
+      "Italic": "斜体",
+      "Strikethrough": "删除线",
+      "Code Text": "代码文本",
+      "Hyperlink": "超链接"
+    },
+    "line_settings": {
+      "title": "行设置(编辑器)",
+      "Bullet List": "项目符号列表",
+      "Numbered List": "编号列表",
+      "Quote": "引用",
+      "Code Block": "代码块",
+      "Comment Out": "隐藏",
+      "Comment Out Desc": "(注释)"
     }
   },
   "modal_resolve_conflict": {
@@ -487,6 +535,8 @@
   },
   "sidebar_ai_assistant": {
     "reference_pages_label": "参考页面",
+    "recent_chat": "最近聊天",
+    "no_recent_chat": "最近没有聊天",
     "knowledge_assistant_placeholder": "问我任何问题。",
     "editor_assistant_placeholder": "有什么需要帮忙的吗?",
     "summary_mode_label": "摘要模式",
@@ -541,6 +591,17 @@
       "create_failed": "创建助手失败",
       "update_failed": "更新助手失败"
     },
+    "select_source_pages": "选择助手要参考的页面",
+    "search_reference_pages_by_keyword": "按关键词搜索助手参考的页面",
+    "search_by_keyword": "按关键词搜索",
+    "max_items_space_separated_hint": "请输入最多5个项目,用空格分隔",
+    "select_assistant_reference_pages": "请选择助手参考的页面",
+    "enter_keywords": "输入关键词",
+    "reference_pages": "参考页面",
+    "no_pages_selected": "未选择任何页面",
+    "can_add_later": "稍后也可以添加",
+    "next": "下一步",
+    "select_from_page_tree": "从页面树选择",
     "edit_page_description": "编辑助手可以参考的页面。<br> 助手可以参考最多 {{limitLearnablePageCountPerAssistant}} 个页面,包括子页面。",
     "default_instruction": "您是这个Wiki的知识助手。\n\n## 多语言支持:\n请使用用户输入中使用的相同语言进行回复。\n",
     "add_page_button": "添加页面",
@@ -592,11 +653,12 @@
   "default_ai_assistant": {
     "not_set": "未设置默认助手"
   },
-  "ai_assistant_tree": {
+  "ai_assistant_substance": {
     "add_assistant": "添加助手",
     "my_assistants": "我的助手",
     "team_assistants": "团队助手",
     "thread_does_not_exist": "暂无会话",
+    "recent_threads": "最近的项目",
     "toaster": {
       "ai_assistant_deleted_success": "已删除助手",
       "ai_assistant_deleted_failed": "删除助手失败",
@@ -604,6 +666,10 @@
       "thread_deleted_failed": "删除会话失败",
       "ai_assistant_set_default_success": "已成功设置默认助手",
       "ai_assistant_set_default_failed": "设置默认助手失败"
+    },
+    "delete_modal": {
+      "title": "删除助手",
+      "confirm_message": "确定要删除此助手吗?"
     }
   },
   "link_edit": {
@@ -836,7 +902,7 @@
     "Password field is required": "密码字段是必需的",
     "Username or E-mail has invalid characters": "用户名或电子邮件有无效的字符",
     "user_not_found": "未找到用户",
-    "provider_duplicated_username_exception": "<p><strong><span class='material-symbols-outlined me-1'>cancel</span>发生了重复用户名异常</strong></p><p class='mb-0'> 你的 {{ failedProviderForDuplicatedUsernameException }} 认证成功了,但不能创建新的用户。参见问题<a href='https://github.com/weseek/growi/issues/193'>#193</a>.</p>"
+    "provider_duplicated_username_exception": "<p><strong><span class='material-symbols-outlined me-1'>cancel</span>发生了重复用户名异常</strong></p><p class='mb-0'> 你的 {{ failedProviderForDuplicatedUsernameException }} 认证成功了,但不能创建新的用户。参见问题<a href='https://github.com/growilabs/growi/issues/193'>#193</a>.</p>"
   },
   "grid_edit": {
     "create_bootstrap_4_grid": "创建Bootstrap 4网格",
@@ -957,23 +1023,6 @@
     "move_to_root": "移动到根部",
     "root": "root (default)"
   },
-  "questionnaire": {
-    "give_us_feedback": "向我们提供反馈以进行改进",
-    "thank_you_for_answering": "谢谢你的回答",
-    "additional_feedback": "从用户图标下拉菜单向我们发送更多反馈。",
-    "dont_show_again": "不再显示",
-    "deny": "不要回答",
-    "agree": "同意",
-    "disagree": "不同意",
-    "answer": "答案是",
-    "no_answer": "没有答案",
-    "settings": "问卷设置",
-    "failed_to_send": "无法发送反馈",
-    "denied": "问卷不会再显示",
-    "personal_settings_explanation": "将展示改进 GROWI 的问卷。 如果您有其他反馈,可以从用户图标下拉菜单中发送。",
-    "enable_questionnaire": "启用问卷",
-    "disabled_by_admin": "问卷已被管理员禁用"
-  },
   "v5_page_migration": {
     "page_tree_not_avaliable": "Page Tree 功能不可用",
     "go_to_settings": "进入设置,启用该功能"
@@ -1018,4 +1067,4 @@
     "skipped-toaster": "由于编辑器未激活,因此跳过同步。 请打开编辑器并重试。",
     "error-toaster": "同步最新文本失败"
   }
-}
+}

+ 6 - 8
apps/app/resource/Contributor.js

@@ -104,10 +104,7 @@ const contributors = [
       },
       {
         additionalClass: 'col-md-6 my-4',
-        members: [
-          { name: 'shaminmeerankutty' },
-          { name: 'rabitarochan' },
-        ],
+        members: [{ name: 'shaminmeerankutty' }, { name: 'rabitarochan' }],
       },
       {
         additionalClass: 'col-md-4 my-4',
@@ -150,7 +147,10 @@ const contributors = [
           { position: 'Flatt Security', name: 'stypr' },
           { position: 'Flatt Security', name: 'Azara/Norihide Saito' },
           { position: 'CyberAgent, Inc.', name: 'Daisuke Takahashi' },
-          { position: 'Mitsui Bussan Secure Directions, Inc.', name: 'Yuji Tounai' },
+          {
+            position: 'Mitsui Bussan Secure Directions, Inc.',
+            name: 'Yuji Tounai',
+          },
           { name: 'yy0931' },
         ],
       },
@@ -172,9 +172,7 @@ const contributors = [
       },
       {
         additionalClass: 'col-12 staff-credit-mt-10rem',
-        members: [
-          { name: 'AND YOU' },
-        ],
+        members: [{ name: 'AND YOU' }],
       },
     ],
   },

+ 14 - 0
apps/app/resource/locales/ko_KR/admin/userInvitation.ejs

@@ -0,0 +1,14 @@
+안녕하세요, <%- email %>님
+
+Wiki에 초대되셨습니다. 다음 계정으로 로그인할 수 있습니다:
+
+이메일: <%- email %>
+비밀번호: <%- password %>
+(이 비밀번호는 자동으로 생성되었습니다. 처음 로그인할 때 변경해야 합니다)
+
+기다리고 있겠습니다!
+<%- url %>
+
+--
+<%- appTitle %>
+<%- url %>

+ 11 - 0
apps/app/resource/locales/ko_KR/admin/userResetPassword.ejs

@@ -0,0 +1,11 @@
+안녕하세요, <%- email %>님
+
+관리자에 의해 비밀번호가 재설정되었습니다. 다음 계정으로 로그인할 수 있습니다:
+
+이메일: <%- email %>
+새 비밀번호: <%- password %>
+(이 비밀번호는 자동으로 생성되었습니다. 처음 로그인할 때 변경해야 합니다)
+
+--
+<%- appTitle %>
+<%- url %>

+ 20 - 0
apps/app/resource/locales/ko_KR/admin/userWaitingActivation.ejs

@@ -0,0 +1,20 @@
+안녕하세요, <%- adminUser.name %>님
+
+<%- appTitle %>에 사용자가 등록했습니다.
+
+
+====
+생성된 사용자:
+
+이름: <%- createdUser.name %>
+사용자명: <%- createdUser.username %>
+이메일: <%- createdUser.email %>
+====
+
+다음 URL에서 조치를 취해주세요:
+<%- url %>/admin/users
+
+
+--
+<%- appTitle %>
+<%- url %>

+ 9 - 0
apps/app/resource/locales/ko_KR/notifications/comment.ejs

@@ -0,0 +1,9 @@
+<%- username %>님이 <%- path %>에 댓글을 남겼습니다.
+
+----------------------
+
+<%- comment %>
+
+----------------------
+
+GROWI: <%- appTitle %>

+ 5 - 0
apps/app/resource/locales/ko_KR/notifications/pageCreate.ejs

@@ -0,0 +1,5 @@
+<%- username %>님이 <%- path %> 아래에 새 페이지를 만들었습니다.
+
+----------------------
+
+GROWI: <%- appTitle %>

+ 5 - 0
apps/app/resource/locales/ko_KR/notifications/pageDelete.ejs

@@ -0,0 +1,5 @@
+<%- username %>님이 <%- path %> 페이지를 삭제했습니다.
+
+----------------------
+
+GROWI: <%- appTitle %>

+ 5 - 0
apps/app/resource/locales/ko_KR/notifications/pageEdit.ejs

@@ -0,0 +1,5 @@
+<%- username %>님이 <%- path %> 페이지를 수정했습니다.
+
+----------------------
+
+GROWI: <%- appTitle %>

+ 5 - 0
apps/app/resource/locales/ko_KR/notifications/pageLike.ejs

@@ -0,0 +1,5 @@
+<%- username %>님이 <%- path %> 페이지를 좋아합니다.
+
+----------------------
+
+GROWI: <%- appTitle %>

+ 5 - 0
apps/app/resource/locales/ko_KR/notifications/pageMove.ejs

@@ -0,0 +1,5 @@
+<%- username %>님이 <%- oldPath %> 페이지를 <%- newPath %>(으)로 이동했습니다.
+
+----------------------
+
+GROWI: <%- appTitle %>

+ 12 - 0
apps/app/resource/locales/ko_KR/notifications/passwordReset.ejs

@@ -0,0 +1,12 @@
+비밀번호 재설정
+
+안녕하세요, <%- email %>님
+
+GROWI (<%- appTitle %>) 계정의 비밀번호 변경 요청이 접수되었습니다.
+비밀번호를 재설정하려면 아래 링크를 클릭하세요.
+
+<%- url %>
+
+이 링크는 <%- expiredAt %>에 10분 후에 만료됩니다.
+
+비밀번호 재설정을 요청하지 않으셨다면 이 이메일을 무시하셔도 됩니다.

+ 8 - 0
apps/app/resource/locales/ko_KR/notifications/passwordResetSuccessful.ejs

@@ -0,0 +1,8 @@
+비밀번호 재설정 완료
+
+안녕하세요 <%- email %>님
+
+비밀번호가 성공적으로 재설정되었습니다.
+새 비밀번호로 로그인해주세요.
+
+감사합니다,

+ 12 - 0
apps/app/resource/locales/ko_KR/notifications/userActivation.ejs

@@ -0,0 +1,12 @@
+계정 확인
+
+안녕하세요, <%- email %>님
+
+GROWI (<%- appTitle %>)에 계정이 생성되었습니다.
+계정을 활성화하려면 아래 링크를 클릭하세요.
+
+<%- url %>
+
+이 링크는 <%- expiredAt %>에 1시간 후에 만료됩니다.
+
+계정을 만들지 않으셨다면 이 이메일을 무시하셔도 됩니다.

Некоторые файлы не были показаны из-за большого количества измененных файлов