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

Merge branch 'master' into support/gw7886-dependabot-alert-jpeg-js

Shun Miyazawa 3 лет назад
Родитель
Сommit
563b6d69be
100 измененных файлов с 2415 добавлено и 1815 удалено
  1. 1 0
      .devcontainer/Dockerfile
  2. 19 19
      .devcontainer/devcontainer.json
  3. 2 0
      .devcontainer/docker-compose.yml
  4. 22 0
      .eslintrc.js
  5. 4 2
      .github/dependabot.yml
  6. 13 3
      .github/workflows/ci-app-prod.yml
  7. 17 9
      .github/workflows/ci-app.yml
  8. 2 2
      .github/workflows/draft-release.yml
  9. 4 4
      .github/workflows/list-unhealthy-branches.yml
  10. 1 1
      .github/workflows/release-rc.yml
  11. 2 2
      .github/workflows/release-slackbot-proxy.yml
  12. 3 3
      .github/workflows/release.yml
  13. 24 12
      .github/workflows/reusable-app-prod.yml
  14. 3 0
      .gitignore
  15. 43 27
      .vscode/launch.json
  16. 29 1
      CHANGELOG.md
  17. 33 11
      THIRD-PARTY-NOTICES.md
  18. 1 1
      lerna.json
  19. 17 12
      package.json
  20. 0 0
      packages-obsolete/plugin-attachment-refs/.eslintignore
  21. 0 0
      packages-obsolete/plugin-attachment-refs/.gitignore
  22. 0 0
      packages-obsolete/plugin-attachment-refs/README.md
  23. 4 3
      packages-obsolete/plugin-attachment-refs/package.json
  24. 0 0
      packages-obsolete/plugin-attachment-refs/src/client-entry.js
  25. 0 0
      packages-obsolete/plugin-attachment-refs/src/client/css/index.css
  26. 5 3
      packages-obsolete/plugin-attachment-refs/src/client/js/components/AttachmentList.jsx
  27. 2 1
      packages-obsolete/plugin-attachment-refs/src/client/js/components/ExtractedAttachments.jsx
  28. 0 0
      packages-obsolete/plugin-attachment-refs/src/client/js/util/GalleryContext.js
  29. 2 1
      packages-obsolete/plugin-attachment-refs/src/client/js/util/Interceptor/RefsPostRenderInterceptor.js
  30. 0 0
      packages-obsolete/plugin-attachment-refs/src/client/js/util/Interceptor/RefsPreRenderInterceptor.js
  31. 0 0
      packages-obsolete/plugin-attachment-refs/src/client/js/util/RefsContext.js
  32. 0 0
      packages-obsolete/plugin-attachment-refs/src/client/js/util/TagCacheManagerFactory.js
  33. 0 0
      packages-obsolete/plugin-attachment-refs/src/index.js
  34. 0 0
      packages-obsolete/plugin-attachment-refs/src/server-entry.js
  35. 0 0
      packages-obsolete/plugin-attachment-refs/src/server/routes/index.js
  36. 0 0
      packages-obsolete/plugin-attachment-refs/src/server/routes/refs.js
  37. 0 0
      packages-obsolete/plugin-attachment-refs/src/utils/logger/index.ts
  38. 0 0
      packages-obsolete/plugin-attachment-refs/tsconfig.base.json
  39. 0 0
      packages-obsolete/plugin-attachment-refs/tsconfig.build.cjs.json
  40. 0 0
      packages-obsolete/plugin-attachment-refs/tsconfig.build.esm.json
  41. 10 0
      packages-obsolete/plugin-attachment-refs/tsconfig.json
  42. 0 1
      packages/app/.env.development
  43. 5 0
      packages/app/.eslintignore
  44. 12 3
      packages/app/.eslintrc.js
  45. 5 2
      packages/app/.gitignore
  46. 1 0
      packages/app/_obsolete/config/webpack.common.js
  47. 1 0
      packages/app/_obsolete/config/webpack.dev.dll.js
  48. 1 0
      packages/app/_obsolete/config/webpack.dev.js
  49. 1 0
      packages/app/_obsolete/config/webpack.prod.js
  50. 4 16
      packages/app/_obsolete/src/client/app.jsx
  51. 2 5
      packages/app/_obsolete/src/client/base.jsx
  52. 5 0
      packages/app/_obsolete/src/client/boot.js
  53. 0 0
      packages/app/_obsolete/src/client/installer.jsx
  54. 0 0
      packages/app/_obsolete/src/client/nologin.jsx
  55. 0 0
      packages/app/_obsolete/src/client/plugin.js
  56. 26 22
      packages/app/_obsolete/src/client/services/AppContainer.js
  57. 37 59
      packages/app/_obsolete/src/client/services/ContextExtractor.tsx
  58. 26 119
      packages/app/_obsolete/src/client/services/PageContainer.js
  59. 144 0
      packages/app/_obsolete/src/components/MyDraftList/Draft.tsx
  60. 11 10
      packages/app/_obsolete/src/components/MyDraftList/MyDraftList.jsx
  61. 5 0
      packages/app/_obsolete/src/util/i18n.js
  62. 0 0
      packages/app/_obsolete/src/util/old-ios.js
  63. 0 56
      packages/app/bin/generate-plugin-definitions-source.ts
  64. 1 2
      packages/app/bin/github-actions/update-readme.sh
  65. 0 1
      packages/app/config/ci/.env.local.for-ci
  66. 6 1
      packages/app/config/migrate-mongo-config.js
  67. 27 0
      packages/app/config/next-i18next.config.ts
  68. 1 1
      packages/app/config/rate-limiter.ts
  69. 2 1
      packages/app/cypress.json
  70. 13 6
      packages/app/docker/Dockerfile
  71. 3 4
      packages/app/docker/README.md
  72. 8 1
      packages/app/jest.config.js
  73. 5 0
      packages/app/next-env.d.ts
  74. 114 0
      packages/app/next.config.js
  75. 86 90
      packages/app/package.json
  76. BIN
      packages/app/public/static/fonts/Lato-Bold-latin-ext.woff2
  77. BIN
      packages/app/public/static/fonts/Lato-Bold-latin.woff2
  78. BIN
      packages/app/public/static/fonts/Lato-Regular-latin-ext.woff2
  79. BIN
      packages/app/public/static/fonts/Lato-Regular-latin.woff2
  80. BIN
      packages/app/public/static/fonts/PressStart2P-latin-ext.woff2
  81. BIN
      packages/app/public/static/fonts/PressStart2P-latin.woff2
  82. 345 12
      packages/app/public/static/locales/en_US/admin.json
  83. 100 0
      packages/app/public/static/locales/en_US/commons.json
  84. 56 391
      packages/app/public/static/locales/en_US/translation.json
  85. 0 2
      packages/app/public/static/locales/index.js
  86. 351 11
      packages/app/public/static/locales/ja_JP/admin.json
  87. 100 0
      packages/app/public/static/locales/ja_JP/commons.json
  88. 57 388
      packages/app/public/static/locales/ja_JP/translation.json
  89. 356 12
      packages/app/public/static/locales/zh_CN/admin.json
  90. 100 0
      packages/app/public/static/locales/zh_CN/commons.json
  91. 57 391
      packages/app/public/static/locales/zh_CN/translation.json
  92. 0 7
      packages/app/resource/cdn-manifests.js
  93. 1 1
      packages/app/resource/locales/en_US/sandbox-diagrams.md
  94. 1 1
      packages/app/resource/locales/en_US/sandbox-math.md
  95. 34 37
      packages/app/resource/locales/en_US/sandbox.md
  96. 3 3
      packages/app/resource/locales/en_US/welcome.md
  97. 1 1
      packages/app/resource/locales/ja_JP/sandbox-diagrams.md
  98. 1 1
      packages/app/resource/locales/ja_JP/sandbox-math.md
  99. 34 37
      packages/app/resource/locales/ja_JP/sandbox.md
  100. 3 3
      packages/app/resource/locales/ja_JP/welcome.md

+ 1 - 0
.devcontainer/Dockerfile

@@ -16,6 +16,7 @@ ARG USER_GID=$USER_UID
 RUN mkdir -p /workspace/growi/node_modules
 RUN mkdir -p /workspace/growi/packages/app/node_modules
 RUN mkdir -p /workspace/growi/packages/slackbot-proxy/node_modules
+RUN mkdir -p /workspace/growi/packages/app/.next
 
 # [Optional] Update UID/GID if needed
 RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \

+ 19 - 19
.devcontainer/devcontainer.json

@@ -2,18 +2,18 @@
 // https://github.com/microsoft/vscode-dev-containers/tree/v0.117.1/containers/javascript-node-12-mongo
 // If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
 {
-	"name": "GROWI-Dev",
-	"dockerComposeFile": "docker-compose.yml",
-	"service": "node",
-	"workspaceFolder": "/workspace/growi",
+  "name": "GROWI-Dev",
+  "dockerComposeFile": "docker-compose.yml",
+  "service": "node",
+  "workspaceFolder": "/workspace/growi",
 
-	// Set *default* container specific settings.json values on container create.
-	"settings": {
-		"terminal.integrated.defaultProfile.linux": "bash"
-	},
+  // Set *default* container specific settings.json values on container create.
+  "settings": {
+    "terminal.integrated.defaultProfile.linux": "bash"
+  },
 
-	// Add the IDs of extensions you want installed when the container is created.
-	"extensions": [
+  // Add the IDs of extensions you want installed when the container is created.
+  "extensions": [
     "dbaeumer.vscode-eslint",
     "mhutchie.git-graph",
     "eamodio.gitlens",
@@ -26,17 +26,17 @@
     "esbenp.prettier-vscode",
     "shinnn.stylelint",
     "stylelint.vscode-stylelint"
-	],
+  ],
 
-	// Uncomment the next line if you want start specific services in your Docker Compose config.
-	// "runServices": [],
+  // Uncomment the next line if you want start specific services in your Docker Compose config.
+  // "runServices": [],
 
-	// Uncomment the line below if you want to keep your containers running after VS Code shuts down.
-	// "shutdownAction": "none",
+  // Uncomment the line below if you want to keep your containers running after VS Code shuts down.
+  // "shutdownAction": "none",
 
-	// Use 'postCreateCommand' to run commands after the container is created.
-	// "postCreateCommand": "yarn install",
+  // Use 'postCreateCommand' to run commands after the container is created.
+  // "postCreateCommand": "yarn install",
 
-	// Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
-	"remoteUser": "node"
+  // Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
+  "remoteUser": "node"
 }

+ 2 - 0
.devcontainer/docker-compose.yml

@@ -22,6 +22,7 @@ services:
       - node_modules:/workspace/growi/node_modules
       - node_modules_app:/workspace/growi/packages/app/node_modules
       - node_modules_slackbot-proxy:/workspace/growi/packages/slackbot-proxy/node_modules
+      - buildcache_app:/workspace/growi/packages/app/.next
       - ../../growi-docker-compose:/workspace/growi-docker-compose:delegated
 
     tty: true
@@ -96,3 +97,4 @@ volumes:
   node_modules:
   node_modules_app:
   node_modules_slackbot-proxy:
+  buildcache_app:

+ 22 - 0
.eslintrc.js

@@ -35,6 +35,18 @@ module.exports = {
             group: 'parent',
             position: 'before',
           },
+          {
+            pattern: '*.css',
+            group: 'type',
+            patternOptions: { matchBase: true },
+            position: 'after',
+          },
+          {
+            pattern: '*.scss',
+            group: 'type',
+            patternOptions: { matchBase: true },
+            position: 'after',
+          },
         ],
         alphabetize: {
           order: 'asc',
@@ -44,6 +56,7 @@ module.exports = {
       },
     ],
     '@typescript-eslint/no-explicit-any': 'off',
+    '@typescript-eslint/explicit-module-boundary-types': 'off',
     indent: [
       'error',
       2,
@@ -68,4 +81,13 @@ module.exports = {
       },
     ]],
   },
+  overrides: [
+    {
+      // enable the rule specifically for TypeScript files
+      files: ['*.ts', '*.tsx'],
+      rules: {
+        '@typescript-eslint/explicit-module-boundary-types': ['error'],
+      },
+    },
+  ],
 };

+ 4 - 2
.github/dependabot.yml

@@ -2,16 +2,18 @@ version: 2
 updates:
   - package-ecosystem: github-actions
     directory: '/'
+    open-pull-requests-limit: 0
     schedule:
-      interval: daily
+      interval: monthly
     commit-message:
       prefix: ci
       include: scope
 
   - package-ecosystem: npm
     directory: '/'
+    open-pull-requests-limit: 0
     schedule:
-      interval: daily
+      interval: weekly
     commit-message:
       prefix: ci
       include: scope

+ 13 - 3
.github/workflows/ci-app-prod.yml

@@ -12,13 +12,14 @@ on:
       - yarn.lock
       - packages/app/**
       - '!packages/app/docker/**'
+      - packages/codemirror-textlint/**
       - packages/core/**
+      - packages/remark-*/**
       - packages/slack/**
       - packages/ui/**
-      - packages/plugin-**
   pull_request:
     branches:
-        - master
+      - master
     types: [opened, reopened, synchronize]
     paths:
       - .github/workflows/ci-app-prod.yml
@@ -28,10 +29,18 @@ on:
       - yarn.lock
       - packages/app/**
       - '!packages/app/docker/**'
+      - packages/codemirror-textlint/**
       - packages/core/**
+      - packages/remark-*/**
       - packages/slack/**
       - packages/ui/**
-      - packages/plugin-**
+  workflow_call:
+    inputs:
+      cypress-config-video:
+        description: 'Enable video when running Cypress test'
+        type: boolean
+        default: false
+
 
 jobs:
 
@@ -50,6 +59,7 @@ jobs:
       node-version: 16.x
       skip-cypress: ${{ contains( github.event.pull_request.labels.*.name, 'dependencies' ) && contains( github.event.pull_request.labels.*.name, 'github_actions' ) }}
       cypress-report-artifact-name: Cypress report
+      cypress-config-video: ${{ inputs.cypress-config-video || false }}
     secrets:
       SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
 

+ 17 - 9
.github/workflows/ci-app.yml

@@ -14,10 +14,11 @@ on:
       - yarn.lock
       - packages/app/**
       - '!packages/app/docker/**'
+      - packages/codemirror-textlint/**
       - packages/core/**
+      - packages/remark-*/**
       - packages/slack/**
       - packages/ui/**
-      - packages/plugin-*/**
 
 jobs:
   lint:
@@ -53,10 +54,10 @@ jobs:
 
       - name: lerna run lint for plugins
         run: |
-          yarn lerna run lint --scope @growi/plugin-*
+          yarn lerna run lint --scope @growi/remark-*
       - name: lerna run lint for app
         run: |
-          yarn lerna run lint --scope @growi/app --scope @growi/codemirror-textlint --scope @growi/core --scope @growi/ui
+          yarn lerna run lint --scope @growi/app --scope @growi/codemirror-textlint --scope @growi/core --scope @growi/slack --scope @growi/ui
 
       - name: Slack Notification
         uses: weseek/ghaction-slack-notification@master
@@ -105,7 +106,11 @@ jobs:
         run: |
           npx lerna bootstrap -- --frozen-lockfile
 
-      - name: yarn test
+      - name: lerna run test for plugins
+        run: |
+          yarn lerna run test --scope @growi/remark-*
+
+      - name: Test app
         working-directory: ./packages/app
         run: |
           yarn test:ci --selectProjects unit server ; yarn test:ci --selectProjects server-v5
@@ -116,7 +121,9 @@ jobs:
         uses: actions/upload-artifact@v3
         with:
           name: Coverage Report
-          path: packages/app/coverage
+          path: |
+            packages/app/coverage
+            packages/remark-growi-plugin/coverage
 
       - name: Slack Notification
         uses: weseek/ghaction-slack-notification@master
@@ -150,16 +157,17 @@ jobs:
           cache: 'yarn'
           cache-dependency-path: '**/yarn.lock'
 
-      - name: Cache/Restore node_modules
+      - name: Cache/Restore node_modules and next cache files
         id: cache-dependencies
         uses: actions/cache@v3
         with:
           path: |
             **/node_modules
-          key: node_modules-${{ runner.OS }}-node${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}-${{ hashFiles('packages/app/package.json') }}
+            ${{ github.workspace }}/packages/app/.next/cache
+          key: dev-${{ runner.OS }}-node${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}-${{ hashFiles('packages/app/package.json') }}
           restore-keys: |
-            node_modules-${{ runner.OS }}-node${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}-
-            node_modules-${{ runner.OS }}-node${{ matrix.node-version }}-
+            dev-${{ runner.OS }}-node${{ matrix.node-version }}-${{ hashFiles('**/yarn.lock') }}-
+            dev-${{ runner.OS }}-node${{ matrix.node-version }}-
 
       - name: lerna bootstrap
         run: |

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

@@ -19,7 +19,7 @@ jobs:
       - uses: actions/checkout@v3
 
       - name: Retrieve information from package.json
-        uses: myrotvorets/info-from-package-json-action@1.1.0
+        uses: myrotvorets/info-from-package-json-action@1.2.0
         id: package-json
 
       # Drafts your next Release notes as Pull Requests are merged into "master"
@@ -48,7 +48,7 @@ jobs:
         id: release-version
         run: |
           RELEASE_VERSION=`npx semver -i patch ${{ needs.update-release-draft.outputs.CURRENT_VERSION }}`
-          echo ::set-output name=RELEASE_VERSION::$RELEASE_VERSION
+          echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_OUTPUT
 
       # See: https://github.com/bakunyo/git-pr-release-action/issues/15, https://github.com/samunohito/SimpleVolumeMixer/commit/2059044c71236509466cf9b1bb2d56d515274938
       - name: Create/Update Pull Request

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

@@ -23,10 +23,10 @@ jobs:
       run: |
         export SLACK_ATTACHMENTS_ILLEGAL=`node bin/github-actions/list-branches --illegal`
         export SLACK_ATTACHMENTS_INACTIVE=`node bin/github-actions/list-branches --inactive`
-        echo ::set-output name=SLACK_ATTACHMENTS_ILLEGAL::$SLACK_ATTACHMENTS_ILLEGAL
-        echo ::set-output name=SLACK_ATTACHMENTS_INACTIVE::$SLACK_ATTACHMENTS_INACTIVE
-        echo ::set-output name=SLACK_ATTACHMENTS_LENGTH_ILLEGAL::$(echo $SLACK_ATTACHMENTS_ILLEGAL | jq '. | length')
-        echo ::set-output name=SLACK_ATTACHMENTS_LENGTH_INACTIVE::$(echo $SLACK_ATTACHMENTS_INACTIVE | jq '. | length')
+        echo "SLACK_ATTACHMENTS_ILLEGAL=$SLACK_ATTACHMENTS_ILLEGAL" >> $GITHUB_OUTPUT
+        echo "SLACK_ATTACHMENTS_INACTIVE=$SLACK_ATTACHMENTS_INACTIVE" >> $GITHUB_OUTPUT
+        echo "SLACK_ATTACHMENTS_LENGTH_ILLEGAL=$(echo $SLACK_ATTACHMENTS_ILLEGAL | jq '. | length')" >> $GITHUB_OUTPUT
+        echo "SLACK_ATTACHMENTS_LENGTH_INACTIVE=$(echo $SLACK_ATTACHMENTS_INACTIVE | jq '. | length')" >> $GITHUB_OUTPUT
 
     - name: Slack Notification for illegal named branches
       if: steps.list-branches.outputs.SLACK_ATTACHMENTS_LENGTH_ILLEGAL > 0

+ 1 - 1
.github/workflows/release-rc.yml

@@ -17,7 +17,7 @@ jobs:
         lfs: true
 
     - name: Retrieve information from package.json
-      uses: myrotvorets/info-from-package-json-action@1.1.0
+      uses: myrotvorets/info-from-package-json-action@1.2.0
       id: package-json
 
     - name: Docker meta

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

@@ -17,7 +17,7 @@ jobs:
         ref: ${{ github.event.pull_request.base.ref }}
 
     - name: Retrieve information from package.json
-      uses: myrotvorets/info-from-package-json-action@1.1.0
+      uses: myrotvorets/info-from-package-json-action@1.2.0
       id: package-json
       with:
         workingDir: packages/slackbot-proxy
@@ -115,7 +115,7 @@ jobs:
         yarn bump-versions:slackbot-proxy
 
     - name: Retrieve information from package.json
-      uses: myrotvorets/info-from-package-json-action@1.1.0
+      uses: myrotvorets/info-from-package-json-action@1.2.0
       id: package-json
       with:
         workingDir: packages/slackbot-proxy

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

@@ -38,7 +38,7 @@ jobs:
         sh ./packages/app/bin/github-actions/update-readme.sh
 
     - name: Retrieve information from package.json
-      uses: myrotvorets/info-from-package-json-action@1.1.0
+      uses: myrotvorets/info-from-package-json-action@1.2.0
       id: package-json
 
     - name: Update Changelog
@@ -99,7 +99,7 @@ jobs:
         yarn bump-versions:slackbot-proxy
 
     - name: Retrieve information from package.json
-      uses: myrotvorets/info-from-package-json-action@1.1.0
+      uses: myrotvorets/info-from-package-json-action@1.2.0
       id: package-json
 
     - name: Commit
@@ -140,7 +140,7 @@ jobs:
       id: suffix
       run: |
         [[ ${{ matrix.flavor }} = "nocdn" ]] && suffix="-nocdn" || suffix=""
-        echo "::set-output name=SUFFIX::$suffix"
+        echo "SUFFIX=$suffix" >> $GITHUB_OUTPUT
 
     - name: Docker meta
       id: meta

+ 24 - 12
.github/workflows/reusable-app-prod.yml

@@ -10,6 +10,9 @@ on:
         type: boolean
       cypress-report-artifact-name:
         type: string
+      cypress-config-video:
+        type: boolean
+        default: false
     secrets:
       SLACK_WEBHOOK_URL:
         required: true
@@ -49,6 +52,7 @@ jobs:
     - name: Remove unnecessary packages
       run: |
         rm -rf packages/slackbot-proxy
+        rm -f "node_modules/@growi/slackbot-proxy"
 
     - name: Build
       run: |
@@ -59,29 +63,31 @@ jobs:
     - name: Archive production files
       id: archive-prod-files
       run: |
-        tar -cf production.tar \
+        tar -zcf production.tar.gz \
           package.json \
+          packages/app/.next \
           packages/app/config \
           packages/app/public \
           packages/app/resource \
           packages/app/tmp \
-          packages/app/migrate-mongo-config.js \
           packages/app/.env.production* \
           packages/*/package.json \
           packages/*/dist
-        echo ::set-output name=file::production.tar
+        echo "file=production.tar.gz" >> $GITHUB_OUTPUT
 
     - name: Upload production files as artifact
       uses: actions/upload-artifact@v3
       with:
-        name: Production Files
+        name: Production Files (node${{ inputs.node-version }})
         path: ${{ steps.archive-prod-files.outputs.file }}
 
     - name: Upload report as artifact
       uses: actions/upload-artifact@v3
       with:
         name: Bundle Analyzing Report
-        path: packages/app/report/bundle-analyzer.html
+        path: |
+          packages/app/.next/analyze/client.html
+          packages/app/.next/analyze/server.html
 
     - name: Slack Notification
       uses: weseek/ghaction-slack-notification@master
@@ -123,8 +129,8 @@ jobs:
     - name: Get Date
       id: get-date
       run: |
-        echo "::set-output name=dateYmdHM::$(/bin/date -u "+%Y%m%d%H%M")"
-        echo "::set-output name=dateYm::$(/bin/date -u "+%Y%m")"
+        echo "dateYmdHM=$(/bin/date -u "+%Y%m%d%H%M")" >> $GITHUB_OUTPUT
+        echo "dateYm=$(/bin/date -u "+%Y%m")" >> $GITHUB_OUTPUT
 
     - name: Cache/Restore node_modules (not reused)
       id: cache-dependencies
@@ -143,6 +149,7 @@ jobs:
     - name: Remove unnecessary packages
       run: |
         rm -rf packages/slackbot-proxy
+        rm -f "node_modules/@growi/slackbot-proxy"
 
     - name: lerna bootstrap --production
       run: |
@@ -151,7 +158,7 @@ jobs:
     - name: Download production files artifact
       uses: actions/download-artifact@v3
       with:
-        name: Production Files
+        name: Production Files (node${{ inputs.node-version }})
 
     - name: Extract procution files artifact
       run: |
@@ -211,7 +218,7 @@ jobs:
 
     - uses: actions/setup-node@v3
       with:
-        node-version: ${{ matrix.node-version }}
+        node-version: ${{ inputs.node-version }}
         cache: 'yarn'
         cache-dependency-path: '**/yarn.lock'
 
@@ -228,12 +235,16 @@ jobs:
 
     - name: lerna bootstrap
       run: |
-        npx lerna bootstrap -- --frozen-lockfile
+        npx lerna bootstrap -- --production
+
+    - name: lerna add packages needed for CI
+      run: |
+        npx lerna add yargs
 
     - name: Download production files artifact
       uses: actions/download-artifact@v3
       with:
-        name: Production Files
+        name: Production Files (node${{ inputs.node-version }})
 
     - name: Extract procution files artifact
       run: |
@@ -243,7 +254,7 @@ jobs:
       id: determine-spec-exp
       run: |
         SPEC=`node bin/github-actions/generate-cypress-spec-arg.js --prefix="test/cypress/integration/" --suffix="-*/**" "${{ matrix.spec-group }}"`
-        echo "::set-output name=value::$SPEC"
+        echo "value=$SPEC" >> $GITHUB_OUTPUT
 
     - name: Copy dotenv file for ci
       working-directory: ./packages/app
@@ -270,6 +281,7 @@ jobs:
         spec: '${{ steps.determine-spec-exp.outputs.value }}'
         start: yarn server
         wait-on: 'http://localhost:3000'
+        config: video=${{ inputs.cypress-config-video }}
       env:
         MONGO_URI: mongodb://localhost:${{ job.services.mongodb.ports['27017'] }}/growi-vrt
         ELASTICSEARCH_URI: http://localhost:${{ job.services.elasticsearch.ports['9200'] }}/growi

+ 3 - 0
.gitignore

@@ -26,6 +26,9 @@ yarn-error.log*
 .env.test.local
 .env.production.local
 
+# typescript
+*.tsbuildinfo
+
 # IDE, dev #
 .idea
 *.orig

+ 43 - 27
.vscode/launch.json

@@ -1,37 +1,57 @@
 {
-    // IntelliSense を使用して利用可能な属性を学べます。
-    // 既存の属性の説明をホバーして表示します。
-    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
     "version": "0.2.0",
     "configurations": [
       {
-        "type": "node",
+        "type": "pwa-node",
         "request": "attach",
         "name": "Debug: Attach Debugger to Server",
-        "port": 9229
+        "port": 9229,
+        "cwd": "${workspaceFolder}/packages/app",
+        "sourceMapPathOverrides": {
+          "webpack://@growi/app/*": "${workspaceFolder}/packages/app/*"
+        }
       },
       {
-        "type": "node",
+        "type": "pwa-node",
+        "request": "launch",
+        "name": "Debug: Current File",
+        "skipFiles": [
+          "<node_internals>/**"
+        ],
+        "console": "integratedTerminal",
+        "cwd": "${fileDirname}",
+        "runtimeExecutable": "yarn",
+        "runtimeArgs": [
+          "ts-node",
+          "${file}"
+        ]
+      },
+      {
+        "type": "pwa-node",
         "request": "launch",
         "name": "Debug: Server",
         "cwd": "${workspaceFolder}/packages/app",
-        "runtimeExecutable": "npm",
+        "runtimeExecutable": "yarn",
         "runtimeArgs": [
-          "run",
-          "dev:server"
+          "dev"
+        ],
+        "skipFiles": [
+          "<node_internals>/**"
         ],
-        "port": 9229,
         "restart": true,
         "console": "integratedTerminal",
-        "internalConsoleOptions": "neverOpen"
+        "internalConsoleOptions": "neverOpen",
+        "sourceMapPathOverrides": {
+          "webpack://@growi/app/*": "${workspaceFolder}/packages/app/*"
+        }
       },
       {
-        "type": "chrome",
+        "type": "pwa-chrome",
         "request": "launch",
         "name": "Debug: Chrome",
         "sourceMaps": true,
         "sourceMapPathOverrides": {
-          "webpack:///*": "${workspaceFolder}/packages/app/*"
+          "webpack://_N_E/*": "${workspaceFolder}/packages/app/*"
         },
         "webRoot": "${workspaceFolder}/packages/app/public",
         "url": "http://localhost:3000"
@@ -41,33 +61,29 @@
         "request": "launch",
         "name": "Debug: Firefox",
         "reAttach": true,
-        "url": "http://localhost:3000",
         "webRoot": "${workspaceFolder}/packages/app/public",
+        "url": "http://localhost:3000",
         "pathMappings": [
           {
-            "url": "webpack:///core",
-            "path": "${workspaceFolder}/packages/core"
+            "url": "webpack://_n_e/src",
+            "path": "${workspaceFolder}/packages/app/src"
           },
           {
-            "url": "webpack:///plugin-attachment-refs",
-            "path": "${workspaceFolder}/packages/plugin-attachment-refs"
+            "url": "webpack://_n_e/core",
+            "path": "${workspaceFolder}/packages/core"
           },
           {
-            "url": "webpack:///plugin-pukiwiki-like-linker",
-            "path": "${workspaceFolder}/packages/plugin-pukiwiki-like-linker"
+            "url": "webpack://_n_e/remark-lsx",
+            "path": "${workspaceFolder}/packages/remark-lsx"
           },
           {
-            "url": "webpack:///plugin-lsx",
-            "path": "${workspaceFolder}/packages/plugin-lsx"
+            "url": "webpack://_n_e/slack",
+            "path": "${workspaceFolder}/packages/app/slack"
           },
           {
-            "url": "webpack:///ui",
+            "url": "webpack://_n_e/ui",
             "path": "${workspaceFolder}/packages/ui"
           },
-          {
-            "url": "webpack:///src",
-            "path": "${workspaceFolder}/packages/app/src"
-          },
           {
             "url": "http://localhost:3000",
             "path": "${workspaceFolder}/packages/app/public"

+ 29 - 1
CHANGELOG.md

@@ -1,9 +1,37 @@
 # Changelog
 
-## [Unreleased](https://github.com/weseek/growi/compare/v5.1.4...HEAD)
+## [Unreleased](https://github.com/weseek/growi/compare/v5.1.7...HEAD)
 
 *Please do not manually update this file. We've automated the process.*
 
+## [v5.1.7](https://github.com/weseek/growi/compare/v5.1.6...v5.1.7) - 2022-10-26
+
+### 🐛 Bug Fixes
+
+- fix: Page move event notification message (#6823) @hakumizuki
+
+## [v5.1.6](https://github.com/weseek/growi/compare/v5.1.5...v5.1.6) - 2022-10-19
+
+### 🐛 Bug Fixes
+
+- fix: image not showing and exceed crop modal area (#6712) @mudana-grune
+- fix: Conflict Diff Modal Error getCurrentOptionsToSave is not a function (#6745) @kaoritokashiki
+
+## [v5.1.5](https://github.com/weseek/growi/compare/v5.1.4...v5.1.5) - 2022-10-04
+
+### 💎 Features
+
+- feat: Add option to not use crop modal on brand logo upload (#6677) @Yohei-Shiina
+
+### 🚀 Improvement
+
+- imprv: Emoji picker performance for v5.x (#6689) @hakumizuki
+
+### 🐛 Bug Fixes
+
+- fix(auditlog): Attachment download is displayed even if the filter is unchecked (#6688) @miya
+- fix: firstName and lastName japanese translations in SAML  (#6631) @kaoritokashiki
+
 ## [v5.1.4](https://github.com/weseek/growi/compare/v5.1.3...v5.1.4) - 2022-09-12
 
 ### 💎 Features

+ 33 - 11
THIRD-PARTY-NOTICES.md

@@ -13,10 +13,12 @@ https://github.com/weseek/growi.
 
 
 1. Apache License, Version 2.0 Derivative Works
-2. crowi/crowi (https://github.com/crowi/crowi)
-3. Microsoft/vscode (https://github.com/Microsoft/vscode)
-4. stephenhutchings/typicons.font (https://github.com/stephenhutchings/typicons.font)
-5. Kuromoji.js (https://github.com/takuyaa/kuromoji.js)
+1. crowi/crowi (https://github.com/crowi/crowi)
+1. Microsoft/vscode (https://github.com/Microsoft/vscode)
+1. Kuromoji.js (https://github.com/takuyaa/kuromoji.js)
+1. Lato (https://fonts.google.com/specimen/Lato)
+1. Press Start 2P (https://fonts.google.com/specimen/Press+Start+2P)
+1. stephenhutchings/typicons.font (https://github.com/stephenhutchings/typicons.font)
 
 
 License Notice for Apache License, Version 2.0 Derivative Works
@@ -90,21 +92,41 @@ SOFTWARE.
 ```
 
 
-License Notice for Typicons
+License Notice for Kuromoji.js
 ------------------------
 
-https://creativecommons.org/licenses/by-sa/3.0/
+https://github.com/takuyaa/kuromoji.js/blob/master/LICENSE-2.0.txt
 
 ```
-Copyright (c) 2018 Stephen Hutchings
+author: "Takuya Asano <takuya.a@gmail.com>"
 ```
 
 
-License Notice for Kuromoji.js
-------------------------
+License Notice for Lato
+---------------------
 
-https://github.com/takuyaa/kuromoji.js/blob/master/LICENSE-2.0.txt
+https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL
 
 ```
-author: "Takuya Asano <takuya.a@gmail.com>"
+Designed by Łukasz Dziedzic 
 ```
+
+
+License Notice for Press Start 2P
+------------------------------
+
+https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL
+
+```
+Designed by CodeMan38
+```
+
+
+License Notice for Typicons
+------------------------
+
+https://creativecommons.org/licenses/by-sa/3.0/
+
+```
+Copyright (c) 2018 Stephen Hutchings
+```

+ 1 - 1
lerna.json

@@ -1,7 +1,7 @@
 {
   "npmClient": "yarn",
   "useWorkspaces": true,
-  "version": "5.1.5-RC.0",
+  "version": "6.0.0-RC.9",
   "packages": [
     "packages/*"
   ]

+ 17 - 12
package.json

@@ -1,6 +1,6 @@
 {
   "name": "growi",
-  "version": "5.1.5-RC.0",
+  "version": "6.0.0-RC.9",
   "description": "Team collaboration software using markdown",
   "tags": [
     "wiki",
@@ -48,24 +48,29 @@
     "cross-env": "^7.0.0",
     "dotenv-flow": "^3.2.0",
     "npm-run-all": "^4.1.5",
+    "ts-deepmerge": "^3.0.0",
     "tslib": "^2.3.1"
   },
   "devDependencies": {
+    "@swc/core": "^1.2.239",
+    "@swc/helpers": "^0.4.7",
     "@testing-library/cypress": "^8.0.2",
+    "@types/css-modules": "^1.0.2",
     "@types/jest": "^26.0.22",
-    "@types/node": "^14.14.35",
+    "@types/node": "^17.0.43",
     "@types/rewire": "^2.5.28",
-    "@typescript-eslint/eslint-plugin": "^4.28.5",
-    "@typescript-eslint/parser": "^4.28.5",
+    "@typescript-eslint/eslint-plugin": "^5.0.0",
+    "@typescript-eslint/parser": "^5.0.0",
     "cypress": "^9.2.0",
-    "eslint": "^7.31.0",
+    "eslint": "^8.18.0",
+    "eslint-config-next": "^12.1.6",
     "eslint-config-weseek": "^2.1.0",
-    "eslint-import-resolver-typescript": "^2.4.0",
-    "eslint-plugin-import": "^2.23.4",
-    "eslint-plugin-jest": "^24.3.2",
-    "eslint-plugin-react": "^7.24.0",
-    "eslint-plugin-react-hooks": "^4.2.0",
-    "jest": "^27.0.6",
+    "eslint-import-resolver-typescript": "^3.2.5",
+    "eslint-plugin-import": "^2.26.0",
+    "eslint-plugin-jest": "^26.5.3",
+    "eslint-plugin-react": "^7.30.1",
+    "eslint-plugin-react-hooks": "^4.6.0",
+    "jest": "^28.1.3",
     "jest-date-mock": "^1.0.8",
     "jest-localstorage-mock": "^2.4.14",
     "lerna": "^4.0.0",
@@ -80,7 +85,7 @@
     "shipjs": "^0.24.1",
     "stylelint": "^14.2.0",
     "stylelint-config-recess-order": "^3.0.0",
-    "ts-jest": "^27.0.4",
+    "ts-jest": "^28.0.7",
     "ts-node": "^10.9.1",
     "tsconfig-paths": "^3.9.0",
     "typescript": "~4.7",

+ 0 - 0
packages/plugin-attachment-refs/.eslintignore → packages-obsolete/plugin-attachment-refs/.eslintignore


+ 0 - 0
packages/plugin-attachment-refs/.gitignore → packages-obsolete/plugin-attachment-refs/.gitignore


+ 0 - 0
packages/plugin-attachment-refs/README.md → packages-obsolete/plugin-attachment-refs/README.md


+ 4 - 3
packages/plugin-attachment-refs/package.json → packages-obsolete/plugin-attachment-refs/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/plugin-attachment-refs",
-  "version": "5.1.5-RC.0",
+  "version": "6.0.0-RC.9",
   "description": "GROWI Plugin to add ref/refimg/refs/refsimg tags",
   "license": "MIT",
   "keywords": [
@@ -16,6 +16,7 @@
     "build": "run-p build:*",
     "build:cjs": "tsc -p tsconfig.build.cjs.json && tsc-alias -p tsconfig.build.cjs.json",
     "build:esm": "tsc -p tsconfig.build.esm.json && tsc-alias -p tsconfig.build.esm.json",
+    "clean": "npx -y shx rm -rf dist",
     "lint:js": "eslint **/*.{js,jsx,ts,tsx}",
     "lint:styles": "stylelint src/**/*.scss src/**/*.css",
     "lint": "run-p lint:*",
@@ -32,7 +33,7 @@
   "devDependencies": {
     "eslint-plugin-regex": "^1.8.0",
     "npm-run-all": "^4.1.5",
-    "react": "^16.8.3",
-    "react-dom": "^16.8.3"
+    "react": "^18.2.0",
+    "react-dom": "^18.2.0"
   }
 }

+ 0 - 0
packages/plugin-attachment-refs/src/client-entry.js → packages-obsolete/plugin-attachment-refs/src/client-entry.js


+ 0 - 0
packages/plugin-attachment-refs/src/client/css/index.css → packages-obsolete/plugin-attachment-refs/src/client/css/index.css


+ 5 - 3
packages/plugin-attachment-refs/src/client/js/components/AttachmentList.jsx → packages-obsolete/plugin-attachment-refs/src/client/js/components/AttachmentList.jsx

@@ -1,11 +1,11 @@
+import React from 'react';
+
 import { Attachment } from '@growi/ui';
 import axios from 'axios'; // import axios from growi dependencies
 import PropTypes from 'prop-types';
-import React from 'react';
 
 // eslint-disable-next-line import/no-unresolved
 
-import styles from '../../css/index.css';
 import RefsContext from '../util/RefsContext';
 import TagCacheManagerFactory from '../util/TagCacheManagerFactory';
 
@@ -13,6 +13,8 @@ import TagCacheManagerFactory from '../util/TagCacheManagerFactory';
 
 import ExtractedAttachments from './ExtractedAttachments';
 
+import styles from '../../css/index.css';
+
 const AttachmentLink = Attachment;
 
 export default class AttachmentList extends React.Component {
@@ -32,7 +34,7 @@ export default class AttachmentList extends React.Component {
     this.tagCacheManager = TagCacheManagerFactory.getInstance();
   }
 
-  async componentWillMount() {
+  async UNSAFE_componentWillMount() {
     const { refsContext } = this.props;
 
     // get state object cache

+ 2 - 1
packages/plugin-attachment-refs/src/client/js/components/ExtractedAttachments.jsx → packages-obsolete/plugin-attachment-refs/src/client/js/components/ExtractedAttachments.jsx

@@ -1,5 +1,6 @@
-import PropTypes from 'prop-types';
 import React from 'react';
+
+import PropTypes from 'prop-types';
 import Carousel, { Modal, ModalGateway } from 'react-images';
 
 import RefsContext from '../util/RefsContext';

+ 0 - 0
packages/plugin-attachment-refs/src/client/js/util/GalleryContext.js → packages-obsolete/plugin-attachment-refs/src/client/js/util/GalleryContext.js


+ 2 - 1
packages/plugin-attachment-refs/src/client/js/util/Interceptor/RefsPostRenderInterceptor.js → packages-obsolete/plugin-attachment-refs/src/client/js/util/Interceptor/RefsPostRenderInterceptor.js

@@ -1,5 +1,6 @@
-import { BasicInterceptor } from '@growi/core';
 import React from 'react';
+
+import { BasicInterceptor } from '@growi/core';
 import ReactDOM from 'react-dom';
 
 

+ 0 - 0
packages/plugin-attachment-refs/src/client/js/util/Interceptor/RefsPreRenderInterceptor.js → packages-obsolete/plugin-attachment-refs/src/client/js/util/Interceptor/RefsPreRenderInterceptor.js


+ 0 - 0
packages/plugin-attachment-refs/src/client/js/util/RefsContext.js → packages-obsolete/plugin-attachment-refs/src/client/js/util/RefsContext.js


+ 0 - 0
packages/plugin-attachment-refs/src/client/js/util/TagCacheManagerFactory.js → packages-obsolete/plugin-attachment-refs/src/client/js/util/TagCacheManagerFactory.js


+ 0 - 0
packages/plugin-attachment-refs/src/index.js → packages-obsolete/plugin-attachment-refs/src/index.js


+ 0 - 0
packages/plugin-attachment-refs/src/server-entry.js → packages-obsolete/plugin-attachment-refs/src/server-entry.js


+ 0 - 0
packages/plugin-attachment-refs/src/server/routes/index.js → packages-obsolete/plugin-attachment-refs/src/server/routes/index.js


+ 0 - 0
packages/plugin-attachment-refs/src/server/routes/refs.js → packages-obsolete/plugin-attachment-refs/src/server/routes/refs.js


+ 0 - 0
packages/plugin-attachment-refs/src/utils/logger/index.ts → packages-obsolete/plugin-attachment-refs/src/utils/logger/index.ts


+ 0 - 0
packages/plugin-attachment-refs/tsconfig.base.json → packages-obsolete/plugin-attachment-refs/tsconfig.base.json


+ 0 - 0
packages/plugin-attachment-refs/tsconfig.build.cjs.json → packages-obsolete/plugin-attachment-refs/tsconfig.build.cjs.json


+ 0 - 0
packages/plugin-attachment-refs/tsconfig.build.esm.json → packages-obsolete/plugin-attachment-refs/tsconfig.build.esm.json


+ 10 - 0
packages-obsolete/plugin-attachment-refs/tsconfig.json

@@ -0,0 +1,10 @@
+{
+  "extends": "./tsconfig.base.json",
+  "compilerOptions": {
+    "baseUrl": ".",
+    "paths": {
+      "~/*": ["./src/*"],
+      "@growi/*": ["../*/src"]
+    }
+  }
+}

+ 0 - 1
packages/app/.env.development

@@ -7,7 +7,6 @@ MIGRATIONS_DIR=src/migrations/
 APP_SITE_URL=http://localhost:3000
 FILE_UPLOAD=mongodb
 # MONGO_GRIDFS_TOTAL_LIMIT=10485760
-MATHJAX=1
 # NO_CDN=true
 MONGO_URI="mongodb://mongo:27017/growi"
 # REDIS_URI="http://redis:6379"

+ 5 - 0
packages/app/.eslintignore

@@ -1,6 +1,11 @@
+/_obsolete/**
 /dist/**
+/transpiled/**
 /public/**
+/config/next-i18next.config.js
 /src/client/legacy/thirdparty-js/**
 /src/client/util/reveal/plugins/markdown.js
 /src/linter-checker/**
+/src/utils/next.config.utils.js
 /tmp/**
+/next-env.d.ts

+ 12 - 3
packages/app/.eslintrc.js

@@ -1,7 +1,6 @@
 module.exports = {
   extends: [
-    'weseek/react',
-    'weseek/typescript',
+    'next/core-web-vitals',
   ],
   plugins: [
     'regex',
@@ -39,9 +38,19 @@ module.exports = {
     '@typescript-eslint/no-var-requires': 'off',
 
     // set 'warn' temporarily -- 2021.08.02 Yuki Takei
-    '@typescript-eslint/explicit-module-boundary-types': ['warn'],
     '@typescript-eslint/no-use-before-define': ['warn'],
     '@typescript-eslint/no-this-alias': ['warn'],
     'jest/no-done-callback': ['warn'],
   },
+  overrides: [
+    {
+      // enable the rule specifically for TypeScript files
+      files: ['*.ts', '*.tsx'],
+      rules: {
+        // '@typescript-eslint/explicit-module-boundary-types': ['error'],
+        // set 'warn' temporarily -- 2022.07.25 Yuki Takei
+        '@typescript-eslint/explicit-module-boundary-types': ['warn'],
+      },
+    },
+  ],
 };

+ 5 - 2
packages/app/.gitignore

@@ -8,14 +8,17 @@ test/cypress/videos
 .reg
 
 # dist
+/build/
 /dist/
 /transpiled/
-/report/
 /public/static/js
 /public/static/styles
 /public/uploads
 /tmp/
-*.d.ts
+
+# transpiled configuration files for production build
+/config/next-i18next.config.js
+/src/utils/next.config.utils.js
 
 # dist (for GROWI v4.x and below)
 /public/*.chunk.js

+ 1 - 0
packages/app/config/webpack.common.js → packages/app/_obsolete/config/webpack.common.js

@@ -1,3 +1,4 @@
+/* eslint-disable */
 /**
  * @author: Yuki Takei <yuki@weseek.co.jp>
  */

+ 1 - 0
packages/app/config/webpack.dev.dll.js → packages/app/_obsolete/config/webpack.dev.dll.js

@@ -1,3 +1,4 @@
+/* eslint-disable */
 /**
  * @author: Yuki Takei <yuki@weseek.co.jp>
  */

+ 1 - 0
packages/app/config/webpack.dev.js → packages/app/_obsolete/config/webpack.dev.js

@@ -1,3 +1,4 @@
+/* eslint-disable */
 /**
  * @author: Yuki Takei <yuki@weseek.co.jp>
  */

+ 1 - 0
packages/app/config/webpack.prod.js → packages/app/_obsolete/config/webpack.prod.js

@@ -1,3 +1,4 @@
+/* eslint-disable */
 /**
  * @author: Yuki Takei <yuki@weseek.co.jp>
  */

+ 4 - 16
packages/app/src/client/app.jsx → packages/app/_obsolete/src/client/app.jsx

@@ -10,7 +10,7 @@ import { Provider } from 'unstated';
 import ContextExtractor from '~/client/services/ContextExtractor';
 import EditorContainer from '~/client/services/EditorContainer';
 import PageContainer from '~/client/services/PageContainer';
-import IdenticalPathPage from '~/components/IdenticalPathPage';
+import { IdenticalPathPage } from '~/components/IdenticalPathPage';
 import PrivateLegacyPages from '~/components/PrivateLegacyPages';
 import loggerFactory from '~/utils/logger';
 import { swrGlobalConfiguration } from '~/utils/swr-utils';
@@ -20,28 +20,24 @@ import Fab from '../components/Fab';
 import ForbiddenPage from '../components/ForbiddenPage';
 import RecentlyCreatedIcon from '../components/Icons/RecentlyCreatedIcon';
 import InAppNotificationPage from '../components/InAppNotification/InAppNotificationPage';
-import MaintenanceModeContent from '../components/MaintenanceModeContent';
 import PersonalSettings from '../components/Me/PersonalSettings';
 import MyDraftList from '../components/MyDraftList/MyDraftList';
 import GrowiContextualSubNavigation from '../components/Navbar/GrowiContextualSubNavigation';
 import GrowiSubNavigationSwitcher from '../components/Navbar/GrowiSubNavigationSwitcher';
 import NotFoundPage from '../components/NotFoundPage';
-import Page from '../components/Page';
+import { Page } from '../components/Page';
 import DisplaySwitcher from '../components/Page/DisplaySwitcher';
-import FixPageGrantAlert from '../components/Page/FixPageGrantAlert';
 import RedirectedAlert from '../components/Page/RedirectedAlert';
 import ShareLinkAlert from '../components/Page/ShareLinkAlert';
-import TrashPageAlert from '../components/Page/TrashPageAlert';
-import PageComment from '../components/PageComment';
+import { PageComment } from '../components/PageComment';
 import CommentEditorLazyRenderer from '../components/PageComment/CommentEditorLazyRenderer';
 import PageContentFooter from '../components/PageContentFooter';
 import BookmarkList from '../components/PageList/BookmarkList';
 import PageStatusAlert from '../components/PageStatusAlert';
-import PageTimeline from '../components/PageTimeline';
+import { PageTimeline } from '../components/PageTimeline';
 import RecentCreated from '../components/RecentCreated/RecentCreated';
 import { SearchPage } from '../components/SearchPage';
 import Sidebar from '../components/Sidebar';
-import TagPage from '../components/TagPage';
 import TrashPageList from '../components/TrashPageList';
 
 import { appContainer, componentMappings } from './base';
@@ -77,14 +73,11 @@ Object.assign(componentMappings, {
   'identical-path-page': <IdenticalPathPage />,
 
   // 'revision-history': <PageHistory pageId={pageId} />,
-  'tags-page': <TagPage />,
 
   'grw-page-status-alert-container': <PageStatusAlert />,
 
   'maintenance-mode-content': <MaintenanceModeContent />,
 
-  'trash-page-alert': <TrashPageAlert />,
-
   'trash-page-list-container': <TrashPageList />,
 
   'not-found-page': <NotFoundPage />,
@@ -116,11 +109,6 @@ if (pageContainer.state.pageId != null) {
 
     'recent-created-icon': <RecentlyCreatedIcon />,
   });
-  if (!pageContainer.state.isEmpty) {
-    Object.assign(componentMappings, {
-      'fix-page-grant-alert': <FixPageGrantAlert />,
-    });
-  }
 }
 if (pageContainer.state.creator != null) {
   Object.assign(componentMappings, {

+ 2 - 5
packages/app/src/client/base.jsx → packages/app/_obsolete/src/client/base.jsx

@@ -3,7 +3,6 @@ import React from 'react';
 import EventEmitter from 'events';
 
 import AppContainer from '~/client/services/AppContainer';
-import SocketIoContainer from '~/client/services/SocketIoContainer';
 import { DescendantsPageListModal } from '~/components/DescendantsPageListModal';
 import PutbackPageModal from '~/components/PutbackPageModal';
 import ShortcutsModal from '~/components/ShortcutsModal';
@@ -13,8 +12,8 @@ import loggerFactory from '~/utils/logger';
 
 import EmptyTrashModal from '../components/EmptyTrashModal';
 import HotkeysManager from '../components/Hotkeys/HotkeysManager';
-import GrowiNavbar from '../components/Navbar/GrowiNavbar';
-import GrowiNavbarBottom from '../components/Navbar/GrowiNavbarBottom';
+import { GrowiNavbar } from '../components/Navbar/GrowiNavbar';
+import { GrowiNavbarBottom } from '../components/Navbar/GrowiNavbarBottom';
 import PageAccessoriesModal from '../components/PageAccessoriesModal';
 import PageCreateModal from '../components/PageCreateModal';
 import PageDeleteModal from '../components/PageDeleteModal';
@@ -35,8 +34,6 @@ window.interceptorManager = new InterceptorManager();
 
 // create unstated container instance
 const appContainer = new AppContainer();
-// eslint-disable-next-line no-unused-vars
-const socketIoContainer = new SocketIoContainer(appContainer);
 
 appContainer.initApp();
 

+ 5 - 0
packages/app/_obsolete/src/client/boot.js

@@ -0,0 +1,5 @@
+import {
+  applyOldIos,
+} from './util/old-ios';
+
+applyOldIos();

+ 0 - 0
packages/app/src/client/installer.jsx → packages/app/_obsolete/src/client/installer.jsx


+ 0 - 0
packages/app/src/client/nologin.jsx → packages/app/_obsolete/src/client/nologin.jsx


+ 0 - 0
packages/app/src/client/plugin.js → packages/app/_obsolete/src/client/plugin.js


+ 26 - 22
packages/app/src/client/services/AppContainer.js → packages/app/_obsolete/src/client/services/AppContainer.js

@@ -1,9 +1,6 @@
 import { Container } from 'unstated';
 
-
-import GrowiRenderer, { generatePreviewRenderer } from '~/services/renderer/growi-renderer';
-
-import { i18nFactory } from '../util/i18n';
+// import { i18nFactory } from '../util/i18n';
 
 /**
  * Service container related to options for Application
@@ -23,7 +20,7 @@ export default class AppContainer extends Container {
       const currentUser = JSON.parse(currentUserElem.textContent);
       userLocaleId = currentUser?.lang;
     }
-    this.i18n = i18nFactory(userLocaleId);
+    // this.i18n = i18nFactory(userLocaleId);
 
     this.containerInstances = {};
     this.componentInstances = {};
@@ -59,17 +56,19 @@ export default class AppContainer extends Container {
   }
 
   injectToWindow() {
-    window.appContainer = this;
+    // for fix lint error
+
+    // window.appContainer = this;
 
-    const growiRenderer = new GrowiRenderer(this.getConfig());
-    growiRenderer.init();
+    // const growiRenderer = new GrowiRenderer(this.getConfig());
+    // growiRenderer.init();
 
-    window.growiRenderer = growiRenderer;
+    // window.growiRenderer = growiRenderer;
 
-    // backward compatibility
-    window.crowi = this;
-    window.crowiRenderer = window.growiRenderer;
-    window.crowiPlugin = window.growiPlugin;
+    // // backward compatibility
+    // window.crowi = this;
+    // window.crowiRenderer = window.growiRenderer;
+    // window.crowiPlugin = window.growiPlugin;
   }
 
   getConfig() {
@@ -105,25 +104,30 @@ export default class AppContainer extends Container {
     return this.containerInstances[className];
   }
 
+
+  /*
+  * Note: Use globalEmitter instaead of registerComponentInstance and getComponentInstance
+  */
+
   /**
    * Register React component instance
    * @param {string} id
    * @param {object} instance React component instance
    */
-  registerComponentInstance(id, instance) {
-    if (instance == null) {
-      throw new Error('The specified instance must not be null');
-    }
+  // registerComponentInstance(id, instance) {
+  //   if (instance == null) {
+  //     throw new Error('The specified instance must not be null');
+  //   }
 
-    this.componentInstances[id] = instance;
-  }
+  //   this.componentInstances[id] = instance;
+  // }
 
   /**
    * Get registered React component instance
    * @param {string} id
    */
-  getComponentInstance(id) {
-    return this.componentInstances[id];
-  }
+  // getComponentInstance(id) {
+  //   return this.componentInstances[id];
+  // }
 
 }

+ 37 - 59
packages/app/src/client/services/ContextExtractor.tsx → packages/app/_obsolete/src/client/services/ContextExtractor.tsx

@@ -1,28 +1,28 @@
+/* eslint-disable */
 import React, { FC, useEffect, useState } from 'react';
 
 import { pagePathUtils } from '@growi/core';
 
 import { CustomWindow } from '~/interfaces/global';
 import { IUserUISettings } from '~/interfaces/user-ui-settings';
-import { generatePreviewRenderer } from '~/services/renderer/growi-renderer';
-import { useRendererSettings } from '~/stores/renderer';
+// import { generatePreviewRenderer } from '~/services/renderer/growi-renderer';
 import {
   useIsDeviceSmallerThanMd, useIsDeviceSmallerThanLg,
   usePreferDrawerModeByUser, usePreferDrawerModeOnEditByUser, useSidebarCollapsed, useCurrentSidebarContents, useCurrentProductNavWidth,
-  useSelectedGrant, useSelectedGrantGroupId, useSelectedGrantGroupName,
+  useSelectedGrant,
 } from '~/stores/ui';
 import { useSetupGlobalSocket, useSetupGlobalAdminSocket } from '~/stores/websocket';
 
 import {
   useSiteUrl,
-  useCurrentCreatedAt, useDeleteUsername, useDeletedAt, useHasChildren, useHasDraftOnHackmd,
-  useIsNotCreatable, useIsTrashPage, useIsUserPage, useLastUpdateUsername,
+  useDeleteUsername, useDeletedAt, useHasChildren, useHasDraftOnHackmd,
+  useIsTrashPage, useIsUserPage, useLastUpdateUsername,
   useCurrentPageId, usePageIdOnHackmd, usePageUser, useCurrentPagePath, useRevisionCreatedAt, useRevisionId, useRevisionIdHackmdSynced,
-  useShareLinkId, useShareLinksNumber, useTemplateTagData, useCurrentUpdatedAt, useCreator, useRevisionAuthor, useCurrentUser, useTargetAndAncestors,
-  useNotFoundTargetPathOrId, useIsSearchPage, useIsForbidden, useIsIdenticalPath, useHasParent,
+  useShareLinkId, useShareLinksNumber, useTemplateTagData, useCurrentUser, useTargetAndAncestors,
+  useIsSearchPage, useIsForbidden, useIsIdenticalPath, useHasParent,
   useIsAclEnabled, useIsSearchServiceConfigured, useIsSearchServiceReachable, useIsEnabledAttachTitleHeader,
-  useDefaultIndentSize, useIsIndentSizeForced, useCsrfToken, useIsEmptyPage, useEmptyPageId, useGrowiVersion, useAuditLogEnabled,
-  useActivityExpirationSeconds, useAuditLogAvailableActions, useGrowiRendererConfig,
+  useDefaultIndentSize, useIsIndentSizeForced, useCsrfToken, useGrowiVersion, useAuditLogEnabled,
+  useActivityExpirationSeconds, useAuditLogAvailableActions, useRendererConfig,
 } from '../../stores/context';
 
 const { isTrashPage: _isTrashPage } = pagePathUtils;
@@ -63,17 +63,9 @@ const ContextExtractorOnce: FC = () => {
   const path = decodeURI(mainContent?.getAttribute('data-path') || '');
   // assign `null` to avoid returning empty string
   const pageId = mainContent?.getAttribute('data-page-id') || null;
-  const emptyPageId = notFoundContext?.getAttribute('data-page-id') || null;
 
   const revisionCreatedAt = +(mainContent?.getAttribute('data-page-revision-created') || '');
 
-  // createdAt
-  const createdAtAttribute = mainContent?.getAttribute('data-page-created-at');
-  const createdAt: Date | null = (createdAtAttribute != null) ? new Date(createdAtAttribute) : null;
-  // updatedAt
-  const updatedAtAttribute = mainContent?.getAttribute('data-page-updated-at');
-  const updatedAt: Date | null = (updatedAtAttribute != null) ? new Date(updatedAtAttribute) : null;
-
   const deletedAt = mainContent?.getAttribute('data-page-deleted-at') || null;
   const isIdenticalPath = JSON.parse(mainContent?.getAttribute('data-identical-path') || jsonNull) ?? false;
   const isUserPage = JSON.parse(mainContent?.getAttribute('data-page-user') || jsonNull) != null;
@@ -91,8 +83,6 @@ const ContextExtractorOnce: FC = () => {
   const deleteUsername = mainContent?.getAttribute('data-page-delete-username') || null;
   const pageIdOnHackmd = mainContent?.getAttribute('data-page-id-on-hackmd') || null;
   const hasDraftOnHackmd = !!mainContent?.getAttribute('data-page-has-draft-on-hackmd');
-  const creator = JSON.parse(mainContent?.getAttribute('data-page-creator') || jsonNull);
-  const revisionAuthor = JSON.parse(mainContent?.getAttribute('data-page-revision-author') || jsonNull);
   const targetAndAncestors = JSON.parse(document.getElementById('growi-pagetree-target-and-ancestors')?.textContent || jsonNull);
   const notFoundTargetPathOrId = JSON.parse(notFoundContentForPt?.getAttribute('data-not-found-target-path-or-id') || jsonNull);
   const isSearchPage = document.getElementById('search-page') != null;
@@ -129,38 +119,36 @@ const ContextExtractorOnce: FC = () => {
   useActivityExpirationSeconds(configByContextHydrate.activityExpirationSeconds);
   useAuditLogAvailableActions(configByContextHydrate.auditLogAvailableActions);
   useGrowiVersion(configByContextHydrate.crowi.version);
-  useRendererSettings({
+  useRendererConfig({
     isEnabledLinebreaks: configByContextHydrate.isEnabledLinebreaks,
     isEnabledLinebreaksInComments: configByContextHydrate.isEnabledLinebreaksInComments,
     adminPreferredIndentSize: configByContextHydrate.adminPreferredIndentSize,
     isIndentSizeForced: configByContextHydrate.isIndentSizeForced,
-  });
-  useGrowiRendererConfig({
+
     isEnabledXssPrevention: configByContextHydrate.isEnabledXssPrevention,
     attrWhiteList: configByContextHydrate.attrWhiteList,
     tagWhiteList: configByContextHydrate.tagWhiteList,
     highlightJsStyleBorder: configByContextHydrate.highlightJsStyleBorder,
-    env: {
-      MATHJAX: configByContextHydrate.env.MATHJAX,
-      PLANTUML_URI: configByContextHydrate.env.PLANTUML_URI,
-      BLOCKDIAG_URI: configByContextHydrate.env.BLOCKDIAG_URI,
-    },
+
+    plantumlUri: configByContextHydrate.env.PLANTUML_URI,
+    blockdiagUri: configByContextHydrate.env.BLOCKDIAG_URI,
   });
+  // useNoCdn(configByContextHydrate.env.NO_CDN);
+  // useUploadableImage(configByContextHydrate.upload.image);
+  // useUploadableFile(configByContextHydrate.upload.file);
 
   // Page
-  useCurrentCreatedAt(createdAt);
   useDeleteUsername(deleteUsername);
   useDeletedAt(deletedAt);
   useHasChildren(hasChildren);
   useHasDraftOnHackmd(hasDraftOnHackmd);
   useIsIdenticalPath(isIdenticalPath);
-  useIsNotCreatable(isNotCreatable);
+  // useIsNotCreatable(isNotCreatable);
   useIsForbidden(isForbidden);
-  useIsTrashPage(isTrashPage);
+  // useIsTrashPage(isTrashPage);
   useIsUserPage(isUserPage);
   useLastUpdateUsername(lastUpdateUsername);
   useCurrentPageId(pageId);
-  useEmptyPageId(emptyPageId);
   usePageIdOnHackmd(pageIdOnHackmd);
   usePageUser(pageUser);
   useCurrentPagePath(path);
@@ -170,13 +158,8 @@ const ContextExtractorOnce: FC = () => {
   useShareLinkId(shareLinkId);
   useShareLinksNumber(shareLinksNumber);
   useTemplateTagData(templateTagData);
-  useCurrentUpdatedAt(updatedAt);
-  useCreator(creator);
-  useRevisionAuthor(revisionAuthor);
   useTargetAndAncestors(targetAndAncestors);
-  useNotFoundTargetPathOrId(notFoundTargetPathOrId);
   useIsSearchPage(isSearchPage);
-  useIsEmptyPage(isEmptyPage);
   useHasParent(hasParent);
 
   // Navigation
@@ -184,15 +167,10 @@ const ContextExtractorOnce: FC = () => {
   usePreferDrawerModeOnEditByUser();
   useIsDeviceSmallerThanMd();
 
-  // Navigation
-  usePreferDrawerModeByUser();
-  usePreferDrawerModeOnEditByUser();
-  useIsDeviceSmallerThanMd();
-
   // Editor
-  useSelectedGrant(grant);
-  useSelectedGrantGroupId(grantGroupId);
-  useSelectedGrantGroupName(grantGroupName);
+  // useSelectedGrant(grant);
+  // useSelectedGrantGroupId(grantGroupId);
+  // useSelectedGrantGroupName(grantGroupName);
 
   // SearchResult
   useIsDeviceSmallerThanLg();
@@ -204,21 +182,21 @@ const ContextExtractorOnce: FC = () => {
 
   // TODO: Remove this code when reveal.js is omitted. see: https://github.com/weseek/growi/pull/6223
   // Do not access this property from other than reveal.js plugins.
-  (window as CustomWindow).previewRenderer = generatePreviewRenderer(
-    {
-      isEnabledXssPrevention: configByContextHydrate.isEnabledXssPrevention,
-      attrWhiteList: configByContextHydrate.attrWhiteList,
-      tagWhiteList: configByContextHydrate.tagWhiteList,
-      highlightJsStyleBorder: configByContextHydrate.highlightJsStyleBorder,
-      env: {
-        MATHJAX: configByContextHydrate.env.MATHJAX,
-        PLANTUML_URI: configByContextHydrate.env.PLANTUML_URI,
-        BLOCKDIAG_URI: configByContextHydrate.env.BLOCKDIAG_URI,
-      },
-    },
-    null,
-    path,
-  );
+  // (window as CustomWindow).previewRenderer = generatePreviewRenderer(
+  //   {
+  //     isEnabledXssPrevention: configByContextHydrate.isEnabledXssPrevention,
+  //     attrWhiteList: configByContextHydrate.attrWhiteList,
+  //     tagWhiteList: configByContextHydrate.tagWhiteList,
+  //     highlightJsStyleBorder: configByContextHydrate.highlightJsStyleBorder,
+  //     env: {
+  //       MATHJAX: configByContextHydrate.env.MATHJAX,
+  //       PLANTUML_URI: configByContextHydrate.env.PLANTUML_URI,
+  //       BLOCKDIAG_URI: configByContextHydrate.env.BLOCKDIAG_URI,
+  //     },
+  //   },
+  //   null,
+  //   path,
+  // );
 
   return null;
 };

+ 26 - 119
packages/app/src/client/services/PageContainer.js → packages/app/_obsolete/src/client/services/PageContainer.js

@@ -7,9 +7,6 @@ import { Container } from 'unstated';
 import { EditorMode } from '~/stores/ui';
 import loggerFactory from '~/utils/logger';
 
-import { toastError } from '../util/apiNotification';
-import { apiPost } from '../util/apiv1-client';
-import { apiv3Post } from '../util/apiv3-client';
 import {
   DetachCodeBlockInterceptor,
   RestoreCodeBlockInterceptor,
@@ -54,9 +51,6 @@ export default class PageContainer extends Container {
       path,
       isEmpty: mainContent.getAttribute('data-page-is-empty'),
 
-      createdAt: mainContent.getAttribute('data-page-created-at'),
-      // please use useCurrentUpdatedAt instead
-      updatedAt: mainContent.getAttribute('data-page-updated-at'),
       deletedAt: mainContent.getAttribute('data-page-deleted-at') || null,
 
       isUserPage: JSON.parse(mainContent.getAttribute('data-page-user')) != null,
@@ -138,6 +132,7 @@ export default class PageContainer extends Container {
 
   /**
    * initialize state for markdown data
+   * [Already SWRized]
    */
   initStateMarkdown() {
     let pageContent = '';
@@ -177,38 +172,31 @@ export default class PageContainer extends Container {
    */
   updateStateAfterSave(page, tags, revision, editorMode) {
     // update state of PageContainer
-    const newState = {
-      pageId: page._id,
-      revisionId: revision._id,
-      revisionCreatedAt: new Date(revision.createdAt).getTime() / 1000,
-      remoteRevisionId: revision._id,
-      revisionAuthor: revision.author,
-      revisionIdHackmdSynced: page.revisionHackmdSynced,
-      hasDraftOnHackmd: page.hasDraftOnHackmd,
-      markdown: revision.body,
-      createdAt: page.createdAt,
-      updatedAt: page.updatedAt,
-    };
-    if (tags != null) {
-      newState.tags = tags;
-    }
-    this.setState(newState);
-
-    // Update PageEditor component
-    if (editorMode !== EditorMode.Editor) {
-      // eslint-disable-next-line no-undef
-      globalEmitter.emit('updateEditorValue', newState.markdown);
-    }
+    // const newState = {
+    //   pageId: page._id,
+    //   revisionId: revision._id,
+    //   revisionCreatedAt: new Date(revision.createdAt).getTime() / 1000,
+    //   remoteRevisionId: revision._id,
+    //   revisionAuthor: revision.author,
+    //   revisionIdHackmdSynced: page.revisionHackmdSynced,
+    //   hasDraftOnHackmd: page.hasDraftOnHackmd,
+    //   markdown: revision.body,
+    //   createdAt: page.createdAt,
+    //   updatedAt: page.updatedAt,
+    // };
+    // if (tags != null) {
+    //   newState.tags = tags;
+    // }
+    // this.setState(newState);
 
     // PageEditorByHackmd component
-    const pageEditorByHackmd = this.appContainer.getComponentInstance('PageEditorByHackmd');
-    if (pageEditorByHackmd != null) {
-      // reset
-      if (editorMode !== EditorMode.HackMD) {
-        pageEditorByHackmd.reset();
-      }
-    }
-
+    // const pageEditorByHackmd = this.appContainer.getComponentInstance('PageEditorByHackmd');
+    // if (pageEditorByHackmd != null) {
+    //   // reset
+    //   if (editorMode !== EditorMode.HackMD) {
+    //     pageEditorByHackmd.reset();
+    //   }
+    // }
   }
 
   /**
@@ -265,81 +253,6 @@ export default class PageContainer extends Container {
     return res;
   }
 
-  async saveAndReload(optionsToSave, editorMode) {
-    if (optionsToSave == null) {
-      const msg = '\'saveAndReload\' requires the \'optionsToSave\' param';
-      throw new Error(msg);
-    }
-
-    if (editorMode == null) {
-      logger.warn('\'saveAndReload\' requires the \'editorMode\' param');
-      return;
-    }
-
-    const { pageId, path } = this.state;
-    let { revisionId } = this.state;
-
-    const options = Object.assign({}, optionsToSave);
-
-    let markdown;
-    if (editorMode === EditorMode.HackMD) {
-      const pageEditorByHackmd = this.appContainer.getComponentInstance('PageEditorByHackmd');
-      markdown = await pageEditorByHackmd.getMarkdown();
-      // set option to sync
-      options.isSyncRevisionToHackmd = true;
-      revisionId = this.state.revisionIdHackmdSynced;
-    }
-    else {
-      const pageEditor = this.appContainer.getComponentInstance('PageEditor');
-      markdown = pageEditor.getMarkdown();
-    }
-
-    let res;
-    if (pageId == null) {
-      res = await this.createPage(path, markdown, options);
-    }
-    else {
-      res = await this.updatePage(pageId, revisionId, markdown, options);
-    }
-
-    const editorContainer = this.appContainer.getContainer('EditorContainer');
-    editorContainer.clearDraft(path);
-    window.location.href = path;
-
-    return res;
-  }
-
-  async createPage(pagePath, markdown, tmpParams) {
-    const socketIoContainer = this.appContainer.getContainer('SocketIoContainer');
-
-    // clone
-    const params = Object.assign(tmpParams, {
-      path: pagePath,
-      body: markdown,
-    });
-
-    const res = await apiv3Post('/pages/', params);
-    const { page, tags, revision } = res.data;
-
-    return { page, tags, revision };
-  }
-
-  async updatePage(pageId, revisionId, markdown, tmpParams) {
-    const socketIoContainer = this.appContainer.getContainer('SocketIoContainer');
-
-    // clone
-    const params = Object.assign(tmpParams, {
-      page_id: pageId,
-      revision_id: revisionId,
-      body: markdown,
-    });
-
-    const res = await apiPost('/pages.update', params);
-    if (!res.ok) {
-      throw new Error(res.error);
-    }
-    return res;
-  }
 
   showSuccessToastr() {
     toastr.success(undefined, 'Saved successfully', {
@@ -423,23 +336,17 @@ export default class PageContainer extends Container {
   retrieveMyBookmarkList() {
   }
 
-  async resolveConflict(markdown, editorMode) {
+  async resolveConflict(markdown, editorMode, optionsToSave) {
 
     const { pageId, remoteRevisionId, path } = this.state;
     const editorContainer = this.appContainer.getContainer('EditorContainer');
-    const options = editorContainer.getCurrentOptionsToSave();
-    const optionsToSave = Object.assign({}, options);
 
     const res = await this.updatePage(pageId, remoteRevisionId, markdown, optionsToSave);
 
     editorContainer.clearDraft(path);
     this.updateStateAfterSave(res.page, res.tags, res.revision, editorMode);
 
-    // Update PageEditor component
-    if (editorMode !== EditorMode.Editor) {
-      // eslint-disable-next-line no-undef
-      globalEmitter.emit('updateEditorValue', markdown);
-    }
+    window.globalEmitter.emit('updateEditorValue', markdown);
 
     editorContainer.setState({ tags: res.tags });
 

+ 144 - 0
packages/app/_obsolete/src/components/MyDraftList/Draft.tsx

@@ -0,0 +1,144 @@
+import React, { useState } from 'react';
+
+import { useTranslation } from 'next-i18next';
+import { CopyToClipboard } from 'react-copy-to-clipboard';
+import ReactMarkdown from 'react-markdown';
+import {
+  Collapse,
+  UncontrolledTooltip,
+} from 'reactstrap';
+
+import { useDraftOptions } from '~/stores/renderer';
+
+type DraftProps = {
+  path: string,
+  isExist: boolean,
+  index: number,
+  markdown: string,
+  clearDraft: (path: string) => void,
+}
+
+export const Draft = (props: DraftProps): JSX.Element => {
+
+  const {
+    path, isExist, index, markdown, clearDraft,
+  } = props;
+  const { t } = useTranslation();
+  const { data: rendererOptions } = useDraftOptions();
+  const [isPanelExpanded, setIsPanelExpanded] = useState(false);
+  const [showCopiedMessage, setShowCopiedMessage] = useState(false);
+
+  const changeToolTipLabel = () => {
+    setShowCopiedMessage(true);
+    setTimeout(() => {
+      setShowCopiedMessage(false);
+    }, 1000);
+  };
+
+  const collapsePanelHandler = () => {
+    setIsPanelExpanded(false);
+  };
+
+  const expandPanelHandler = () => {
+    setIsPanelExpanded(true);
+  };
+
+  const Controls = () => {
+
+    const tooltipTargetId = `draft-copied-tooltip_${index}`;
+
+    return (
+      <div className="icon-container">
+        {isExist
+          ? null
+          : (
+            <a
+              href={`${path}#edit`}
+              target="_blank"
+              rel="noopener noreferrer"
+              data-toggle="tooltip"
+              title={t('Edit')}
+            >
+              <i className="mx-2 icon-note" />
+            </a>
+          )
+        }
+        <span id={tooltipTargetId}>
+          <CopyToClipboard text={markdown} onCopy={changeToolTipLabel}>
+            <a
+              className="text-center draft-copy"
+            >
+              <i className="mx-2 ti-clipboard" />
+            </a>
+          </CopyToClipboard>
+        </span>
+        <UncontrolledTooltip placement="top" target={tooltipTargetId} fade={false} trigger="hover">
+          { showCopiedMessage && (
+            <strong>copied!</strong>
+          ) }
+          { !showCopiedMessage && (
+            <span>{t('Copy')}</span>
+          ) }
+        </UncontrolledTooltip>
+        <a
+          className="text-danger text-center"
+          data-toggle="tooltip"
+          data-placement="top"
+          title={t('Delete')}
+          onClick={() => { return clearDraft(path) }}
+        >
+          <i className="mx-2 icon-trash" />
+        </a>
+      </div>
+    );
+  };
+
+  const AccordionTitle = () => {
+    const iconClass = isPanelExpanded ? 'fa-rotate-90' : '';
+
+    return (
+      <span>
+
+        <span className="mr-2 draft-path" onClick={() => setIsPanelExpanded(!isPanelExpanded)}>
+          <i className={`fa fa-fw fa-angle-right mr-2 ${iconClass}`}></i>
+          {path}
+        </span>
+        { isExist && (
+          <span className="badge badge-warning">{t('page exists')}</span>
+        ) }
+        { !isExist && (
+          <span className="badge badge-info">draft</span>
+        ) }
+
+        <a className="ml-2" href={path}><i className="icon icon-login"></i></a>
+      </span>
+    );
+  };
+
+
+  return (
+    <div className="accordion draft-list-item" role="tablist">
+      <div className="card">
+
+        <div className="card-header d-flex" role="tab">
+          <AccordionTitle/>
+
+          <div className="flex-grow-1"></div>
+
+          <Controls/>
+        </div>
+
+        <Collapse isOpen={isPanelExpanded} onEntering={expandPanelHandler} onExiting={collapsePanelHandler}>
+          <div className="card-body">
+            { isPanelExpanded && (
+              <ReactMarkdown {...rendererOptions} className='wiki'>
+                {markdown}
+              </ReactMarkdown>
+            ) }
+          </div>
+        </Collapse>
+
+      </div>
+    </div>
+  );
+};

+ 11 - 10
packages/app/src/components/MyDraftList/MyDraftList.jsx → packages/app/_obsolete/src/components/MyDraftList/MyDraftList.jsx

@@ -1,16 +1,15 @@
 import React from 'react';
 
+import { useTranslation } from 'next-i18next';
 import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
 
-import EditorContainer from '~/client/services/EditorContainer';
 import PageContainer from '~/client/services/PageContainer';
 import { apiGet } from '~/client/util/apiv1-client';
 
 import PaginationWrapper from '../PaginationWrapper';
 import { withUnstatedContainers } from '../UnstatedUtils';
 
-import Draft from './Draft';
+import { Draft } from './Draft';
 
 class MyDraftList extends React.Component {
 
@@ -32,7 +31,7 @@ class MyDraftList extends React.Component {
     this.clearAllDrafts = this.clearAllDrafts.bind(this);
   }
 
-  async componentWillMount() {
+  async UNSAFE_componentWillMount() {
     await this.getDraftsFromLocalStorage();
     this.getCurrentDrafts(1);
   }
@@ -105,7 +104,7 @@ class MyDraftList extends React.Component {
   }
 
   clearDraft(path) {
-    this.props.editorContainer.clearDraft(path);
+    // this.props.editorContainer.clearDraft(path);
 
     this.setState((prevState) => {
       return {
@@ -116,7 +115,7 @@ class MyDraftList extends React.Component {
   }
 
   clearAllDrafts() {
-    this.props.editorContainer.clearAllDrafts();
+    // this.props.editorContainer.clearAllDrafts();
 
     this.setState({
       drafts: [],
@@ -172,10 +171,10 @@ class MyDraftList extends React.Component {
 }
 
 MyDraftList.propTypes = {
-  t: PropTypes.func.isRequired, // react-i18next
+  t: PropTypes.func.isRequired, // i18next
 
   pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
-  editorContainer: PropTypes.instanceOf(EditorContainer).isRequired,
+  // editorContainer: PropTypes.instanceOf(EditorContainer).isRequired,
 };
 
 const MyDraftListWrapperFC = (props) => {
@@ -183,9 +182,11 @@ const MyDraftListWrapperFC = (props) => {
   return <MyDraftList t={t} {...props} />;
 };
 
+export default MyDraftListWrapperFC;
+
 /**
  * Wrapper component for using unstated
  */
-const MyDraftListWrapper = withUnstatedContainers(MyDraftListWrapperFC, [PageContainer, EditorContainer]);
+// const MyDraftListWrapper = withUnstatedContainers(MyDraftListWrapperFC, [PageContainer, EditorContainer]);
 
-export default MyDraftListWrapper;
+// export default MyDraftListWrapper;

+ 5 - 0
packages/app/src/client/util/i18n.js → packages/app/_obsolete/src/util/i18n.js

@@ -1,3 +1,5 @@
+
+/* eslint-disable */
 import i18n from 'i18next';
 import LanguageDetector from 'i18next-browser-languagedetector';
 import { initReactI18next } from 'react-i18next';
@@ -14,6 +16,9 @@ Object.values(locales).forEach((locale) => {
   });
 });
 
+/*
+* Note: This file will be deleted. use "^/config/next-i18next.config" instead
+*/
 // extract metadata list from 'public/static/locales/${locale}/meta.json'
 export const localeMetadatas = Object.values(locales).map(locale => locale.meta);
 

+ 0 - 0
packages/app/src/client/util/old-ios.js → packages/app/_obsolete/src/util/old-ios.js


+ 0 - 56
packages/app/bin/generate-plugin-definitions-source.ts

@@ -1,56 +0,0 @@
-/**
- * the tool for genetion of plugin definitions source code
- *
- * @author Yuki Takei <yuki@weseek.co.jp>
- */
-import fs from 'graceful-fs';
-import normalize from 'normalize-path';
-import swig from 'swig-templates';
-
-import { PluginDefinitionV4 } from '@growi/core';
-
-import PluginUtils from '../src/server/plugins/plugin-utils';
-import loggerFactory from '../src/utils/logger';
-import { resolveFromRoot } from '../src/utils/project-dir-utils';
-
-const logger = loggerFactory('growi:bin:generate-plugin-definitions-source');
-
-
-const pluginUtils = new PluginUtils();
-
-const TEMPLATE = resolveFromRoot('bin/templates/plugin-definitions.js.swig');
-const OUT = resolveFromRoot('tmp/plugins/plugin-definitions.js');
-
-// list plugin names
-const pluginNames: string[] = pluginUtils.listPluginNames();
-logger.info('Detected plugins: ', pluginNames);
-
-async function main(): Promise<void> {
-
-  // get definitions
-  const definitions: PluginDefinitionV4[] = [];
-  for (const pluginName of pluginNames) {
-    // eslint-disable-next-line no-await-in-loop
-    const definition = await pluginUtils.generatePluginDefinition(pluginName, true);
-    if (definition != null) {
-      definitions.push(definition);
-    }
-  }
-
-  definitions.map((definition) => {
-    // convert backslash to slash
-    definition.entries = definition.entries.map((entryPath) => {
-      return normalize(entryPath);
-    });
-    return definition;
-  });
-
-  const compiledTemplate = swig.compileFile(TEMPLATE);
-  const code = compiledTemplate({ definitions });
-
-  // write
-  fs.writeFileSync(OUT, code);
-
-}
-
-main();

+ 1 - 2
packages/app/bin/github-actions/update-readme.sh

@@ -2,5 +2,4 @@
 
 cd docker
 
-sed -i -e "s/^\([*] \[\`\)[^\`]\+\(\`, \`5\.1\`, .\+\]\)\(.\+\/blob\/v\).\+\(\/packages\/app\/docker\/Dockerfile.\+\)$/\1${RELEASED_VERSION}\2\3${RELEASED_VERSION}\4/" README.md
-sed -i -e "s/^\([*] \[\`\)[^\`]\+\(\`, \`5\.1-nocdn\`, .\+\]\)\(.\+\/blob\/v\).\+\(\/packages\/app\/docker\/Dockerfile.\+\)$/\1${RELEASED_VERSION}-nocdn\2\3${RELEASED_VERSION}\4/" README.md
+sed -i -e "s/^\([*] \[\`\)[^\`]\+\(\`, \`6\.0\`, .\+\]\)\(.\+\/blob\/v\).\+\(\/packages\/app\/docker\/Dockerfile.\+\)$/\1${RELEASED_VERSION}\2\3${RELEASED_VERSION}\4/" README.md

+ 0 - 1
packages/app/config/ci/.env.local.for-ci

@@ -1,2 +1 @@
 FORMAT_NODE_LOG=true
-MATHJAX=1

+ 6 - 1
packages/app/migrate-mongo-config.js → packages/app/config/migrate-mongo-config.js

@@ -4,16 +4,21 @@
  *
  * @author Yuki Takei <yuki@weseek.co.jp>
  */
+const isProduction = process.env.NODE_ENV === 'production';
 
 const { URL } = require('url');
 
+const { initMongooseGlobalSettings, getMongoUri, mongoOptions } = isProduction
+  // 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
 const migrationsDir = process.env.MIGRATIONS_DIR;
 if (migrationsDir == null) {
   throw new Error('An env var MIGRATIONS_DIR must be set.');
 }
 
-const { initMongooseGlobalSettings, getMongoUri, mongoOptions } = require('@growi/core');
 
 initMongooseGlobalSettings();
 

+ 27 - 0
packages/app/config/next-i18next.config.ts

@@ -0,0 +1,27 @@
+import path from 'path';
+
+import { isServer, AllLang, Lang } from '@growi/core';
+import I18nextChainedBackend from 'i18next-chained-backend';
+import I18NextHttpBackend from 'i18next-http-backend';
+import I18NextLocalStorageBackend from 'i18next-localstorage-backend';
+
+const isDev = process.env.NODE_ENV === 'development';
+
+export const i18n = {
+  defaultLocale: Lang.en_US,
+  locales: AllLang,
+};
+export const defaultNS = 'translation';
+export const localePath = path.resolve('./public/static/locales');
+
+export const serializeConfig = false;
+export const use = isServer() ? [] : [I18nextChainedBackend];
+export const backend = {
+  backends: isServer() ? [] : [I18NextLocalStorageBackend, I18NextHttpBackend],
+  backendOptions: [
+    // options for i18next-localstorage-backend
+    { expirationTime: isDev ? 0 : 24 * 60 * 60 * 1000 }, // 1 day in production
+    // options for i18next-http-backend
+    { loadPath: '/static/locales/{{lng}}/{{ns}}.json' },
+  ],
+};

+ 1 - 1
packages/app/config/rate-limiter.ts

@@ -33,7 +33,7 @@ export const defaultConfig: IApiRateLimitEndpointMap = {
     maxRequests: MAX_REQUESTS_TIER_1,
     usersPerIpProspection: 100,
   },
-  '/login/activateInvited': {
+  '/invited': {
     method: 'POST',
     maxRequests: MAX_REQUESTS_TIER_2,
   },

+ 2 - 1
packages/app/cypress.json

@@ -13,5 +13,6 @@
   "viewportWidth": 1400,
   "viewportHeight": 1024,
 
-  "experimentalSessionSupport": true
+  "experimentalSessionSupport": true,
+  "defaultCommandTimeout": 30000
 }

+ 13 - 6
packages/app/docker/Dockerfile

@@ -26,6 +26,10 @@ ENV optDir /opt
 
 WORKDIR ${optDir}
 
+ENV nodeModulesGrowiPackagesDir ${optDir}/node_modules/@growi
+# expect a string seperated by commas (e.g. "A,B")
+ENV removeNodeModulesSymlinkPaths ${nodeModulesGrowiPackagesDir}/slackbot-proxy
+
 # copy files
 COPY --from=packages-json-picker ${optDir} .
 
@@ -33,6 +37,9 @@ COPY --from=packages-json-picker ${optDir} .
 RUN yarn config set network-timeout 300000
 RUN npx -y lerna bootstrap -- --frozen-lockfile
 
+# remove unnecessary symlinks
+RUN rm -f $(echo ${removeNodeModulesSymlinkPaths} | sed -e "s/,/ /g")
+
 # make artifacts
 RUN tar -cf node_modules.tar \
   node_modules \
@@ -55,7 +62,6 @@ RUN tar -cf node_modules.tar \
   packages/*/node_modules
 
 
-
 ##
 ## prebuilder-default
 ##
@@ -74,7 +80,6 @@ RUN tar -xf node_modules.tar
 RUN rm node_modules.tar
 
 
-
 ##
 ## prebuilder-nocdn
 ##
@@ -94,16 +99,18 @@ ENV optDir /opt
 
 WORKDIR ${optDir}
 
+# ignore eslint and stylelint
 COPY ["package.json", "lerna.json", "tsconfig.base.json", "./"]
 # copy all related packages
 COPY packages/app packages/app
 COPY packages/core packages/core
 COPY packages/codemirror-textlint packages/codemirror-textlint
-COPY packages/plugin-attachment-refs packages/plugin-attachment-refs
-COPY packages/plugin-lsx packages/plugin-lsx
-COPY packages/plugin-pukiwiki-like-linker packages/plugin-pukiwiki-like-linker
 COPY packages/slack packages/slack
 COPY packages/ui packages/ui
+COPY packages/remark-drawio-plugin packages/remark-drawio-plugin
+COPY packages/remark-growi-plugin packages/remark-growi-plugin
+COPY packages/remark-lsx packages/remark-lsx
+COPY packages/hackmd packages/hackmd
 
 # build
 RUN yarn lerna run build
@@ -111,11 +118,11 @@ RUN yarn lerna run build
 # make artifacts
 RUN tar -cf packages.tar \
   package.json \
+  packages/app/.next \
   packages/app/config \
   packages/app/public \
   packages/app/resource \
   packages/app/tmp \
-  packages/app/migrate-mongo-config.js \
   packages/app/.env.production* \
   packages/*/package.json \
   packages/*/dist

+ 3 - 4
packages/app/docker/README.md

@@ -10,10 +10,9 @@ GROWI Official docker image
 Supported tags and respective Dockerfile links
 ------------------------------------------------
 
-* [`5.1.4`, `5.1`, `5`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v5.1.4/packages/app/docker/Dockerfile)
-* [`5.1.4-nocdn`, `5.1-nocdn`, `5-nocdn`, `latest-nocdn` (Dockerfile)](https://github.com/weseek/growi/blob/v5.1.4/packages/app/docker/Dockerfile)
-* [`5.0.11`, `5.0` (Dockerfile)](https://github.com/weseek/growi/blob/v5.0.11/packages/app/docker/Dockerfile)
-* [`5.0.11-nocdn`, `5.0-nocdn` (Dockerfile)](https://github.com/weseek/growi/blob/v5.0.11/packages/app/docker/Dockerfile)
+* [`6.0.0`, `6.0`, `6`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v6.0.0/packages/app/docker/Dockerfile)
+* [`5.1.7`, `5.1`, `5`](https://github.com/weseek/growi/blob/v5.1.7/packages/app/docker/Dockerfile)
+* [`5.1.7-nocdn`, `5.1-nocdn`, `5-nocdn`](https://github.com/weseek/growi/blob/v5.1.7/packages/app/docker/Dockerfile)
 * [`4.5.23`, `4.5`, `4`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v4.5.23/packages/app/docker/Dockerfile)
 * [`4.5.23-nocdn`, `4.5-nocdn`, `4-nocdn`, `latest-nocdn` (Dockerfile)](https://github.com/weseek/growi/blob/v4.5.23/packages/app/docker/Dockerfile)
 

+ 8 - 1
packages/app/jest.config.js

@@ -5,7 +5,8 @@
 const MODULE_NAME_MAPPING = {
   '^\\^/(.+)$': '<rootDir>/$1',
   '^~/(.+)$': '<rootDir>/src/$1',
-  '^@growi/(.+)$': '<rootDir>/../$1/src',
+  '^@growi/([^/]+)$': '<rootDir>/../$1/src',
+  '^@growi/([^/]+)/(.+)$': '<rootDir>/../$1/src/$2',
 };
 
 module.exports = {
@@ -20,6 +21,11 @@ module.exports = {
 
       preset: 'ts-jest/presets/js-with-ts',
 
+      // transform ESM to CJS
+      transformIgnorePatterns: [
+        '/node_modules/(?!remark-gfm)/',
+      ],
+
       rootDir: '.',
       roots: ['<rootDir>'],
       testMatch: ['<rootDir>/test/unit/**/*.test.ts', '<rootDir>/test/unit/**/*.test.js'],
@@ -29,6 +35,7 @@ module.exports = {
       // Automatically clear mock calls and instances between every test
       clearMocks: true,
       moduleNameMapper: MODULE_NAME_MAPPING,
+
     },
     {
       displayName: 'server',

+ 5 - 0
packages/app/next-env.d.ts

@@ -0,0 +1,5 @@
+/// <reference types="next" />
+/// <reference types="next/image-types/global" />
+
+// NOTE: This file should not be edited
+// see https://nextjs.org/docs/basic-features/typescript for more information.

+ 114 - 0
packages/app/next.config.js

@@ -0,0 +1,114 @@
+/**
+ * == Notes for production build==
+ * The modules required from this file must be transpiled before running `next build`.
+ *
+ * See: https://github.com/vercel/next.js/discussions/35969#discussioncomment-2522954
+ */
+
+const { withSuperjson } = require('next-superjson');
+const { PHASE_PRODUCTION_BUILD, PHASE_PRODUCTION_SERVER } = require('next/constants');
+
+
+const setupTranspileModules = () => {
+  const eazyLogger = require('eazy-logger');
+  const { listScopedPackages, listPrefixedPackages } = require('./src/utils/next.config.utils');
+
+  // setup logger
+  const logger = eazyLogger.Logger({
+    prefix: '[{green:next.config.js}] ',
+    useLevelPrefixes: false,
+  });
+
+  // define transpiled packages for '@growi/*'
+  const packages = [
+    ...listScopedPackages(['@growi'], { ignorePackageNames: ['@growi/app'] }),
+    // listing ESM packages until experimental.esmExternals works correctly to avoid ERR_REQUIRE_ESM
+    'react-markdown',
+    'unified',
+    'markdown-table',
+    'character-entities-html4',
+    'comma-separated-tokens',
+    'decode-named-character-reference',
+    'hastscript',
+    'html-void-elements',
+    'is-absolute-url',
+    'longest-streak',
+    'property-information',
+    'space-separated-tokens',
+    'stringify-entities',
+    'trim-lines',
+    'trough',
+    'web-namespaces',
+    'vfile',
+    'zwitch',
+    'emoticon',
+    'direction', // for hast-util-select
+    'bcp-47-match', // for hast-util-select
+    ...listPrefixedPackages(['remark-', 'rehype-', 'hast-', 'mdast-', 'micromark-', 'unist-']),
+  ];
+
+  // logger.info('{bold:Listing scoped packages for transpiling:}');
+  // logger.unprefixed('info', `{grey:${JSON.stringify(packages, null, 2)}}`);
+
+  return require('next-transpile-modules')(packages);
+};
+
+
+module.exports = async(phase, { defaultConfig }) => {
+
+  const { i18n, localePath } = require('./config/next-i18next.config');
+
+  /** @type {import('next').NextConfig} */
+  const nextConfig = {
+    // == DOES NOT WORK
+    // see: https://github.com/vercel/next.js/discussions/27876
+    // experimental: { esmExternals: true }, // Prefer loading of ES Modules over CommonJS
+
+    eslint: {
+      ignoreDuringBuilds: true,
+    },
+    reactStrictMode: true,
+    swcMinify: true,
+    typescript: {
+      tsconfigPath: 'tsconfig.build.client.json',
+    },
+    pageExtensions: ['page.tsx', 'page.ts', 'page.jsx', 'page.js'],
+
+    i18n,
+
+    /** @param config {import('next').NextConfig} */
+    webpack(config, options) {
+      // Avoid "Module not found: Can't resolve 'fs'"
+      // See: https://stackoverflow.com/a/68511591
+      if (!options.isServer) {
+        config.resolve.fallback.fs = false;
+      }
+
+      // See: https://webpack.js.org/configuration/externals/
+      // This provides a way of excluding dependencies from the output bundles
+      config.externals.push('dtrace-provider');
+      config.externals.push('mongoose');
+
+      // setup i18next-hmr
+      if (!options.isServer && options.dev) {
+        const { I18NextHMRPlugin } = require('i18next-hmr/plugin');
+        config.plugins.push(new I18NextHMRPlugin({ localesDir: localePath }));
+      }
+
+      return config;
+    },
+
+  };
+
+  // production server
+  if (phase === PHASE_PRODUCTION_SERVER) {
+    return withSuperjson()(nextConfig);
+  }
+
+  const withTM = setupTranspileModules();
+  const withBundleAnalyzer = require('@next/bundle-analyzer')({
+    enabled: phase === PHASE_PRODUCTION_BUILD || process.env.ANALYZE === 'true',
+  });
+
+  return withBundleAnalyzer(withTM(withSuperjson()(nextConfig)));
+};

+ 86 - 90
packages/app/package.json

@@ -1,36 +1,34 @@
 {
   "name": "@growi/app",
-  "version": "5.1.5-RC.0",
+  "version": "6.0.0-RC.9",
   "license": "MIT",
   "scripts": {
     "//// for production": "",
-    "start": "yarn build && yarn server",
     "build": "run-p build:*",
-    "build:client": "yarn cross-env NODE_ENV=production webpack --config config/webpack.prod.js",
-    "build:server": "yarn cross-env NODE_ENV=production tsc -p tsconfig.build.server.json && tsc-alias -p tsconfig.build.server.json",
+    "start": "yarn next start",
+    "build:client": "yarn next build",
+    "prebuild:client": "tsc -p tsconfig.build.next.config.json",
+    "build:server": "yarn cross-env NODE_ENV=production tsc -p tsconfig.build.server.json && tsc-alias -p tsconfig.build.server-tsc-alias.json",
+    "postbuild:server": "npx -y shx echo \"Listing files under transpiled\" && npx -y shx ls transpiled && npx -y shx mv transpiled/src dist && npx -y shx cp -r transpiled/config/* config && npx -y shx cp -r src/server/views dist/server/ && npx -y shx rm -rf transpiled",
     "clean": "npx -y shx rm -rf dist transpiled",
     "prebuild": "yarn cross-env NODE_ENV=production run-p clean resources:*",
-    "postbuild": "npx -y shx mv transpiled/src dist && npx -y shx cp -r transpiled/config/* config && npx -y shx cp -r src/server/views dist/server/ && npx -y shx rm -rf transpiled",
     "server": "yarn cross-env NODE_ENV=production node -r dotenv-flow/config dist/server/app.js",
     "server:ci": "yarn server --ci",
     "preserver": "yarn cross-env NODE_ENV=production yarn migrate",
-    "migrate": "node -r dotenv-flow/config node_modules/.bin/migrate-mongo up",
+    "migrate": "node -r dotenv-flow/config node_modules/.bin/migrate-mongo up -f config/migrate-mongo-config.js",
     "//// for development": "",
-    "dev": "run-p dev:client dev:server",
-    "dev:client": "yarn cross-env NODE_ENV=development webpack --config config/webpack.dev.js --progress --watch",
-    "dev:client:nowatch": "yarn cross-env NODE_ENV=development webpack --config config/webpack.dev.js",
-    "dev:server": "yarn cross-env NODE_ENV=development ts-node-dev --inspect -r tsconfig-paths/register -r dotenv-flow/config --transpile-only src/server/app.ts",
-    "predev:client": "yarn cross-env NODE_ENV=development run-p resources:*",
-    "predev:server": "yarn cross-env NODE_ENV=development yarn dev:migrate:up",
+    "dev": "yarn cross-env NODE_ENV=development ts-node-dev -r tsconfig-paths/register -r dotenv-flow/config --inspect --transpile-only src/server/app.ts",
+    "predev": "yarn cross-env NODE_ENV=development run-p resources:* dev:migrate:up",
+    "dev:analyze": "yarn cross-env ANALYZE=true yarn dev",
     "dev:migrate-mongo": "yarn cross-env NODE_ENV=development yarn ts-node node_modules/.bin/migrate-mongo",
     "dev:migrate": "yarn dev:migrate:up",
-    "dev:migrate:create": "yarn dev:migrate-mongo create",
-    "dev:migrate:status": "yarn dev:migrate-mongo status",
-    "dev:migrate:up": "yarn dev:migrate-mongo up",
-    "dev:migrate:down": "yarn dev:migrate-mongo down",
+    "dev:migrate:create": "yarn dev:migrate-mongo create -f config/migrate-mongo-config.js",
+    "dev:migrate:status": "yarn dev:migrate-mongo status -f config/migrate-mongo-config.js",
+    "dev:migrate:up": "yarn dev:migrate-mongo up -f config/migrate-mongo-config.js",
+    "dev:migrate:down": "yarn dev:migrate-mongo down -f config/migrate-mongo-config.js",
     "cy:run": "cypress run --browser chrome",
     "//// for CI": "",
-    "dev:ci": "yarn dev:client:nowatch && yarn dev:server --ci",
+    "dev:ci": "yarn dev --ci",
     "predev:ci": "run-p resources:*",
     "lint:typecheck": "npx -y tsc",
     "lint:eslint": "eslint --quiet \"**/*.{js,jsx,ts,tsx}\"",
@@ -39,7 +37,7 @@
     "lint": "run-p lint:*",
     "test": "cross-env NODE_ENV=test jest --passWithNoTests -- ",
     "test:ci": "cross-env NODE_ENV=test jest",
-    "prelint:eslint": "yarn resources:plugin",
+    "// prelint:eslint": "yarn resources:plugin",
     "prelint:swagger2openapi": "yarn openapi:v3",
     "reg:run": "reg-suit run",
     "//// misc": "",
@@ -47,9 +45,11 @@
     "swagger-jsdoc": "swagger-jsdoc -o tmp/swagger.json -d config/swagger-definition.js",
     "openapi:v3": "yarn cross-env API_VERSION=3 yarn swagger-jsdoc -- \"src/server/routes/apiv3/**/*.js\" \"src/server/models/**/*.js\"",
     "openapi:v1": "yarn cross-env API_VERSION=1 yarn swagger-jsdoc -- \"src/server/*/*.js\" \"src/server/models/**/*.js\"",
-    "resources:plugin": "yarn ts-node bin/generate-plugin-definitions-source.ts",
-    "resources:dl-resources": "yarn ts-node bin/download-cdn-resources.ts",
-    "ts-node": "ts-node -r tsconfig-paths/register -r dotenv-flow/config --transpile-only"
+    "resources:hackmd": "yarn lerna run build --scope=@growi/hackmd",
+    "resources:dummy": "true",
+    "// resources:plugin": "yarn ts-node bin/generate-plugin-definitions-source.ts",
+    "// resources:dl-resources": "yarn ts-node bin/download-cdn-resources.ts",
+    "ts-node": "node -r ts-node/register -r tsconfig-paths/register -r dotenv-flow/config"
   },
   "// comments for dependencies": {
     "openid-client": "Node.js 12 or higher is required for openid-client@3 and above.",
@@ -57,6 +57,7 @@
     "string-width": "5.0.0 or above exports only ESM."
   },
   "dependencies": {
+    "@akebifiky/remark-simple-plantuml": "^1.0.2",
     "@aws-sdk/client-s3": "^3.58.0",
     "@aws-sdk/s3-request-presigner": "^3.58.0",
     "@browser-bunyan/console-formatted-stream": "^1.8.0",
@@ -64,12 +65,13 @@
     "@elastic/elasticsearch7": "npm:@elastic/elasticsearch@^7.17.0",
     "@godaddy/terminus": "^4.9.0",
     "@google-cloud/storage": "^5.8.5",
-    "@growi/codemirror-textlint": "^5.1.5-RC.0",
-    "@growi/core": "^5.1.5-RC.0",
-    "@growi/plugin-attachment-refs": "^5.1.5-RC.0",
-    "@growi/plugin-lsx": "^5.1.5-RC.0",
-    "@growi/plugin-pukiwiki-like-linker": "^5.1.5-RC.0",
-    "@growi/slack": "^5.1.5-RC.0",
+    "@growi/codemirror-textlint": "^6.0.0-RC.9",
+    "@growi/core": "^6.0.0-RC.9",
+    "@growi/hackmd": "^6.0.0-RC.9",
+    "@growi/remark-drawio-plugin": "^6.0.0-RC.9",
+    "@growi/remark-growi-plugin": "^6.0.0-RC.9",
+    "@growi/remark-lsx": "^6.0.0-RC.9",
+    "@growi/slack": "^6.0.0-RC.9",
     "@promster/express": "^7.0.2",
     "@promster/server": "^7.0.4",
     "@slack/events-api": "^3.0.0",
@@ -84,6 +86,7 @@
     "axios-retry": "^3.2.4",
     "body-parser": "^1.18.2",
     "browser-bunyan": "^1.8.0",
+    "bson-objectid": "^2.0.3",
     "bunyan": "^1.8.15",
     "check-node-version": "^4.1.0",
     "compression": "^1.7.4",
@@ -91,11 +94,13 @@
     "connect-mongo": "^4.6.0",
     "connect-redis": "^4.0.4",
     "cookie-parser": "^1.4.5",
-    "csrf": "^3.1.0",
+    "csurf": "^1.11.0",
+    "csv-to-markdown-table": "^1.1.0",
     "date-fns": "^2.23.0",
     "detect-indent": "^7.0.0",
     "diff": "^5.0.0",
     "diff_match_patch": "^0.1.1",
+    "ejs": "^3.1.8",
     "entities": "^2.0.0",
     "esa-node": "^0.2.2",
     "escape-string-regexp": "=4.0.0",
@@ -109,14 +114,16 @@
     "express-webpack-assets": "^0.1.0",
     "extensible-custom-error": "^0.0.7",
     "graceful-fs": "^4.1.11",
+    "hast-util-select": "^5.0.2",
     "helmet": "^4.6.0",
     "http-errors": "^2.0.0",
-    "i18next": "^20.3.2",
-    "i18next-express-middleware": "^2.0.0",
-    "i18next-node-fs-backend": "^2.1.3",
-    "i18next-sprintf-postprocessor": "^0.2.2",
+    "i18next-chained-backend": "^4.0.0",
+    "i18next-http-backend": "^2.0.0",
+    "i18next-localstorage-backend": "^4.0.0",
+    "is-absolute-url": "^4.0.1",
     "is-iso-date": "^0.0.1",
     "lucene-query-parser": "^1.2.0",
+    "markdown-table": "^1.1.1",
     "md5": "^2.2.1",
     "method-override": "^3.0.0",
     "migrate-mongo": "^8.2.3",
@@ -127,12 +134,16 @@
     "mongoose-unique-validator": "^2.0.3",
     "multer": "~1.4.0",
     "multer-autoreap": "^1.0.3",
+    "next": "^12.2.5",
+    "next-i18next": "^12.1.0",
+    "next-superjson": "^0.0.4",
+    "next-themes": "^0.2.0",
     "nocache": "^3.0.1",
     "nodemailer": "^6.6.2",
     "nodemailer-ses-transport": "~1.5.0",
     "openid-client": "^5.1.2",
     "p-retry": "^4.0.0",
-    "passport": "^0.5.0",
+    "passport": "^0.6.0",
     "passport-github": "^1.1.0",
     "passport-google-oauth20": "^2.0.0",
     "passport-http": "^0.3.0",
@@ -140,47 +151,74 @@
     "passport-local": "^1.0.0",
     "passport-saml": "^3.2.0",
     "passport-twitter": "^1.0.4",
+    "prism-themes": "^1.9.0",
     "prom-client": "^13.0.0",
     "rate-limiter-flexible": "^2.3.7",
+    "react": "^18.2.0",
+    "react-bootstrap-typeahead": "^5.2.2",
     "react-card-flip": "^1.0.10",
     "react-datepicker": "^4.7.0",
     "react-dnd": "^14.0.5",
     "react-dnd-html5-backend": "^14.1.0",
+    "react-dom": "^18.2.0",
     "react-image-crop": "^8.3.0",
+    "react-markdown": "^8.0.3",
     "react-multiline-clamp": "^2.0.0",
+    "react-scroll": "^1.8.7",
+    "react-syntax-highlighter": "^15.5.0",
+    "react-use-ripple": "^1.5.2",
+    "reactstrap": "^8.9.0",
     "reconnecting-websocket": "^4.4.0",
     "redis": "^3.0.2",
+    "rehype-katex": "^6.0.2",
+    "rehype-raw": "^6.1.1",
+    "rehype-sanitize": "^5.0.1",
+    "rehype-slug": "^5.0.1",
+    "rehype-toc": "^3.0.2",
+    "remark-breaks": "^3.0.2",
+    "remark-emoji": "^3.0.2",
+    "remark-gfm": "^3.0.1",
+    "remark-math": "^5.1.1",
+    "remark-wiki-link": "^1.0.4",
     "rimraf": "^3.0.0",
+    "simplebar-react": "^2.3.6",
     "socket.io": "^4.2.0",
+    "sticky-events": "^3.4.11",
     "stream-to-promise": "^3.0.0",
     "string-width": "=4.2.2",
+    "superjson": "^1.9.1",
     "swagger-jsdoc": "^6.1.0",
     "swig-templates": "^2.0.2",
+    "swr": "^1.3.0",
+    "throttle-debounce": "^3.0.1",
+    "toastr": "^2.1.2",
     "uglifycss": "^0.0.29",
     "universal-bunyan": "^0.9.2",
+    "unstated": "^2.1.1",
     "unzipper": "^0.10.5",
     "url-join": "^4.0.0",
+    "usehooks-ts": "^2.6.0",
     "validator": "^13.7.0",
     "ws": "^8.3.0",
     "xss": "^1.0.6"
   },
   "// comments for defDependencies": {
     "@handsontable/react": "v3 requires handsontable >= 7.0.0.",
-    "handsontable": "v7.0.0 or above is no loger MIT lisence.",
-    "ts-loader": "v9 is not compatible with webpack@5",
-    "ts-node": "v10 occurs 'SyntaxError: Cannot use import statement outside a module' when using migrate-mongo"
+    "handsontable": "v7.0.0 or above is no loger MIT lisence."
   },
   "devDependencies": {
-    "@alienfast/i18next-loader": "^1.1.4",
-    "@growi/ui": "^5.1.5-RC.0",
+    "@growi/ui": "^6.0.0-RC.9",
     "@handsontable/react": "=2.1.0",
+    "@icon/themify-icons": "1.0.1-alpha.3",
+    "@next/bundle-analyzer": "^12.2.3",
     "@types/compression": "^1.7.0",
     "@types/express": "^4.17.11",
     "@types/jquery": "^3.5.8",
     "@types/multer": "^1.4.5",
-    "@types/react-dom": "^17.0.9",
+    "@types/react-scroll": "^1.8.4",
     "autoprefixer": "^9.0.0",
-    "bootstrap": "^4.5.0",
+    "babel-loader": "^8.2.5",
+    "bootstrap": "^4.6.1",
     "browser-sync": "^2.27.7",
     "bunyan-debug": "^2.0.0",
     "cli": "~1.0.1",
@@ -188,82 +226,40 @@
     "colors": "=1.4.0",
     "connect-browser-sync": "^2.1.0",
     "core-js": "=2.6.9",
-    "css-loader": "^3.0.0",
-    "csv-to-markdown-table": "^1.0.1",
     "diff2html": "^3.1.2",
     "eazy-logger": "^3.1.0",
     "emoji-mart": "npm:panta82-emoji-mart@^3.0.1",
     "eslint-plugin-cypress": "^2.12.1",
     "eslint-plugin-regex": "^1.8.0",
-    "file-loader": "^5.0.2",
+    "font-awesome": "^4.7.0",
     "handsontable": "=6.2.2",
-    "hard-source-webpack-plugin": "^0.13.1",
-    "i18next-browser-languagedetector": "^4.0.1",
-    "imports-loader": "^0.8.0",
+    "i18next-hmr": "^1.11.0",
     "jquery-slimscroll": "^1.3.8",
-    "jquery-ui": "^1.12.1",
     "jquery.cookie": "~1.4.1",
     "jshint": "^2.13.0",
     "load-css-file": "^1.0.0",
-    "lodash-webpack-plugin": "^0.11.5",
-    "markdown-it": "^10.0.0",
-    "markdown-it-blockdiag": "^1.1.1",
-    "markdown-it-drawio-viewer": "^1.4.0",
-    "markdown-it-emoji": "^1.4.0",
-    "markdown-it-emoji-mart": "^0.1.1",
-    "markdown-it-footnote": "^3.0.1",
-    "markdown-it-mathjax": "^2.0.0",
-    "markdown-it-named-headers": "^0.0.4",
-    "markdown-it-plantuml": "^1.3.0",
-    "markdown-it-task-checkbox": "^1.0.6",
-    "markdown-it-toc-and-anchor-with-slugid": "^1.1.4",
-    "markdown-table": "^1.1.1",
-    "mini-css-extract-plugin": "^0.9.0",
+    "material-icons": "^1.11.3",
     "morgan": "^1.10.0",
-    "node-dev": "^4.0.0",
+    "next-transpile-modules": "^9.0.0",
     "normalize-path": "^3.0.0",
-    "null-loader": "^3.0.0",
-    "on-headers": "^1.0.1",
-    "optimize-css-assets-webpack-plugin": "^5.0.3",
     "penpal": "^4.0.0",
     "plantuml-encoder": "^1.2.5",
-    "postcss-loader": "^3.0.0",
     "prettier": "^1.19.1",
-    "react": "^16.8.3",
-    "react-bootstrap-typeahead": "^5.2.2",
     "react-codemirror2": "^6.0.0",
     "react-copy-to-clipboard": "^5.0.1",
-    "react-dom": "^16.8.3",
     "react-dropzone": "^11.2.4",
     "react-frame-component": "^4.0.0",
     "react-hotkeys": "^2.0.0",
-    "react-i18next": "^11.1.0",
     "react-waypoint": "^10.1.0",
-    "reactstrap": "^8.9.0",
+    "rehype-rewrite": "^3.0.6",
     "replacestream": "^4.0.3",
     "reveal.js": "^4.3.1",
-    "sass": "^1.43.4",
-    "sass-loader": "^10.1.1",
+    "sass": "^1.53.0",
+    "simple-line-icons": "^2.5.5",
     "simple-load-script": "^1.0.2",
-    "simplebar-react": "^2.3.6",
     "socket.io-client": "^4.2.0",
-    "sticky-events": "^3.4.11",
-    "style-loader": "^1.0.0",
-    "styled-components": "^5.0.1",
     "swagger2openapi": "^5.3.1",
-    "swr": "^1.1.2",
-    "terser-webpack-plugin": "^4.1.0",
-    "throttle-debounce": "^3.0.1",
-    "toastr": "^2.1.2",
-    "ts-loader": "^8.3.0",
-    "ts-node": "^9.1.1",
     "ts-node-dev": "^2.0.0",
-    "tsc-alias": "^1.2.9",
-    "tsconfig-paths-webpack-plugin": "^3.5.1",
-    "unstated": "^2.1.1",
-    "webpack": "^4.46.0",
-    "webpack-assets-manifest": "^3.1.1",
-    "webpack-bundle-analyzer": "^3.9.0",
-    "webpack-cli": "^4.9.1"
+    "tsc-alias": "^1.2.9"
   }
 }

BIN
packages/app/public/static/fonts/Lato-Bold-latin-ext.woff2


BIN
packages/app/public/static/fonts/Lato-Bold-latin.woff2


BIN
packages/app/public/static/fonts/Lato-Regular-latin-ext.woff2


BIN
packages/app/public/static/fonts/Lato-Regular-latin.woff2


BIN
packages/app/public/static/fonts/PressStart2P-latin-ext.woff2


BIN
packages/app/public/static/fonts/PressStart2P-latin.woff2


+ 345 - 12
packages/app/public/static/locales/en_US/admin/admin.json → packages/app/public/static/locales/en_US/admin.json

@@ -1,4 +1,284 @@
 {
+  "meta": {
+    "display_name": "English"
+  },
+  "wiki_management_home_page": "Wiki Management Home Page",
+  "last_login": "Last login",
+  "anyone_with_the_link": "anyone with the link",
+  "only_me": "only me",
+  "only_inside_the_group": "only inside the group",
+  "security_settings": {
+    "security_settings": "Security Settings",
+    "scope_of_page_disclosure": "Scope of page disclosure",
+    "set_point": "Set point",
+    "Guest Users Access": "Guest users access",
+    "always_hidden": "Always hidden",
+    "always_displayed": "Always displayed",
+    "displayed_or_hidden": "Displayed / Hidden",
+    "Fixed by env var": "This is fixed by the env var <code>{{key}}={{value}}</code>.",
+    "register_limitation": "Register limitation",
+    "register_limitation_desc": "Restriction of new users' registration",
+    "The whitelist of registration permission E-mail address": "The whitelist of registration permission E-mail address",
+    "users_without_account": "Users without account is not accessible",
+    "example": "Example",
+    "restrict_emails": "You can restrict email registration to your wiki by writing an email domain (beginning with @). ",
+    "for_example": " For example, if you would like to restrict registration to users within the growi.org domain, you can write ",
+    "in_this_case": "; in this case, only users within the growi.org domain would be able to register, and all other users would be rejected.",
+    "insert_single": "Please insert single e-mail address per line.",
+    "page_list_and_search_results": "Page list / Search results",
+    "page_listing_1": "Page listing/searching<br>restricted by 'Only me'",
+    "page_listing_1_desc": "Show pages that are restricted by 'Only me' option when listing/searching",
+    "page_listing_2": "Page listing/searching<br>restricted by User group",
+    "page_listing_2_desc": "Show pages that are restricted by User group when listing/searching",
+    "page_access_rights": "Page access",
+    "page_delete_rights": "Delete rights",
+    "page_delete": "Page Delete",
+    "page_delete_completely": "Page Delete Completely",
+    "other_options": "Other options",
+    "deletion_explain": "Restricts users who can trash the selected single page.",
+    "complete_deletion_explain": "Restricts users who can completely delete  selected single page.",
+    "recursive_deletion_explain": "Restricts users who can trash pages including descendants.",
+    "recursive_complete_deletion_explain": "Restricts users who can completely delete pages including descendants.",
+    "inherit": "Inherit(Use the same setting as for a single page)",
+    "admin_only": "Admin only",
+    "admin_and_author": "Admin and author",
+    "anyone": "Anyone",
+    "session": "Session",
+    "max_age": "Max age (msec)",
+    "max_age_desc": "Specifies the number (in milliseconds) to expire users session.<br>Default: 2592000000 (30days)",
+    "max_age_caution": "Restarting the server is required after you modify this value.",
+    "forced_update_desc": "Settings have been forcibly changed. Previous setting: ",
+    "page_delete_rights_caution": "The \"Delete / Delete All\" permission (including descendant pages) is forced to be stronger than the \"Delete / Completely Delete\" permission. <br> <br> Admin only > Admin and autor > Anyone",
+    "Authentication mechanism settings": "Authentication Mechanism Settings",
+    "setup_is_not_yet_complete": "Setup is not yet complete",
+    "xss_prevent_setting": "Prevent XSS(Cross Site Scripting)",
+    "xss_prevent_setting_link": "Go to Markdown Settings",
+    "callback_URL": "Callback URL",
+    "providerName": "Provider Name",
+    "issuerHost": "Issuer Host",
+    "scope": "Scope",
+    "desc_of_callback_URL": "Use it in the setting of the {{AuthName}} Identity provider",
+    "authorization_endpoint": "Authorization Endpoint",
+    "token_endpoint": "Token Endpoint",
+    "revocation_endpoint": "Revocation Endpoint",
+    "introspection_endpoint": "Introspection Endpoint",
+    "userinfo_endpoint": "UserInfo Endpoint",
+    "end_session_endpoint": "EndSessioin Endpoint",
+    "registration_endpoint": "Registration Endpoint",
+    "jwks_uri": "JSON Web Key Set URL",
+    "clientID": "Client ID",
+    "client_secret": "Client Secret",
+    "updated_general_security_setting": "Succeeded to update security setting",
+    "setup_not_completed_yet": "Setup not completed yet",
+    "guest_mode": {
+      "deny": "Deny (Registered users only)",
+      "readonly": "Accept (Guests can read only)"
+    },
+    "registration_mode": {
+      "open": "Open (Anyone can register)",
+      "restricted": "Restricted (Requires approval by administrators)",
+      "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",
+    "share_link_rights": "Share link rights",
+    "enable_link_sharing": "Enable link sharing",
+    "all_share_links": "All share links",
+    "configuration": " Configuration",
+    "optional": "Optional",
+    "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": "Password reset by users",
+      "enable_password_reset_by_users": "Enable password reset by users",
+      "password_reset_desc": "when forgot password, users are able to reset it by themselves.",
+      "email_authentication": "Email authentication on user registration",
+      "enable_email_authentication": "Enable email authentication",
+      "enable_email_authentication_desc": "Email authentication is going to be performed for user registration.",
+      "need_complete_mail_setting_warning": "To use the following functions, please complete the mail settings."
+    },
+    "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"
+    },
+    "Basic": {
+      "enable_basic": "Enable Basic",
+      "name": "Basic Authentication",
+      "desc_1": "Login with <code>username</code> in Authorization header.",
+      "desc_2": "User will be automatically generated if not exist.",
+      "updated_basic": "Succeeded to update Basic 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"
+      },
+      "Facebook": {
+        "name": "Facebook OAuth"
+      },
+      "Twitter": {
+        "enable_twitter": "Enable Twitter OAuth",
+        "name": "Twitter OAuth",
+        "register_1": "Access {{link}}",
+        "register_2": "Sign in Twitter",
+        "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_twitter": "Succeeded to update Twitter 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 %s when creating new users",
+        "register_1": "Contant to OIDC IdP Administrator",
+        "register_2": "Register your OIDC App with \"Authorization callback URL\" as <code>%s</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?",
+        "twitter": "How to configure Twitter 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": "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": "Enable/disable Notification",
+    "link_notification_help": "<strong>The page that is able to be viewed only by those who know the link 'Anyone with the link'</strong> is not notified always.",
+    "just_me_notification_help": "<strong>The page that is restricted by 'Only Me'</strong> is notify when the page edited.",
+    "group_notification_help": "<strong>The page that is restricted by 'User Group'</strong> is notify when the page edited.",
+    "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": "Not found the global notification id"
+  },
   "mailer_setup_required":"<a href='/admin/app'>Email settings</a> are required to send.",
   "admin_top": {
     "management_wiki": "Management Wiki",
@@ -20,8 +300,6 @@
     "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>"
   },
   "v5_page_migration": {
-    "page_tree_not_avaliable" : "Page tree feature is not available yet.",
-    "go_to_settings": "Go to settings to enable the feature",
     "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.",
     "migration_note": "Note: You will lose unique constraints from the page paths.",
     "upgrade_to_v5": "Convert to v5 compatibility",
@@ -51,9 +329,12 @@
     "site_name": "Site name",
     "sitename_change": "You can change site name which is used for header and HTML title.",
     "header_content": "The contents entered here will be shown in the header etc.",
-    "site_url_desc": "This is for the site URL setting.",
-    "site_url_warn": "Some features don't work because the site URL is not set.",
-    "siteurl_help": "Site full URL beginning from <code>http://</code> or <code>https://</code>.",
+    "site_url": {
+      "title": "Site URL settings",
+      "desc": "This is for the site URL setting.",
+      "warn": "Some features don't work because the site URL is not set.",
+      "help": "Site full URL beginning from <code>http://</code> or <code>https://</code>."
+    },
     "confidential_name": "Confidential name",
     "confidential_example": "ex): internal use only",
     "default_language": "Default language for new users",
@@ -99,13 +380,14 @@
     "custom_endpoint_change": "Input the URL of the endpoint of an object storage service like MinIO that has a S3-compatible API.  Amazon S3 is used if empty.",
     "plugin_settings": "Plugin settings",
     "enable_plugin_loading": "Enable plugin loading",
-    "load_plugins": "Load_plugins",
+    "load_plugins": "Load plugins",
     "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> ."
   },
-  "markdown_setting": {
+  "markdown_settings": {
+    "markdown_settings": "Markdown Settings",
     "lineBreak_header": "Line break setting",
     "lineBreak_desc": "You can change line break settings.",
     "lineBreak_options": {
@@ -148,7 +430,8 @@
       "import_recommended": "Import recommended {{target}}"
     }
   },
-  "customize_setting": {
+  "customize_settings": {
+    "customize_settings": "Customize",
     "default_sidebar_mode": {
       "title": "Default sidebar mode",
       "desc": "You can set the sidebar mode for new users and guests visiting the page.",
@@ -193,8 +476,6 @@
       "select_search_scope_children_as_default": "Select 'Only children of this tree' as default value of search range",
       "select_search_scope_children_as_default_desc": "When the setting value is off, 'All pages' is used as default value of search range."
     },
-    "code_highlight": "Code highlight",
-    "nocdn_desc": "This function is disabled when the environment variable <code>NO_CDN=true</code>.<br>Github style has been forcibly applied.",
     "custom_title": "Custom title",
     "custom_title_detail": "You can customize <code>&lt;title&gt;</code> tag. Following placeholders will be automatically replaced:",
     "custom_title_detail_placeholder1": "<code>&#123;&#123;sitename&#125;&#125;</code> - The site name of this wiki.",
@@ -216,6 +497,7 @@
     "delete_logo": "Delete Logo"
   },
   "importer_management": {
+    "import_data": "Import Data",
     "beta_warning": "This function is Beta.",
     "import_from": "Import from {{from}}",
     "import_growi_archive": "Import GROWI archive",
@@ -287,6 +569,7 @@
     "Directory_hierarchy_tag": "Directory hierarchy tag"
   },
   "export_management": {
+    "export_archive_data": "Export Archive Data",
     "exporting_collection_list": "Exporting Collection List",
     "exported_data_list": "Exported Archive Data List",
     "export_collections": "Export Collections",
@@ -297,7 +580,7 @@
     "export": "Export",
     "cancel": "Cancel",
     "file": "File",
-    "growi_version": "Growi Version",
+    "growi_version": "GROWI Version",
     "collections": "Collections",
     "exported_at": "Exported At",
     "export_menu": "Export Menu",
@@ -305,12 +588,14 @@
     "delete": "Delete"
   },
   "external_notification": {
+    "external_notification": "External Notification",
     "enabled": "Enabled",
     "disabled": "Disabled",
     "header_status": "Slack Integration Status",
     "caution_enabled": "CAUTION: Currently, notifications that are configured in this page will send only to the Slack Workspace set as primary."
   },
   "slack_integration": {
+    "slack_integration": "Slack Integration",
     "selecting_bot_types": {
       "slack_bot": "Slack bot",
       "detailed_explanation": "Detailed explanation",
@@ -422,12 +707,16 @@
     }
   },
   "slack_integration_legacy": {
+    "slack_integration_legacy": "Legacy Slack Integration",
+    "alert_disabled": "This 'Slack Legacy Intenfation' has been currently disabled since <a href='/admin/slack-integration'>New settings</a> are enabled",
     "alert_Pd": "This 'Legacy Slack Integration' is currently disabled because <a href='/admin/slack-integration'>the new settings</a> is enabled.",
     "alert_deplicated": "This 'Legacy Slack Integration' is outdated and will be discontinued in the future. Use <a href='/admin/slack-integration'>the new settings</a> instead. "
   },
   "user_management": {
+    "user_management": "User Management",
     "invite_users": "Temporarily issue a new user",
     "click_twice_same_checkbox": "You should check at least one checkbox.",
+    "status": "Status",
     "invite_modal": {
       "emails": "Emails (Possible to issue multiple people with new lines)",
       "description1":"Temporarily issue new users by email addresses.",
@@ -483,12 +772,14 @@
     "current_users": "Current users:"
   },
   "user_group_management": {
+    "user_group_management": "User Group Management",
     "create_group": "Create new group",
     "add_child_group": "Add child group",
     "remove_child_group": "Remove",
     "deny_create_group": "You can't create a new group with the current settings.",
     "group_name": "Group name",
     "group_example": "e.g. : Group1",
+    "child_user_group": "Child User Group",
     "parent_group": "Parent Group",
     "select_parent_group": "Select Parent Group",
     "release_parent_group": "Release parent group",
@@ -528,7 +819,32 @@
       "force_update_parents_description": "Enable this option to force the addition of missing users to the ancestor groups if they exist after changing a parent group."
     }
   },
+  "full_text_search_management": {
+    "full_text_search_management": "Full Text Search Management",
+    "elasticsearch_management": "Elasticsearch management",
+    "connection_status": "Connection status",
+    "connection_status_label_unconfigured": "UNCONFIGURED",
+    "connection_status_label_connected": "CONNECTED",
+    "connection_status_label_disconnected": "DISCONNECTED",
+    "connection_status_label_erroroccured": "ERROR OCCURED ON SEARCH SERVICE",
+    "indices_status": "Indices Status",
+    "indices_status_label_normalized": "NORMALIZED",
+    "indices_status_label_unnormalized": "REBUILDING or BROKEN",
+    "indices_summary": "Indices summary",
+    "reconnect": "Reconnect",
+    "reconnect_button": "Try to reconnect",
+    "reconnect_description": "Click the button to try to reconnect to Elasticsearch.",
+    "normalize": "Normalize",
+    "normalize_button": "Normalize indices",
+    "normalize_description": "Click the button to repair broken indices.",
+    "rebuild": "Rebuild",
+    "rebuild_button": "Rebuild index",
+    "rebuild_description_1": "Click the button to rebuild index and add all page datas.",
+    "rebuild_description_2": "This may take a while."
+  },
   "audit_log_management": {
+    "audit_log": "Audit Log",
+    "audit_log_settings": "Audit Log Settings",
     "user": "User",
     "username": "Username",
     "date": "Date",
@@ -549,6 +865,9 @@
       "log_type": "https://docs.growi.org/en/admin-guide/admin-cookbook/audit-log-setup.html#log-types"
     }
   },
+  "cloud_setting_management": {
+    "to_cloud_settings": "Open GROWI.cloud Settings"
+  },
   "audit_log_action_category": {
     "Page": "Page",
     "Comment": "Comment",
@@ -598,6 +917,10 @@
     "PAGE_DELETE_COMPLETELY": "Delete completely page",
     "PAGE_REVERT": "Revert page",
     "PAGE_EMPTY_TRASH": "Empty trash",
+    "PAGE_RECURSIVELY_RENAME": "Recursive page rename",
+    "PAGE_RECURSIVELY_DELETE": "Recursive page delete",
+    "PAGE_RECURSIVELY_DELETE_COMPLETELY": "Recursive page delete completely",
+    "PAGE_RECURSIVELY_REVERT": "Recursive page revert",
     "PAGE_SUBSCRIBE": "Subscribe page",
     "PAGE_UNSUBSCRIBE": "Unsubscribe page",
     "PAGE_EXPORT": "Export page",
@@ -615,7 +938,7 @@
     "SHARE_LINK_NOT_FOUND": "Page view (Not found share link)",
     "ATTACHMENT_ADD": "Add Attachment",
     "ATTACHMENT_REMOVE": "Delete Attachment",
-    "ACTION_ATTACHMENT_DOWNLOAD": "Download Attachment",
+    "ATTACHMENT_DOWNLOAD": "Download Attachment",
     "SEARCH_PAGE": "Page Search",
     "SEARCH_PAGE_VIEW": "Page view(Search results page)",
     "ADMIN_APP_SETTING_UPDATE": "Update App Settings",
@@ -715,5 +1038,15 @@
     "ADMIN_SEARCH_CONNECTION": "Attempting to reconnect to Elasticsearch",
     "ADMIN_SEARCH_INDICES_NORMALIZE": "Normalize of Elasticsearch indexes",
     "ADMIN_SEARCH_INDICES_REBUILD": "Rebuild Elasticsearch indexes"
+  },
+  "toaster": {
+    "give_user_admin": "Succeeded to give {{username}} admin",
+    "remove_user_admin": "Succeeded to remove {{username}} admin",
+    "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": "Succeeded to update share link setting",
+    "failed_to_reset_password":"Failed to reset password"
   }
 }

+ 100 - 0
packages/app/public/static/locales/en_US/commons.json

@@ -0,0 +1,100 @@
+{
+  "Show": "Show",
+  "Hide": "Hide",
+  "Add": "Add",
+  "Reset": "Reset",
+  "Sign out": "Logout",
+  "New": "New",
+
+  "meta": {
+    "display_name": "English"
+  },
+  "toaster": {
+    "create_succeeded": "Succeeded to create {{target}}",
+    "create_failed": "Failed to create {{target}}",
+    "update_successed": "Succeeded to update {{target}}",
+    "update_failed": "Failed to update {{target}}",
+
+    "remove_share_link_success": "Succeeded to remove {{shareLinkId}}",
+    "remove_share_link": "Succeeded to remove {{count}} share links"
+  },
+  "alert": {
+    "siteUrl_is_not_set": "'Site URL' is NOT set. Set it from the {{link}}",
+    "please_enable_mailer": "Please setup mailer first."
+  },
+  "headers": {
+    "app_settings": "App Settings"
+  },
+
+  "header_search_box": {
+    "label": {
+      "All pages": "All pages",
+      "This tree": "This tree"
+    },
+    "item_label": {
+      "All pages": "All pages",
+      "This tree": "Only children of this tree"
+    }
+  },
+
+  "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",
+    "no_notification": "You don't have any notificatios.",
+    "all": "All",
+    "unopend": "Unread",
+    "mark_all_as_read": "Mark all as read"
+  },
+
+  "personal_dropdown": {
+    "home": "Home",
+    "settings": "Settings",
+    "color_mode": "Color mode",
+    "sidebar_mode": "Sidebar mode",
+    "sidebar_mode_editor": "Sidebar mode on editor",
+    "use_os_settings": "Use OS settings"
+  },
+
+  "copy_to_clipboard": {
+    "Copy to clipboard": "Copy to clipboard",
+    "Page path": "Page path",
+    "Page URL": "Page URL",
+    "Permanent link": "Permanent link",
+    "Page path and permanent link": "Page path and permanent link",
+    "Markdown link": "Markdown link"
+  },
+
+  "crop_image_modal": {
+    "image_crop": "Image Crop",
+    "crop": "Crop",
+    "save": "Save",
+    "cancel": "Cancel"
+  },
+
+  "handsontable_modal": {
+    "title": "Edit Table",
+    "data_import": "Data Import",
+    "save": "Save",
+    "cancel": "Cancel",
+    "done": "Done",
+    "data_import_form": {
+      "select_data_format": "Select Data Format",
+      "import_data": "Import Data",
+      "paste_table_data": "Paste table data",
+      "parse_error": "Parse Error",
+      "cancel": "Cancel",
+      "import": "Import"
+    }
+  },
+
+  "not_found_page": {
+    "page_not_exist": "This page does not exist."
+  }
+}

+ 56 - 391
packages/app/public/static/locales/en_US/translation.json

@@ -1,4 +1,7 @@
 {
+  "meta": {
+    "display_name": "English"
+  },
   "Help": "Help",
   "view": "View",
   "Edit": "Edit",
@@ -16,6 +19,7 @@
   "Move/Rename": "Move/Rename",
   "Redirected": "Redirected",
   "Unlinked": "Unlinked",
+  "unlink_redirection": "Unlink redirection",
   "Done": "Done",
   "Cancel": "Cancel",
   "Create": "Create",
@@ -24,9 +28,9 @@
   "administrator": "Admin",
   "Tag": "Tag",
   "Tags": "Tags",
-  "New": "New",
   "Close": "Close",
   "Shortcuts": "Shortcuts",
+  "CustomSidebar": "Custom Sidebar",
   "eg": "e.g.",
   "add": "Add",
   "Undo": "Undo",
@@ -35,7 +39,6 @@
   "Page Path": "Page path",
   "Category": "Category",
   "User": "User",
-  "status": "Status",
   "account_id": "Account Id",
   "Update": "Update",
   "Update Page": "Update Page",
@@ -74,7 +77,6 @@
   "username": "Username",
   "Created": "Created",
   "Last updated": "Updated",
-  "Last_Login": "Last login",
   "Share": "Share",
   "Markdown Link": "Markdown Link",
   "Create/Edit Template": "Create/Edit template page",
@@ -97,8 +99,6 @@
   "Updated": "Updated",
   "Upload new image": "Upload new image",
   "Connected": "Connected",
-  "Show": "Show",
-  "Hide": "Hide",
   "Loading": "Loading...",
   "Disclose E-mail": "Disclose E-mail",
   "page exists": "this page already exists",
@@ -109,31 +109,13 @@
   "Input page name (optional)": "Input page name (optional)",
   "New Page": "New page",
   "Create under": "Create page under below:",
-  "Wiki Management Home Page": "Wiki Management Home Page",
-  "App Settings": "App Settings",
   "V5 Page Migration": "Convert To V5 Compatibility",
   "GROWI.5.0_new_schema": "GROWI.5.0 new schema",
-  "See_more_detail_on_new_schema": "See more detail on <a href='#'>{{url}}</a> <i class='icon-share-alt'></i> ",
-  "Site URL settings": "Site URL settings",
-  "Markdown Settings": "Markdown Settings",
-  "Customize": "Customize",
-  "Notification Settings": "Notification Settings",
-  "slack_integration": "Slack Integration",
-  "External_Notification": "External Notification",
-  "Legacy_Slack_Integration": "Legacy Slack Integration",
-  "User_Management": "User Management",
+  "See_more_detail_on_new_schema": "See more detail on <a href='https://docs.growi.org/en/admin-guide/upgrading/50x.html#about-the-new-v5-compatible-format' target='_blank'>{{title}}</a> <i class='icon-share-alt'></i> ",
   "external_account_management": "External Account Management",
   "UserGroup": "UserGroup",
-  "ChildUserGroup": "ChildUserGroup",
-  "UserGroup Management": "UserGroup Management",
-  "AuditLog": "Audit Log",
-  "AuditLog Settings": "Audit Log Settings",
-  "Full Text Search Management": "Full Text Search Management",
-  "Import Data": "Import Data",
-  "Export Archive Data": "Export Archive Data",
   "Basic Settings": "Basic Settings",
   "Basic authentication": "Basic authentication",
-  "Register limitation": "Register limitation",
   "The contents entered here will be shown in the header etc": "The contents entered here will be shown in the header etc",
   "Public": "Public",
   "Anyone with the link": "Anyone with the link",
@@ -141,11 +123,6 @@
   "Only me": "Only me",
   "Only inside the group": "Only inside the group",
   "page_list": "Page List",
-  "scope_of_page_disclosure": "Scope of page disclosure",
-  "set_point": "Set point",
-  "always_displayed": "Always displayed",
-  "always_hidden": "Always hidden",
-  "displayed_or_hidden": "Displayed / Hidden",
   "Reselect the group": "Reselect the group",
   "Shareable link": "Shareable link",
   "The whitelist of registration permission E-mail address": "The whitelist of registration permission E-mail address",
@@ -159,13 +136,11 @@
   "edited this page": "edited this page.",
   "List Drafts": "Drafts",
   "Deleted Pages": "Deleted Pages",
-  "Sign out": "Logout",
   "Disassociate": "Disassociate",
   "No bookmarks yet": "No bookmarks yet",
   "add_bookmark": "Add to Bookmarks",
   "remove_bookmark": "Remove from Bookmarks",
   "wide_view": "Wide View",
-  "Recent Created": "Recent Created",
   "Recent Changes": "Recent Changes",
   "Page Tree": "Page Tree",
   "original_path":"Original path",
@@ -177,34 +152,25 @@
   "not_allowed_to_see_this_page": "You cannot see this page",
   "Confirm": "Confirm",
   "Successfully requested": "Successfully requested.",
-  "personal_dropdown": {
-    "home": "Home",
-    "settings": "Settings",
-    "color_mode": "Color mode",
-    "sidebar_mode": "Sidebar mode",
-    "sidebar_mode_editor": "Sidebar mode on editor",
-    "use_os_settings": "Use OS settings"
-  },
   "form_validation": {
     "error_message": "Some values ​​are incorrect",
     "required": "%s is required",
     "invalid_syntax": "The syntax of %s is invalid.",
     "title_required": "Title is required."
   },
-  "not_found_page": {
-    "Create Page": "Create Page",
-    "page_not_exist": "This page does not exist.",
-    "page_not_exist_alert": "This page does not exist. Please create a new page."
+  "not_creatable_page": {
+    "could_not_creata_path": "Couldn't create path."
   },
   "custom_navigation": {
-    "no_page_list": "There are no pages under this page.",
-    "link_sharing_is_disabled": "Link sharing is disabled."
+    "no_page_list": "There are no pages under this page."
   },
   "installer": {
     "setup": "Setup",
     "create_initial_account": "Create an initial account",
     "initial_account_will_be_administrator_automatically": "The initial account will be administrator automatically.",
-    "unavaliable_user_id": "This 'User ID' is unavailable."
+    "unavaliable_user_id": "This 'User ID' is unavailable.",
+    "failed_to_install": "Failed to install GROWI. Please try again.",
+    "failed_to_login_after_install": "Failed to login after installation. Redirecting to the login form ..."
   },
   "breaking_changes": {
     "v346_using_basic_auth": "Basic Authentication currently in use will <strong>no longer be available</strong> in the near future. Remove settings from %s"
@@ -248,15 +214,10 @@
     "new_password_confirm": "Re-enter new password",
     "password_is_not_set": "Password is not set"
   },
-  "security_settings": "Security settings",
   "share_links": {
     "Shere this page link to public": "Shere this page link to public",
     "share_link_list": "Share link list",
     "share_link_management": "Share Link Management",
-    "No_share_links":"No share links",
-    "Share Link": "Share Link",
-    "Page Path": "Page Path",
-    "share_link_notice":"remove all share links",
     "delete_all_share_links":"Delete all share links",
     "expire": "Expiration",
     "Days": "Days",
@@ -266,30 +227,13 @@
     "Unlimited": "unlimited",
     "Issue": "Issue",
     "share_settings" :"Share settings",
-    "Invalid_Number_of_Date" : "You entered invalid value"
+    "Invalid_Number_of_Date" : "You entered invalid value",
+    "link_sharing_is_disabled": "Link sharing is disabled"
   },
   "API Settings": "API settings",
   "API Token Settings": "API token settings",
   "Current API Token": "Current API token",
   "Update API Token": "Update API token",
-  "header_search_box": {
-    "label": {
-      "All pages": "All pages",
-      "This tree": "This tree"
-    },
-    "item_label": {
-      "All pages": "All pages",
-      "This tree": "Only children of this tree"
-    }
-  },
-  "in_app_notification": {
-    "notification_list": "In-App Notification List",
-    "see_all": "See All",
-    "no_notification": "You don't have any notificatios.",
-    "all": "All",
-    "unopend": "Unread",
-    "mark_all_as_read": "Mark all as read"
-  },
   "in_app_notification_settings": {
     "in_app_notification_settings": "In-App Notification Settings",
     "subscribe_settings": "Settings to automatically subscribe (Receive notifications) to pages",
@@ -334,14 +278,6 @@
       "no_nfd": "textlint rule that disallow to use NFD like UTF8-MAC Sonant mark."
     }
   },
-  "copy_to_clipboard": {
-    "Copy to clipboard": "Copy to clipboard",
-    "Page path": "Page path",
-    "Page URL": "Page URL",
-    "Permanent link": "Permanent link",
-    "Page path and permanent link": "Page path and permanent link",
-    "Markdown link": "Markdown link"
-  },
   "search_help": {
     "title": "Searching Help",
     "and": {
@@ -390,7 +326,8 @@
     "overwrite_scopes": "{{operation}} and Overwrite scopes of all descendants",
     "notice": {
       "conflict": "Couldn't save the changes you made because someone else was editing this page. Please re-edit the affected section after reloading the page."
-    }
+    },
+    "changes_not_saved": "Changes you made may not be saved."
   },
   "page_comment": {
     "display_the_page_when_posting_this_comment": "Display the page when posting this comment",
@@ -400,7 +337,8 @@
     "notfound_or_forbidden": "Original page is not found or forbidden.",
     "already_exists": "Page with the path already exists.",
     "outdated": "Page is updated someone and now outdated.",
-    "user_not_admin": "Only admin user can delete"
+    "user_not_admin": "Only admin user can delete",
+    "single_deletion_empty_pages": "Empty pages cannot be single deleted"
   },
   "page_history": {
     "revision_list": "Revision list",
@@ -534,24 +472,10 @@
     "page_not_found_in_preview": "\"{{path}}\" is not a GROWI page."
   },
   "toaster": {
-    "create_succeeded": "Succeeded to create {{target}}",
-    "create_failed": "Failed to create {{target}}",
-    "update_successed": "Succeeded to update {{target}}",
-    "update_failed": "Failed to update {{target}}",
     "file_upload_succeeded": "File upload succeeded.",
     "file_upload_failed": "File upload failed.",
-    "initialize_successed": "Succeeded to initialize {{target}}",
-    "give_user_admin": "Succeeded to give {{username}} admin",
-    "remove_user_admin": "Succeeded to remove {{username}} admin",
-    "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}}",
-    "remove_share_link_success": "Succeeded to remove {{shareLinkId}}",
-    "issue_share_link": "Succeeded to issue new share link",
-    "remove_share_link": "Succeeded to remove {{count}} share links",
-    "switch_disable_link_sharing_success": "Succeeded to update share link setting",
-    "failed_to_reset_password":"Failed to reset password"
+    "save_succeeded": "Saved successfully",
+    "issue_share_link": "Succeeded to issue new share link"
   },
   "template": {
     "modal_label": {
@@ -681,295 +605,16 @@
       "error_duplicate_pages_found": "Multiple pages with the same path name were found. Please rename or delete and try again."
     }
   },
-  "security_setting": {
-    "Guest Users Access": "Guest users access",
-    "Fixed by env var": "This is fixed by the env var <code>{{key}}={{value}}</code>.",
-    "Register limitation": "Register limitation",
-    "Register limitation desc": "Restriction of new users' registration",
-    "The whitelist of registration permission E-mail address": "The whitelist of registration permission E-mail address",
-    "users_without_account": "Users without account is not accessible",
-    "example": "Example",
-    "restrict_emails": "You can restrict email registration to your wiki by writing an email domain (beginning with @). ",
-    "for_example": " For example, if you would like to restrict registration to users within the growi.org domain, you can write ",
-    "in_this_case": "; in this case, only users within the growi.org domain would be able to register, and all other users would be rejected.",
-    "insert_single": "Please insert single e-mail address per line.",
-    "page_list_and_search_results": "Page list / Search results",
-    "page_listing_1": "Page listing/searching<br>restricted by 'Only me'",
-    "page_listing_1_desc": "Show pages that are restricted by 'Only me' option when listing/searching",
-    "page_listing_2": "Page listing/searching<br>restricted by User group",
-    "page_listing_2_desc": "Show pages that are restricted by User group when listing/searching",
-    "page_access_rights": "Page access",
-    "page_delete_rights": "Delete rights",
-    "page_delete": "Page Delete",
-    "page_delete_completely": "Page Delete Completely",
-    "other_options": "Other options",
-    "deletion_explain": "Restricts users who can trash the selected single page.",
-    "complete_deletion_explain": "Restricts users who can completely delete  selected single page.",
-    "recursive_deletion_explain": "Restricts users who can trash pages including descendants.",
-    "recursive_complete_deletion_explain": "Restricts users who can completely delete pages including descendants.",
-    "inherit": "Inherit(Use the same setting as for a single page)",
-    "admin_only": "Admin only",
-    "admin_and_author": "Admin and author",
-    "anyone": "Anyone",
-    "session": "Session",
-    "max_age": "Max age (msec)",
-    "max_age_desc": "Specifies the number (in milliseconds) to expire users session.<br>Default: 2592000000 (30days)",
-    "max_age_caution": "Restarting the server is required after you modify this value.",
-    "forced_update_desc": "Settings have been forcibly changed. Previous setting: ",
-    "page_delete_rights_caution": "The \"Delete / Delete All\" permission (including descendant pages) is forced to be stronger than the \"Delete / Completely Delete\" permission. <br> <br> Admin only > Admin and autor > Anyone",
-    "Authentication mechanism settings": "Authentication Mechanism Settings",
-    "setup_is_not_yet_complete": "Setup is not yet complete",
-    "alert_siteUrl_is_not_set": "'Site URL' is NOT set. Set it from the {{link}}",
-    "xss_prevent_setting": "Prevent XSS(Cross Site Scripting)",
-    "xss_prevent_setting_link": "Go to Markdown Settings",
-    "callback_URL": "Callback URL",
-    "providerName": "Provider Name",
-    "issuerHost": "Issuer Host",
-    "scope": "Scope",
-    "desc_of_callback_URL": "Use it in the setting of the {{AuthName}} Identity provider",
-    "authorization_endpoint": "Authorization Endpoint",
-    "token_endpoint": "Token Endpoint",
-    "revocation_endpoint": "Revocation Endpoint",
-    "introspection_endpoint": "Introspection Endpoint",
-    "userinfo_endpoint": "UserInfo Endpoint",
-    "end_session_endpoint": "EndSessioin Endpoint",
-    "registration_endpoint": "Registration Endpoint",
-    "jwks_uri": "JSON Web Key Set URL",
-    "clientID": "Client ID",
-    "client_secret": "Client Secret",
-    "updated_general_security_setting": "Succeeded to update security setting",
-    "setup_not_completed_yet": "Setup not completed yet",
-    "guest_mode": {
-      "deny": "Deny (Registered users only)",
-      "readonly": "Accept (Guests can read only)"
-    },
-    "registration_mode": {
-      "open": "Open (Anyone can register)",
-      "restricted": "Restricted (Requires approval by administrators)",
-      "closed": "Closed (Invitation Only)"
-    },
-    "share_link_rights": "Share link rights",
-    "enable_link_sharing": "Enable link sharing",
-    "all_share_links": "All share links",
-    "configuration": " Configuration",
-    "optional": "Optional",
-    "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": "Password reset by users",
-      "enable_password_reset_by_users": "Enable password reset by users",
-      "password_reset_desc": "when forgot password, users are able to reset it by themselves.",
-      "email_authentication": "Email authentication on user registration",
-      "enable_email_authentication": "Enable email authentication",
-      "enable_email_authentication_desc": "Email authentication is going to be performed for user registration.",
-      "please_enable_mailer": "Please setup mailer first.",
-      "need_complete_mail_setting_warning": "To use the following functions, please complete the mail settings."
-    },
-    "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"
-    },
-    "Basic": {
-      "enable_basic": "Enable Basic",
-      "name": "Basic Authentication",
-      "desc_1": "Login with <code>username</code> in Authorization header.",
-      "desc_2": "User will be automatically generated if not exist.",
-      "updated_basic": "Succeeded to update Basic 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"
-      },
-      "Facebook": {
-        "name": "Facebook OAuth"
-      },
-      "Twitter": {
-        "enable_twitter": "Enable Twitter OAuth",
-        "name": "Twitter OAuth",
-        "register_1": "Access {{link}}",
-        "register_2": "Sign in Twitter",
-        "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_twitter": "Succeeded to update Twitter 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 %s when creating new users",
-        "register_1": "Contant to OIDC IdP Administrator",
-        "register_2": "Register your OIDC App with \"Authorization callback URL\" as <code>%s</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?",
-        "twitter": "How to configure Twitter 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_setting": {
-    "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": "Enable/disable Notification",
-    "link_notification_help": "<strong>The page that is able to be viewed only by those who know the link 'Anyone with the link'</strong> is not notified always.",
-    "just_me_notification_help": "<strong>The page that is restricted by 'Only Me'</strong> is notify when the page edited.",
-    "group_notification_help": "<strong>The page that is restricted by 'User Group'</strong> is notify when the page edited.",
-    "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}}"
-  },
-  "full_text_search_management": {
-    "elasticsearch_management": "Elasticsearch management",
-    "connection_status": "Connection status",
-    "connection_status_label_unconfigured": "UNCONFIGURED",
-    "connection_status_label_connected": "CONNECTED",
-    "connection_status_label_disconnected": "DISCONNECTED",
-    "connection_status_label_erroroccured": "ERROR OCCURED ON SEARCH SERVICE",
-    "indices_status": "Indices Status",
-    "indices_status_label_normalized": "NORMALIZED",
-    "indices_status_label_unnormalized": "REBUILDING or BROKEN",
-    "indices_summary": "Indices summary",
-    "reconnect": "Reconnect",
-    "reconnect_button": "Try to reconnect",
-    "reconnect_description": "Click the button to try to reconnect to Elasticsearch.",
-    "normalize": "Normalize",
-    "normalize_button": "Normalize indices",
-    "normalize_description": "Click the button to repair broken indices.",
-    "rebuild": "Rebuild",
-    "rebuild_button": "Rebuild index",
-    "rebuild_description_1": "Click the button to rebuild index and add all page datas.",
-    "rebuild_description_2": "This may take a while."
-  },
-  "to_cloud_settings": "Open GROWI.cloud Settings",
   "login": {
     "Sign in error": "Login error",
-    "Registration successful": "Registration successful",
-    "Setup": "Setup"
+    "Registration successful": "Registration successful. Please wait for administrator approval.",
+    "Setup": "Setup",
+    "enabled_ldap_has_configuration_problem":"LDAP is enabled but the configuration has something wrong.",
+    "set_env_var_for_logs": "(Please set the environment variables <code>DEBUG=crowi:service:PassportService</code> to get the logs)"
+  },
+  "invited": {
+    "discription_heading": "Create Account",
+    "discription": "Create an your account with the invited email address"
   },
   "export_bulk": {
     "failed_to_export": "Failed to export",
@@ -983,8 +628,9 @@
     "fail_to_fetch_access_token": "Failed to fetch access_token. Please do connect again.",
     "successfully_disconnected": "Successfully Disconnected!",
     "strategy_has_not_been_set_up": "{{strategy}} has not been set up",
+    "ldap_user_not_valid": "Ldap user is no valid",
+    "external_account_not_exist": "Failed to find or create External account",
     "maximum_number_of_users": "Can not register more than the maximum number of users.",
-    "database_error": "Database Server Error occured",
     "sign_in_failure": "Sign in failure.",
     "aws_sttings_required": "AWS settings required to use this function. Please ask the administrator.",
     "application_already_installed": "Application already installed.",
@@ -993,6 +639,8 @@
     "username_should_not_be_null":"Username should not be null. Please check Authentication Mechanism Settings on admin page",
     "email_address_is_already_registered":"This email address is already registered.",
     "can_not_register_maximum_number_of_users":"Can not register more than the maximum number of users.",
+    "email_settings_is_not_setup":"E-mail settings is not set up. Please ask the administrator.",
+    "email_authentication_is_not_enabled": "Email authentication is not enabled. Please ask the administrator.",
     "failed_to_register":"Failed to register.",
     "successfully_created":"The user {{username}} is successfully created.",
     "can_not_activate_maximum_number_of_users":"Can not activate more than the maximum number of users.",
@@ -1002,7 +650,21 @@
     "complete_to_install2":"Complete to Install GROWI ! Please check each settings on this page first.",
     "failed_to_create_admin_user":"Failed to create admin user. {{errMessage}}",
     "successfully_send_email_auth":"We sent an email to {{email}}. Please click the URL in the email and complete the registration.",
-    "incorrect_token_or_expired_url": "The token is incorrect or the URL has expired."
+    "incorrect_token_or_expired_url": "The token is incorrect or the URL has expired.",
+    "user_already_loggedin": "You cannot create a new account when you are logged in.",
+    "registration_closed": "You are not authorized to create a new account.",
+    "Username has invalid characters": "Username has invalid characters.",
+    "Username field is required": "User ID field is required.",
+    "Name field is required": "Name field is required.",
+    "Email format is invalid": "Email format is invalid.",
+    "Email field is required": "Email field is required.",
+    "Password has invalid character": "Password has invalid character.",
+    "Password minimum character should be more than 8 characters": "Password minimum character should be more than 8 characters.",
+    "Password field is required": "Password field is required.",
+    "Username or E-mail has invalid characters": "Username or E-mail has invalid characters.",
+    "Password minimum character should be more than 6 characters": "Password minimum character should be more than 6 characters.",
+    "user_not_found": "User not found.",
+    "provider_duplicated_username_exception": "<p><strong><i class='icon-fw icon-ban'></i>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>"
   },
   "grid_edit":{
     "create_bootstrap_4_grid":"Create Bootstrap 4 Grid",
@@ -1029,6 +691,7 @@
     "confirm_new_password": "Confirm the new password",
     "email_is_required": "Email is required",
     "success_to_send_email": "Success to send email",
+    "feature_is_unavailable": "This feature is unavailable.",
     "incorrect_token_or_expired_url": "The token is incorrect or the URL has expired. Please resend a password reset request via the link below.",
     "password_and_confirm_password_does_not_match": "Password and confirm password does not match"
   },
@@ -1085,12 +748,6 @@
     "belonging_to_no_group": "Could not find the groups you belong to.",
     "manage_user_groups": "Manage user groups"
   },
-  "crop_image_modal": {
-    "image_crop": "Image Crop",
-    "crop": "Crop",
-    "reset": "Reset",
-    "cancel": "Cancel"
-  },
   "fix_page_grant": {
     "modal": {
       "no_grant_available": "The list of selectable permissions could not be found. Please modify the permissions on the parent page first and try again.",
@@ -1134,5 +791,13 @@
   "page_operation":{
     "paths_recovered": "Paths recovered successfully",
     "path_recovery_failed":"Path recovery failed"
+  },
+  "footer": {
+    "bookmarks": "Bookmarks",
+    "recently_created": "Recently Created"
+  },
+  "v5_page_migration": {
+    "page_tree_not_avaliable" : "Page tree feature is not available yet.",
+    "go_to_settings": "Go to settings to enable the feature"
   }
 }

+ 0 - 2
packages/app/public/static/locales/index.js

@@ -1,2 +0,0 @@
-// !!DO NOT EDIT/REMOVE THIS FILE!!
-// entry point for @alienfast/i18next-loader

+ 351 - 11
packages/app/public/static/locales/ja_JP/admin/admin.json → packages/app/public/static/locales/ja_JP/admin.json

@@ -1,4 +1,310 @@
 {
+  "meta": {
+    "display_name": "日本語"
+  },
+  "Update": "更新",
+  "Delete": "削除",
+  "User": "ユーザー",
+  "Name": "名前",
+  "Page": "ページ",
+  "Created": "作成日",
+  "Edit": "編集",
+  "Description": "説明",
+  "last_login": "最終ログイン",
+  "wiki_management_home_page": "Wiki管理トップ",
+  "public": "公開",
+  "anyone_with_the_link": "リンクを知っている人のみ",
+  "specified_users": "特定ユーザーのみ",
+  "only_me": "自分のみ",
+  "only_inside_the_group": "特定グループのみ",
+  "security_settings": {
+    "security_settings": "セキュリティ設定",
+    "scope_of_page_disclosure": "ページの公開範囲",
+    "set_point": "設定値",
+    "Guest Users Access":"ゲストユーザーのアクセス",
+    "always_hidden": "非表示 (固定)",
+    "always_displayed": "表示 (固定)",
+    "displayed_or_hidden": "表示 / 非表示",
+    "Fixed by env var": "環境変数 <code>{{forcewikimode}}={{wikimode}}</code> により固定されています。",
+    "register_limitation": "登録の制限",
+    "register_limitation_desc": "新しいユーザーを登録する方法を制限します。",
+    "The whitelist of registration permission E-mail address": "登録許可メールアドレスの<br>ホワイトリスト",
+    "users_without_account": "アカウントを持たないユーザーはアクセス不可",
+    "example": "例",
+    "restrict_emails": "登録可能なメールアドレスを制限することができます。",
+    "for_example": "例えば、",
+    "in_this_case": "と記載することで、そのドメインのメールアドレスを持っている人のみ登録可能になります。",
+    "insert_single": "1行に1メールアドレス入力してください。",
+    "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": "完全に削除する",
+    "other_options": "その他のオプション",
+    "deletion_explain": "ページをゴミ箱に入れることができるユーザーを制限します。",
+    "complete_deletion_explain": "ページを完全削除することができるユーザーを制限します。",
+    "recursive_deletion_explain": "子孫を含めたページをゴミ箱に入れることができるユーザーを制限します。",
+    "recursive_complete_deletion_explain": "子孫を含めたページを完全削除することができるユーザーを制限します。",
+    "inherit": "単体のみと同じ",
+    "admin_only": "管理者のみ可能",
+    "admin_and_author": "管理者とページ作者が可能",
+    "anyone": "誰でも可能",
+    "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(Cross Site Scripting)対策設定",
+    "xss_prevent_setting_link": "マークダウン設定ページに移動",
+    "callback_URL": "コールバックURL",
+    "desc_of_callback_URL": "{{AuthName}} プロバイダ側の設定で利用してください。",
+    "authorization_endpoint": "認可エンドポイント",
+    "token_endpoint": "トークンエンドポイント",
+    "revocation_endpoint": "失効エンドポイント",
+    "introspection_endpoint": "検証エンドポイント",
+    "userinfo_endpoint": "ユーザ情報エンドポイント",
+    "end_session_endpoint": "セッション終了エンドポイント",
+    "registration_endpoint": "登録エンドポイント",
+    "jwks_uri": "JSON Web Key Set URL",
+    "clientID": "クライアントID",
+    "client_secret": "クライアントシークレット",
+    "updated_general_security_setting": "セキュリティ設定を更新しました。",
+    "setup_not_completed_yet": "まだセットアップは完了していません。",
+    "guest_mode": {
+      "deny": "拒否 (アカウントを持つユーザーのみ利用可能)",
+      "readonly": "許可 (ゲストユーザーも閲覧のみ可能)"
+    },
+    "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": "設定",
+    "optional": "オプション",
+    "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/Password",
+      "note for the only env option": "現在LOCAL認証のON/OFFは環境変数の値によって制限されています<br>この設定を変更する場合は環境変数 <code>{{env}}</code> の値をfalseに変更もしくは削除してください",
+      "enable_local": "ID/Password を有効にする",
+      "password_reset_by_users": "ユーザーによるパスワード再設定",
+      "enable_password_reset_by_users": "ユーザーによるパスワード再設定を有効にする",
+      "password_reset_desc": "ログイン時のパスワードを忘れた際に、ユーザー自身がパスワードを再設定できます。",
+      "email_authentication": "ユーザー登録時のメール認証",
+      "enable_email_authentication": "メール認証を有効にする",
+      "enable_email_authentication_desc": "ユーザー登録時にメール認証を行います。",
+      "need_complete_mail_setting_warning": "以下の機能を使えるようにするには、メール設定を完了させてください。"
+    },
+    "ldap": {
+      "enable_ldap": "LDAP を有効にする",
+      "server_url_detail": "LDAP URLを <code>ldap://host:port/DN</code> または <code>ldaps://host:port/DN</code> の形式で入力してください。",
+      "bind_mode": "Bind モード",
+      "bind_manager": "管理者 Bind",
+      "bind_user": "ユーザー Bind",
+      "bind_DN_manager_detail": "ディレクトリーサービスに認証する際のアカウント DN",
+      "bind_DN_user_detail1": "ディレクトリーサービスに Bind するアカウント DN を決定するためのクエリ",
+      "bind_DN_user_detail2": "ログイン時に入力されるユーザー名を使用するには <code>&#123;&#123;username&#125;&#125;</code> の形式を使用してください。",
+      "bind_DN_password": "Bind DN パスワード",
+      "bind_DN_password_manager_detail": "Bind DN アカウントのパスワード",
+      "bind_DN_password_user_detail": "ログイン時のパスワードが使用されます。",
+      "search_filter": "検索フィルター",
+      "search_filter_detail1": "認証されるユーザーを一意に決定するための LDAP フィルタ",
+      "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": "'sAMAccountName' に一致 (Active Directory)",
+      "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>uid</code> を含む <code>memberUid</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 Identity プロバイダ内で一意に識別可能な値を格納している属性",
+      "username_detail": "新規ユーザーのアカウント名(<code>username</code>)に関連付ける属性",
+      "mapping_detail": "新規ユーザーの{{target}}に関連付ける属性",
+      "cert_detail": "IdP からのレスポンスの validation を行うためのPEMエンコードされた X.509 証明書",
+      "Use env var if empty": "データベース側の値が空の場合、環境変数 <code>{{env}}</code> の値を利用します",
+      "note for the only env option": "現在SAML認証のON/OFFの設定値及びハイライトされている設定値は環境変数の値のみを使用するようになっています<br>この設定を変更する場合は環境変数 <code>{{env}}</code> の値をfalseに変更もしくは削除してください",
+      "attr_based_login_control_detail": "SAMLの <code>&lt;saml:AttributeStatement&gt;</code> 要素に含まれる <code>&lt;saml:Attribute&gt;</code> 要素と、その子要素 <code>&lt;saml:AttributeValue&gt;</code> を利用してログインの可否を制御します。",
+      "attr_based_login_control_rule_help": "<h5>利用可能なクエリ:</h5><ul><li>Terms</li><li>Fields</li><li>AND/NOT/OR Operator</li><li>Grouping</li></ul><h5>利用不可なクエリ:</h5><ul><li>Wildcard, Fuzzy, Proximity, Range and Boosting</li><li>+/- Operator</li><li>Field Grouping</li></ul><h5>特殊文字のエスケープ</h5>次の特殊文字はエスケープする必要があります。<code>+ - && || ! ( ) { } [ ] ^ &quot; &tilde; * ? : &#92;</code> and <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> を持つユーザーにログインを<strong>許可</strong>します。",
+      "attr_based_login_control_rule_exampl2": "<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": "Succeeded to update SAML setting"
+    },
+    "Basic": {
+      "enable_basic": "Basic を有効にする",
+      "name": "Basic 認証",
+      "desc_1": "Authorization ヘッダに格納されている <code>username</code> でログインします。",
+      "desc_2": "ユーザーが存在しなかった場合は自動生成します。",
+      "updated_basic": "Basic認証 を更新しました"
+    },
+    "OAuth": {
+      "enable_oidc": "OIDC を有効にする",
+      "register": "%sに登録",
+      "change_redirect_url": "承認済みのリダイレクトURLに、 <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>としてGrowiを登録",
+        "register_5": "上記フォームにクライアントIDとクライアントシークレットを入力",
+        "updated_google": "Google OAuth を更新しました"
+      },
+      "Facebook": {
+        "name": "Facebook OAuth"
+      },
+      "Twitter": {
+        "enable_twitter": "Twitter OAuth を有効にする",
+        "name": "Twitter OAuth",
+        "register_1": "{{link}} へアクセス",
+        "register_2": "Twitterにサインイン",
+        "register_3": "Create New Appをクリック &rightarrow; Application Detailsの各項目を入力",
+        "register_4": "Create your Twitter Applicationで作成",
+        "register_5": "上記フォームにクライアントIDとクライアントシークレットを入力",
+        "updated_twitter": "Twitter OAuth を更新しました"
+      },
+      "GitHub": {
+        "enable_github": "GitHub OAuth を有効にする",
+        "name": "GitHub OAuth",
+        "register_1": "{{link}} へアクセス",
+        "register_2": "\"Authorization callback URL\"を<code>{{url}}</code>としてGrowiを登録",
+        "register_3": "上記フォームにクライアントIDとクライアントシークレットを入力",
+        "updated_github": "GitHub OAuth を更新しました"
+      },
+      "OIDC": {
+        "name": "OpenID Connect",
+        "id_detail": "OIDC claims で一意に識別可能な値を格納している属性",
+        "username_detail": "新規ユーザーのアカウント名(<code>username</code>)に関連付ける属性",
+        "name_detail": "新規ユーザー名(<code>name</code>)に関連付ける属性",
+        "mapping_detail": "新規ユーザーの{{target}}に関連付ける属性",
+        "updated_oidc": "OpenID Connect を更新しました",
+        "Use discovered URL if empty": "データベース側の値が空の場合、\"Issuer Host\"から検出した値を利用します。"
+      },
+      "how_to": {
+        "google": "Google OAuth の設定方法",
+        "github": "GitHub OAuth の設定方法",
+        "twitter": "Twitter OAuth の設定方法"
+      }
+    },
+    "form_item_name": {
+      "entryPoint": "エントリーポイント",
+      "issuer": "発行者",
+      "cert": "証明書",
+      "attrMapId": "ID",
+      "attrMapUsername": "ユーザー名",
+      "attrMapMail": "メールアドレス",
+      "attrMapFirstName": "名",
+      "attrMapLastName": "姓",
+      "ABLCRule": "ルール"
+    }
+  },
+  "notification_settings": {
+    "notification_settings": "通知設定",
+    "slack_incoming_configuration": "Slack Incoming Webhooks 設定",
+    "prioritize_webhook": "Slack アプリより Incoming Webhook を優先する",
+    "prioritize_webhook_desc": "このオプションをオンにすると、 Slack App が有効になっていても GROWI は Incoming Webhook を使用します。",
+    "slack_app_configuration": "Slack App 設定",
+    "slack_app_configuration_desc": "Crowi 互換の機能です。<br /> <strong>設定が複雑すぎる</strong>のでオススメしません。",
+    "use_instead": "代わりに Slack Incoming Webhooks 設定を使用してください。",
+    "how_to": {
+      "header": "Incoming Webhooks の設定方法",
+      "workspace": "ワークスペースで Webhook を追加します。",
+      "workspace_desc1": "<a href='https://slack.com/services/new/incoming-webhook'>Incoming Webhooks Configuration page</a> にアクセスします。",
+      "workspace_desc2": "投稿するチャンネルを選びます。",
+      "workspace_desc3": "追加します。",
+      "at_growi": "GROWI 管理画面で Webhook URL を設定します。",
+      "at_growi_desc": "このページで &rdquo;Webhook URL&rdquo; を入力して送信します。"
+    },
+    "user_trigger_notification_header": "デフォルトパターンの通知設定",
+    "pattern": "パターン",
+    "channel": "チャンネル名",
+    "pattern_desc": "Wiki のパス名。 パスには <code>*</code> を使用できます。",
+    "channel_desc": "<code>#</code> を除いた Slack チャンネル名",
+    "valid_page": "通知の有効 / 無効",
+    "link_notification_help": "<strong>linkを知っている人のみ閲覧できるページ</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": "SlackApp設定を更新しました",
+    "add_notification_pattern": "通知パターンを追加しました。",
+    "delete_notification_pattern": "通知パターンを削除しました。",
+    "delete_notification_pattern_desc1": "Path: {{path}} を削除します。",
+    "delete_notification_pattern_desc2": "Once deleted, it cannot be recovered",
+    "toggle_notification": "{{path}}の通知設定を変更しました",
+    "not_found_global_notification_triggerid": "アクセス先の通知設定は見つかりませんでした"
+  },
+  "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": "SearchService でエラーが発生しています",
+    "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'>メールの設定</a> が必要です。",
   "admin_top": {
     "management_wiki": "Wiki管理",
@@ -20,8 +326,6 @@
     "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>"
   },
   "v5_page_migration": {
-    "page_tree_not_avaliable" : "Page Tree 機能は現在使用できません。",
-    "go_to_settings": "設定する",
     "migration_desc": "公開されているページに 古い v4 互換形式のものが存在します。ページツリーや簡単なリネームなどの新機能を利用するには、全てのページを v5 互換形式に変換してください。",
     "migration_note": "注意: ページパスからユニーク制約が失われます。",
     "upgrade_to_v5": "v5 互換形式 へ変換",
@@ -51,9 +355,12 @@
     "site_name": "サイト名",
     "sitename_change": "ヘッダーや HTML タイトルに使用されるサイト名を変更できます。",
     "header_content": "ここに入力した内容は、ヘッダー等に表示されます。",
-    "site_url_desc": "サイトURLを設定します。",
-    "site_url_warn": "サイトURLが設定されていないため、一部機能が動作しない状態になっています。",
-    "siteurl_help": "<code>http://</code> または <code>https://</code> から始まるサイトのURL",
+    "site_url": {
+      "title": "サイトURL設定",
+      "desc": "サイトURLを設定します。",
+      "warn": "サイトURLが設定されていないため、一部機能が動作しない状態になっています。",
+      "help": "<code>http://</code> または <code>https://</code> から始まるサイトのURL"
+    },
     "confidential_name": "コンフィデンシャル表示",
     "confidential_example": "例: 社外秘",
     "default_language": "新規ユーザーのデフォルト設定言語",
@@ -105,7 +412,8 @@
     "use_env_var_if_empty": "データベース側の値が空の場合、環境変数 <code>{{variable}}</code> の値を利用します",
     "note_for_the_only_env_option": "現在GCS設定は環境変数の値によって制限されています<br>この設定を変更する場合は環境変数 <code>{{env}}</code> の値をfalseに変更もしくは削除してください"
   },
-  "markdown_setting": {
+  "markdown_settings": {
+    "markdown_settings": "マークダウン設定",
     "lineBreak_header": "Line Break設定",
     "lineBreak_desc": "Line Breakの設定を変更できます。",
     "lineBreak_options": {
@@ -148,7 +456,8 @@
       "import_recommended": "{{target}} のおすすめをインポート"
     }
   },
-  "customize_setting": {
+  "customize_settings": {
+    "customize_settings": "カスタマイズ",
     "default_sidebar_mode": {
       "title": "デフォルトのサイドバーモード",
       "desc": "新規ユーザー、ページを訪れたゲストのサイドバーモードを設定できます。",
@@ -193,8 +502,6 @@
       "select_search_scope_children_as_default": "検索範囲のデフォルト設定を「この階層下の子ページ」にする",
       "select_search_scope_children_as_default_desc": "OFFの場合、検索範囲のデフォルト設定は「全てのページ」になります。"
     },
-    "code_highlight": "コードハイライト",
-    "nocdn_desc": "この機能は、環境変数 <code>NO_CDN=true</code> の時は無効化されます。<br>GitHub スタイルが適用されています。",
     "custom_title": "カスタム Title",
     "custom_title_detail": "<code>&lt;title&gt;</code>タグのコンテンツをカスタマイズできます。以下のプレースホルダーは自動的に置換されます:",
     "custom_title_detail_placeholder1": "<code>&#123;&#123;sitename&#125;&#125;</code> - この Wiki のサイト名",
@@ -216,6 +523,7 @@
     "delete_logo": "ロゴを削除"
   },
   "export_management": {
+    "export_archive_data": "データアーカイブ",
     "exporting_collection_list": "エクスポート中のコレクション",
     "exported_data_list": "エクスポートされたアーカイブリスト",
     "export_collections": "コレクションのエクスポート",
@@ -226,7 +534,7 @@
     "export": "エクスポート",
     "cancel": "キャンセル",
     "file": "ファイル名",
-    "growi_version": "Growi バージョン",
+    "growi_version": "GROWI バージョン",
     "collections": "コレクション",
     "exported_at": "エクスポートされた時間",
     "export_menu": "エクスポートメニュー",
@@ -234,6 +542,12 @@
     "delete": "削除"
   },
   "importer_management": {
+    "import_data": "データインポート",
+    "article": "記事",
+    "category": "カテゴリー",
+    "tag": "タグ",
+    "page": "ページ",
+    "page_path": "ページパス",
     "beta_warning": "この機能はベータ版です",
     "import_from": "{{from}} からインポート",
     "import_growi_archive": "GROWI アーカイブをインポート",
@@ -305,12 +619,14 @@
     "Directory_hierarchy_tag": "ディレクトリ階層タグ"
   },
   "external_notification": {
+    "external_notification": "外部ツールへの通知",
     "enabled": "有効",
     "disabled": "無効",
     "header_status": "Slack 連携の状態",
     "caution_enabled": "CAUTION: このページで設定される通知は、Primary として設定された Slack ワークスペースにのみ送信されます。 "
   },
   "slack_integration": {
+    "slack_integration": "Slack連携",
     "selecting_bot_types": {
       "slack_bot": "Slack bot",
       "detailed_explanation": "詳しい説明はこちら",
@@ -421,12 +737,15 @@
     }
   },
   "slack_integration_legacy": {
+    "slack_integration_legacy":  "Slack連携 (レガシー)",
     "alert_disabled": "<a href='/admin/slack-integration'>新しい設定</a>が有効になっているため、この 'Slack連携 (レガシー)' は現在無効になっています。",
     "alert_deplicated": "この 'Slack連携 (レガシー)' は将来廃止されます。代わりに<a href='/admin/slack-integration'>新しいSlack連携機能</a>を利用してください。"
   },
   "user_management": {
+    "user_management": "ユーザー管理",
     "invite_users": "新規ユーザーの仮発行",
     "click_twice_same_checkbox": "少なくとも一つはチェックしてください。",
+    "status": "ステータス",
     "invite_modal": {
       "emails": "メールアドレス (複数行入力で複数人発行可能)",
       "description1": "メールアドレスを使用して新規ユーザーを仮発行します。",
@@ -482,12 +801,14 @@
     "current_users": "現在のユーザー数:"
   },
   "user_group_management": {
+    "user_group_management": "グループ管理",
     "create_group": "新規グループの作成",
     "add_child_group": "子グループの追加",
     "remove_child_group": "解除",
     "deny_create_group": "新規グループの作成はできません。",
     "group_name": "グループ名",
     "group_example": "例: Group1",
+    "child_user_group": "子グループ",
     "parent_group": "親グループ",
     "select_parent_group": "親グループを選択",
     "release_parent_group": "親グループの解除",
@@ -528,6 +849,8 @@
     }
   },
   "audit_log_management": {
+    "audit_log": "監査ログ",
+    "audit_log_settings": "監査ログ設定",
     "user": "ユーザー",
     "username": "ユーザー名",
     "date": "日付",
@@ -548,6 +871,9 @@
       "log_type": "https://docs.growi.org/ja/admin-guide/admin-cookbook/audit-log-setup.html#log-types"
     }
   },
+  "cloud_setting_management": {
+    "to_cloud_settings": "GROWI.cloud の管理画面へ"
+  },
   "audit_log_action_category": {
     "Page": "ページ",
     "Comment": "コメント",
@@ -597,6 +923,10 @@
     "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": "マークダウン形式でページをエクスポート",
@@ -614,7 +944,7 @@
     "SHARE_LINK_NOT_FOUND": "ページ閲覧(存在しない共有リンク)",
     "ATTACHMENT_ADD": "添付データの追加",
     "ATTACHMENT_REMOVE": "添付データの削除",
-    "ACTION_ATTACHMENT_DOWNLOAD": "添付データのダウンロード",
+    "ATTACHMENT_DOWNLOAD": "添付データのダウンロード",
     "SEARCH_PAGE": "ページの検索",
     "SEARCH_PAGE_VIEW": "ページ閲覧(検索結果ページ)",
     "ADMIN_APP_SETTING_UPDATE": "アプリ設定の更新",
@@ -714,5 +1044,15 @@
     "ADMIN_SEARCH_CONNECTION": "Elasticsearch の再接続の試行",
     "ADMIN_SEARCH_INDICES_NORMALIZE": "Elasticsearch のインデックスの正規化",
     "ADMIN_SEARCH_INDICES_REBUILD": "Elasticsearch のインデックスのリビルド"
+  },
+  "toaster": {
+    "give_user_admin": "{{username}}を管理者に設定しました",
+    "remove_user_admin": "{{username}}を管理者から外しました",
+    "activate_user_success": "{{username}}を有効化しました",
+    "deactivate_user_success": "{{username}}を無効化しました",
+    "remove_user_success": "{{username}}を削除しました",
+    "remove_external_user_success": "{{accountId}}を削除しました",
+    "switch_disable_link_sharing_success": "共有リンクの設定を変更しました",
+    "failed_to_reset_password":"パスワードのリセットに失敗しました"
   }
 }

+ 100 - 0
packages/app/public/static/locales/ja_JP/commons.json

@@ -0,0 +1,100 @@
+{
+  "Show": "公開",
+  "Hide": "非公開",
+  "Add": "追加",
+  "Reset": "リセット",
+  "Sign out": "ログアウト",
+  "New": "作成",
+
+  "meta": {
+    "display_name": "日本語"
+  },
+  "toaster": {
+    "create_succeeded": "新しい{{target}}が作成されました",
+    "create_failed": "{{target}}の作成に失敗しました",
+    "update_successed": "{{target}}を更新しました",
+    "update_failed": "{{target}}の更新に失敗しました",
+
+    "remove_share_link_success": "{{shareLinkId}}を削除しました",
+    "remove_share_link": "共有リンクを{{count}}件削除しました"
+  },
+  "alert": {
+    "siteUrl_is_not_set": "'サイトURL' が設定されていません。{{link}} から設定してください。",
+    "please_enable_mailer": "メール認証を有効にするには、メール設定を完了させてください。"
+  },
+  "headers": {
+    "app_settings": "アプリ設定"
+  },
+
+  "header_search_box": {
+    "label": {
+      "All pages": "全てのページ",
+      "This tree": "この階層"
+    },
+    "item_label": {
+      "All pages": "全てのページ",
+      "This tree": "この階層下の子ページのみ"
+    }
+  },
+
+  "share_links": {
+    "Share Link": "共有用リンク",
+    "Page Path": "ページパス",
+    "expire": "有効期限",
+    "description": "概要"
+  },
+
+  "in_app_notification": {
+    "notification_list": "アプリ内通知一覧",
+    "see_all": "通知一覧を見る",
+    "no_notification": "通知はありません",
+    "all": "全て",
+    "unopend": "未読",
+    "mark_all_as_read": "全て既読にする"
+  },
+
+  "personal_dropdown": {
+    "home": "ホーム",
+    "settings": "設定",
+    "color_mode": "カラーモード",
+    "sidebar_mode": "サイドバーモード",
+    "sidebar_mode_editor": "サイドバーモード(編集時)",
+    "use_os_settings": "OS設定を利用する"
+  },
+
+  "copy_to_clipboard": {
+    "Copy to clipboard": "クリップボードにコピー",
+    "Page path": "ページ名",
+    "Page URL": "ページURL",
+    "Permanent link": "パーマリンク",
+    "Page path and permanent link": "ページ名とパーマリンク",
+    "Markdown link": "マークダウン形式のリンク"
+  },
+
+  "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": "このページは存在しません。"
+  }
+}

+ 57 - 388
packages/app/public/static/locales/ja_JP/translation.json

@@ -1,4 +1,7 @@
 {
+  "meta": {
+    "display_name": "日本語"
+  },
   "Help": "ヘルプ",
   "view": "View",
   "Edit": "編集",
@@ -16,6 +19,7 @@
   "Move/Rename": "移動/名前変更",
   "Redirected": "リダイレクトされました",
   "Unlinked": "リダイレクト削除",
+  "unlink_redirection": "リダイレクト削除",
   "Done": "完了",
   "Cancel": "キャンセル",
   "Create": "作成",
@@ -24,18 +28,12 @@
   "administrator": "管理者",
   "Tag": "タグ",
   "Tags": "タグ",
-  "New": "作成",
   "Close": "閉じる",
   "Shortcuts": "ショートカット",
+  "CustomSidebar": "カスタムサイドバー",
   "eg": "例:",
   "add": "追加",
   "Undo": "元に戻す",
-  "Article": "記事",
-  "Page": "ページ",
-  "Page Path": "ページパス",
-  "Category": "カテゴリー",
-  "User": "ユーザー",
-  "status": "ステータス",
   "account_id": "アカウントID",
   "Initialize": "初期化",
   "Update": "更新",
@@ -74,7 +72,6 @@
   "username": "ユーザー名",
   "Created": "作成日",
   "Last updated": "最終更新",
-  "Last_Login": "最終ログイン",
   "Share": "共有",
   "Markdown Link": "Markdown形式のリンク",
   "Create/Edit Template": "テンプレートページの作成/編集",
@@ -109,30 +106,12 @@
   "Input page name (optional)": "ページ名を入力(空欄OK)",
   "New Page": "新規ページ",
   "Create under": "ページを以下に作成",
-  "Wiki Management Home Page": "Wiki管理トップ",
-  "App Settings": "アプリ設定",
   "V5 Page Migration": "V5 互換形式 への変換",
   "GROWI.5.0_new_schema": "GROWI.5.0における新スキーマについて",
-  "See_more_detail_on_new_schema": "詳しくは<a href='#'>{{url}}</a><i class='icon-share-alt'></i>を参照ください。",
-  "Site URL settings": "サイトURL設定",
-  "Markdown Settings": "マークダウン設定",
-  "Customize": "カスタマイズ",
-  "Notification Settings": "通知設定",
-  "slack_integration": "Slack連携",
-  "External_Notification": "外部ツールへの通知",
-  "Legacy_Slack_Integration": "Slack連携 (レガシー)",
-  "User_Management": "ユーザー管理",
+  "See_more_detail_on_new_schema": "詳しくは<a href='https://docs.growi.org/ja/admin-guide/upgrading/50x.html#新しい-v5-互換形式について' target='_blank'>{{title}}</a><i class='icon-share-alt'></i>を参照ください。",
   "external_account_management": "外部アカウント管理",
   "UserGroup": "グループ",
-  "ChildUserGroup": "子グループ",
-  "UserGroup Management": "グループ管理",
-  "AuditLog": "監査ログ",
-  "AuditLog Settings": "監査ログ設定",
-  "Full Text Search Management": "全文検索管理",
-  "Import Data": "データインポート",
-  "Export Archive Data": "データアーカイブ",
   "Basic Settings": "基本設定",
-  "Register limitation": "登録の制限",
   "The contents entered here will be shown in the header etc": "ここに入力した内容は、ヘッダー等に表示されます。",
   "Public": "公開",
   "Anyone with the link": "リンクを知っている人のみ",
@@ -140,11 +119,6 @@
   "Only me": "自分のみ",
   "Only inside the group": "特定グループのみ",
   "page_list": "ページリスト",
-  "scope_of_page_disclosure": "ページの公開範囲",
-  "set_point": "設定値",
-  "always_displayed": "表示 (固定)",
-  "always_hidden": "非表示 (固定)",
-  "displayed_or_hidden": "表示 / 非表示",
   "Reselect the group": "グループの再選択",
   "Shareable link": "このページの共有用URL",
   "The whitelist of registration permission E-mail address": "登録許可メールアドレスの<br>ホワイトリスト",
@@ -158,7 +132,6 @@
   "edited this page": "さんがこのページを編集しました。",
   "List Drafts": "下書き一覧",
   "Deleted Pages": "削除済みページ",
-  "Sign out": "ログアウト",
   "Disassociate": "連携解除",
   "Color mode": "カラーモード",
   "Sidebar mode": "サイドバーモード",
@@ -167,7 +140,6 @@
   "add_bookmark": "ブックマークに追加",
   "remove_bookmark": "ブックマークから削除",
   "wide_view": "ワイドビュー",
-  "Recent Created": "最新の作成",
   "Recent Changes": "最新の変更",
   "Page Tree": "ページツリー",
   "original_path":"元のパス",
@@ -179,34 +151,25 @@
   "not_allowed_to_see_this_page": "このページは閲覧できません",
   "Confirm": "確認",
   "Successfully requested": "正常に処理を受け付けました",
-  "personal_dropdown": {
-    "home": "ホーム",
-    "settings": "設定",
-    "color_mode": "カラーモード",
-    "sidebar_mode": "サイドバーモード",
-    "sidebar_mode_editor": "サイドバーモード(編集時)",
-    "use_os_settings": "OS設定を利用する"
-  },
   "form_validation": {
     "error_message": "いくつかの値が設定されていません",
     "required": "%sに値を入力してください",
     "invalid_syntax": "%sの構文が不正です",
     "title_required": "タイトルを入力してください"
   },
-  "not_found_page": {
-    "Create Page": "ページを作成する",
-    "page_not_exist": "このページは存在しません。",
-    "page_not_exist_alert": "このページは存在しません。新たに作成する必要があります。"
+  "not_creatable_page": {
+    "could_not_creata_path": "パスを作成できませんでした。"
   },
   "custom_navigation": {
-    "no_page_list": "このページの配下にはページが存在しません。",
-    "link_sharing_is_disabled": "リンクのシェアは無効化されています"
+    "no_page_list": "このページの配下にはページが存在しません。"
   },
   "installer": {
     "setup": "セットアップ",
     "create_initial_account": "最初のアカウントの作成",
     "initial_account_will_be_administrator_automatically": "初めに作成するアカウントは、自動的に管理者権限が付与されます",
-    "unavaliable_user_id": "このユーザーIDは利用できません。"
+    "unavaliable_user_id": "このユーザーIDは利用できません。",
+    "failed_to_install": "GROWI のインストールに失敗しました。再度お試しください。",
+    "failed_to_login_after_install": "インストール後、ログインに失敗しました。ログインフォームに遷移しています ..."
   },
   "breaking_changes": {
     "v346_using_basic_auth": "現在利用中の Basic 認証機能は、近い将来<strong>廃止されます</strong>。%s から設定を削除してください。"
@@ -250,15 +213,10 @@
     "new_password_confirm": "(確認用)",
     "password_is_not_set": "パスワードが設定されていません"
   },
-  "security_settings": "セキュリティ設定",
   "share_links": {
     "Shere this page link to public": "外部に共有するリンクを発行する",
     "share_link_list": "共有リンクリスト",
     "share_link_management": "共有リンク管理",
-    "No_share_links":"共有リンクが存在しません",
-    "Share Link": "共有用リンク",
-    "Page Path": "ページパス",
-    "share_link_notice":"共有リンクを全て削除します",
     "delete_all_share_links":"全ての共有リンクを削除します",
     "expire": "有効期限",
     "Days": "日間",
@@ -268,30 +226,13 @@
     "Unlimited": "無期限",
     "Issue": "発行",
     "share_settings" :"共有設定",
-    "Invalid_Number_of_Date" : "有効期限の日数には整数を入力してください"
+    "Invalid_Number_of_Date" : "有効期限の日数には整数を入力してください",
+    "link_sharing_is_disabled": "リンクのシェアは無効化されています"
   },
   "API Settings": "API設定",
   "API Token Settings": "API Token設定",
   "Current API Token": "現在のAPI Token",
   "Update API Token": "API Tokenを更新",
-  "header_search_box": {
-    "label": {
-      "All pages": "全てのページ",
-      "This tree": "この階層"
-    },
-    "item_label": {
-      "All pages": "全てのページ",
-      "This tree": "この階層下の子ページのみ"
-    }
-  },
-  "in_app_notification": {
-    "notification_list": "アプリ内通知一覧",
-    "see_all": "通知一覧を見る",
-    "no_notification": "通知はありません",
-    "all": "全て",
-    "unopend": "未読",
-    "mark_all_as_read": "全て既読にする"
-  },
   "in_app_notification_settings": {
     "in_app_notification_settings": "アプリ内通知設定",
     "subscribe_settings": "自動でページをサブスクライブする(通知を受け取る)設定",
@@ -335,14 +276,6 @@
       "no_nfd": "UTF8-MAC濁点のようなNFDの使用を禁止します。"
     }
   },
-  "copy_to_clipboard": {
-    "Copy to clipboard": "クリップボードにコピー",
-    "Page path": "ページ名",
-    "Page URL": "ページURL",
-    "Permanent link": "パーマリンク",
-    "Page path and permanent link": "ページ名とパーマリンク",
-    "Markdown link": "マークダウン形式のリンク"
-  },
   "search_help": {
     "title": "検索のヘルプ",
     "and": {
@@ -374,7 +307,7 @@
   },
   "page_page": {
     "notice": {
-      "version": "これは現在の版ではありません。",
+      "version": "これは最新のバージョンではありません。",
       "redirected": "リダイレクト元 >>",
       "redirected_period":"",
       "unlinked": "このページへのリダイレクトは削除されました。",
@@ -390,7 +323,8 @@
     "overwrite_scopes": "{{operation}}と同時に全ての配下ページのスコープを上書き",
     "notice": {
       "conflict": "すでに他の人がこのページを編集していたため保存できませんでした。ページを再読み込み後、自分の編集箇所のみ再度編集してください。"
-    }
+    },
+    "changes_not_saved": "変更が保存されていない可能性があります。"
   },
   "page_comment": {
     "display_the_page_when_posting_this_comment": "投稿時のページを表示する",
@@ -400,7 +334,8 @@
     "notfound_or_forbidden": "元のページが見つからないか、アクセス権がありません。",
     "already_exists": "そのパスを持つページは既に存在しています。",
     "outdated": "ページが他のユーザーによって更新されました。",
-    "user_not_admin": "権限のあるユーザーのみが削除できます"
+    "user_not_admin": "権限のあるユーザーのみが削除できます",
+    "single_deletion_empty_pages": "空ページの単体削除はできません"
   },
   "page_history": {
     "revision_list": "更新履歴",
@@ -534,24 +469,10 @@
     "page_not_found_in_preview": "\"{{path}}\" というページはありません。"
   },
   "toaster": {
-    "create_succeeded": "新しい{{target}}が作成されました",
-    "create_failed": "{{target}}の作成に失敗しました",
-    "update_successed": "{{target}}を更新しました",
-    "update_failed": "{{target}}の更新に失敗しました",
     "file_upload_succeeded": "ファイルをアップロードしました",
     "file_upload_failed": "ファイルのアップロードに失敗しました",
-    "initialize_successed": "{{target}}を初期化しました",
-    "give_user_admin": "{{username}}を管理者に設定しました",
-    "remove_user_admin": "{{username}}を管理者から外しました",
-    "activate_user_success": "{{username}}を有効化しました",
-    "deactivate_user_success": "{{username}}を無効化しました",
-    "remove_user_success": "{{username}}を削除しました",
-    "remove_external_user_success": "{{accountId}}を削除しました",
-    "remove_share_link_success": "{{shareLinkId}}を削除しました",
-    "issue_share_link": "共有リンクを作成しました",
-    "remove_share_link": "共有リンクを{{count}}件削除しました",
-    "switch_disable_link_sharing_success": "共有リンクの設定を変更しました",
-    "failed_to_reset_password":"パスワードのリセットに失敗しました"
+    "save_succeeded": "保存に成功しました",
+    "issue_share_link": "共有リンクを作成しました"
   },
   "template": {
     "modal_label": {
@@ -681,288 +602,16 @@
       "error_duplicate_pages_found": "同名のパスを持つページが複数見つかりました。リネームまたは削除してから再度実行してください"
     }
   },
-  "security_setting": {
-    "Guest Users Access": "ゲストユーザーのアクセス",
-    "Fixed by env var": "環境変数 <code>{{forcewikimode}}={{wikimode}}</code> により固定されています。",
-    "Register limitation": "登録の制限",
-    "Register limitation desc": "新しいユーザーを登録する方法を制限します.",
-    "The whitelist of registration permission E-mail address": "登録許可メールアドレスの<br>ホワイトリスト",
-    "users_without_account": "アカウントを持たないユーザーはアクセス不可",
-    "example": "例",
-    "restrict_emails": "登録可能なメールアドレスを制限することができます。",
-    "for_example": "例えば、",
-    "in_this_case": "と記載することで、そのドメインのメールアドレスを持っている人のみ登録可能になります。",
-    "insert_single": "1行に1メールアドレス入力してください。",
-    "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": "完全に削除する",
-    "other_options": "その他のオプション",
-    "deletion_explain": "ページをゴミ箱に入れることができるユーザーを制限します。",
-    "complete_deletion_explain": "ページを完全削除することができるユーザーを制限します。",
-    "recursive_deletion_explain": "子孫を含めたページをゴミ箱に入れることができるユーザーを制限します。",
-    "recursive_complete_deletion_explain": "子孫を含めたページを完全削除することができるユーザーを制限します。",
-    "inherit": "単体のみと同じ",
-    "admin_only": "管理者のみ可能",
-    "admin_and_author": "管理者とページ作者が可能",
-    "anyone": "誰でも可能",
-    "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":"セットアップはまだ完了してません",
-    "alert_siteUrl_is_not_set": "'サイトURL' が設定されていません。{{link}} から設定してください。",
-    "xss_prevent_setting": "XSS(Cross Site Scripting)対策設定",
-    "xss_prevent_setting_link": "マークダウン設定ページに移動",
-    "callback_URL": "コールバックURL",
-    "desc_of_callback_URL": "{{AuthName}} プロバイダ側の設定で利用してください。",
-    "authorization_endpoint": "認可エンドポイント",
-    "token_endpoint": "トークンエンドポイント",
-    "revocation_endpoint": "失効エンドポイント",
-    "introspection_endpoint": "検証エンドポイント",
-    "userinfo_endpoint": "ユーザ情報エンドポイント",
-    "end_session_endpoint": "セッション終了エンドポイント",
-    "registration_endpoint": "登録エンドポイント",
-    "jwks_uri": "JSON Web Key Set URL",
-    "clientID": "クライアントID",
-    "client_secret": "クライアントシークレット",
-    "updated_general_security_setting": "セキュリティ設定を更新しました。",
-    "setup_not_completed_yet": "まだセットアップは完了していません。",
-    "guest_mode": {
-      "deny": "拒否 (アカウントを持つユーザーのみ利用可能)",
-      "readonly": "許可 (ゲストユーザーも閲覧のみ可能)"
-    },
-    "registration_mode": {
-      "open": "公開 (だれでも登録可能)",
-      "restricted": "制限 (登録完了には管理者の承認が必要)",
-      "closed": "非公開 (登録には管理者による招待が必要)"
-    },
-    "share_link_rights": "シェアリンクの権限",
-    "enable_link_sharing": "リンクのシェアを許可",
-    "all_share_links": "全てのシェアリンク",
-    "configuration": "設定",
-    "optional": "オプション",
-    "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/Password",
-      "note for the only env option": "現在LOCAL認証のON/OFFは環境変数の値によって制限されています<br>この設定を変更する場合は環境変数 <code>{{env}}</code> の値をfalseに変更もしくは削除してください",
-      "enable_local": "ID/Password を有効にする",
-      "password_reset_by_users": "ユーザーによるパスワード再設定",
-      "enable_password_reset_by_users": "ユーザーによるパスワード再設定を有効にする",
-      "password_reset_desc": "ログイン時のパスワードを忘れた際に、ユーザー自身がパスワードを再設定できます。",
-      "email_authentication": "ユーザー登録時のメール認証",
-      "enable_email_authentication": "メール認証を有効にする",
-      "enable_email_authentication_desc": "ユーザー登録時にメール認証を行います。",
-      "please_enable_mailer": "メール認証を有効にするには、メール設定を完了させてください。",
-      "need_complete_mail_setting_warning": "以下の機能を使えるようにするには、メール設定を完了させてください。"
-    },
-    "ldap": {
-      "enable_ldap": "LDAP を有効にする",
-      "server_url_detail": "LDAP URLを <code>ldap://host:port/DN</code> または <code>ldaps://host:port/DN</code> の形式で入力してください。",
-      "bind_mode": "Bind モード",
-      "bind_manager": "管理者 Bind",
-      "bind_user": "ユーザー Bind",
-      "bind_DN_manager_detail": "ディレクトリーサービスに認証する際のアカウント DN",
-      "bind_DN_user_detail1": "ディレクトリーサービスに Bind するアカウント DN を決定するためのクエリ",
-      "bind_DN_user_detail2": "ログイン時に入力されるユーザー名を使用するには <code>&#123;&#123;username&#125;&#125;</code> の形式を使用してください。",
-      "bind_DN_password": "Bind DN パスワード",
-      "bind_DN_password_manager_detail": "Bind DN アカウントのパスワード",
-      "bind_DN_password_user_detail": "ログイン時のパスワードが使用されます。",
-      "search_filter": "検索フィルター",
-      "search_filter_detail1": "認証されるユーザーを一意に決定するための LDAP フィルタ",
-      "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": "'sAMAccountName' に一致 (Active Directory)",
-      "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>uid</code> を含む <code>memberUid</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 Identity プロバイダ内で一意に識別可能な値を格納している属性",
-      "username_detail": "新規ユーザーのアカウント名(<code>username</code>)に関連付ける属性",
-      "mapping_detail": "新規ユーザーの{{target}}に関連付ける属性",
-      "cert_detail": "IdP からのレスポンスの validation を行うためのPEMエンコードされた X.509 証明書",
-      "Use env var if empty": "データベース側の値が空の場合、環境変数 <code>{{env}}</code> の値を利用します",
-      "note for the only env option": "現在SAML認証のON/OFFの設定値及びハイライトされている設定値は環境変数の値のみを使用するようになっています<br>この設定を変更する場合は環境変数 <code>{{env}}</code> の値をfalseに変更もしくは削除してください",
-      "attr_based_login_control_detail": "SAMLの <code>&lt;saml:AttributeStatement&gt;</code> 要素に含まれる <code>&lt;saml:Attribute&gt;</code> 要素と、その子要素 <code>&lt;saml:AttributeValue&gt;</code> を利用してログインの可否を制御します。",
-      "attr_based_login_control_rule_help": "<h5>利用可能なクエリ:</h5><ul><li>Terms</li><li>Fields</li><li>AND/NOT/OR Operator</li><li>Grouping</li></ul><h5>利用不可なクエリ:</h5><ul><li>Wildcard, Fuzzy, Proximity, Range and Boosting</li><li>+/- Operator</li><li>Field Grouping</li></ul><h5>特殊文字のエスケープ</h5>次の特殊文字はエスケープする必要があります。<code>+ - && || ! ( ) { } [ ] ^ &quot; &tilde; * ? : &#92;</code> and <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> を持つユーザーにログインを<strong>許可</strong>します。",
-      "attr_based_login_control_rule_exampl2": "<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": "Succeeded to update SAML setting"
-    },
-    "Basic": {
-      "enable_basic": "Basic を有効にする",
-      "name": "Basic 認証",
-      "desc_1": "Authorization ヘッダに格納されている <code>username</code> でログインします。",
-      "desc_2": "ユーザーが存在しなかった場合は自動生成します。",
-      "updated_basic": "Basic認証 を更新しました"
-    },
-    "OAuth": {
-      "enable_oidc": "OIDC を有効にする",
-      "register": "%sに登録",
-      "change_redirect_url": "承認済みのリダイレクトURLに、 <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>としてGrowiを登録",
-        "register_5": "上記フォームにクライアントIDとクライアントシークレットを入力",
-        "updated_google": "Google OAuth を更新しました"
-      },
-      "Facebook": {
-        "name": "Facebook OAuth"
-      },
-      "Twitter": {
-        "enable_twitter": "Twitter OAuth を有効にする",
-        "name": "Twitter OAuth",
-        "register_1": "{{link}} へアクセス",
-        "register_2": "Twitterにサインイン",
-        "register_3": "Create New Appをクリック &rightarrow; Application Detailsの各項目を入力",
-        "register_4": "Create your Twitter Applicationで作成",
-        "register_5": "上記フォームにクライアントIDとクライアントシークレットを入力",
-        "updated_twitter": "Twitter OAuth を更新しました"
-      },
-      "GitHub": {
-        "enable_github": "GitHub OAuth を有効にする",
-        "name": "GitHub OAuth",
-        "register_1": "{{link}} へアクセス",
-        "register_2": "\"Authorization callback URL\"を<code>{{url}}</code>としてGrowiを登録",
-        "register_3": "上記フォームにクライアントIDとクライアントシークレットを入力",
-        "updated_github": "GitHub OAuth を更新しました"
-      },
-      "OIDC": {
-        "name": "OpenID Connect",
-        "id_detail": "OIDC claims で一意に識別可能な値を格納している属性",
-        "username_detail": "新規ユーザーのアカウント名(<code>username</code>)に関連付ける属性",
-        "name_detail": "新規ユーザー名(<code>name</code>)に関連付ける属性",
-        "mapping_detail": "新規ユーザーの{{target}}に関連付ける属性",
-        "updated_oidc": "OpenID Connect を更新しました",
-        "Use discovered URL if empty": "データベース側の値が空の場合、\"Issuer Host\"から検出した値を利用します。"
-      },
-      "how_to": {
-        "google": "Google OAuth の設定方法",
-        "github": "GitHub OAuth の設定方法",
-        "twitter": "Twitter OAuth の設定方法"
-      }
-    },
-    "form_item_name": {
-      "entryPoint": "エントリーポイント",
-      "issuer": "発行者",
-      "cert": "証明書",
-      "attrMapId": "ID",
-      "attrMapUsername": "ユーザー名",
-      "attrMapMail": "メールアドレス",
-      "attrMapFirstName": "姓",
-      "attrMapLastName": "名",
-      "ABLCRule": "ルール"
-    }
-  },
-  "notification_setting": {
-    "slack_incoming_configuration": "Slack Incoming Webhooks 設定",
-    "prioritize_webhook": "Slack アプリより Incoming Webhook を優先する",
-    "prioritize_webhook_desc": "このオプションをオンにすると、 Slack App が有効になっていても GROWI は Incoming Webhook を使用します。",
-    "slack_app_configuration": "Slack App 設定",
-    "slack_app_configuration_desc": "Crowi 互換の機能です。<br /> <strong>設定が複雑すぎる</strong>のでオススメしません。",
-    "use_instead": "代わりに Slack Incoming Webhooks 設定を使用してください。",
-    "how_to": {
-      "header": "Incoming Webhooks の設定方法",
-      "workspace": "ワークスペースで Webhook を追加します。",
-      "workspace_desc1": "<a href='https://slack.com/services/new/incoming-webhook'>Incoming Webhooks Configuration page</a> にアクセスします。",
-      "workspace_desc2": "投稿するチャンネルを選びます。",
-      "workspace_desc3": "追加します。",
-      "at_growi": "GROWI 管理画面で Webhook URL を設定します。",
-      "at_growi_desc": "このページで &rdquo;Webhook URL&rdquo; を入力して送信します。"
-    },
-    "user_trigger_notification_header": "デフォルトパターンの通知設定",
-    "pattern": "パターン",
-    "channel": "チャンネル名",
-    "pattern_desc": "Wiki のパス名。 パスには <code>*</code> を使用できます。",
-    "channel_desc": "<code>#</code> を除いた Slack チャンネル名",
-    "valid_page": "通知の有効 / 無効",
-    "link_notification_help": "<strong>linkを知っている人のみ閲覧できるページ</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": "SlackApp設定を更新しました",
-    "add_notification_pattern": "通知パターンを追加しました。",
-    "delete_notification_pattern": "通知パターンを削除しました。",
-    "delete_notification_pattern_desc1": "Path: {{path}} を削除します。",
-    "delete_notification_pattern_desc2": "Once deleted, it cannot be recovered",
-    "toggle_notification": "{{path}}の通知設定を変更しました"
-  },
-  "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": "SearchService でエラーが発生しています",
-    "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": "この作業には数秒かかります。"
-  },
-  "to_cloud_settings": "GROWI.cloud の管理画面へ",
   "login": {
     "Sign in error": "ログインエラー",
-    "Registration successful": "登録完了",
-    "Setup": "セットアップ"
+    "Registration successful": "登録が完了しました。管理者の承認をお待ちください。",
+    "Setup": "セットアップ",
+    "enabled_ldap_has_configuration_problem":"LDAPは有効ですが、設定に問題があります。",
+    "set_env_var_for_logs": "(ログを取得するためには、環境変数 <code>DEBUG=crowi:service:PassportService</code> を設定してください。)"
+  },
+  "invited": {
+    "discription_heading": "アカウント作成",
+    "discription": "招待を受け取ったメールアドレスでアカウントを作成します"
   },
   "export_bulk": {
     "failed_to_export": "ページのエクスポートに失敗しました",
@@ -976,8 +625,9 @@
     "fail_to_fetch_access_token": "アクセストークンの取得に失敗しました、再度お試しください。",
     "successfully_disconnected": "切断に成功しました!",
     "strategy_has_not_been_set_up": "{{strategy}} はセットアップされていません。",
+    "ldap_user_not_valid": "Ldap user is no valid",
+    "external_account_not_exist": "外部アカウントが見つからない、または作成に失敗しました",
     "maximum_number_of_users": "ユーザー数が上限を超えたためアクティベートできません。",
-    "database_error":"データベースサーバーに問題があります。",
     "sign_in_failure": "ログインに失敗しました。",
     "aws_sttings_required": "この機能にはAWS設定が必要です。管理者に訪ねて下さい。",
     "application_already_installed": "アプリケーションのインストールが完了しました。",
@@ -986,6 +636,8 @@
     "username_should_not_be_null":"Username が null になっています 管理画面の認証機構設定にて設定の確認をしてください",
     "email_address_is_already_registered":"このメールアドレスは既に登録されています。",
     "can_not_register_maximum_number_of_users":"ユーザー数が上限を超えたため登録できません。",
+    "email_settings_is_not_setup":"E-mail 設定が完了していません。管理者に問い合わせてください。",
+    "email_authentication_is_not_enabled": "メール認証が有効になっていません。管理者に問い合わせてください。",
     "failed_to_register":"登録に失敗しました。",
     "successfully_created":"{{username}} が作成されました。",
     "can_not_activate_maximum_number_of_users":"ユーザーが上限に達したためアクティベートできません。",
@@ -995,7 +647,21 @@
     "complete_to_install2":"GROWI のインストールが完了しました!はじめに、このページで各種設定を確認してください。",
     "failed_to_create_admin_user":"管理ユーザーの作成に失敗しました。{{errMessage}}",
     "successfully_send_email_auth":"{{email}} にメールを送信しました。添付されたURLをクリックし、本登録を完了させてください",
-    "incorrect_token_or_expired_url":"トークンが正しくないか、URLの有効期限が切れています。"
+    "incorrect_token_or_expired_url":"トークンが正しくないか、URLの有効期限が切れています。",
+    "user_already_loggedin": "ログイン中のため、新規アカウントを作成できませんでした。",
+    "registration_closed": "新しいアカウントを作成する権限がありません。",
+    "Username has invalid characters": "ユーザー名に不正な文字が含まれています.",
+    "Username field is required": "User ID は必須項目です",
+    "Name field is required": "ユーザーID は必須項目です",
+    "Email format is invalid": "メールアドレスのフォーマットが無効です",
+    "Email field is required": "メールアドレスは必須項目です",
+    "Password has invalid character": "パスワードに無効な文字があります",
+    "Password minimum character should be more than 8 characters": "パスワードの最小文字数は8文字以上です",
+    "Password field is required": "パスワードの欄は必ず入力してください",
+    "Username or E-mail has invalid characters": "ユーザー名または、メールアドレスに無効な文字があります",
+    "Password minimum character should be more than 6 characters": "パスワードの最小文字数は6文字以上です",
+    "user_not_found": "ユーザーが見つかりません",
+    "provider_duplicated_username_exception": "<p><strong><i class='icon-fw icon-ban'></i>エラー: DuplicatedUsernameException</strong></p><p class='mb-0'> {{ failedProviderForDuplicatedUsernameException }} 認証は成功しましたが、新しいユーザーを作成できませんでした。詳しくは<a href='https://github.com/weseek/growi/issues/193'>こちら: #193</a>.</p>"
   },
   "grid_edit":{
     "create_bootstrap_4_grid":"Bootstrap 4 グリッドを作成",
@@ -1022,6 +688,7 @@
     "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": "パスワードと確認パスワードが一致しません"
   },
@@ -1078,12 +745,6 @@
     "belonging_to_no_group": "所属しているグループが見つかりませんでした。",
     "manage_user_groups": "グループ管理"
   },
-  "crop_image_modal": {
-    "image_crop": "画像の切り抜き",
-    "crop": "トリミング",
-    "reset": "リセット",
-    "cancel": "キャンセル"
-  },
   "fix_page_grant": {
     "modal": {
       "no_grant_available": "選択可能な権限のリストが見つかりませんでした。まず親ページの権限を修正したのちに再試行してください。",
@@ -1127,5 +788,13 @@
   "page_operation":{
     "paths_recovered": "パスを修復しました",
     "path_recovery_failed":"パスを修復できませんでした"
+  },
+  "footer": {
+    "bookmarks": "ブックマーク",
+    "recently_created": "最近作成したページ"
+  },
+  "v5_page_migration": {
+    "page_tree_not_avaliable" : "Page Tree 機能は現在使用できません。",
+    "go_to_settings": "設定する"
   }
 }

+ 356 - 12
packages/app/public/static/locales/zh_CN/admin/admin.json → packages/app/public/static/locales/zh_CN/admin.json

@@ -1,4 +1,315 @@
 {
+  "meta": {
+    "display_name": "简体中文"
+  },
+  "Update": "更新",
+  "Delete": "删除",
+  "User": "用户",
+  "Name": "姓名",
+  "Created": "创建",
+  "Edit": "编辑",
+  "Description": "描述",
+  "last_login": "上次登录",
+  "wiki_management_home_page": "Wiki管理首页",
+  "public": "公共",
+  "anyone_with_the_link": "任何人",
+  "specified_users": "仅指定用户",
+  "only_me": "只有我",
+  "only_inside_the_group": "仅组内",
+  "security_settings": {
+    "security_settings": "安全设置",
+    "scope_of_page_disclosure": "页面公开范围",
+    "set_point": "设定值",
+    "always_displayed": "始终显示",
+    "always_hidden": "总是隐藏",
+    "displayed_or_hidden": "显示/隐藏",
+    "Guest 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": "请每行插入一个电子邮件地址。",
+    "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": "彻底删除",
+    "other_options": "其他选项",
+    "deletion_explain": "限制用户对选定的单一页面进行垃圾处理。",
+    "complete_deletion_explain": "限制可以完全删除所选单页的用户。",
+    "recursive_deletion_explain": "限制用户可以捣毁包括子孙在内的页面。",
+    "recursive_complete_deletion_explain": "限制可以完全删除页面的用户,包括子孙。",
+    "inherit": "继承(使用与单页相同的设置)。",
+		"admin_only": "仅管理员",
+		"admin_and_author": "管理员|作者",
+		"anyone": "任何人",
+    "session": "会议",
+    "max_age": "有效期间  (msec)",
+    "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": "转到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",
+    "introspection_endpoint": "Introspection Endpoint",
+    "userinfo_endpoint": "UserInfo Endpoint",
+    "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": "安装尚未完成",
+		"guest_mode": {
+			"deny": "拒绝(仅限注册用户)",
+			"readonly": "接受(来宾可以只读)"
+		},
+		"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",
+    "share_link_rights": "分享链接权",
+    "enable_link_sharing": "启用链接共享",
+    "all_share_links": "所有共享链接",
+		"configuration": " 配置",
+		"optional": "可选的",
+		"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": "启用用户重置密码",
+      "password_reset_desc": "忘记密码时,用户可以自行重置",
+      "email_authentication": "用户注册时的电子邮件身份验证",
+      "enable_email_authentication": "启用电子邮件身份验证",
+      "enable_email_authentication_desc": "用户注册将执行电子邮件身份验证。",
+      "need_complete_mail_setting_warning": "要使用以下功能,请完成邮件设置。"
+		},
+		"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"
+		},
+		"Basic": {
+			"enable_basic": "Enable Basic",
+			"name": "Basic Authentication",
+			"desc_1": "Login with <code>username</code> in Authorization header.",
+			"desc_2": "User will be automatically generated if not exist.",
+			"updated_basic": "Succeeded to update Basic 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"
+			},
+			"Facebook": {
+				"name": "Facebook OAuth"
+			},
+			"Twitter": {
+				"enable_twitter": "Enable Twitter OAuth",
+				"name": "Twitter OAuth",
+				"register_1": "Access {{link}}",
+				"register_2": "Sign in Twitter",
+				"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_twitter": "Succeeded to update Twitter 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 %s when creating new users",
+				"register_1": "Contant to OIDC IdP Administrator",
+				"register_2": "Register your OIDC App with \"Authorization callback URL\" as <code>%s</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?",
+				"twitter": "How to configure Twitter 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": {
+		"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": "这可能需要一段时间。"
+	},
   "mailer_setup_required": "<a href='/admin/app'>Email settings</a> are required to send.",
   "admin_top": {
     "management_wiki": "管理Wiki",
@@ -20,8 +331,6 @@
     "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>"
   },
   "v5_page_migration": {
-    "page_tree_not_avaliable": "Page Tree 功能不可用",
-    "go_to_settings": "进入设置,启用该功能",
     "migration_desc": "有一些页面具有旧的v4兼容性。为了利用新的功能,如页面树和容易重命名,请将您的所有页面转换为v5兼容性。",
     "migration_note": "注意:你将失去页面路径的唯一约束。",
     "upgrade_to_v5": "转换为v5兼容性",
@@ -51,9 +360,12 @@
     "site_name": "网站名称 ",
     "sitename_change": "您可以更改用于标题和HTML标题的网站名称。",
     "header_content": "此处输入的内容将显示在标题等中。",
-    "site_url_desc": "用于网站URL设置。",
-    "site_url_warn": "某些功能不起作用,因为未设置网站URL。",
-    "siteurl_help": "网站完整URL起始于 <code>http://</code> or <code>https://</code>.",
+    "site_url": {
+      "title": "主页URL设置",
+      "desc": "用于网站URL设置。",
+      "warn": "某些功能不起作用,因为未设置网站URL。",
+      "help": "网站完整URL起始于 <code>http://</code> or <code>https://</code>."
+    },
     "confidential_name": "内部名称",
     "confidential_example": "ex):仅供内部使用",
     "default_language": "新用户的默认语言",
@@ -104,7 +416,8 @@
     "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> ."
   },
-  "markdown_setting": {
+  "markdown_settings": {
+    "markdown_settings": "Markdown设置",
     "lineBreak_header": "换行设置",
     "lineBreak_desc": "您可以更改换行设置。",
     "lineBreak_options": {
@@ -147,7 +460,8 @@
       "import_recommended": "导入建议 {{target}}"
     }
   },
-  "customize_setting": {
+  "customize_settings": {
+    "customize_settings": "页面定制",
     "default_sidebar_mode": {
       "title": "默认的侧边栏模式",
       "desc": "你可以为新用户和访问该网页的客人设置侧边栏模式。",
@@ -203,8 +517,6 @@
       "select_search_scope_children_as_default": "选择“当前分支以下内容”, 作为搜索范围的默认值",
       "select_search_scope_children_as_default_desc": "当设置值为“关”时,“所有页面”被作为搜索范围的默认值。"
     },
-    "code_highlight": "代码突出显示",
-    "nocdn_desc": "当强制应用环境变量<code>NO_CDN=true</code><br>Github样式时,此函数被禁用。",
     "custom_title": "自定义标题",
     "custom_title_detail": "您可以自定义<code>&lt;title&gt;</code>标记。<br><code>&123;&123;sitename&&125;&125;</code>将自动替换为应用程序名称,并且<code>&123;&123;page&&125;&125;</code>将替换为页面名称/路径。",
     "custom_title_detail_placeholder1": "<code>&#123;&#123;站点名称&#125;&#125;</code>-此wiki的站点名称。",
@@ -226,6 +538,12 @@
     "delete_logo": "删除徽标"
   },
   "importer_management": {
+    "import_data": "导入数据",
+    "article": "主题",
+    "category": "分类",
+    "tag": "标签",
+    "page": "页面",
+    "page_path": "相对路径",
     "beta_warning": "这个函数是Beta。",
     "import_from": "Import from {{from}}",
     "import_growi_archive": "Import GROWI archive",
@@ -297,6 +615,7 @@
     "Directory_hierarchy_tag": "Directory hierarchy tag"
   },
   "export_management": {
+    "export_archive_data": "导出主题数据",
     "exporting_collection_list": "正在导出集合列表",
     "exported_data_list": "导出的存档数据列表",
     "export_collections": "导出集合",
@@ -307,7 +626,7 @@
     "export": "导出",
     "cancel": "取消",
     "file": "文件",
-    "growi_version": "Growi Version",
+    "growi_version": "GROWI Version",
     "collections": "Collections",
     "exported_at": "Exported At",
     "export_menu": "导出菜单",
@@ -315,12 +634,14 @@
     "delete": "删除"
   },
   "external_notification": {
+    "external_notification": "外部通知",
     "enabled": "Enabled",
     "disabled": "Disabled",
     "header_status": "Slack整合状态",
     "caution_enabled": "CAUTION: 目前,在此页面中配置的通知只会通知设置为主要的 Slack 工作区。 "
   },
   "slack_integration": {
+    "slack_integration": "Slack一体化",
     "selecting_bot_types": {
       "slack_bot": "Slack bot",
       "detailed_explanation": "详细说明",
@@ -431,12 +752,15 @@
     }
   },
   "slack_integration_legacy": {
+    "slack_integration_legacy": "旧版Slack一体化",
     "alert_disabled": "由于<a href='/admin/slack-integration'>新设置</a>已启用,因此该'旧版Slack一体化'目前已被禁用。",
     "alert_deplicated": "这个 '旧版Slack一体化' 已经过时了,将来会停止使用。使用<a href='/admin/slack-integration'>新的设置</a>来代替。"
   },
   "user_management": {
+    "user_management": "用户管理",
     "invite_users": "临时发布新用户",
     "click_twice_same_checkbox": "您应该至少选中一个复选框。",
+    "status": "状态",
     "invite_modal": {
       "emails": "电子邮件",
       "description1": "通过电子邮件地址临时发布新用户。",
@@ -492,12 +816,14 @@
     "current_users": "当前用户:"
   },
   "user_group_management": {
+    "user_group_management": "用户组管理",
     "create_group": "创建新组",
     "add_child_group": "添加一个子组",
     "remove_child_group": "移除",
     "deny_create_group": "不能用当前设置创建新组。",
     "group_name": "组名",
     "group_example": "e.g.:第1组",
+    "child_user_group": "儿童用户组",
     "parent_group": "父母组",
     "select_parent_group": "选择父组",
     "release_parent_group": "Release parent group",
@@ -538,6 +864,8 @@
     }
   },
   "audit_log_management": {
+    "audit_log": "审计日志",
+    "audit_log_settings": "审计日志设置",
     "user": "用户",
     "username": "帐号",
     "date": "日期",
@@ -557,7 +885,9 @@
     "docs_url": {
       "log_type": "https://docs.growi.org/en/admin-guide/admin-cookbook/audit-log-setup.html#log-types"
     }
-
+  },
+  "cloud_setting_management": {
+    "to_cloud_settings": "進入 GROWI.cloud 的管理界面"
   },
   "audit_log_action_category": {
     "Page": "页面",
@@ -608,6 +938,10 @@
     "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": "导出页面",
@@ -625,7 +959,7 @@
     "SHARE_LINK_NOT_FOUND": "页面浏览量(未找到分享链接)",
     "ATTACHMENT_ADD": "添加附件",
     "ATTACHMENT_REMOVE": "删除附件",
-    "ACTION_ATTACHMENT_DOWNLOAD": "下载附件",
+    "ATTACHMENT_DOWNLOAD": "下载附件",
     "SEARCH_PAGE": "页面搜索",
     "SEARCH_PAGE_VIEW": "页面浏览量(搜索结果页面)",
     "ADMIN_APP_SETTING_UPDATE": "更新应用设置",
@@ -725,5 +1059,15 @@
     "ADMIN_SEARCH_CONNECTION": "重试Elasticsearch连接",
     "ADMIN_SEARCH_INDICES_NORMALIZE": "试图重新连接Elasticsearch",
     "ADMIN_SEARCH_INDICES_REBUILD": "重建 Elasticsearch 索引"
+  },
+  "toaster": {
+    "give_user_admin": "Succeeded to give {{username}} admin",
+    "remove_user_admin": "Succeeded to remove {{username}} admin ",
+		"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": "成功更新分享链接设置",
+    "failed_to_reset_password":"Failed to reset password"
   }
 }

+ 100 - 0
packages/app/public/static/locales/zh_CN/commons.json

@@ -0,0 +1,100 @@
+{
+	"Show": "显示",
+	"Hide": "隐藏",
+  "Add": "添加",
+  "Reset": "重启",
+	"Sign out": "退出",
+  "New": "新建",
+
+  "meta": {
+    "display_name": "简体中文"
+  },
+  "toaster": {
+    "create_succeeded": "Succeeded to create {{target}}",
+    "create_failed": "Failed to create {{target}}",
+    "update_successed": "Succeeded to update {{target}}",
+    "update_failed": "Failed to update {{target}}",
+
+    "remove_share_link_success": "Succeeded to remove {{shareLinkId}}",
+    "remove_share_link": "Succeeded to remove {{count}} share links"
+  },
+  "alert": {
+    "siteUrl_is_not_set": "主页URL未设置,通过 {{link}} 设置",
+    "please_enable_mailer": "请先设置邮件程序。"
+  },
+  "headers": {
+    "app_settings": "系统设置"
+  },
+
+  "header_search_box": {
+		"label": {
+			"All pages": "所有页面",
+			"This tree": "当前分支"
+		},
+		"item_label": {
+			"All pages": "所有页面",
+			"This tree": "当前分支以下内容"
+		}
+  },
+
+  "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" : "标记为已读"
+  },
+
+  "personal_dropdown": {
+    "home": "家",
+    "settings": "设置",
+		"color_mode": "颜色模式",
+		"sidebar_mode": "边栏模式",
+		"sidebar_mode_editor": "编辑器上的边栏模式",
+		"use_os_settings": "使用操作系统设置"
+  },
+
+	"copy_to_clipboard": {
+		"Copy to clipboard": "复制到剪贴板",
+		"Page path": "页面路径",
+		"Page URL": "页面Url",
+		"Parmanent link": "参数化链接",
+		"Page path and parmanent link": "页面路径及参数化链接",
+		"Markdown link": "Markdown链接"
+	},
+
+  "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": "该页面不存在"
+  }
+}

+ 57 - 391
packages/app/public/static/locales/zh_CN/translation.json

@@ -1,4 +1,7 @@
 {
+  "meta": {
+    "display_name": "简体中文"
+  },
   "Help": "帮助",
   "view": "View",
 	"Edit": "编辑",
@@ -17,26 +20,20 @@
 	"Move/Rename": "移动/重命名",
 	"Redirected": "重定向",
 	"Unlinked": "Unlinked",
+  "unlink_redirection": "取消链接重定向",
   "Done": "Done",
   "Cancel": "取消",
 	"Create": "创建",
   "Description": "描述",
 	"Admin": "管理",
 	"administrator": "管理员",
-	"Tag": "标签",
 	"Tags": "Tags",
-  "New": "新建",
   "Close": "Close",
 	"Shortcuts": "快捷方式",
+  "CustomSidebar": "Custom Sidebar",
 	"eg": "e.g.",
 	"add": "添加",
 	"Undo": "撤销",
-	"Article": "主题",
-	"Page": "页面",
-	"Page Path": "相对路径",
-	"Category": "分类",
-	"User": "用户",
-	"status": "状态",
 	"account_id": "用户Id",
 	"Initialize": "初始化",
   "Update": "更新",
@@ -75,7 +72,6 @@
   "username": "用户名",
 	"Created": "创建",
 	"Last updated": "上次更新",
-  "Last_Login": "上次登录",
 	"Share": "分享",
   "Share Link": "分享链接",
 	"Markdown Link": "Markdown链接",
@@ -117,31 +113,16 @@
 	"Input page name (optional)": "Input page name (optional)",
 	"New Page": "新页面",
 	"Create under": "Create page under below:",
-	"Wiki Management Home Page": "Wiki管理首页",
-	"App Settings": "系统设置",
   "V5 Page Migration": "转换为V5的兼容性",
   "GROWI.5.0_new_schema": "GROWI.5.0 new schema",
-  "See_more_detail_on_new_schema": "更多详情请见<a href='#'>{{url}}</a> <i class='icon-share-alt'></i> ",
-	"Site URL settings": "主页URL设置",
+  "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> <i class='icon-share-alt'></i> ",
 	"Markdown Settings": "Markdown设置",
-	"Customize": "页面定制",
 	"Notification Settings": "通知设置",
-  "slack_integration": "Slack一体化",
-  "External_Notification": "外部通知",
-  "Legacy_Slack_Integration": "旧版Slack一体化",
-	"User_Management": "用户管理",
 	"external_account_management": "外部账户管理",
   "UserGroup": "用户组",
   "ChildUserGroup": "儿童用户组",
-	"UserGroup Management": "用户组管理",
-  "AuditLog": "审计日志",
-  "AuditLog Settings": "审计日志设置",
-	"Full Text Search Management": "全文搜索管理",
-	"Import Data": "导入数据",
-	"Export Archive Data": "导出主题数据",
 	"Basic Settings": "基础设置",
 	"Basic authentication": "基本身份验证",
-	"Register limitation": "注册限制",
 	"The contents entered here will be shown in the header etc": "此处输入的内容将显示在标题等中",
 	"Public": "公共",
 	"Anyone with the link": "任何人",
@@ -149,11 +130,6 @@
 	"Only me": "只有我",
   "Only inside the group": "仅组内",
   "page_list": "Page List",
-	"scope_of_page_disclosure": "页面公开范围",
-	"set_point": "设定值",
-	"always_displayed": "始终显示",
-	"always_hidden": "总是隐藏",
-	"displayed_or_hidden": "显示/隐藏",
 	"Reselect the group": "重新选择组",
 	"Shareable link": "可分享链接",
 	"The whitelist of registration permission E-mail address": "注册许可电子邮件地址的白名单",
@@ -167,13 +143,11 @@
 	"edited this page": "edited this page.",
 	"List Drafts": "草稿",
 	"Deleted Pages": "已删除页",
-	"Sign out": "退出",
   "Disassociate": "解除关联",
   "No bookmarks yet": "暂无书签",
   "add_bookmark": "添加到书签",
   "remove_bookmark": "从书签中删除",
   "wide_view": "视野开阔",
-	"Recent Created": "最新创建",
   "Recent Changes": "最新修改",
   "Page Tree": "页面树",
   "original_path":"Original path",
@@ -191,20 +165,19 @@
 		"invalid_syntax": "%s的语法无效。",
     "title_required": "标题是必需的。"
   },
-  "not_found_page": {
-    "Create Page": "创建页面",
-    "page_not_exist": "该页面不存在",
-    "page_not_exist_alert": "该页面不存在,请创建一个新页面"
+  "not_creatable_page": {
+    "could_not_creata_path": "无法创建路径"
   },
   "custom_navigation": {
-    "no_page_list": "There are no pages under this page.",
-    "link_sharing_is_disabled": "链接共享已被禁用"
+    "no_page_list": "There are no pages under this page."
   },
 	"installer": {
 		"setup": "安装",
 		"create_initial_account": "创建初始用户",
 		"initial_account_will_be_administrator_automatically": "初始帐户将自动成为管理员。",
-		"unavaliable_user_id": "用户ID不可用"
+		"unavaliable_user_id": "用户ID不可用",
+    "failed_to_install": "GROWI安装失败。请再试一次。",
+    "failed_to_login_after_install": "安装后登录失败。重定向到登录表格..."
 	},
 	"breaking_changes": {
 		"v346_using_basic_auth": "当前使用的基本身份验证在不久的将来将不再可用。从%s中删除设置"
@@ -248,29 +221,10 @@
 		"new_password_confirm": "重复新密码",
 		"password_is_not_set": "密码未设置"
 	},
-	"Security Settings": "安全设置",
 	"API Settings": "API设置",
 	"API Token Settings": "API token 设置",
 	"Current API Token": "当前 API token",
 	"Update API Token": "更新 API token",
-	"header_search_box": {
-		"label": {
-			"All pages": "所有页面",
-			"This tree": "当前分支"
-		},
-		"item_label": {
-			"All pages": "所有页面",
-			"This tree": "当前分支以下内容"
-		}
-  },
-  "in_app_notification": {
-    "notification_list": "应用内通知列表",
-    "see_all": "查看通知列表",
-    "no_notification": "您没有任何通知",
-    "all": "全部",
-    "unopend": "未读",
-    "mark_all_as_read" : "标记为已读"
-  },
   "in_app_notification_settings": {
     "in_app_notification_settings": "在应用程序通知设置",
     "subscribe_settings": "自动订阅(接收通知)页面的设置",
@@ -314,14 +268,6 @@
       "no_nfd": "禁止使用 UTF8-MAC 浊音等 NFD。"
     }
   },
-	"copy_to_clipboard": {
-		"Copy to clipboard": "复制到剪贴板",
-		"Page path": "页面路径",
-		"Page URL": "页面Url",
-		"Parmanent link": "参数化链接",
-		"Page path and parmanent link": "页面路径及参数化链接",
-		"Markdown link": "Markdown链接"
-	},
 	"search_help": {
 		"title": "搜索帮助",
 		"and": {
@@ -369,7 +315,8 @@
 		"overwrite_scopes": "{{operation}和覆盖所有子体的作用域",
 		"notice": {
 			"conflict": "无法保存您所做的更改,因为其他人正在编辑此页。请在重新加载页面后重新编辑受影响的部分。"
-		}
+		},
+    "changes_not_saved": "您所做的更改可能不会保存。"
   },
   "page_comment": {
     "display_the_page_when_posting_this_comment": "Display the page when posting this comment",
@@ -379,7 +326,8 @@
 		"notfound_or_forbidden": "未找到或禁止原始页。",
 		"already_exists": "具有该路径的页面已存在",
 		"outdated": "页面已被某人更新,现在已过时。",
-		"user_not_admin": "仅管理员用户可以删除"
+		"user_not_admin": "仅管理员用户可以删除",
+    "single_deletion_empty_pages": "空的页面不能被单一删除"
   },
   "page_history": {
     "revision_list": "修订清单",
@@ -512,21 +460,10 @@
     "page_not_found_in_preview": "\"{{path}}\" is not a GROWI page."
   },
 	"toaster": {
-    "create_succeeded": "Succeeded to create {{target}}",
-    "create_failed": "Failed to create {{target}}",
-		"update_successed": "Succeeded to update {{target}}",
-    "update_failed": "Failed to update {{target}}",
     "file_upload_succeeded": "文件上传成功",
     "file_upload_failed": "文件上传失败",
-    "initialize_successed": "Succeeded to initialize {{target}}",
-		"give_user_admin": "Succeeded to give {{username}} admin",
-    "remove_user_admin": "Succeeded to remove {{username}} admin ",
-		"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": "成功更新分享链接设置",
-    "failed_to_reset_password":"Failed to reset password"
+    "save_succeeded": "已成功保存",
+    "issue_share_link": "Succeeded to issue new share link"
   },
 	"template": {
 		"modal_label": {
@@ -602,15 +539,10 @@
     "popover_title": "Slack Notification",
     "popover_desc": "Input channel name. You can notify multiple channels by entering a comma-separated list."
   },
-  "security_settings": "安全设置",
   "share_links": {
     "Shere this page link to public": "Shere this page link to public",
     "share_link_list": "Share link list",
     "share_link_management": "Share Link Management",
-    "No_share_links":"No share links",
-    "Share Link": "Share Link",
-    "Page Path": "Page Path",
-    "share_link_notice":"remove all share links",
     "delete_all_share_links":"Delete all share links",
     "expire": "Expiration",
     "Days": "Days",
@@ -620,300 +552,9 @@
     "Unlimited": "unlimited",
     "Issue": "Issue",
     "share_settings" :"Share settings",
-    "Invalid_Number_of_Date" : "You entered invalid value"
+    "Invalid_Number_of_Date" : "You entered invalid value",
+    "link_sharing_is_disabled": "链接共享已被禁用"
   },
-	"security_setting": {
-		"Guest 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": "请每行插入一个电子邮件地址。",
-    "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": "彻底删除",
-    "other_options": "其他选项",
-    "deletion_explain": "限制用户对选定的单一页面进行垃圾处理。",
-    "complete_deletion_explain": "限制可以完全删除所选单页的用户。",
-    "recursive_deletion_explain": "限制用户可以捣毁包括子孙在内的页面。",
-    "recursive_complete_deletion_explain": "限制可以完全删除页面的用户,包括子孙。",
-    "inherit": "继承(使用与单页相同的设置)。",
-		"admin_only": "仅管理员",
-		"admin_and_author": "管理员|作者",
-		"anyone": "任何人",
-    "session": "会议",
-    "max_age": "有效期间  (msec)",
-    "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": "安装尚未完成",
-		"alert_siteUrl_is_not_set": "主页URL未设置,通过 {{link}} 设置",
-		"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",
-    "introspection_endpoint": "Introspection Endpoint",
-    "userinfo_endpoint": "UserInfo Endpoint",
-    "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": "安装尚未完成",
-		"guest_mode": {
-			"deny": "拒绝(仅限注册用户)",
-			"readonly": "接受(来宾可以只读)"
-		},
-		"registration_mode": {
-			"open": "打开(任何人都可以注册)",
-			"restricted": "受限(需要管理员批准)",
-			"closed": "已关闭(仅限邀请)"
-		},
-    "share_link_rights": "分享链接权",
-    "enable_link_sharing": "启用链接共享",
-    "all_share_links": "所有共享链接",
-		"configuration": " 配置",
-		"optional": "可选的",
-		"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": "启用用户重置密码",
-      "password_reset_desc": "忘记密码时,用户可以自行重置",
-      "email_authentication": "用户注册时的电子邮件身份验证",
-      "enable_email_authentication": "启用电子邮件身份验证",
-      "enable_email_authentication_desc": "用户注册将执行电子邮件身份验证。",
-      "please_enable_mailer": "请先设置邮件程序。",
-      "need_complete_mail_setting_warning": "要使用以下功能,请完成邮件设置。"
-		},
-		"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"
-		},
-		"Basic": {
-			"enable_basic": "Enable Basic",
-			"name": "Basic Authentication",
-			"desc_1": "Login with <code>username</code> in Authorization header.",
-			"desc_2": "User will be automatically generated if not exist.",
-			"updated_basic": "Succeeded to update Basic 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"
-			},
-			"Facebook": {
-				"name": "Facebook OAuth"
-			},
-			"Twitter": {
-				"enable_twitter": "Enable Twitter OAuth",
-				"name": "Twitter OAuth",
-				"register_1": "Access {{link}}",
-				"register_2": "Sign in Twitter",
-				"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_twitter": "Succeeded to update Twitter 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 %s when creating new users",
-				"register_1": "Contant to OIDC IdP Administrator",
-				"register_2": "Register your OIDC App with \"Authorization callback URL\" as <code>%s</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?",
-				"twitter": "How to configure Twitter 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_setting": {
-		"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}}"
-	},
-	"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": "这可能需要一段时间。"
-	},
-	"personal_dropdown": {
-		"home": "家",
-		"settings": "设置",
-		"color_mode": "颜色模式",
-		"sidebar_mode": "边栏模式",
-		"sidebar_mode_editor": "编辑器上的边栏模式",
-		"use_os_settings": "使用操作系统设置"
-	},
 	"search_result": {
 		"result_meta": "搜索结果:",
 		"deletion_mode_btn_lavel": "选择并删除页面",
@@ -968,12 +609,17 @@
       "error_duplicate_pages_found": "发现多个具有相同路径名称的页面。请重新命名或删除并重试。"
     }
   },
-	"to_cloud_settings": "進入 GROWI.cloud 的管理界面",
 	"login": {
 		"Sign in error": "登录错误",
-		"Registration successful": "注册成功",
-		"Setup": "安装程序"
+		"Registration successful": "注册成功。请等待管理员批准",
+		"Setup": "安装程序",
+    "enabled_ldap_has_configuration_problem":"启用了LDAP,但配置有问题。",
+    "set_env_var_for_logs": "(请设置环境变量 <code>DEBUG=crowi:service:PassportService</code> 以获得日志。)"
 	},
+  "invited": {
+    "discription_heading": "创建账户",
+    "discription": "用被邀请的电子邮件地址创建一个你的账户"
+  },
   "export_bulk": {
     "failed_to_export": "导出失败",
     "failed_to_count_pages": "页面计数失败",
@@ -985,9 +631,10 @@
 		"fail_to_save_access_token": "无法保存访问令牌。请再试一次。",
 		"fail_to_fetch_access_token": "无法获取访问令牌。请重新连接。",
 		"successfully_disconnected": "成功断开连接!",
-		"strategy_has_not_been_set_up": "{{strategy}尚未设置",
+    "strategy_has_not_been_set_up": "{{strategy}} 尚未设置",
+    "ldap_user_not_valid": "Ldap user is no valid",
+    "external_account_not_exist": "查找或创建外部账户失败",
 		"maximum_number_of_users": "注册的用户数不能超过最大值。",
-		"database_error": "发生数据库服务器错误",
 		"sign_in_failure": "登录失败。",
 		"aws_sttings_required": "使用此功能所需的AWS设置。请询问管理员。",
 		"application_already_installed": "应用程序已安装。",
@@ -996,6 +643,8 @@
     "username_should_not_be_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": "无法激活超过最大用户数的用户。",
@@ -1005,7 +654,21 @@
 		"complete_to_install2": "完成安装GROWI!请先检查此页上的每个设置。",
 		"failed_to_create_admin_user": "无法创建管理用户。{{errMessage}",
     "successfully_send_email_auth":"我们向 {{email}} 发送了一封电子邮件。 请点击邮件中的网址并完成注册。",
-    "incorrect_token_or_expired_url":"令牌不正确或 URL 已过期。"
+    "incorrect_token_or_expired_url":"令牌不正确或 URL 已过期。",
+    "user_already_loggedin": "当你登录的时候,你不能创建一个新的账户。",
+    "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 8 characters": "密码最小字符应超过8个字符",
+    "Password field is required": "密码字段是必需的",
+    "Username or E-mail has invalid characters": "用户名或电子邮件有无效的字符",
+    "Password minimum character should be more than 6 characters": "密码最小字符应超过6个字符",
+    "user_not_found": "未找到用户",
+    "provider_duplicated_username_exception": "<p><strong><i class='icon-fw icon-ban'></i>发生了重复用户名异常</strong></p><p class='mb-0'> 你的 {{ failedProviderForDuplicatedUsernameException }} 认证成功了,但不能创建新的用户。参见问题<a href='https://github.com/weseek/growi/issues/193'>#193</a>.</p>"
 	},
   "grid_edit":{
     "create_bootstrap_4_grid":"创建Bootstrap 4网格",
@@ -1032,6 +695,7 @@
     "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": "密码和确认密码不匹配"
   },
@@ -1088,12 +752,6 @@
     "belonging_to_no_group": "无法找到你所属的团体。",
     "manage_user_groups": "管理用户组"
   },
-  "crop_image_modal": {
-    "image_crop": "图像裁剪",
-    "crop": "修剪",
-    "reset": "重启",
-    "cancel": "取消"
-  },
   "fix_page_grant": {
     "modal": {
       "no_grant_available": "无法找到可选择的权限列表。 请先修改父页的权限,然后再试一次。",
@@ -1137,5 +795,13 @@
   "page_operation":{
     "paths_recovered": "成功恢复了页面路径",
     "path_recovery_failed":"路径恢复失败"
+  },
+  "footer": {
+    "bookmarks": "书签",
+    "recently_created": "最近创建页面"
+  },
+  "v5_page_migration": {
+    "page_tree_not_avaliable": "Page Tree 功能不可用",
+    "go_to_settings": "进入设置,启用该功能"
   }
 }

+ 0 - 7
packages/app/resource/cdn-manifests.js

@@ -147,13 +147,6 @@ module.exports = {
         integrity: '',
       },
     },
-    {
-      name: 'jquery-ui',
-      url: 'https://cdn.jsdelivr.net/jquery.ui/1.11.4/jquery-ui.min.css',
-      args: {
-        integrity: '',
-      },
-    },
     {
       name: 'highlight-theme-github',
       url: 'https://cdn.jsdelivr.net/npm/highlight.js@9.13.0/styles/github.css',

Разница между файлами не показана из-за своего большого размера
+ 1 - 1
packages/app/resource/locales/en_US/sandbox-diagrams.md


+ 1 - 1
packages/app/resource/locales/en_US/sandbox-math.md

@@ -1,6 +1,6 @@
 # :pencil: Math
 
-See [MathJax](https://www.mathjax.org/).
+See [KaTeX](https://katex.org/).
 
 ## Inline Formula
 

+ 34 - 37
packages/app/resource/locales/en_US/sandbox.md

@@ -245,9 +245,6 @@ You can create links using `[Display text](URL)`.
 
 ## Pukiwiki like linker
 
-(available by [weseek/growi-plugin-pukiwiki-like-linker
-](https://github.com/weseek/growi-plugin-pukiwiki-like-linker) )
-
 This is the most flexible linker.
 Both the page description and link address can be displayed on the page.
 
@@ -354,65 +351,65 @@ aligned    | aligned     | aligned
 | left       | right       | center       |
 | aligned    | aligned     | aligned      |
 
-## TSV (crowi-plus notation)
+## TSV
 
+~~~
+``` tsv
+Content Cell	Content Cell
+Content Cell	Content Cell
 ```
-::: tsv
-Content Cell  Content Cell
-Content Cell  Content Cell
-:::
-```
+~~~
 
-::: tsv
-Content Cell Content Cell
-Content Cell Content Cell
-:::
+``` tsv
+Content Cell	Content Cell
+Content Cell	Content Cell
+```
 
-## TSV with header (crowi-plus notation)
+## TSV with header
 
+~~~
+``` tsv-h
+First Header	Second Header
+Content Cell	Content Cell
+Content Cell	Content Cell
 ```
-::: tsv-h
-First Header Second Header
-Content Cell Content Cell
-Content Cell Content Cell
-:::
-```
+~~~
 
-::: tsv-h
-First Header Second Header
-Content Cell Content Cell
-Content Cell Content Cell
-:::
+``` tsv-h
+First Header	Second Header
+Content Cell	Content Cell
+Content Cell	Content Cell
+```
 
-## CSV (crowi-plus original notation)
+## CSV
 
-```
-::: csv
+~~~
+``` csv
 Content Cell,Content Cell
 Content Cell,Content Cell
-:::
 ```
+~~~
 
-::: csv
+``` csv
 Content Cell,Content Cell
 Content Cell,Content Cell
-:::
+```
 
-## CSV with header (crowi-plus original notation)
+## CSV with header
 
-```
-::: csv-h
+~~~
+``` csv-h
 First Header,Second Header
 Content Cell,Content Cell
 Content Cell,Content Cell
-:::
 ```
+~~~
 
-::: csv-h
+``` csv-h
 First Header,Second Header
 Content Cell,Content Cell
 Content Cell,Content Cell
-:::
+```
 
 
 # :memo: Footnote

+ 3 - 3
packages/app/resource/locales/en_US/welcome.md

@@ -1,7 +1,7 @@
 # :tada: Welcome to GROWI
 
 [![GitHub Releases](https://img.shields.io/github/release/weseek/growi.svg)](https://github.com/weseek/growi/releases/latest)
-[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
+[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/weseek/growi/blob/master/LICENSE)
 
 GROWI is a Wiki for Individuals and Corporations | A knowledge base tool.
 Knowledge in companies, university laboratories, and clubs can be easily shared and anyone can edit the page.
@@ -18,7 +18,7 @@ Let's increase the information exchange everyday.
 - We can create a bullet point by adding `-`  at the beginning of the line.
 - We can also copy and paste, drag and drop attachments such as images, PDF, Word/Excel/PowerPoint, etc.
 - Once we finished, press the "**Update**" button to publish the page.
-    - We can also save it by `Ctrl(⌘) +S`.
+    - We can also save it by `Ctrl(⌘) + S`.
 
 For more information: [Tutorial#Create New Page](https://docs.growi.org/en/guide/tutorial/create_page.html#create-new-page)
 
@@ -29,7 +29,7 @@ For more information: [Tutorial#Create New Page](https://docs.growi.org/en/guide
   <div class="card-body">
     <ul>
       <li>Ctrl(⌘) + "/" to show quick help.</li>
-      <li>We can write HTML with <a href="https://getbootstrap.com/docs/4.5/components/">Bootstrap 4</a>.</li>
+      <li>We can write HTML with <a href="https://getbootstrap.com/docs/4.6/components/">Bootstrap 4</a>.</li>
     </ul>
   </div>
 </div>

Разница между файлами не показана из-за своего большого размера
+ 1 - 1
packages/app/resource/locales/ja_JP/sandbox-diagrams.md


+ 1 - 1
packages/app/resource/locales/ja_JP/sandbox-math.md

@@ -1,6 +1,6 @@
 # :pencil: Math
 
-See [MathJax](https://www.mathjax.org/).
+See [KaTeX](https://katex.org/).
 
 ## Inline Formula
 

+ 34 - 37
packages/app/resource/locales/ja_JP/sandbox.md

@@ -244,9 +244,6 @@ ___
 
 ## Pukiwiki like linker
 
-(available by [weseek/growi-plugin-pukiwiki-like-linker
-](https://github.com/weseek/growi-plugin-pukiwiki-like-linker) )
-
 最も柔軟な Linker です。
 記述中のページを基点とした相対リンクと、表示テキストに対するリンクを同時に実現できます。
 
@@ -353,65 +350,65 @@ aligned    | aligned     | aligned
 | left       | right       | center       |
 | aligned    | aligned     | aligned      |
 
-## TSV (crowi-plus 独自記法)
+## TSV
 
+~~~
+``` tsv
+Content Cell	Content Cell
+Content Cell	Content Cell
 ```
-::: tsv
-Content Cell  Content Cell
-Content Cell  Content Cell
-:::
-```
+~~~
 
-::: tsv
-Content Cell Content Cell
-Content Cell Content Cell
-:::
+``` tsv
+Content Cell	Content Cell
+Content Cell	Content Cell
+```
 
-## TSV ヘッダ付き (crowi-plus 独自記法)
+## TSV (ヘッダ付き)
 
+~~~
+``` tsv-h
+First Header	Second Header
+Content Cell	Content Cell
+Content Cell	Content Cell
 ```
-::: tsv-h
-First Header Second Header
-Content Cell Content Cell
-Content Cell Content Cell
-:::
-```
+~~~
 
-::: tsv-h
-First Header Second Header
-Content Cell Content Cell
-Content Cell Content Cell
-:::
+``` tsv-h
+First Header	Second Header
+Content Cell	Content Cell
+Content Cell	Content Cell
+```
 
-## CSV (crowi-plus 独自記法)
+## CSV
 
-```
-::: csv
+~~~
+``` csv
 Content Cell,Content Cell
 Content Cell,Content Cell
-:::
 ```
+~~~
 
-::: csv
+``` csv
 Content Cell,Content Cell
 Content Cell,Content Cell
-:::
+```
 
-## CSV ヘッダ付き (crowi-plus 独自記法)
+## CSV (ヘッダ付き)
 
-```
-::: csv-h
+~~~
+``` csv-h
 First Header,Second Header
 Content Cell,Content Cell
 Content Cell,Content Cell
-:::
 ```
+~~~
 
-::: csv-h
+``` csv-h
 First Header,Second Header
 Content Cell,Content Cell
 Content Cell,Content Cell
-:::
+```
 
 
 # :memo: Footnote

+ 3 - 3
packages/app/resource/locales/ja_JP/welcome.md

@@ -1,6 +1,6 @@
 # :tada: GROWI へようこそ
 [![GitHub Releases](https://img.shields.io/github/release/weseek/growi.svg)](https://github.com/weseek/growi/releases/latest)
-[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
+[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/weseek/growi/blob/master/LICENSE)
 
 GROWI は個人・法人向けの Wiki | ナレッジベースツールです。  
 会社や大学の研究室、サークルでのナレッジ情報を簡単に共有でき、作られたページは誰でも編集が可能です。
@@ -17,7 +17,7 @@ GROWI は個人・法人向けの Wiki | ナレッジベースツールです。
 - `- ` を行頭につけると、この文章のような箇条書きを書くことができます
 - 画像やPDF、Word/Excel/PowerPointなどの添付ファイルも、コピー&ペースト、ドラッグ&ドロップで貼ることができます
 - 書けたら "**更新**" ボタンを押してページを公開しましょう
-    - `Ctrl(⌘) +S` でも保存できます
+    - `Ctrl(⌘) + S` でも保存できます
 
 さらに詳しくはこちら: [チュートリアル#新規ページ作成](https://docs.growi.org/ja/guide/tutorial/create_page.html#新規ページ作成)
 
@@ -25,7 +25,7 @@ GROWI は個人・法人向けの Wiki | ナレッジベースツールです。
   <div class="card-header bg-primary text-light">Tips</div>
   <div class="card-body"><ul>
     <li>Ctrl(⌘) + "/" でショートカットヘルプを表示します</li>
-    <li>HTML/CSS の記述には、<a href="https://getbootstrap.com/docs/4.5/components/">Bootstrap 4</a> を利用できます</li>
+    <li>HTML/CSS の記述には、<a href="https://getbootstrap.com/docs/4.6/components/">Bootstrap 4</a> を利用できます</li>
   </ul></div>
 </div>
 

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