Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b91775f
Merge pull request #763 from otomatty/main
github-actions[bot] Apr 26, 2026
d1625e2
fix: address PR #757 review follow-ups (#764) (#765)
otomatty Apr 26, 2026
db32451
feat: add input rule for real-time hashtag tagging (#766) (#769)
otomatty Apr 27, 2026
df84e9e
i18n: Add internationalization support for error messages and UI text…
otomatty Apr 27, 2026
688099f
chore(deps): bump googleapis/release-please-action from 4 to 5 (#770)
dependabot[bot] Apr 27, 2026
e617010
chore(deps): bump @hocuspocus/server in /server/hocuspocus (#771)
dependabot[bot] Apr 27, 2026
d535d25
chore(deps): bump @hono/node-server to ^2.0.0 in /server/api (#782)
otomatty Apr 27, 2026
05b8c0d
fix(editor,layout): page heading hierarchy (one h1, body h2+) (#777)
otomatty Apr 27, 2026
c398ad6
chore(deps): bump @hocuspocus/extension-redis in /server/hocuspocus (…
dependabot[bot] Apr 27, 2026
afb1fba
chore(deps): bump @anthropic-ai/sdk from 0.90.0 to 0.91.1 in the mino…
dependabot[bot] Apr 27, 2026
3d23eb7
chore(deps): bump @hocuspocus/provider from 3.4.4 to 4.0.0 (#775)
dependabot[bot] Apr 27, 2026
1a01bbc
feat: implement tag suggestion popover (issue #767 Phase 2) (#778)
otomatty Apr 27, 2026
9c1a07f
ci: add Dependabot bun.lock sync workflow (#785)
otomatty Apr 27, 2026
a2aca6d
fix: prevent autosave from racing soft delete (issue #768) (#786)
otomatty Apr 27, 2026
e6afd2e
feat: Add i18n support to admin panel with Japanese and English trans…
otomatty Apr 27, 2026
752d7c4
Disable JSDoc auto-fixer to prevent empty stub generation (#789)
otomatty Apr 27, 2026
cdd77a0
feat(i18n): phase 2 UI, mermaid, seed, and AI prompts (#779) (#787)
otomatty Apr 27, 2026
ec7e221
fix(editor): align slash heading IDs and labels with real schema leve…
otomatty Apr 27, 2026
a0c1061
fix: strip leading H1 from AI-generated markdown (issue #784) (#791)
otomatty Apr 27, 2026
6ec5d24
feat(notes): domain access share-modal tab (issue #663) (#792)
otomatty Apr 28, 2026
6be1068
feat: role-based share modal tabs and read-only modes (#675) (#794)
otomatty Apr 28, 2026
346c98d
fix(hocuspocus): sync bun lockfile for v4 dependencies (#795)
otomatty Apr 30, 2026
74cdbaa
fix: address PR 793 review comments (#796)
otomatty May 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions .github/workflows/dependabot-bun-lock.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Dependabot bun.lock 同期ワークフロー
# Sync bun.lock for Dependabot pull requests.
#
# Dependabot は npm エコシステムを使うため `package.json` は更新できるが、
# Bun のロックファイル (`bun.lock`) は更新できない。その結果、CI の
# `bun install --frozen-lockfile` がロック不一致で即座に失敗する。
# 本ワークフローは dependabot が作成した PR を検知し、対応する
# `bun install` を実行して `bun.lock` を再生成し、PR ブランチに
# 自動コミット・プッシュする。
#
# Dependabot updates `package.json` via the npm ecosystem but cannot regenerate
# Bun's `bun.lock`. CI then fails immediately at `bun install --frozen-lockfile`
# because the lockfile and manifest disagree. This workflow detects such PRs,
# runs `bun install` in each affected directory, and pushes the regenerated
# lockfile back to the PR branch so CI can pass.
name: Dependabot bun.lock sync

on:
pull_request:
# bun.lock を持つ全ディレクトリの package.json を監視する。
# dependabot.yml は現在 root / server/api / server/hocuspocus を対象にしているが、
# 過去 (PR #374) には admin/package.json も dependabot に更新されており、
# 将来 dependabot.yml が拡張されてもカバーできるよう全ロックを対象にする。
# Watch every package.json that has a sibling bun.lock. Although the
# current dependabot.yml only tracks root / server/api / server/hocuspocus,
# admin/package.json was once updated by Dependabot (PR #374), and this
# list also future-proofs the workflow against expansions of dependabot.yml.
paths:
- "package.json"
- "admin/package.json"
- "server/api/package.json"
- "server/hocuspocus/package.json"
- "server/mcp/package.json"

# bun install で書き戻すため contents: write が必要。
# Needs `contents: write` to push the regenerated lockfile back to the PR branch.
permissions:
contents: write

concurrency:
group: dependabot-bun-lock-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
sync:
name: Sync bun.lock
if: github.actor == 'dependabot[bot]'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
with:
# PR ブランチに直接書き戻すため、head ref をチェックアウトする。
# Check out the PR head ref so we can push commits back to it.
ref: ${{ github.event.pull_request.head.ref }}
# ベースブランチとの差分計算用に履歴を全部取る。
# Fetch full history so we can diff against the PR base.
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

Comment on lines +50 to +59
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

wf="$(fd -t f 'dependabot-bun-lock.yml' .github/workflows | head -n1)"
echo "Checking workflow: $wf"

rg -n 'permissions:|contents:\s*write|uses:\s*actions/checkout@|persist-credentials|bun install|git push' "$wf"

Repository: otomatty/zedi

Length of output: 749


🏁 Script executed:

cat -n .github/workflows/dependabot-bun-lock.yml | sed -n '50,59p;101,109p;111,137p'

Repository: otomatty/zedi

Length of output: 2409


Harden Dependabot lock sync against install-script supply-chain execution.

The workflow runs bun install without --ignore-scripts in an environment with contents: write permission and checkout credentials (lines 50–59, 107). This allows package lifecycle scripts to execute with write access to the PR branch and pre-authenticated git credentials. For lockfile-only sync, disable install scripts, drop credential persistence from checkout, and use explicit token auth for the final push.

🔧 Hardening changes needed
      - uses: actions/checkout@v6.0.2
        with:
          ref: ${{ github.event.pull_request.head.ref }}
          fetch-depth: 0
          token: ${{ secrets.GITHUB_TOKEN }}
+         persist-credentials: false
@@
            (cd "$dir" && bun install --no-summary)
+           (cd "$dir" && bun install --no-summary --ignore-scripts)
@@
-         git push origin "HEAD:${HEAD_REF}"
+         git push "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" "HEAD:${HEAD_REF}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/dependabot-bun-lock.yml around lines 50 - 59, Change the
checkout step to stop persisting credentials and prevent lifecycle script
execution during installs: in the actions/checkout usage
(actions/checkout@v6.0.2) add persist-credentials: false and keep fetch-depth:
0; change the bun install invocation to include --ignore-scripts so package
scripts cannot run; and update the final push step (the step that pushes
lockfile changes) to use an explicit token for auth (e.g., use env
GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} or configure remote with that token)
rather than relying on checkout-persisted credentials.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

セキュリティ強化のご提案ありがとうございます。--ignore-scripts の追加と persist-credentials: false + x-access-token 明示認証への切替は、ロックファイル同期ワークフローとして妥当な強化案です。本 PR は develop → main のリリース PR でワークフロー自体は既に develop 側で稼働中のため、追従の develop PR で 3 点 (1) actions/checkoutpersist-credentials: false、(2) bun install --no-summary --ignore-scripts、(3) push に https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git を利用、を一括で適用します。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@otomatty ご確認ありがとうございます!3点すべてのセキュリティ強化を次の develop PR でご対応いただける旨、承知しました。適用後、ワークフローが引き続き正常に動作することを確認いただければ幸いです。

(ˆ▿ˆ)っ✉


✏️ Learnings added
Learnt from: otomatty
Repo: otomatty/zedi PR: 793
File: .github/workflows/dependabot-bun-lock.yml:50-59
Timestamp: 2026-04-28T02:13:19.536Z
Learning: In the zedi repository, the `dependabot-bun-lock.yml` workflow security hardening best practice is to apply these three changes together: (1) add `persist-credentials: false` to the `actions/checkout` step, (2) use `bun install --no-summary --ignore-scripts` to prevent lifecycle script execution, and (3) use `https://x-access-token:${{ secrets.GITHUB_TOKEN }}github.com/${{ github.repository }}.git` for the explicit push instead of relying on checkout-persisted credentials.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: otomatty
Repo: otomatty/zedi PR: 158
File: server/api/Dockerfile:0-0
Timestamp: 2026-03-01T21:44:49.751Z
Learning: In the zedi repository, for Bun-based Docker builds in server/api/Dockerfile, the monorepo's root bun.lock file is copied to server/api/ during CI/deployment steps before building the Docker image, and the Dockerfile uses `bun install --frozen-lockfile` for deterministic builds.

Learnt from: CR
Repo: otomatty/zedi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-26T12:37:45.354Z
Learning: When merging `main` → `develop` sync PRs, always use 'Create a merge commit' instead of Squash to avoid reintroducing conflicts

Learnt from: CR
Repo: otomatty/zedi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-26T12:37:45.354Z
Learning: PR title should follow Conventional Commits format and accurately describe changes (e.g., `feat(admin): AIモデル管理UI拡張 (`#218`)`)

Learnt from: CR
Repo: otomatty/zedi PR: 0
File: .cursor/rules/pr-and-branch-naming.mdc:0-0
Timestamp: 2026-03-08T07:34:11.938Z
Learning: PR titles must accurately represent the changes made. Use Conventional Commits format (e.g., `feat(admin): AIモデル管理UI拡張 (`#218`)`). For single-topic PRs, use the representative commit message directly. Match the language (Japanese or English) to the majority language of commits.

Learnt from: CR
Repo: otomatty/zedi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-26T12:37:45.354Z
Learning: PR review focus: security, performance impact, breaking API/type changes, error handling, logging appropriateness, and Japanese/English comment tone alignment

Learnt from: CR
Repo: otomatty/zedi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-14T12:40:46.017Z
Learning: PR review focus areas: check for security and performance impacts, breaking changes in public APIs or types, proper error handling and logging, and ensure comments in Japanese/English match project tone.

Learnt from: CR
Repo: otomatty/zedi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-14T12:40:46.017Z
Learning: PR titles must follow Conventional Commits format (e.g., `feat(admin): AIモデル管理UI拡張 (`#218`)`) and accurately represent the changes. When using Cursor Cloud Agent, include instructions in the prompt to ensure PR titles follow Conventional Commits format.

Learnt from: otomatty
Repo: otomatty/zedi PR: 785
File: .github/workflows/dependabot-bun-lock.yml:101-109
Timestamp: 2026-04-27T05:29:23.690Z
Learning: For CI GitHub Actions workflows that run Bun (Bun v1.3.11+), prefer `bun install --no-summary` over `bun install --silent` when you still need error and warning visibility. `--silent` suppresses all logging (including errors and warnings), while `--no-summary` only removes the install summary and keeps progress output plus errors and warnings.

- uses: actions/setup-node@v6
with:
node-version-file: ".nvmrc"

- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3"

- name: Detect changed package.json directories
id: detect
env:
BASE_REF: ${{ github.event.pull_request.base.ref }}
run: |
set -euo pipefail
git fetch --no-tags --depth=1 origin "$BASE_REF"
changed=$(git diff --name-only "origin/${BASE_REF}...HEAD")
echo "Changed files in PR:"
echo "$changed"

dirs=()
# bun.lock を持つ全ディレクトリ。`on.paths` と一致させる。
# Every directory with a sibling bun.lock; keep in sync with `on.paths`.
for path in \
"package.json" \
"admin/package.json" \
"server/api/package.json" \
"server/hocuspocus/package.json" \
"server/mcp/package.json"; do
if printf '%s\n' "$changed" | grep -Fxq "$path"; then
dir=$(dirname "$path")
dirs+=("$dir")
fi
done

if [ ${#dirs[@]} -eq 0 ]; then
echo "No tracked package.json changed; nothing to do."
echo "dirs=" >> "$GITHUB_OUTPUT"
else
echo "dirs=${dirs[*]}" >> "$GITHUB_OUTPUT"
fi

- name: Regenerate bun.lock
if: steps.detect.outputs.dirs != ''
run: |
set -euo pipefail
for dir in ${{ steps.detect.outputs.dirs }}; do
echo "::group::bun install ($dir)"
(cd "$dir" && bun install --no-summary)
echo "::endgroup::"
done

- name: Commit and push bun.lock changes
if: steps.detect.outputs.dirs != ''
env:
HEAD_REF: ${{ github.event.pull_request.head.ref }}
run: |
set -euo pipefail
# bun.lock 以外の変更(例: node_modules メタ情報)は無視。
# Only stage bun.lock files; ignore any other side effects.
git add -- ':(glob)**/bun.lock' bun.lock 2>/dev/null || true

if git diff --cached --quiet; then
echo "bun.lock is already in sync; nothing to commit."
exit 0
fi

git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git commit -m "chore(deps): sync bun.lock with package.json changes"
# GITHUB_TOKEN による push は新規ワークフロー実行をトリガーしないため、
# 無限ループは発生しない (GitHub Actions の組み込み安全機構)。
# PAT や GitHub App トークンに切り替える場合は、コミッタを確認する等の
# 別途ループ防止ロジックが必要になる。
# Pushes made with GITHUB_TOKEN do not trigger new workflow runs, so
# no infinite loop occurs (built-in GitHub Actions safety feature).
# If switching to a PAT or GitHub App token, add separate
# loop-prevention logic (e.g. checking the committer).
git push origin "HEAD:${HEAD_REF}"
2 changes: 1 addition & 1 deletion .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:

- name: Run Release Please
id: rp
uses: googleapis/release-please-action@v4
uses: googleapis/release-please-action@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
config-file: .release-please-config.json
Expand Down
3 changes: 3 additions & 0 deletions admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
},
"dependencies": {
"@zedi/ui": "workspace:*",
"i18next": "^26.0.1",
"i18next-browser-languagedetector": "^8.2.1",
"lucide-react": "^1.7.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-i18next": "^17.0.1",
"react-router-dom": "^7.13.2"
},
"devDependencies": {
Expand Down
11 changes: 7 additions & 4 deletions admin/src/components/ConfirmActionDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useState, useCallback } from "react";
import { useTranslation } from "react-i18next";
import {
AlertDialog,
AlertDialogContent,
Expand Down Expand Up @@ -71,14 +72,16 @@ export function ConfirmActionDialog({
onOpenChange,
title,
description,
confirmLabel = "確認",
confirmLabel,
destructive = false,
loading = false,
confirmPhrase,
confirmPhraseLabel,
onConfirm,
children,
}: ConfirmActionDialogProps) {
const { t } = useTranslation();
const resolvedConfirmLabel = confirmLabel ?? t("common.confirm");
const [phraseInput, setPhraseInput] = useState("");

// ダイアログ閉じ時に確認フレーズ入力をリセット / Reset phrase input when dialog closes
Expand Down Expand Up @@ -116,7 +119,7 @@ export function ConfirmActionDialog({
<div className="grid gap-2">
<Label htmlFor="confirm-phrase-input">
{confirmPhraseLabel ??
`確認のため「${confirmPhrase}」を入力してください / Type "${confirmPhrase}" to confirm`}
t("common.confirmPhraseDefault", { phrase: confirmPhrase })}
</Label>
<Input
id="confirm-phrase-input"
Expand All @@ -131,7 +134,7 @@ export function ConfirmActionDialog({
)}

<AlertDialogFooter>
<AlertDialogCancel disabled={loading}>キャンセル</AlertDialogCancel>
<AlertDialogCancel disabled={loading}>{t("common.cancel")}</AlertDialogCancel>
<AlertDialogAction
className={cn(
destructive && "bg-destructive text-destructive-foreground hover:bg-destructive/90",
Expand All @@ -148,7 +151,7 @@ export function ConfirmActionDialog({
handleConfirm();
}}
>
{loading ? "処理中..." : confirmLabel}
{loading ? t("common.processing") : resolvedConfirmLabel}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
Expand Down
72 changes: 72 additions & 0 deletions admin/src/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";

// 翻訳をドメインごとに分割(1ファイルあたりのコード量を抑える)
// Translations are split per domain to keep individual files small.
import jaCommon from "./locales/ja/common.json";
import jaNav from "./locales/ja/nav.json";
import jaAuth from "./locales/ja/auth.json";
import jaUsers from "./locales/ja/users.json";
import jaAudit from "./locales/ja/audit.json";
import jaWikiHealth from "./locales/ja/wikiHealth.json";
import jaActivityLog from "./locales/ja/activityLog.json";
import jaAiModels from "./locales/ja/aiModels.json";
import enCommon from "./locales/en/common.json";
import enNav from "./locales/en/nav.json";
import enAuth from "./locales/en/auth.json";
import enUsers from "./locales/en/users.json";
import enAudit from "./locales/en/audit.json";
import enWikiHealth from "./locales/en/wikiHealth.json";
import enActivityLog from "./locales/en/activityLog.json";
import enAiModels from "./locales/en/aiModels.json";

const ja = {
common: jaCommon,
nav: jaNav,
auth: jaAuth,
users: jaUsers,
audit: jaAudit,
wikiHealth: jaWikiHealth,
activityLog: jaActivityLog,
aiModels: jaAiModels,
};

const en = {
common: enCommon,
nav: enNav,
auth: enAuth,
users: enUsers,
audit: enAudit,
wikiHealth: enWikiHealth,
activityLog: enActivityLog,
aiModels: enAiModels,
};

/**
* 管理画面用 i18n インスタンス。
* 本体アプリと同じ localStorage キー(`zedi-i18next-lng`)を共有して、
* 言語設定が両画面間で一貫するようにする。
*
* Admin i18n instance. Shares the same localStorage key as the main app
* (`zedi-i18next-lng`) so language preference stays consistent across surfaces.
*/
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
resources: {
ja: { translation: ja },
en: { translation: en },
},
fallbackLng: "ja",
interpolation: {
escapeValue: false,
},
detection: {
order: ["localStorage", "navigator"],
lookupLocalStorage: "zedi-i18next-lng",
},
});

export default i18n;
29 changes: 29 additions & 0 deletions admin/src/i18n/locales/en/activityLog.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"title": "Activity Log",
"filters": {
"kind": "Kind",
"actor": "Actor"
},
"columns": {
"kind": "Kind",
"actor": "Actor",
"detail": "Detail",
"relatedPages": "Related pages",
"createdAt": "Recorded at"
},
"empty": "No activity logs yet.",
"showing": "Showing {{shown}} of {{total}}",
"kinds": {
"clip_ingest": "Clip ingest",
"chat_promote": "Chat promote",
"lint_run": "Lint run",
"wiki_generate": "Wiki generate",
"index_build": "Index build",
"wiki_schema_update": "Schema update"
},
"actors": {
"user": "User",
"ai": "AI",
"system": "System"
}
}
30 changes: 30 additions & 0 deletions admin/src/i18n/locales/en/aiModels.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"title": "AI Model Management",
"syncing": "Syncing...",
"syncWithProvider": "Sync with provider",
"syncResult": "Sync result:",
"syncStat": "Added {{added}} / Deactivated {{deactivated}}",
"columns": {
"reorder": "Reorder",
"provider": "Provider",
"modelId": "Model ID",
"displayName": "Display name",
"tier": "Tier",
"active": "Active",
"sortOrder": "Order"
},
"summary": "{{total}} models (active: {{active}})",
"dragHint": "Drag to reorder",
"displayNameAriaLabel": "Display name for {{modelId}}",
"tierAriaLabel": "Tier for {{name}}",
"preview": {
"title": "Sync preview",
"description": "New models will be added, and existing models no longer in scope will be deactivated. Existing models' display names and pricing are not overwritten. Sonnet-family models are added as inactive.",
"noChanges": "No changes",
"addLabel": "Add: {{name}}",
"deactivateLabel": "Deactivate: {{name}}",
"inactiveTag": "(inactive)",
"errorWarning": "Some providers reported errors. Providers with errors will not be synced.",
"confirm": "Run sync (Add {{added}} / Deactivate {{deactivated}})"
}
}
20 changes: 20 additions & 0 deletions admin/src/i18n/locales/en/audit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"title": "Audit Logs",
"filters": {
"action": "Filter by action",
"from": "From",
"to": "To"
},
"columns": {
"createdAt": "Timestamp",
"actor": "Actor",
"action": "Action",
"target": "Target",
"diff": "Changes",
"ipAddress": "IP"
},
"empty": "No audit logs.",
"actions": {
"user.role.update": "User: Role change"
}
}
7 changes: 7 additions & 0 deletions admin/src/i18n/locales/en/auth.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"title": "Zedi Admin",
"description": "To log in as an administrator, please sign in to the main app first.",
"signInButton": "Sign in to continue",
"afterSignIn": "After signing in, return to this page.",
"guardLoading": "Loading..."
}
19 changes: 19 additions & 0 deletions admin/src/i18n/locales/en/common.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"cancel": "Cancel",
"confirm": "Confirm",
"loading": "Loading...",
"saving": "Saving...",
"processing": "Processing...",
"previous": "Previous",
"next": "Next",
"all": "All",
"save": "Save",
"delete": "Delete",
"reload": "Reload",
"running": "Running...",
"page": "Page {{page}} / {{count}}",
"showingRange": "Showing {{rangeStart}}-{{rangeEnd}} of {{total}}",
"showingZero": "Showing 0 of {{total}}",
"totalCount": "Total: {{count}}",
"confirmPhraseDefault": "Type \"{{phrase}}\" to confirm"
}
Loading
Loading