Merge branch 'develop' into no-websocket
This commit is contained in:
commit
631715c86e
|
@ -165,6 +165,11 @@ id: 'aidx'
|
||||||
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
#sentryForFrontend:
|
#sentryForFrontend:
|
||||||
|
# vueIntegration:
|
||||||
|
# tracingOptions:
|
||||||
|
# trackComponents: true
|
||||||
|
# browserTracingIntegration:
|
||||||
|
# replayIntegration:
|
||||||
# options:
|
# options:
|
||||||
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
|
|
|
@ -177,6 +177,11 @@ id: 'aidx'
|
||||||
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
#sentryForFrontend:
|
#sentryForFrontend:
|
||||||
|
# vueIntegration:
|
||||||
|
# tracingOptions:
|
||||||
|
# trackComponents: true
|
||||||
|
# browserTracingIntegration:
|
||||||
|
# replayIntegration:
|
||||||
# options:
|
# options:
|
||||||
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
|
|
|
@ -259,6 +259,11 @@ id: 'aidx'
|
||||||
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
#sentryForFrontend:
|
#sentryForFrontend:
|
||||||
|
# vueIntegration:
|
||||||
|
# tracingOptions:
|
||||||
|
# trackComponents: true
|
||||||
|
# browserTracingIntegration:
|
||||||
|
# replayIntegration:
|
||||||
# options:
|
# options:
|
||||||
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
|
|
|
@ -152,6 +152,11 @@ id: 'aidx'
|
||||||
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
#sentryForFrontend:
|
#sentryForFrontend:
|
||||||
|
# vueIntegration:
|
||||||
|
# tracingOptions:
|
||||||
|
# trackComponents: true
|
||||||
|
# browserTracingIntegration:
|
||||||
|
# replayIntegration:
|
||||||
# options:
|
# options:
|
||||||
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ jobs:
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4.2.0
|
uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -14,7 +14,7 @@ jobs:
|
||||||
- name: Checkout head
|
- name: Checkout head
|
||||||
uses: actions/checkout@v4.2.2
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4.2.0
|
uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ jobs:
|
||||||
|
|
||||||
- name: setup node
|
- name: setup node
|
||||||
id: setup-node
|
id: setup-node
|
||||||
uses: actions/setup-node@v4.2.0
|
uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
|
@ -33,7 +33,7 @@ jobs:
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.2.0
|
uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -38,7 +38,7 @@ jobs:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
- uses: actions/setup-node@v4.2.0
|
- uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
@ -69,13 +69,13 @@ jobs:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
- uses: actions/setup-node@v4.2.0
|
- uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
- run: pnpm i --frozen-lockfile
|
- run: pnpm i --frozen-lockfile
|
||||||
- name: Restore eslint cache
|
- name: Restore eslint cache
|
||||||
uses: actions/cache@v4.2.2
|
uses: actions/cache@v4.2.3
|
||||||
with:
|
with:
|
||||||
path: ${{ env.eslint-cache-path }}
|
path: ${{ env.eslint-cache-path }}
|
||||||
key: eslint-${{ env.eslint-cache-version }}-${{ matrix.workspace }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }}
|
key: eslint-${{ env.eslint-cache-version }}-${{ matrix.workspace }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }}
|
||||||
|
@ -99,7 +99,7 @@ jobs:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
- uses: actions/setup-node@v4.2.0
|
- uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -20,7 +20,7 @@ jobs:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
- uses: actions/setup-node@v4.2.0
|
- uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -26,7 +26,7 @@ jobs:
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.2.0
|
uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -11,14 +11,15 @@ on:
|
||||||
# Storybook CI is checked on the "push" event of "develop" branch so it would cause a duplicate build.
|
# Storybook CI is checked on the "push" event of "develop" branch so it would cause a duplicate build.
|
||||||
# This is a waste of chromatic build quota, so we don't run storybook CI on pull requests targets master.
|
# This is a waste of chromatic build quota, so we don't run storybook CI on pull requests targets master.
|
||||||
- master
|
- master
|
||||||
# Neither Dependabot nor Renovate will change the actual behavior for components.
|
|
||||||
- dependabot/**
|
|
||||||
- renovate/**
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
# chromatic is not likely to be available for fork repositories, so we disable for fork repositories.
|
# Chromatic is not likely to be available for fork repositories, so we disable for fork repositories.
|
||||||
if: github.repository == 'misskey-dev/misskey'
|
# Neither Dependabot nor Renovate will change the actual behavior for components.
|
||||||
|
if: >-
|
||||||
|
github.repository == 'misskey-dev/misskey' &&
|
||||||
|
startsWith(github.head_ref, 'refs/heads/dependabot/') != true &&
|
||||||
|
startsWith(github.head_ref, 'refs/heads/renovate/') != true
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
@ -45,7 +46,7 @@ jobs:
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
- name: Use Node.js 20.x
|
- name: Use Node.js 20.x
|
||||||
uses: actions/setup-node@v4.2.0
|
uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version-file: '.node-version'
|
node-version-file: '.node-version'
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -62,7 +62,7 @@ jobs:
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.2.0
|
uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
@ -109,7 +109,7 @@ jobs:
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.2.0
|
uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -44,7 +44,7 @@ jobs:
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.2.0
|
uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -38,7 +38,7 @@ jobs:
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.2.0
|
uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
@ -93,7 +93,7 @@ jobs:
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.2.0
|
uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -33,7 +33,7 @@ jobs:
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
|
|
||||||
- name: Setup Node.js ${{ matrix.node-version }}
|
- name: Setup Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.2.0
|
uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -26,7 +26,7 @@ jobs:
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.2.0
|
uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
|
@ -27,7 +27,7 @@ jobs:
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v4.1.0
|
uses: pnpm/action-setup@v4.1.0
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4.2.0
|
uses: actions/setup-node@v4.3.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|
55
CHANGELOG.md
55
CHANGELOG.md
|
@ -1,7 +1,32 @@
|
||||||
## 2025.3.2
|
## 2025.4.1
|
||||||
|
|
||||||
### General
|
### General
|
||||||
- Feat: チャットがリニューアルして復活しました(beta)
|
- Enhance: チャットの新規メッセージをプッシュ通知するように
|
||||||
|
|
||||||
|
### Client
|
||||||
|
- Feat: チャットウィジェットを追加
|
||||||
|
- Feat: デッキにチャットカラムを追加
|
||||||
|
- Enhance: Unicode絵文字をslugから入力する際に`:ok:`のように最後の`:`を入力したあとにUnicode絵文字に変換できるように
|
||||||
|
- Enhance: テーマでページヘッダーの色を変更できるように
|
||||||
|
- Enhance: デザインのブラッシュアップ
|
||||||
|
- Fix: ログアウトした際に処理が終了しない問題を修正
|
||||||
|
- Fix: 自動バックアップが設定されている環境でログアウト直前に設定をバックアップするように
|
||||||
|
- Fix: フォルダを開いた状態でメニューからアップロードしてもルートフォルダにアップロードされる問題を修正 #15836
|
||||||
|
- Fix: タイムラインのスクロール位置を記憶するように修正
|
||||||
|
- Fix: ノートの直後のノートを表示する機能で表示が逆順になっていた問題を修正 #15841
|
||||||
|
- Fix: アカウントの移行時にアンテナのフィルターのユーザが更新されない問題を修正 #15843
|
||||||
|
|
||||||
|
### Server
|
||||||
|
- Enhance: フォローしているユーザーならフォロワー限定投稿のノートでもアンテナで検知できるように
|
||||||
|
(Cherry-picked from https://github.com/yojo-art/cherrypick/pull/568 and https://github.com/team-shahu/misskey/pull/38)
|
||||||
|
- Fix: システムアカウントの名前がサーバー名と同期されない問題を修正
|
||||||
|
- Fix: 大文字を含むユーザの URL で紹介された場合に 404 エラーを返す問題 #15813
|
||||||
|
- Fix: リードレプリカ設定時にレコードの追加・更新・削除を伴うクエリを発行した際はmasterノードで実行されるように調整( #10897 )
|
||||||
|
|
||||||
|
## 2025.4.0
|
||||||
|
|
||||||
|
### General
|
||||||
|
- Feat: チャット(ダイレクトメッセージ)がリニューアルして復活しました
|
||||||
- 既存のDM機能よりも便利で効率的な実装になっています
|
- 既存のDM機能よりも便利で効率的な実装になっています
|
||||||
- チャットを受け付ける相手を制限可能です
|
- チャットを受け付ける相手を制限可能です
|
||||||
- 誰でも / フォローユーザーのみ / フォロワーのみ / 相互のみ / 受け付けない から選択できます
|
- 誰でも / フォローユーザーのみ / フォロワーのみ / 相互のみ / 受け付けない から選択できます
|
||||||
|
@ -11,9 +36,17 @@
|
||||||
- 過去自分が送ったメッセージ・自分に送られたメッセージの検索が可能です
|
- 過去自分が送ったメッセージ・自分に送られたメッセージの検索が可能です
|
||||||
- 参加中のルームをミュートして通知が来ないように設定可能です
|
- 参加中のルームをミュートして通知が来ないように設定可能です
|
||||||
- メッセージにはリアクションも可能です
|
- メッセージにはリアクションも可能です
|
||||||
|
- 現在、リモートユーザーがチャットを受け付ける設定になっているかどうかを取得する術がないため、ローカルユーザー間でのみ利用可能です
|
||||||
|
- Feat: アカウントの移行時に古いアカウントからあたらしいアカウントにロールをコピーできるようになりました。
|
||||||
|
- 管理者がロールの設定でマイグレーション時にコピーするかを指定できるようになります。
|
||||||
- Enhance: セキュリティを強化するため、ジョブキューのダッシュボード(bull-board)統合が削除されました。
|
- Enhance: セキュリティを強化するため、ジョブキューのダッシュボード(bull-board)統合が削除されました。
|
||||||
- Misskeyネイティブでダッシュボードを実装予定です
|
- Misskeyネイティブでダッシュボードを実装予定です
|
||||||
|
- Enhance: フロントエンドのエラートラッキングができるように
|
||||||
|
- `.config/default.yml`中の項目`sentryForFrontend`を適宜設定してください。
|
||||||
|
- 外部サービスであるSentryへエラー情報が送信されます。ご利用の地域の法令に従い、適切なプライバシーポリシーを策定の上で運用してください。
|
||||||
- Enhance: ミュートしているユーザーをユーザー検索の結果から除外するように
|
- Enhance: ミュートしているユーザーをユーザー検索の結果から除外するように
|
||||||
|
- Enhance: アンテナでセンシティブなチャンネルのノートを除外できるように `#14177`
|
||||||
|
- Fix: 通知のページネーションで2つ以上読み込めなくなることがある問題を修正
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
- Feat: 設定の管理が強化されました
|
- Feat: 設定の管理が強化されました
|
||||||
|
@ -22,7 +55,7 @@
|
||||||
- プラグイン、テーマ、クライアントに追加されたすべてのアカウント情報も含まれるようになりました
|
- プラグイン、テーマ、クライアントに追加されたすべてのアカウント情報も含まれるようになりました
|
||||||
- 自動で設定データをサーバーにバックアップできるように
|
- 自動で設定データをサーバーにバックアップできるように
|
||||||
- 設定→設定のプロファイル→自動バックアップ で有効にできます
|
- 設定→設定のプロファイル→自動バックアップ で有効にできます
|
||||||
- 新しいデバイスからログインしたり、ブラウザから設定データが消えてしまったときに自動で復元されます(復元をスキップすることも可能)
|
- ログインしたとき、ブラウザから設定データが消えてしまったときに自動で復元されます(復元をスキップすることも可能)
|
||||||
- 任意の設定項目をデバイス間で同期できるように
|
- 任意の設定項目をデバイス間で同期できるように
|
||||||
- 設定項目の「...」メニュー→「デバイス間で同期」
|
- 設定項目の「...」メニュー→「デバイス間で同期」
|
||||||
- 同期をオンにした際にサーバーに保存された値とローカルの値が競合する場合はどちらを優先するか選択できます
|
- 同期をオンにした際にサーバーに保存された値とローカルの値が競合する場合はどちらを優先するか選択できます
|
||||||
|
@ -31,13 +64,19 @@
|
||||||
- アカウントごとに設定値が分離される設定とそうでないクライアント設定が混在していた(かつ分離するかどうかを設定不可だった)のを、基本的に一律でクライアント全体に適用されるようにし、個別でアカウントごとに異なる設定を行えるように
|
- アカウントごとに設定値が分離される設定とそうでないクライアント設定が混在していた(かつ分離するかどうかを設定不可だった)のを、基本的に一律でクライアント全体に適用されるようにし、個別でアカウントごとに異なる設定を行えるように
|
||||||
- 設定項目の「...」メニュー→「アカウントで上書き」をオンにすることで、設定値をそのアカウントでだけ適用するようにできます
|
- 設定項目の「...」メニュー→「アカウントで上書き」をオンにすることで、設定値をそのアカウントでだけ適用するようにできます
|
||||||
- ログアウトすると設定データもブラウザから消去されるようになりプライバシーが向上しました
|
- ログアウトすると設定データもブラウザから消去されるようになりプライバシーが向上しました
|
||||||
- 再度ログインすればサーバーのバックアップから設定データを復元可能です
|
- バックアップを有効にしている場合、ログインした後にバックアップから設定データを復元可能です
|
||||||
- エクスポートした設定データを他のサーバーでインポートして適用すること(設定の持ち運び)が可能になりました
|
- エクスポートした設定データを他のサーバーでインポートして適用すること(設定の持ち運び)が可能になりました
|
||||||
|
- 設定情報の移行は自動で行われますが、何らかの理由で失敗した場合、設定→その他→旧設定情報を移行 で再試行可能です
|
||||||
|
- 過去に作成されたバックアップデータとは現在互換性がありませんのでご注意ください
|
||||||
- Feat: 画面を重ねて表示するオプションを実装(実験的)
|
- Feat: 画面を重ねて表示するオプションを実装(実験的)
|
||||||
- 設定 → その他 → 実験的機能 → Enable stacking router view
|
- 設定 → その他 → 実験的機能 → Enable stacking router view
|
||||||
- Enhance: プラグインの管理が強化されました
|
- Enhance: プラグインの管理が強化されました
|
||||||
- インストール/アンインストール/設定の変更時にリロード不要になりました
|
- インストール/アンインストール/設定の変更時にリロード不要になりました
|
||||||
- Enhance: ログアウト時、ブラウザに保存されたWebクライアントのデータを全て消去するように
|
- Enhance: ログアウト時、ブラウザに保存されたWebクライアントのデータを全て消去するように
|
||||||
|
- Enhance: デッキUIでカラム間のマージンを設定できるように
|
||||||
|
- Enhance: デッキUIでデッキメニューの位置を設定できるように
|
||||||
|
- Enhance: デッキUIでナビゲーションバーの位置を設定できるように
|
||||||
|
- Enhance: アイコンのスクロール追従を無効化してパフォーマンス向上できるように
|
||||||
- Enhance: CWの注釈テキストが入力されていない場合, Postボタンを非アクティブに
|
- Enhance: CWの注釈テキストが入力されていない場合, Postボタンを非アクティブに
|
||||||
- Enhance: CWを無効にした場合, 注釈テキストが最大入力文字数を超えていても投稿できるように
|
- Enhance: CWを無効にした場合, 注釈テキストが最大入力文字数を超えていても投稿できるように
|
||||||
- Enhance: テーマ設定画面のデザインを改善
|
- Enhance: テーマ設定画面のデザインを改善
|
||||||
|
@ -46,7 +85,14 @@
|
||||||
- 文字数カウントを復活
|
- 文字数カウントを復活
|
||||||
- Enhance: 2段階認証時のリカバリーコードのファイル名にサーバーURLを含めるように
|
- Enhance: 2段階認証時のリカバリーコードのファイル名にサーバーURLを含めるように
|
||||||
- Enhance: 全体的なブラッシュアップ
|
- Enhance: 全体的なブラッシュアップ
|
||||||
|
- Enhance 全体的なパフォーマンス向上
|
||||||
|
- Enhance: ファイルのアップロードでデフォルトで圧縮するかどうかのオプションが廃止され、アップロード時に圧縮するかどうかを選択するようになりました
|
||||||
|
- 画像データの貼り付け、ドロップ時は圧縮されるようになりました
|
||||||
|
- Fix: 読み込み直後にスクロールしようとすると途中で止まる場合があるのを修正
|
||||||
- Fix: テーマ切り替え時に一部の色が変わらない問題を修正
|
- Fix: テーマ切り替え時に一部の色が変わらない問題を修正
|
||||||
|
- Fix: iPadOSでdeck uiをマウスカーソルによってスクロールできない問題を修正
|
||||||
|
- NOTE: 構造上クラシックUIを新しいデザインシステムに移行することが困難なため、クラシックUIが削除されました
|
||||||
|
- デッキUIでカラムを中央寄せにし、メインカラムの左右にウィジェットカラムを配置し、ナビゲーションバーを上部に表示することである程度クラシックUIを再現できます
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
- Enhance 全体的なパフォーマンス向上
|
- Enhance 全体的なパフォーマンス向上
|
||||||
|
@ -54,6 +100,7 @@
|
||||||
- Fix: ActivityPubリクエストURLチェック実装は仕様に従っていないのを修正
|
- Fix: ActivityPubリクエストURLチェック実装は仕様に従っていないのを修正
|
||||||
- Fix: 連合無しモードでも外部から照会可能だった問題を修正
|
- Fix: 連合無しモードでも外部から照会可能だった問題を修正
|
||||||
- Fix: テスト用WebHookのペイロードの`emojis`パラメータが実際のものと異なる問題を修正
|
- Fix: テスト用WebHookのペイロードの`emojis`パラメータが実際のものと異なる問題を修正
|
||||||
|
- Fix: 非ログインでタイムラインのストリームに接続した際、表示にログイン必須のノートが流れる場合がある問題を修正
|
||||||
|
|
||||||
## 2025.3.1
|
## 2025.3.1
|
||||||
|
|
||||||
|
|
|
@ -173,6 +173,11 @@ id: "aidx"
|
||||||
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
#sentryForFrontend:
|
#sentryForFrontend:
|
||||||
|
# vueIntegration:
|
||||||
|
# tracingOptions:
|
||||||
|
# trackComponents: true
|
||||||
|
# browserTracingIntegration:
|
||||||
|
# replayIntegration:
|
||||||
# options:
|
# options:
|
||||||
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
|
|
|
@ -1240,7 +1240,6 @@ _theme:
|
||||||
shadow: "الظل"
|
shadow: "الظل"
|
||||||
navBg: "خلفية الشريط الجانبي"
|
navBg: "خلفية الشريط الجانبي"
|
||||||
navFg: "نص الشريط الجانبي"
|
navFg: "نص الشريط الجانبي"
|
||||||
navHoverFg: "نص الشريط الجانبي (عند التمرير فوقه)"
|
|
||||||
link: "رابط"
|
link: "رابط"
|
||||||
hashtag: "وسم"
|
hashtag: "وسم"
|
||||||
mention: "أشر الى"
|
mention: "أشر الى"
|
||||||
|
|
|
@ -998,7 +998,6 @@ _theme:
|
||||||
header: "হেডার"
|
header: "হেডার"
|
||||||
navBg: "সাইডবারের পটভূমি"
|
navBg: "সাইডবারের পটভূমি"
|
||||||
navFg: "সাইডবারের পাঠ্য"
|
navFg: "সাইডবারের পাঠ্য"
|
||||||
navHoverFg: "সাইডবারের পাঠ্য (হভার)"
|
|
||||||
navActive: "সাইডবারের পাঠ্য (অ্যাকটিভ)"
|
navActive: "সাইডবারের পাঠ্য (অ্যাকটিভ)"
|
||||||
navIndicator: "সাইডবারের ইনডিকেটর"
|
navIndicator: "সাইডবারের ইনডিকেটর"
|
||||||
link: "লিংক"
|
link: "লিংক"
|
||||||
|
@ -1021,11 +1020,8 @@ _theme:
|
||||||
buttonHoverBg: "বাটনের পটভূমি (হভার)"
|
buttonHoverBg: "বাটনের পটভূমি (হভার)"
|
||||||
inputBorder: "ইনপুট ফিল্ডের বর্ডার"
|
inputBorder: "ইনপুট ফিল্ডের বর্ডার"
|
||||||
driveFolderBg: "ড্রাইভ ফোল্ডারের পটভূমি"
|
driveFolderBg: "ড্রাইভ ফোল্ডারের পটভূমি"
|
||||||
wallpaperOverlay: "ওয়ালপেপার ওভারলে"
|
|
||||||
badge: "ব্যাজ"
|
badge: "ব্যাজ"
|
||||||
messageBg: "চ্যাটের পটভূমি"
|
messageBg: "চ্যাটের পটভূমি"
|
||||||
accentDarken: "অ্যাকসেন্ট (গাঢ়)"
|
|
||||||
accentLighten: "অ্যাকসেন্ট (হাল্কা)"
|
|
||||||
fgHighlighted: "হাইলাইট করা পাঠ্য"
|
fgHighlighted: "হাইলাইট করা পাঠ্য"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "নোটগুলি"
|
note: "নোটগুলি"
|
||||||
|
|
|
@ -356,7 +356,7 @@ banner: "Bàner"
|
||||||
displayOfSensitiveMedia: "Visualització de contingut sensible"
|
displayOfSensitiveMedia: "Visualització de contingut sensible"
|
||||||
whenServerDisconnected: "Quan es perdi la connexió al servidor"
|
whenServerDisconnected: "Quan es perdi la connexió al servidor"
|
||||||
disconnectedFromServer: "Desconnectat pel servidor"
|
disconnectedFromServer: "Desconnectat pel servidor"
|
||||||
reload: "Actualitza"
|
reload: "Actualitzar"
|
||||||
doNothing: "Ignora"
|
doNothing: "Ignora"
|
||||||
reloadConfirm: "Vols recarregar?"
|
reloadConfirm: "Vols recarregar?"
|
||||||
watch: "Veure"
|
watch: "Veure"
|
||||||
|
@ -424,6 +424,7 @@ antennaExcludeBots: "Exclou els bots"
|
||||||
antennaKeywordsDescription: "Separar amb espais per la condició AND o amb salts de línia per la condició OR."
|
antennaKeywordsDescription: "Separar amb espais per la condició AND o amb salts de línia per la condició OR."
|
||||||
notifyAntenna: "Notifica'm les publicacions noves"
|
notifyAntenna: "Notifica'm les publicacions noves"
|
||||||
withFileAntenna: "Només les publicacions amb fitxers"
|
withFileAntenna: "Només les publicacions amb fitxers"
|
||||||
|
excludeNotesInSensitiveChannel: "Excloure notes a canals sensibles"
|
||||||
enableServiceworker: "Activar les notificacions al navegador"
|
enableServiceworker: "Activar les notificacions al navegador"
|
||||||
antennaUsersDescription: "Llistar un nom d'usuari per línia"
|
antennaUsersDescription: "Llistar un nom d'usuari per línia"
|
||||||
caseSensitive: "Sensible a majúscules i minúscules "
|
caseSensitive: "Sensible a majúscules i minúscules "
|
||||||
|
@ -536,7 +537,7 @@ mediaListWithOneImageAppearance: "Altura de la llista de fitxers amb una única
|
||||||
limitTo: "Limita a {x}"
|
limitTo: "Limita a {x}"
|
||||||
noFollowRequests: "No tens sol·licituds de seguiment"
|
noFollowRequests: "No tens sol·licituds de seguiment"
|
||||||
openImageInNewTab: "Obre imatges a una nova pestanya"
|
openImageInNewTab: "Obre imatges a una nova pestanya"
|
||||||
dashboard: "Taulell de control"
|
dashboard: "Tauler de control"
|
||||||
local: "Local"
|
local: "Local"
|
||||||
remote: "Remot"
|
remote: "Remot"
|
||||||
total: "Total"
|
total: "Total"
|
||||||
|
@ -651,7 +652,7 @@ manage: "Administració"
|
||||||
plugins: "Extensions"
|
plugins: "Extensions"
|
||||||
preferencesBackups: "Configuracions de les Còpies de seguretat"
|
preferencesBackups: "Configuracions de les Còpies de seguretat"
|
||||||
deck: "Escriptori"
|
deck: "Escriptori"
|
||||||
undeck: "Tanca l'escriptori"
|
undeck: "Tanca el tauler"
|
||||||
useBlurEffectForModal: "Utilitzar l'efecte de difuminació a modals"
|
useBlurEffectForModal: "Utilitzar l'efecte de difuminació a modals"
|
||||||
useFullReactionPicker: "Utilitza el cercador de reaccions d'escala sencera"
|
useFullReactionPicker: "Utilitza el cercador de reaccions d'escala sencera"
|
||||||
width: "Amplada"
|
width: "Amplada"
|
||||||
|
@ -707,7 +708,7 @@ notificationSetting: "Paràmetres de notificacions"
|
||||||
notificationSettingDesc: "Selecciona els tipus de notificacions que es mostraran"
|
notificationSettingDesc: "Selecciona els tipus de notificacions que es mostraran"
|
||||||
useGlobalSetting: "Fer servir la configuració global"
|
useGlobalSetting: "Fer servir la configuració global"
|
||||||
useGlobalSettingDesc: "Si s'activa, es farà servir la configuració de notificacions del teu comte. Si no s'activa es poden fer configuracions individuals."
|
useGlobalSettingDesc: "Si s'activa, es farà servir la configuració de notificacions del teu comte. Si no s'activa es poden fer configuracions individuals."
|
||||||
other: "Altre"
|
other: "Altres"
|
||||||
regenerateLoginToken: "Regenerar clau de seguretat d'inici de sessió"
|
regenerateLoginToken: "Regenerar clau de seguretat d'inici de sessió"
|
||||||
regenerateLoginTokenDescription: "Regenera la clau de seguretat que es fa servir internament durant l'inici de sessió. Normalment aquesta acció no és necessària. Si es regenera es tancarà la sessió a tots els dispositius amb una sessió activa."
|
regenerateLoginTokenDescription: "Regenera la clau de seguretat que es fa servir internament durant l'inici de sessió. Normalment aquesta acció no és necessària. Si es regenera es tancarà la sessió a tots els dispositius amb una sessió activa."
|
||||||
theKeywordWhenSearchingForCustomEmoji: "Cercar un emoji personalitzat "
|
theKeywordWhenSearchingForCustomEmoji: "Cercar un emoji personalitzat "
|
||||||
|
@ -914,7 +915,7 @@ off: "Desactivar"
|
||||||
emailRequiredForSignup: "Demanar correu electrònic per registrar-se "
|
emailRequiredForSignup: "Demanar correu electrònic per registrar-se "
|
||||||
unread: "Sense llegir"
|
unread: "Sense llegir"
|
||||||
filter: "Filtrar"
|
filter: "Filtrar"
|
||||||
controlPanel: "Taulell de control"
|
controlPanel: "Tauler de control"
|
||||||
manageAccounts: "Gestionar comptes"
|
manageAccounts: "Gestionar comptes"
|
||||||
makeReactionsPublic: "Reaccions públiques "
|
makeReactionsPublic: "Reaccions públiques "
|
||||||
makeReactionsPublicDescription: "Això fa que totes les teves reaccions siguin visibles públicament "
|
makeReactionsPublicDescription: "Això fa que totes les teves reaccions siguin visibles públicament "
|
||||||
|
@ -978,6 +979,7 @@ document: "Documentació"
|
||||||
numberOfPageCache: "Nombre de pàgines a la memòria cau"
|
numberOfPageCache: "Nombre de pàgines a la memòria cau"
|
||||||
numberOfPageCacheDescription: "Incrementant aquest nombre farà que millori l'experiència de l'usuari, però es farà servir més memòria al dispositiu de l'usuari."
|
numberOfPageCacheDescription: "Incrementant aquest nombre farà que millori l'experiència de l'usuari, però es farà servir més memòria al dispositiu de l'usuari."
|
||||||
logoutConfirm: "Vols sortir?"
|
logoutConfirm: "Vols sortir?"
|
||||||
|
logoutWillClearClientData: "En tancar la sessió, la informació del client al navegador s'esborrarà. Per garantir que la informació de configuració es pugui restaurar en tornar a iniciar sessió activa la còpia de seguretat automàtica de la configuració."
|
||||||
lastActiveDate: "Fet servir per última vegada"
|
lastActiveDate: "Fet servir per última vegada"
|
||||||
statusbar: "Barra d'estat"
|
statusbar: "Barra d'estat"
|
||||||
pleaseSelect: "Selecciona una opció"
|
pleaseSelect: "Selecciona una opció"
|
||||||
|
@ -1128,7 +1130,7 @@ pleaseAgreeAllToContinue: "Has d'acceptar tots els camps de dalt per poder conti
|
||||||
continue: "Continuar"
|
continue: "Continuar"
|
||||||
preservedUsernames: "Noms d'usuaris reservats"
|
preservedUsernames: "Noms d'usuaris reservats"
|
||||||
preservedUsernamesDescription: "Llistat de noms d'usuaris que no es poden fer servir separats per salts de linia. Aquests noms d'usuaris no estaran disponibles quan es creï un compte d'usuari normal, però els administradors els poden fer servir per crear comptes manualment. Per altre banda els comptes ja creats amb aquests noms d'usuari no es veure'n afectats."
|
preservedUsernamesDescription: "Llistat de noms d'usuaris que no es poden fer servir separats per salts de linia. Aquests noms d'usuaris no estaran disponibles quan es creï un compte d'usuari normal, però els administradors els poden fer servir per crear comptes manualment. Per altre banda els comptes ja creats amb aquests noms d'usuari no es veure'n afectats."
|
||||||
createNoteFromTheFile: "Compon una nota des d'aquest fitxer"
|
createNoteFromTheFile: "Escriu una nota incloent aquest fitxer"
|
||||||
archive: "Arxiu"
|
archive: "Arxiu"
|
||||||
archived: "Arxivat"
|
archived: "Arxivat"
|
||||||
unarchive: "Desarxivar"
|
unarchive: "Desarxivar"
|
||||||
|
@ -1333,8 +1335,16 @@ postForm: "Formulari de publicació"
|
||||||
textCount: "Nombre de caràcters "
|
textCount: "Nombre de caràcters "
|
||||||
information: "Informació"
|
information: "Informació"
|
||||||
chat: "Xat"
|
chat: "Xat"
|
||||||
migrateOldSettings: "Migració de la configuració antiga "
|
migrateOldSettings: "Migrar la configuració anterior"
|
||||||
migrateOldSettings_description: "Normalment això es fa automàticament, però si la transició no es fa, el procés es pot iniciar manualment. S'esborrarà la configuració actual."
|
migrateOldSettings_description: "Normalment això es fa automàticament, però si la transició no es fa, el procés es pot iniciar manualment. S'esborrarà la configuració actual."
|
||||||
|
compress: "Comprimir "
|
||||||
|
right: "Dreta"
|
||||||
|
bottom: "A baix "
|
||||||
|
top: "A dalt "
|
||||||
|
embed: "Incrustar"
|
||||||
|
settingsMigrating: "Estem migrant la teva configuració. Si us plau espera un moment... (També pots fer la migració més tard, manualment, anant a Preferències → Altres → Migrar configuració antiga)"
|
||||||
|
readonly: "Només lectura"
|
||||||
|
goToDeck: "Tornar al tauler"
|
||||||
_chat:
|
_chat:
|
||||||
noMessagesYet: "Encara no tens missatges "
|
noMessagesYet: "Encara no tens missatges "
|
||||||
newMessage: "Missatge nou"
|
newMessage: "Missatge nou"
|
||||||
|
@ -1350,7 +1360,7 @@ _chat:
|
||||||
noInvitations: "No tens cap invitació "
|
noInvitations: "No tens cap invitació "
|
||||||
history: "Historial de converses "
|
history: "Historial de converses "
|
||||||
noHistory: "No hi ha un registre previ"
|
noHistory: "No hi ha un registre previ"
|
||||||
noRooms: "No hi ha habitacions"
|
noRooms: "No hi ha cap sala"
|
||||||
inviteUser: "Invitar usuaris"
|
inviteUser: "Invitar usuaris"
|
||||||
sentInvitations: "Enviar invitacions"
|
sentInvitations: "Enviar invitacions"
|
||||||
join: "Afegir-se "
|
join: "Afegir-se "
|
||||||
|
@ -1363,6 +1373,9 @@ _chat:
|
||||||
newline: "Línia nova "
|
newline: "Línia nova "
|
||||||
muteThisRoom: "Silenciar aquesta sala"
|
muteThisRoom: "Silenciar aquesta sala"
|
||||||
deleteRoom: "Esborrar la sala"
|
deleteRoom: "Esborrar la sala"
|
||||||
|
chatNotAvailableForThisAccountOrServer: "El xat no està disponible per aquest servidor o aquest compte."
|
||||||
|
chatIsReadOnlyForThisAccountOrServer: "El xat és només de lectura en aquest servidor o compte. No es poden escriure nous missatges ni crear o unir-se a sales de xat."
|
||||||
|
chatNotAvailableInOtherAccount: "La funció de xat es troba desactivada al compte de l'altre usuari."
|
||||||
cannotChatWithTheUser: "No pots xatejar amb aquest usuari"
|
cannotChatWithTheUser: "No pots xatejar amb aquest usuari"
|
||||||
cannotChatWithTheUser_description: "El xat està desactivat o l'altra part encara no l'ha obert."
|
cannotChatWithTheUser_description: "El xat està desactivat o l'altra part encara no l'ha obert."
|
||||||
chatWithThisUser: "Xateja amb aquest usuari"
|
chatWithThisUser: "Xateja amb aquest usuari"
|
||||||
|
@ -1403,9 +1416,11 @@ _settings:
|
||||||
timelineAndNote: "Línia de temps i nota"
|
timelineAndNote: "Línia de temps i nota"
|
||||||
makeEveryTextElementsSelectable: "Fes que tots els elements del text siguin seleccionables"
|
makeEveryTextElementsSelectable: "Fes que tots els elements del text siguin seleccionables"
|
||||||
makeEveryTextElementsSelectable_description: "L'activació pot reduir la usabilitat en determinades ocasions."
|
makeEveryTextElementsSelectable_description: "L'activació pot reduir la usabilitat en determinades ocasions."
|
||||||
|
useStickyIcons: "Utilitza icones fixes"
|
||||||
showNavbarSubButtons: "Mostrar sub botons a la barra de navegació "
|
showNavbarSubButtons: "Mostrar sub botons a la barra de navegació "
|
||||||
ifOn: "Quan s'encén "
|
ifOn: "Quan s'activa"
|
||||||
ifOff: "Quan s'apaga "
|
ifOff: "Quan es desactiva"
|
||||||
|
enableSyncThemesBetweenDevices: "Sincronitzar els temes instal·lats entre dispositius"
|
||||||
_chat:
|
_chat:
|
||||||
showSenderName: "Mostrar el nom del remitent"
|
showSenderName: "Mostrar el nom del remitent"
|
||||||
sendOnEnter: "Introdueix per enviar"
|
sendOnEnter: "Introdueix per enviar"
|
||||||
|
@ -1590,7 +1605,7 @@ _accountMigration:
|
||||||
moveTo: "Migrar aquest compte a un altre"
|
moveTo: "Migrar aquest compte a un altre"
|
||||||
moveToLabel: "Compte al qual es vol migrar:"
|
moveToLabel: "Compte al qual es vol migrar:"
|
||||||
moveCannotBeUndone: "Les migracions dels comptes no es poden desfer."
|
moveCannotBeUndone: "Les migracions dels comptes no es poden desfer."
|
||||||
moveAccountDescription: "Això migrarà la teva compte a un altre diferent.\n ・Els seguidors d'aquest compte és passaran al compte nou de forma automàtica\n ・Es deixaran de seguir a tots els usuaris que es segueixen actualment en aquest compte\n ・No es poden crear notes noves, etc. en aquest compte\n\nSi bé la migració de seguidors es automàtica, has de preparar alguns pasos manualment per migrar la llista d'usuaris que segueixes. Per fer això has d'exportar els seguidors que després importaraes al compte nou mitjançant el menú de configuració. El mateix procediment s'ha de seguir per less teves llistes i els teus usuaris silenciats i bloquejats.\n\n(Aquesta explicació s'aplica a Misskey v13.12.0 i posteriors. Altres aplicacions, com Mastodon, poden funcionar diferent.)"
|
moveAccountDescription: "Això migrarà el teu compte a un altre diferent.\n ・Els seguidors d'aquest compte és passaran al compte nou de forma automàtica\n ・Es deixaran de seguir a tots els usuaris que es segueixen actualment en aquest compte\n ・No es poden crear notes noves, etc. en aquest compte\n\nSi bé la migració de seguidors es automàtica, has de preparar alguns pasos manualment per migrar la llista d'usuaris que segueixes. Per fer això has d'exportar els seguidors que després importaraes al compte nou mitjançant el menú de configuració. El mateix procediment s'ha de seguir per less teves llistes i els teus usuaris silenciats i bloquejats.\n\n(Aquesta explicació s'aplica a Misskey v13.12.0 i posteriors. Altres aplicacions, com Mastodon, poden funcionar diferent.)"
|
||||||
moveAccountHowTo: "Per fer la migració, primer has de crear un àlies per aquest compte al compte al qual vols migrar.\nDesprés de crear l'àlies, introdueix el compte al qual vols migrar amb el format següent: @nomusuari@servidor.exemple.com"
|
moveAccountHowTo: "Per fer la migració, primer has de crear un àlies per aquest compte al compte al qual vols migrar.\nDesprés de crear l'àlies, introdueix el compte al qual vols migrar amb el format següent: @nomusuari@servidor.exemple.com"
|
||||||
startMigration: "Migrar"
|
startMigration: "Migrar"
|
||||||
migrationConfirm: "Vols migrar aquest compte a {account}? Una vegada comenci la migració no es podrà parar O fer marxa enrere i no podràs tornar a fer servir aquest compte mai més."
|
migrationConfirm: "Vols migrar aquest compte a {account}? Una vegada comenci la migració no es podrà parar O fer marxa enrere i no podràs tornar a fer servir aquest compte mai més."
|
||||||
|
@ -1878,6 +1893,8 @@ _role:
|
||||||
descriptionOfIsExplorable: "La línia de temps d'aquest rol i la llista d'usuaris seran públics si s'activa."
|
descriptionOfIsExplorable: "La línia de temps d'aquest rol i la llista d'usuaris seran públics si s'activa."
|
||||||
displayOrder: "Posició "
|
displayOrder: "Posició "
|
||||||
descriptionOfDisplayOrder: "Com més gran és el número, més dalt la seva posició a la interfície."
|
descriptionOfDisplayOrder: "Com més gran és el número, més dalt la seva posició a la interfície."
|
||||||
|
preserveAssignmentOnMoveAccount: "L'estat de l'assignació també es trasllada amb el compte migrat"
|
||||||
|
preserveAssignmentOnMoveAccount_description: "Si s'activa quan es migra un compte amb aquest rol, el compte migrat també heretarà aquest rol."
|
||||||
canEditMembersByModerator: "Permetre que els moderadors editin la llista d'usuaris en aquest rol"
|
canEditMembersByModerator: "Permetre que els moderadors editin la llista d'usuaris en aquest rol"
|
||||||
descriptionOfCanEditMembersByModerator: "Quan s'activa, els moderadors, així com els administradors, podran afegir i treure usuaris d'aquest rol. Si es troba desactivat, només els administradors poden assignar usuaris."
|
descriptionOfCanEditMembersByModerator: "Quan s'activa, els moderadors, així com els administradors, podran afegir i treure usuaris d'aquest rol. Si es troba desactivat, només els administradors poden assignar usuaris."
|
||||||
priority: "Prioritat"
|
priority: "Prioritat"
|
||||||
|
@ -1918,7 +1935,7 @@ _role:
|
||||||
canImportFollowing: "Autoritza la importació de seguidors"
|
canImportFollowing: "Autoritza la importació de seguidors"
|
||||||
canImportMuting: "Autoritza la importació de silenciats"
|
canImportMuting: "Autoritza la importació de silenciats"
|
||||||
canImportUserLists: "Autoritza la importació de llistes d'usuaris "
|
canImportUserLists: "Autoritza la importació de llistes d'usuaris "
|
||||||
canChat: "Pot xatejar"
|
chatAvailability: "Es permet xatejar"
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "Assignat a rols manuals"
|
roleAssignedTo: "Assignat a rols manuals"
|
||||||
isLocal: "Usuari local"
|
isLocal: "Usuari local"
|
||||||
|
@ -2110,12 +2127,11 @@ _theme:
|
||||||
fg: "Text"
|
fg: "Text"
|
||||||
focus: "Enfocament"
|
focus: "Enfocament"
|
||||||
indicator: "Indicador"
|
indicator: "Indicador"
|
||||||
panel: "Taulell "
|
panel: "Tauler"
|
||||||
shadow: "Ombra"
|
shadow: "Ombra"
|
||||||
header: "Capçalera"
|
header: "Capçalera"
|
||||||
navBg: "Fons de la barra lateral"
|
navBg: "Fons de la barra lateral"
|
||||||
navFg: "Text de la barra lateral"
|
navFg: "Text de la barra lateral"
|
||||||
navHoverFg: "Text barra lateral (en passar per sobre)"
|
|
||||||
navActive: "Text barra lateral (actiu)"
|
navActive: "Text barra lateral (actiu)"
|
||||||
navIndicator: "Indicador barra lateral"
|
navIndicator: "Indicador barra lateral"
|
||||||
link: "Enllaç"
|
link: "Enllaç"
|
||||||
|
@ -2138,11 +2154,8 @@ _theme:
|
||||||
buttonHoverBg: "Fons botó (en passar-hi per sobre)"
|
buttonHoverBg: "Fons botó (en passar-hi per sobre)"
|
||||||
inputBorder: "Contorn del cap d'introducció "
|
inputBorder: "Contorn del cap d'introducció "
|
||||||
driveFolderBg: "Fons de la carpeta Disc"
|
driveFolderBg: "Fons de la carpeta Disc"
|
||||||
wallpaperOverlay: "Superposició del fons de pantalla "
|
|
||||||
badge: "Insígnia "
|
badge: "Insígnia "
|
||||||
messageBg: "Fons del xat"
|
messageBg: "Fons del xat"
|
||||||
accentDarken: "Accent (fosc)"
|
|
||||||
accentLighten: "Accent (clar)"
|
|
||||||
fgHighlighted: "Text ressaltat"
|
fgHighlighted: "Text ressaltat"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Notes"
|
note: "Notes"
|
||||||
|
@ -2356,6 +2369,7 @@ _widgets:
|
||||||
chooseList: "Tria una llista"
|
chooseList: "Tria una llista"
|
||||||
clicker: "Clicker"
|
clicker: "Clicker"
|
||||||
birthdayFollowings: "Usuaris que fan l'aniversari avui"
|
birthdayFollowings: "Usuaris que fan l'aniversari avui"
|
||||||
|
chat: "Xat"
|
||||||
_cw:
|
_cw:
|
||||||
hide: "Amagar"
|
hide: "Amagar"
|
||||||
show: "Carregar més"
|
show: "Carregar més"
|
||||||
|
@ -2589,7 +2603,10 @@ _notification:
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "Mostrar sempre la columna principal"
|
alwaysShowMainColumn: "Mostrar sempre la columna principal"
|
||||||
columnAlign: "Alinea les columnes"
|
columnAlign: "Alinea les columnes"
|
||||||
addColumn: "Afig una columna"
|
columnGap: "Espai entre columnes"
|
||||||
|
deckMenuPosition: "Posició del menú del tauler"
|
||||||
|
navbarPosition: "Posició de la barra de navegació "
|
||||||
|
addColumn: "Afegeix una columna"
|
||||||
newNoteNotificationSettings: "Configuració de notificacions per a notes noves"
|
newNoteNotificationSettings: "Configuració de notificacions per a notes noves"
|
||||||
configureColumn: "Configuració de columnes"
|
configureColumn: "Configuració de columnes"
|
||||||
swapLeft: "Mou a l’esquerra"
|
swapLeft: "Mou a l’esquerra"
|
||||||
|
@ -2619,6 +2636,7 @@ _deck:
|
||||||
mentions: "Mencions"
|
mentions: "Mencions"
|
||||||
direct: "Publicacions directes"
|
direct: "Publicacions directes"
|
||||||
roleTimeline: "Línia de temps dels rols"
|
roleTimeline: "Línia de temps dels rols"
|
||||||
|
chat: "Xat"
|
||||||
_dialog:
|
_dialog:
|
||||||
charactersExceeded: "Has arribat al màxim de caràcters! Actualment és {current} de {max}"
|
charactersExceeded: "Has arribat al màxim de caràcters! Actualment és {current} de {max}"
|
||||||
charactersBelow: "Ets per sota del mínim de caràcters! Actualment és {current} de {min}"
|
charactersBelow: "Ets per sota del mínim de caràcters! Actualment és {current} de {min}"
|
||||||
|
@ -2784,7 +2802,7 @@ _hemisphere:
|
||||||
_reversi:
|
_reversi:
|
||||||
reversi: "Reversi"
|
reversi: "Reversi"
|
||||||
gameSettings: "Opcions del joc"
|
gameSettings: "Opcions del joc"
|
||||||
chooseBoard: "Escull un taulell"
|
chooseBoard: "Escull un tauler"
|
||||||
blackOrWhite: "Negres/Blanques"
|
blackOrWhite: "Negres/Blanques"
|
||||||
blackIs: "{name} juga amb negres "
|
blackIs: "{name} juga amb negres "
|
||||||
rules: "Regles"
|
rules: "Regles"
|
||||||
|
|
|
@ -1626,7 +1626,6 @@ _theme:
|
||||||
header: "Nadpis"
|
header: "Nadpis"
|
||||||
navBg: "Pozadí postranního panelu"
|
navBg: "Pozadí postranního panelu"
|
||||||
navFg: "Text na postranním panelu"
|
navFg: "Text na postranním panelu"
|
||||||
navHoverFg: "Text na postranním panelu (Hover)"
|
|
||||||
navActive: "Text na postranním panelu (Aktivní)"
|
navActive: "Text na postranním panelu (Aktivní)"
|
||||||
navIndicator: "Indikátor na postranním panelu"
|
navIndicator: "Indikátor na postranním panelu"
|
||||||
link: "Odkaz"
|
link: "Odkaz"
|
||||||
|
@ -1649,11 +1648,8 @@ _theme:
|
||||||
buttonHoverBg: "Pozadí tlačítka (Hover)"
|
buttonHoverBg: "Pozadí tlačítka (Hover)"
|
||||||
inputBorder: "Ohraničení vstupního pole"
|
inputBorder: "Ohraničení vstupního pole"
|
||||||
driveFolderBg: "Pozadí složky disku"
|
driveFolderBg: "Pozadí složky disku"
|
||||||
wallpaperOverlay: "Překrytí tapety"
|
|
||||||
badge: "Odznak"
|
badge: "Odznak"
|
||||||
messageBg: "Pozadí chatu"
|
messageBg: "Pozadí chatu"
|
||||||
accentDarken: "Akcent (Ztmavený)"
|
|
||||||
accentLighten: "Akcent (Zesvětlený)"
|
|
||||||
fgHighlighted: "Zvýrazněný text"
|
fgHighlighted: "Zvýrazněný text"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Poznámky"
|
note: "Poznámky"
|
||||||
|
|
|
@ -301,6 +301,7 @@ uploadFromUrlMayTakeTime: "Es kann eine Weile dauern, bis das Hochladen abgeschl
|
||||||
explore: "Erkunden"
|
explore: "Erkunden"
|
||||||
messageRead: "Gelesen"
|
messageRead: "Gelesen"
|
||||||
noMoreHistory: "Kein weiterer Verlauf vorhanden"
|
noMoreHistory: "Kein weiterer Verlauf vorhanden"
|
||||||
|
startChat: "Chat starten"
|
||||||
nUsersRead: "Von {n} Benutzern gelesen"
|
nUsersRead: "Von {n} Benutzern gelesen"
|
||||||
agreeTo: "Ich stimme {0} zu"
|
agreeTo: "Ich stimme {0} zu"
|
||||||
agree: "Zustimmen"
|
agree: "Zustimmen"
|
||||||
|
@ -423,6 +424,7 @@ antennaExcludeBots: "Bot-Accounts ausschließen"
|
||||||
antennaKeywordsDescription: "Zum Nutzen einer \"UND\"-Verknüpfung Einträge mit Leerzeichen trennen, zum Nutzen einer \"ODER\"-Verknüpfung Einträge mit einem Zeilenumbruch trennen"
|
antennaKeywordsDescription: "Zum Nutzen einer \"UND\"-Verknüpfung Einträge mit Leerzeichen trennen, zum Nutzen einer \"ODER\"-Verknüpfung Einträge mit einem Zeilenumbruch trennen"
|
||||||
notifyAntenna: "Über neue Notizen benachrichtigen"
|
notifyAntenna: "Über neue Notizen benachrichtigen"
|
||||||
withFileAntenna: "Nur Notizen mit Dateien"
|
withFileAntenna: "Nur Notizen mit Dateien"
|
||||||
|
excludeNotesInSensitiveChannel: "Schließe Notizen von sensitive Kanäle aus"
|
||||||
enableServiceworker: "Push-Benachrichtigungen im Browser aktivieren"
|
enableServiceworker: "Push-Benachrichtigungen im Browser aktivieren"
|
||||||
antennaUsersDescription: "Benutzernamen getrennt durch Zeilenumbrüche angeben"
|
antennaUsersDescription: "Benutzernamen getrennt durch Zeilenumbrüche angeben"
|
||||||
caseSensitive: "Groß-/Kleinschreibung unterscheiden"
|
caseSensitive: "Groß-/Kleinschreibung unterscheiden"
|
||||||
|
@ -961,8 +963,8 @@ cropImageAsk: "Möchtest du das Bild zuschneiden?"
|
||||||
cropYes: "Zuschneiden"
|
cropYes: "Zuschneiden"
|
||||||
cropNo: "Unbearbeitet verwenden"
|
cropNo: "Unbearbeitet verwenden"
|
||||||
file: "Datei"
|
file: "Datei"
|
||||||
recentNHours: "Letzten {n} Stunden"
|
recentNHours: "Letzte {n} Stunden"
|
||||||
recentNDays: "Letzten {n} Tage"
|
recentNDays: "Letzte {n} Tage"
|
||||||
noEmailServerWarning: "Es ist kein Email-Server konfiguriert."
|
noEmailServerWarning: "Es ist kein Email-Server konfiguriert."
|
||||||
thereIsUnresolvedAbuseReportWarning: "Es liegen ungelöste Meldungen vor."
|
thereIsUnresolvedAbuseReportWarning: "Es liegen ungelöste Meldungen vor."
|
||||||
recommended: "Empfehlung"
|
recommended: "Empfehlung"
|
||||||
|
@ -970,7 +972,7 @@ check: "Check"
|
||||||
driveCapOverrideLabel: "Die Drive-Kapazität dieses Nutzers verändern"
|
driveCapOverrideLabel: "Die Drive-Kapazität dieses Nutzers verändern"
|
||||||
driveCapOverrideCaption: "Gib einen Wert von 0 oder weniger ein, um die Kapazität auf den Standard zurückzusetzen."
|
driveCapOverrideCaption: "Gib einen Wert von 0 oder weniger ein, um die Kapazität auf den Standard zurückzusetzen."
|
||||||
requireAdminForView: "Melde dich mit einem Administratorkonto an, um dies einzusehen."
|
requireAdminForView: "Melde dich mit einem Administratorkonto an, um dies einzusehen."
|
||||||
isSystemAccount: "Ein Benutzerkonto, dass durch das System erstellt und automatisch kontrolliert wird."
|
isSystemAccount: "Ein Benutzerkonto, das durch das System erstellt und automatisch verwaltet wird."
|
||||||
typeToConfirm: "Bitte gib zur Bestätigung {x} ein"
|
typeToConfirm: "Bitte gib zur Bestätigung {x} ein"
|
||||||
deleteAccount: "Benutzerkonto löschen"
|
deleteAccount: "Benutzerkonto löschen"
|
||||||
document: "Dokumentation"
|
document: "Dokumentation"
|
||||||
|
@ -1256,7 +1258,7 @@ replaying: "Aufzeichnung"
|
||||||
endReplay: "Aufzeichnung verlassen"
|
endReplay: "Aufzeichnung verlassen"
|
||||||
copyReplayData: "Aufzeichnung kopieren"
|
copyReplayData: "Aufzeichnung kopieren"
|
||||||
ranking: "Rangliste"
|
ranking: "Rangliste"
|
||||||
lastNDays: "Letzten {n} Tage"
|
lastNDays: "Letzte {n} Tage"
|
||||||
backToTitle: "Zurück zum Startbildschirm"
|
backToTitle: "Zurück zum Startbildschirm"
|
||||||
hemisphere: "Hemisphäre"
|
hemisphere: "Hemisphäre"
|
||||||
withSensitive: "Zeige \"sensitive Inhalte\" an"
|
withSensitive: "Zeige \"sensitive Inhalte\" an"
|
||||||
|
@ -1303,6 +1305,7 @@ thisContentsAreMarkedAsSigninRequiredByAuthor: "Logge dich ein, um weitere Inhal
|
||||||
lockdown: "Sperren"
|
lockdown: "Sperren"
|
||||||
pleaseSelectAccount: "Bitte Konto auswählen"
|
pleaseSelectAccount: "Bitte Konto auswählen"
|
||||||
availableRoles: "Verfügbare Rollen"
|
availableRoles: "Verfügbare Rollen"
|
||||||
|
acknowledgeNotesAndEnable: "Schalten Sie dies erst ein, wenn Sie die Vorsichtsmaßnahmen verstanden haben."
|
||||||
federationSpecified: "Dieser Server arbeitet mit Whitelist-Föderation. Er kann nicht mit anderen als den vom Administrator angegebenen Servern interagieren."
|
federationSpecified: "Dieser Server arbeitet mit Whitelist-Föderation. Er kann nicht mit anderen als den vom Administrator angegebenen Servern interagieren."
|
||||||
federationDisabled: "Föderation ist auf diesem Server deaktiviert. Es ist nicht möglich, mit Benutzern auf anderen Servern zu interagieren."
|
federationDisabled: "Föderation ist auf diesem Server deaktiviert. Es ist nicht möglich, mit Benutzern auf anderen Servern zu interagieren."
|
||||||
confirmOnReact: "Reagieren bestätigen"
|
confirmOnReact: "Reagieren bestätigen"
|
||||||
|
@ -1310,33 +1313,119 @@ reactAreYouSure: "Willst du eine \"{emoji}\"-Reaktion hinzufügen?"
|
||||||
markAsSensitiveConfirm: "Möchtest du dieses Medium als sensibel kennzeichnen?"
|
markAsSensitiveConfirm: "Möchtest du dieses Medium als sensibel kennzeichnen?"
|
||||||
unmarkAsSensitiveConfirm: "Möchtest du die Kennzeichnung dieses Mediums als sensibel aufheben?"
|
unmarkAsSensitiveConfirm: "Möchtest du die Kennzeichnung dieses Mediums als sensibel aufheben?"
|
||||||
preferences: "Einstellungen"
|
preferences: "Einstellungen"
|
||||||
|
accessibility: "Eingabehilfe"
|
||||||
preferencesProfile: "Einstellungsprofil"
|
preferencesProfile: "Einstellungsprofil"
|
||||||
copyPreferenceId: "Kopiere die Einstellungs-ID"
|
copyPreferenceId: "Kopiere die Einstellungs-ID"
|
||||||
resetToDefaultValue: "Auf Standard zurücksetzen"
|
resetToDefaultValue: "Auf Standard zurücksetzen"
|
||||||
|
overrideByAccount: "Überschreibung durch das Konto"
|
||||||
untitled: "Unbenannt"
|
untitled: "Unbenannt"
|
||||||
noName: "Kein Name"
|
noName: "Kein Name"
|
||||||
skip: "Überspringen"
|
skip: "Überspringen"
|
||||||
restore: "Wiederherstellen"
|
restore: "Wiederherstellen"
|
||||||
syncBetweenDevices: "Zwischen Geräten synchronisieren"
|
syncBetweenDevices: "Zwischen Geräten synchronisieren"
|
||||||
|
preferenceSyncConflictTitle: "Der konfigurierte Wert ist auf dem Server bereits vorhanden."
|
||||||
|
preferenceSyncConflictText: "Die Einstellungen mit aktivierter Synchronisierung werden ihre Werte auf dem Server speichern. Es gibt jedoch bereits Werte auf dem Server. Welche Einstellungswerte sollen überschrieben werden?"
|
||||||
|
preferenceSyncConflictChoiceServer: "Konfigurierte Werte auf dem Server"
|
||||||
|
preferenceSyncConflictChoiceDevice: "Konfigurierte Werte auf dem Gerät"
|
||||||
|
preferenceSyncConflictChoiceCancel: "Einrichten der Synchronisierung abbrechen"
|
||||||
paste: "Einfügen"
|
paste: "Einfügen"
|
||||||
|
emojiPalette: "Emoji-Palette"
|
||||||
postForm: "Notizfenster"
|
postForm: "Notizfenster"
|
||||||
textCount: "Zeichenanzahl"
|
textCount: "Zeichenanzahl"
|
||||||
information: "Über"
|
information: "Über"
|
||||||
|
chat: "Chat"
|
||||||
|
migrateOldSettings: "Alte Client-Einstellungen migrieren"
|
||||||
|
migrateOldSettings_description: "Dies sollte normalerweise automatisch geschehen, aber wenn die Migration aus irgendeinem Grund nicht erfolgreich war, kannst du den Migrationsprozess selbst manuell auslösen. Die aktuellen Konfigurationsinformationen werden dabei überschrieben."
|
||||||
|
compress: "Komprimieren"
|
||||||
|
right: "Rechts"
|
||||||
|
bottom: "Unten"
|
||||||
|
top: "Oben"
|
||||||
|
embed: "Einbetten"
|
||||||
|
settingsMigrating: "Ihre Einstellungen werden gerade migriert, Bitte warten Sie einen Moment... (Sie können die Einstellungen später auch manuell migrieren, indem Sie zu Einstellungen → Sonstiges → Alte Einstellungen migrieren gehen)"
|
||||||
|
readonly: "Nur Lesezugriff"
|
||||||
|
goToDeck: "Zurück zum Deck"
|
||||||
_chat:
|
_chat:
|
||||||
|
noMessagesYet: "Noch keine Nachrichten"
|
||||||
|
newMessage: "Neue Nachricht"
|
||||||
|
individualChat: "Privater Chat"
|
||||||
|
individualChat_description: "Führe einen privaten Chat mit einer anderen Person."
|
||||||
|
roomChat: "Chatraum"
|
||||||
|
roomChat_description: "Ein Chat-Raum, an dem mehrere Personen teilnehmen können.\nDu kannst auch Personen einladen, die keine privaten Chats zulassen, wenn sie die Einladung annehmen."
|
||||||
|
createRoom: "Raum erstellen"
|
||||||
|
inviteUserToChat: "Lade Benutzer ein, um mit dem Chatten zu beginnen"
|
||||||
|
yourRooms: "Erstellte Räume"
|
||||||
|
joiningRooms: "Raum beitreten"
|
||||||
invitations: "Einladen"
|
invitations: "Einladen"
|
||||||
|
noInvitations: "Keine Einladungen"
|
||||||
|
history: "Verlauf"
|
||||||
noHistory: "Kein Verlauf gefunden"
|
noHistory: "Kein Verlauf gefunden"
|
||||||
|
noRooms: "Keine Räume gefunden"
|
||||||
|
inviteUser: "Benutzer einladen"
|
||||||
|
sentInvitations: "Verschickte Einladungen"
|
||||||
|
join: "Beitreten"
|
||||||
|
ignore: "Ignorieren"
|
||||||
|
leave: "Raum verlassen"
|
||||||
members: "Mitglieder"
|
members: "Mitglieder"
|
||||||
|
searchMessages: "Nachrichten suchen"
|
||||||
home: "Startseite"
|
home: "Startseite"
|
||||||
send: "Senden"
|
send: "Senden"
|
||||||
|
newline: "Neue Zeile"
|
||||||
|
muteThisRoom: "Raum stummschalten"
|
||||||
|
deleteRoom: "Raum löschen"
|
||||||
|
chatNotAvailableForThisAccountOrServer: "Der Chat ist auf diesem Server oder für dieses Konto nicht aktiviert."
|
||||||
|
chatIsReadOnlyForThisAccountOrServer: "Der Chat ist auf dieser Instanz oder diesem Konto nur zum Lesen freigegeben. Es ist nicht möglich, neue Nachrichten zu schreiben oder Chaträume zu erstellen oder zu betreten."
|
||||||
|
chatNotAvailableInOtherAccount: "Die Chatfunktion wurde vom anderen Benutzer deaktiviert."
|
||||||
|
cannotChatWithTheUser: "Starten eines Chats mit diesem Benutzer nicht möglich"
|
||||||
|
cannotChatWithTheUser_description: "Der Chat ist entweder nicht verfügbar oder die andere Seite hat den Chat nicht aktiviert."
|
||||||
|
chatWithThisUser: "Mit dem Benutzer chatten"
|
||||||
|
thisUserAllowsChatOnlyFromFollowers: "Dieser Benutzer nimmt nur Chats von Followern an."
|
||||||
|
thisUserAllowsChatOnlyFromFollowing: "Dieser Benutzer nimmt nur Chats von Benutzern an, denen er folgt."
|
||||||
|
thisUserAllowsChatOnlyFromMutualFollowing: "Dieser Benutzer akzeptiert nur Chats von Benutzern, die sich gegenseitig folgen."
|
||||||
|
thisUserNotAllowedChatAnyone: "Dieser Benutzer nimmt keine Chats von anderen Benutzern an."
|
||||||
|
chatAllowedUsers: "Wem das Chatten erlaubt werden soll"
|
||||||
|
chatAllowedUsers_note: "Du kannst unabhängig von dieser Einstellung mit allen Personen chatten, denen du eine Chat-Nachricht gesendet hast."
|
||||||
|
_chatAllowedUsers:
|
||||||
|
everyone: "Jeder"
|
||||||
|
followers: "Nur deine Follower"
|
||||||
|
following: "Nur Benutzer, denen du folgst"
|
||||||
|
mutual: "Nur Benutzer, die sich gegenseitig folgen"
|
||||||
|
none: "Niemand"
|
||||||
_emojiPalette:
|
_emojiPalette:
|
||||||
palettes: "Palette"
|
palettes: "Palette"
|
||||||
enableSyncBetweenDevicesForPalettes: "Synchronisierung der Paletten zwischen Geräten aktivieren"
|
enableSyncBetweenDevicesForPalettes: "Synchronisierung der Paletten zwischen Geräten aktivieren"
|
||||||
paletteForMain: "Hauptpalette"
|
paletteForMain: "Hauptpalette"
|
||||||
|
paletteForReaction: "Reaktions-Palette"
|
||||||
_settings:
|
_settings:
|
||||||
|
driveBanner: "Du kannst den Drive verwalten und konfigurieren, die Auslastung überprüfen und Einstellungen für das Hochladen von Dateien vornehmen."
|
||||||
|
pluginBanner: "Du kannst die Funktionen des Clients mit Plugins erweitern. Plugins können installiert, individuell konfiguriert und verwaltet werden."
|
||||||
|
notificationsBanner: "Sie können die Arten und den Umfang der Benachrichtigungen vom Server und der Push- Mitteilungen konfigurieren."
|
||||||
api: "API"
|
api: "API"
|
||||||
webhook: "Webhook"
|
webhook: "Webhook"
|
||||||
|
serviceConnection: "Integrierte Dienste"
|
||||||
|
serviceConnectionBanner: "Du kannst Zugriffstoken und Webhooks für die Integration mit externen Anwendungen und Diensten verwalten und konfigurieren."
|
||||||
accountData: "Kontodaten"
|
accountData: "Kontodaten"
|
||||||
|
accountDataBanner: "Export/Import und Verwaltung von Kontodatenarchiven."
|
||||||
|
muteAndBlockBanner: "Du kannst Einstellungen konfigurieren und verwalten, um Inhalte auszublenden und Aktionen für bestimmte Benutzer zu beschränken."
|
||||||
|
accessibilityBanner: "Die Clients können personalisiert und für eine optimale Nutzung im Hinblick auf ihre Darstellung und ihr Verhalten eingerichtet werden."
|
||||||
|
privacyBanner: "Du kannst Einstellungen für die Privatsphäre deines Kontos vornehmen, z. B. inwieweit Inhalte veröffentlicht werden, wie leicht sie zu finden sind und ob Follower genehmigt werden müssen."
|
||||||
|
securityBanner: "Du kannst Einstellungen für die Kontosicherheit konfigurieren, z. B. Passwörter, Anmeldemethoden, Authentifizierungs-Apps und Passkeys."
|
||||||
|
preferencesBanner: "Sie können das Gesamtverhalten des Clients nach Ihren Wünschen konfigurieren."
|
||||||
|
appearanceBanner: "Du kannst das Erscheinungsbild und die Anzeigeeinstellungen für den Client nach deinen Wünschen konfigurieren."
|
||||||
|
soundsBanner: "Du kannst die Einstellungen für die Wiedergabe von Klängen im Client konfigurieren."
|
||||||
|
timelineAndNote: "Chroniken und Notizen"
|
||||||
|
makeEveryTextElementsSelectable: "Alle Textelemente auswählbar machen"
|
||||||
|
makeEveryTextElementsSelectable_description: "Die Aktivierung kann in manchen Situationen die Benutzerfreundlichkeit beeinträchtigen."
|
||||||
|
useStickyIcons: "Icons beim Scrollen folgen lassen"
|
||||||
|
showNavbarSubButtons: "Unterschaltflächen in der Navigationsleiste anzeigen"
|
||||||
|
ifOn: "Wenn eingeschaltet"
|
||||||
|
ifOff: "Wenn ausgeschaltet"
|
||||||
|
enableSyncThemesBetweenDevices: "Synchronisierung von installierten Themen auf verschiedenen Endgeräten"
|
||||||
|
_chat:
|
||||||
|
showSenderName: "Name des Absenders anzeigen"
|
||||||
|
sendOnEnter: "Eingabetaste sendet Nachricht"
|
||||||
_preferencesProfile:
|
_preferencesProfile:
|
||||||
|
profileName: "Profilname"
|
||||||
|
profileNameDescription: "Lege einen Namen fest, der dieses Gerät identifiziert."
|
||||||
profileNameDescription2: "Beispiel: \"Haupt-PC\", \"Smartphone\""
|
profileNameDescription2: "Beispiel: \"Haupt-PC\", \"Smartphone\""
|
||||||
_preferencesBackup:
|
_preferencesBackup:
|
||||||
autoBackup: "Automatische Sicherung"
|
autoBackup: "Automatische Sicherung"
|
||||||
|
@ -1353,9 +1442,12 @@ _accountSettings:
|
||||||
requireSigninToViewContentsDescription2: "Der Inhalt wird nicht in URL-Vorschauen (OGP), eingebettet in Webseiten oder auf Servern, die keine Zitate unterstützen, angezeigt."
|
requireSigninToViewContentsDescription2: "Der Inhalt wird nicht in URL-Vorschauen (OGP), eingebettet in Webseiten oder auf Servern, die keine Zitate unterstützen, angezeigt."
|
||||||
requireSigninToViewContentsDescription3: "Diese Einschränkungen gelten möglicherweise nicht für föderierte Inhalte von anderen Servern."
|
requireSigninToViewContentsDescription3: "Diese Einschränkungen gelten möglicherweise nicht für föderierte Inhalte von anderen Servern."
|
||||||
makeNotesFollowersOnlyBefore: "Macht frühere Notizen nur für Follower sichtbar"
|
makeNotesFollowersOnlyBefore: "Macht frühere Notizen nur für Follower sichtbar"
|
||||||
|
makeNotesFollowersOnlyBeforeDescription: "Solange diese Funktion aktiviert ist, sind Notizen, die nach dem eingestellten Datum und der eingestellten Zeit liegen oder die eingestellte Zeit abgelaufen ist, nur für Follower sichtbar. Bei Deaktivierung wird auch der öffentliche Status der Notiz wiederhergestellt."
|
||||||
makeNotesHiddenBefore: "Frühere Notizen privat machen"
|
makeNotesHiddenBefore: "Frühere Notizen privat machen"
|
||||||
makeNotesHiddenBeforeDescription: ""
|
makeNotesHiddenBeforeDescription: ""
|
||||||
mayNotEffectForFederatedNotes: "Dies hat möglicherweise keine Auswirkungen auf Notizen, die an andere Server föderiert werden."
|
mayNotEffectForFederatedNotes: "Dies hat möglicherweise keine Auswirkungen auf Notizen, die an andere Server föderiert werden."
|
||||||
|
mayNotEffectSomeSituations: "Diese Einschränkungen sind vereinfacht. Sie gelten möglicherweise nicht in allen Situationen, z. B. bei der Anzeige auf einem fremden Server oder während der Moderation."
|
||||||
|
notesHavePassedSpecifiedPeriod: "Notizen die nach der folgenden Zeit veröffentlicht worden"
|
||||||
notesOlderThanSpecifiedDateAndTime: "Notizen vor einem bestimmtem Datum und Uhrzeit"
|
notesOlderThanSpecifiedDateAndTime: "Notizen vor einem bestimmtem Datum und Uhrzeit"
|
||||||
_abuseUserReport:
|
_abuseUserReport:
|
||||||
forward: "Weiterleiten"
|
forward: "Weiterleiten"
|
||||||
|
@ -1363,11 +1455,16 @@ _abuseUserReport:
|
||||||
resolve: "lösen"
|
resolve: "lösen"
|
||||||
accept: "Akzeptieren"
|
accept: "Akzeptieren"
|
||||||
reject: "Ablehnen"
|
reject: "Ablehnen"
|
||||||
|
resolveTutorial: "Wenn der Inhalt der Meldung rechtmäßig ist, wähle „Akzeptieren“, um sie als gelöst zu markieren.\nWenn der Inhalt der Meldung unzulässig ist, wähle „Ablehnen“, um sie zu ignorieren."
|
||||||
_delivery:
|
_delivery:
|
||||||
|
status: "Auslieferungsstatus"
|
||||||
stop: "Gesperrt"
|
stop: "Gesperrt"
|
||||||
|
resume: "Zustellung wieder fortsetzen"
|
||||||
_type:
|
_type:
|
||||||
none: "Wird veröffentlicht"
|
none: "Wird veröffentlicht"
|
||||||
manuallySuspended: "Manuell gesperrt"
|
manuallySuspended: "Manuell gesperrt"
|
||||||
|
goneSuspended: "Gesperrt wegen Löschung des Servers"
|
||||||
|
autoSuspendedForNotResponding: "Gesperrt, weil der Server nicht antwortet"
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
howToPlay: "Wie man spielt"
|
howToPlay: "Wie man spielt"
|
||||||
hold: "Halten"
|
hold: "Halten"
|
||||||
|
@ -1377,6 +1474,8 @@ _bubbleGame:
|
||||||
highScore: "Höchstpunktzahl"
|
highScore: "Höchstpunktzahl"
|
||||||
maxChain: "Maximale Anzahl an Verkettungen"
|
maxChain: "Maximale Anzahl an Verkettungen"
|
||||||
yen: "{yen} Yen"
|
yen: "{yen} Yen"
|
||||||
|
estimatedQty: "{qty} Stück"
|
||||||
|
scoreSweets: "{onigiriQtyWithUnit} Onigiri"
|
||||||
_howToPlay:
|
_howToPlay:
|
||||||
section1: "Passe die Position an und lasse das Objekt in das Spielfeld fallen."
|
section1: "Passe die Position an und lasse das Objekt in das Spielfeld fallen."
|
||||||
section2: "Wenn sich zwei Objekte der gleichen Art berühren, verwandeln sie sich in ein anderes Objekt und du bekommst Punkte."
|
section2: "Wenn sich zwei Objekte der gleichen Art berühren, verwandeln sie sich in ein anderes Objekt und du bekommst Punkte."
|
||||||
|
@ -1434,15 +1533,21 @@ _initialTutorial:
|
||||||
reactDone: "Du kannst eine Reaktion zurücknehmen, indem du auf den '-' Button drückst."
|
reactDone: "Du kannst eine Reaktion zurücknehmen, indem du auf den '-' Button drückst."
|
||||||
_timeline:
|
_timeline:
|
||||||
title: "So funktionieren die Chroniken"
|
title: "So funktionieren die Chroniken"
|
||||||
|
description1: "Misskey stellt mehrere Chroniken bereit (einige können je nach den Richtlinien des Servers nicht verfügbar sein)."
|
||||||
home: "Du kannst Beiträge von den Konten sehen, denen du folgst."
|
home: "Du kannst Beiträge von den Konten sehen, denen du folgst."
|
||||||
local: "Du kannst Beiträge aller Benutzer auf diesem Server sehen."
|
local: "Du kannst Beiträge aller Benutzer auf diesem Server sehen."
|
||||||
social: "Notizen von der Startseite und der lokalen Chronik werden angezeigt."
|
social: "Notizen von der Startseite und der lokalen Chronik werden angezeigt."
|
||||||
global: "Du kannst Notizen von allen föderierten Servern sehen."
|
global: "Du kannst Notizen von allen föderierten Servern sehen."
|
||||||
description2: "Du kannst jederzeit am oberen Rand des Bildschirms zwischen den jeweiligen Chroniken wechseln."
|
description2: "Du kannst jederzeit am oberen Rand des Bildschirms zwischen den jeweiligen Chroniken wechseln."
|
||||||
|
description3: "Darüber hinaus gibt es Listen-Chroniken und Kanal-Chroniken. Weitere Einzelheiten findest du unter {link}."
|
||||||
_postNote:
|
_postNote:
|
||||||
|
title: "Optionen bei Abschicken einer Notiz"
|
||||||
|
description1: "Wenn du eine Notiz auf Misskey veröffentlichst, stehen dir verschiedene Optionen zur Verfügung. Die Oberfläche sieht folgendermaßen aus."
|
||||||
_visibility:
|
_visibility:
|
||||||
description: "Du kannst einschränken, wer deine Notiz sehen kann."
|
description: "Du kannst einschränken, wer deine Notiz sehen kann."
|
||||||
public: "Deine Notiz wird für alle Nutzer sichtbar sein."
|
public: "Deine Notiz wird für alle Nutzer sichtbar sein."
|
||||||
|
home: "Nur auf der Startseite sichtbar. Kann von Followern, Profilbesuchern und durch Renotes gesehen werden."
|
||||||
|
followers: "Nur für Follower sichtbar. Nur Follower können es sehen und niemand sonst, und es kann nicht von anderen gerenoted werden."
|
||||||
direct: "Die Notiz wird nur für den angegebenen Benutzer veröffentlicht und der Empfänger wird benachrichtigt. Kann anstelle von Direktnachrichten verwendet werden."
|
direct: "Die Notiz wird nur für den angegebenen Benutzer veröffentlicht und der Empfänger wird benachrichtigt. Kann anstelle von Direktnachrichten verwendet werden."
|
||||||
doNotSendConfidencialOnDirect1: "Sei vorsichtig, wenn du sensible Informationen verschickst!"
|
doNotSendConfidencialOnDirect1: "Sei vorsichtig, wenn du sensible Informationen verschickst!"
|
||||||
doNotSendConfidencialOnDirect2: "Die Administratoren des Servers können den Inhalt der Notiz sehen. Sei vorsichtig mit sensiblen Informationen, wenn du Direktnachrichten an Benutzer auf nicht vertrauenswürdigen Servern sendest."
|
doNotSendConfidencialOnDirect2: "Die Administratoren des Servers können den Inhalt der Notiz sehen. Sei vorsichtig mit sensiblen Informationen, wenn du Direktnachrichten an Benutzer auf nicht vertrauenswürdigen Servern sendest."
|
||||||
|
@ -1453,8 +1558,10 @@ _initialTutorial:
|
||||||
_exampleNote:
|
_exampleNote:
|
||||||
cw: "Das wird dich bestimmt hungrig machen!"
|
cw: "Das wird dich bestimmt hungrig machen!"
|
||||||
note: "Ich hatte gerade einen Donut mit Schokoladenüberzug 🍩😋"
|
note: "Ich hatte gerade einen Donut mit Schokoladenüberzug 🍩😋"
|
||||||
|
useCases: "Dient zur Kennzeichnung von Notizen, wie sie in den Serverrichtlinien vorgeschrieben sind, oder zur eigenen Festlegung von Spoiler-Beiträgen oder sensiblem Text."
|
||||||
_howToMakeAttachmentsSensitive:
|
_howToMakeAttachmentsSensitive:
|
||||||
title: "Wie markiert man Anhänge als sensibel?"
|
title: "Wie markiert man Anhänge als sensibel?"
|
||||||
|
description: "Markiere Anhänge als sensibel, die aufgrund von den Serverregeln nicht sichtbar sein sollen."
|
||||||
tryThisFile: "Versuche, das angehängte Bild als sensibel zu markieren!"
|
tryThisFile: "Versuche, das angehängte Bild als sensibel zu markieren!"
|
||||||
_exampleNote:
|
_exampleNote:
|
||||||
note: "Ups, ich habe es vergeigt, den Natto-Deckel zu öffnen..."
|
note: "Ups, ich habe es vergeigt, den Natto-Deckel zu öffnen..."
|
||||||
|
@ -1465,7 +1572,9 @@ _initialTutorial:
|
||||||
title: "Du hast das Tutorial abgeschlossen! 🎉"
|
title: "Du hast das Tutorial abgeschlossen! 🎉"
|
||||||
description: "Die hier beschriebenen Funktionen sind nur ein kleiner Teil dessen, was Misskey zu bieten hat; um mehr darüber zu erfahren, wie du Misskey benutzen kannst, besuche bitte {link}."
|
description: "Die hier beschriebenen Funktionen sind nur ein kleiner Teil dessen, was Misskey zu bieten hat; um mehr darüber zu erfahren, wie du Misskey benutzen kannst, besuche bitte {link}."
|
||||||
_timelineDescription:
|
_timelineDescription:
|
||||||
|
home: "In der Startseiten-Chronik kannst du Notizen von Konten sehen, denen du folgst."
|
||||||
local: "In der lokalen Chronik siehst du Notizen von allen Benutzern auf diesem Server."
|
local: "In der lokalen Chronik siehst du Notizen von allen Benutzern auf diesem Server."
|
||||||
|
social: "Die soziale Chronik zeigt Notizen von der Startseite und der lokalen Chronik."
|
||||||
global: "In der globalen Chronik siehst du Notizen von allen föderierten Servern."
|
global: "In der globalen Chronik siehst du Notizen von allen föderierten Servern."
|
||||||
_serverRules:
|
_serverRules:
|
||||||
description: "Eine Reihe von Regeln, die vor der Registrierung angezeigt werden. Eine Zusammenfassung der Nutzungsbedingungen anzuzeigen ist empfohlen."
|
description: "Eine Reihe von Regeln, die vor der Registrierung angezeigt werden. Eine Zusammenfassung der Nutzungsbedingungen anzuzeigen ist empfohlen."
|
||||||
|
@ -1483,6 +1592,8 @@ _serverSettings:
|
||||||
fanoutTimelineDbFallbackDescription: "Ist diese Option aktiviert, wird die Chronik auf zusätzliche Abfragen in der Datenbank zurückgreifen, wenn sich die Chronik nicht im Cache befindet. Eine Deaktivierung führt zu geringerer Serverlast, aber schränkt den Zeitraum der abrufbaren Chronik ein. "
|
fanoutTimelineDbFallbackDescription: "Ist diese Option aktiviert, wird die Chronik auf zusätzliche Abfragen in der Datenbank zurückgreifen, wenn sich die Chronik nicht im Cache befindet. Eine Deaktivierung führt zu geringerer Serverlast, aber schränkt den Zeitraum der abrufbaren Chronik ein. "
|
||||||
reactionsBufferingDescription: "Wenn diese Option aktiviert ist, kann sie die Leistung beim Erstellen von Reaktionen erheblich verbessern und die Belastung der Datenbank verringern. Allerdings steigt die Speichernutzung von Redis."
|
reactionsBufferingDescription: "Wenn diese Option aktiviert ist, kann sie die Leistung beim Erstellen von Reaktionen erheblich verbessern und die Belastung der Datenbank verringern. Allerdings steigt die Speichernutzung von Redis."
|
||||||
inquiryUrl: "Kontakt-URL"
|
inquiryUrl: "Kontakt-URL"
|
||||||
|
inquiryUrlDescription: "Gib eine URL für das Kontaktformular der Serverbetreiber oder eine Webseite an, die Kontaktinformationen enthält."
|
||||||
|
openRegistration: "Registrierung von Konten aktivieren"
|
||||||
openRegistrationWarning: "Das Aktivieren von Registrierungen ist riskant. Es wird empfohlen, sie nur dann zu aktivieren, wenn der Server ständig überwacht wird und im Falle eines Problems sofort reagiert werden kann."
|
openRegistrationWarning: "Das Aktivieren von Registrierungen ist riskant. Es wird empfohlen, sie nur dann zu aktivieren, wenn der Server ständig überwacht wird und im Falle eines Problems sofort reagiert werden kann."
|
||||||
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "Wenn über einen bestimmten Zeitraum keine Moderatorenaktivität festgestellt wird, wird diese Einstellung automatisch deaktiviert, um Spam zu verhindern."
|
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "Wenn über einen bestimmten Zeitraum keine Moderatorenaktivität festgestellt wird, wird diese Einstellung automatisch deaktiviert, um Spam zu verhindern."
|
||||||
_accountMigration:
|
_accountMigration:
|
||||||
|
@ -1751,6 +1862,7 @@ _achievements:
|
||||||
_bubbleGameDoubleExplodingHead:
|
_bubbleGameDoubleExplodingHead:
|
||||||
title: "Doppel🤯"
|
title: "Doppel🤯"
|
||||||
description: "Zwei der größten Objekte im Bubble Game zur gleichen Zeit"
|
description: "Zwei der größten Objekte im Bubble Game zur gleichen Zeit"
|
||||||
|
flavor: "Eine Lunchbox kann man auch mit etwas mehr 🤯 🤯 füllen"
|
||||||
_role:
|
_role:
|
||||||
new: "Rolle erstellen"
|
new: "Rolle erstellen"
|
||||||
edit: "Rolle bearbeiten"
|
edit: "Rolle bearbeiten"
|
||||||
|
@ -1780,6 +1892,8 @@ _role:
|
||||||
descriptionOfIsExplorable: "Ist dies aktiviert, so ist die Chronik dieser Rolle, sowie eine Liste der Benutzer mit dieser Rolle, frei zugänglich."
|
descriptionOfIsExplorable: "Ist dies aktiviert, so ist die Chronik dieser Rolle, sowie eine Liste der Benutzer mit dieser Rolle, frei zugänglich."
|
||||||
displayOrder: "Position"
|
displayOrder: "Position"
|
||||||
descriptionOfDisplayOrder: "Je höher die Nummer, desto höher die UI-Position."
|
descriptionOfDisplayOrder: "Je höher die Nummer, desto höher die UI-Position."
|
||||||
|
preserveAssignmentOnMoveAccount: "Rolle übertragbar machen"
|
||||||
|
preserveAssignmentOnMoveAccount_description: "Wenn diese Option aktiviert ist, wird diese Rolle bei der Migration mit übertragen."
|
||||||
canEditMembersByModerator: "Moderatoren können Benutzern diese Rolle zuweisen"
|
canEditMembersByModerator: "Moderatoren können Benutzern diese Rolle zuweisen"
|
||||||
descriptionOfCanEditMembersByModerator: "Wenn aktiviert, so können Moderatoren und Adminstratoren anderen Benutzern diese Rolle zuweisen bzw. diese Zuweisung aufheben. Wenn deaktiviert, so ist es nur Administratoren möglich, Zuweisungen dieser Rolle zu verwalten."
|
descriptionOfCanEditMembersByModerator: "Wenn aktiviert, so können Moderatoren und Adminstratoren anderen Benutzern diese Rolle zuweisen bzw. diese Zuweisung aufheben. Wenn deaktiviert, so ist es nur Administratoren möglich, Zuweisungen dieser Rolle zu verwalten."
|
||||||
priority: "Priorität"
|
priority: "Priorität"
|
||||||
|
@ -1800,6 +1914,7 @@ _role:
|
||||||
canManageAvatarDecorations: "Profilbilddekorationen verwalten"
|
canManageAvatarDecorations: "Profilbilddekorationen verwalten"
|
||||||
driveCapacity: "Drive-Kapazität"
|
driveCapacity: "Drive-Kapazität"
|
||||||
alwaysMarkNsfw: "Dateien immer als NSFW markieren"
|
alwaysMarkNsfw: "Dateien immer als NSFW markieren"
|
||||||
|
canUpdateBioMedia: "Kann ein Profil- oder ein Bannerbild bearbeiten"
|
||||||
pinMax: "Maximale Anzahl an angehefteten Notizen"
|
pinMax: "Maximale Anzahl an angehefteten Notizen"
|
||||||
antennaMax: "Maximale Anzahl an Antennen"
|
antennaMax: "Maximale Anzahl an Antennen"
|
||||||
wordMuteMax: "Maximale Zeichenlänge für Wortstummschaltungen"
|
wordMuteMax: "Maximale Zeichenlänge für Wortstummschaltungen"
|
||||||
|
@ -1815,12 +1930,20 @@ _role:
|
||||||
canUseTranslator: "Verwendung des Übersetzers"
|
canUseTranslator: "Verwendung des Übersetzers"
|
||||||
avatarDecorationLimit: "Maximale Anzahl an Profilbilddekorationen, die angebracht werden können"
|
avatarDecorationLimit: "Maximale Anzahl an Profilbilddekorationen, die angebracht werden können"
|
||||||
canImportAntennas: "Importieren von Antennen erlauben"
|
canImportAntennas: "Importieren von Antennen erlauben"
|
||||||
|
canImportBlocking: "Importieren von Blockierungen zulassen"
|
||||||
|
canImportFollowing: "Importieren von Gefolgten zulassen"
|
||||||
|
canImportMuting: "Importieren von Stummgeschalteten zulassen"
|
||||||
canImportUserLists: "Importieren von Listen erlauben"
|
canImportUserLists: "Importieren von Listen erlauben"
|
||||||
|
chatAvailability: "Chatten erlauben"
|
||||||
_condition:
|
_condition:
|
||||||
|
roleAssignedTo: "Manuellen Rollen zugewiesen"
|
||||||
isLocal: "Lokaler Benutzer"
|
isLocal: "Lokaler Benutzer"
|
||||||
isRemote: "Benutzer fremder Instanz"
|
isRemote: "Benutzer fremder Instanz"
|
||||||
isCat: "Katzen-Benutzer"
|
isCat: "Katzen-Benutzer"
|
||||||
isBot: "Bot-Benutzer"
|
isBot: "Bot-Benutzer"
|
||||||
|
isSuspended: "Gesperrter Benutzer"
|
||||||
|
isLocked: "Private Konten"
|
||||||
|
isExplorable: "Benutzer, die ihr Konto im \"Erkunden\"-Bereich sichtbar machen"
|
||||||
createdLessThan: "Kontoerstellung liegt weniger als X zurück"
|
createdLessThan: "Kontoerstellung liegt weniger als X zurück"
|
||||||
createdMoreThan: "Kontoerstellung liegt mehr als X zurück"
|
createdMoreThan: "Kontoerstellung liegt mehr als X zurück"
|
||||||
followersLessThanOrEq: "Hat X oder weniger Follower"
|
followersLessThanOrEq: "Hat X oder weniger Follower"
|
||||||
|
@ -1975,6 +2098,7 @@ _theme:
|
||||||
installed: "{name} wurde installiert"
|
installed: "{name} wurde installiert"
|
||||||
installedThemes: "Installierte Farbschemata"
|
installedThemes: "Installierte Farbschemata"
|
||||||
builtinThemes: "Eingebaute Farbschemata"
|
builtinThemes: "Eingebaute Farbschemata"
|
||||||
|
instanceTheme: "Server-Thema"
|
||||||
alreadyInstalled: "Dieses Farbschema ist bereits installiert"
|
alreadyInstalled: "Dieses Farbschema ist bereits installiert"
|
||||||
invalid: "Der Code dieses Farbschemas ist ungültig"
|
invalid: "Der Code dieses Farbschemas ist ungültig"
|
||||||
make: "Farbschema erstellen"
|
make: "Farbschema erstellen"
|
||||||
|
@ -2007,7 +2131,6 @@ _theme:
|
||||||
header: "Kopfzeile"
|
header: "Kopfzeile"
|
||||||
navBg: "Hintergrund der Seitenleiste"
|
navBg: "Hintergrund der Seitenleiste"
|
||||||
navFg: "Text der Seitenleiste"
|
navFg: "Text der Seitenleiste"
|
||||||
navHoverFg: "Text der Seitenleiste (Mouseover)"
|
|
||||||
navActive: "Text der Seitenleiste (Aktiv)"
|
navActive: "Text der Seitenleiste (Aktiv)"
|
||||||
navIndicator: "Indikator der Seitenleiste"
|
navIndicator: "Indikator der Seitenleiste"
|
||||||
link: "Link"
|
link: "Link"
|
||||||
|
@ -2030,17 +2153,15 @@ _theme:
|
||||||
buttonHoverBg: "Hintergrund von Schaltflächen (Mouseover)"
|
buttonHoverBg: "Hintergrund von Schaltflächen (Mouseover)"
|
||||||
inputBorder: "Rahmen von Eingabefeldern"
|
inputBorder: "Rahmen von Eingabefeldern"
|
||||||
driveFolderBg: "Hintergrund von Drive-Ordnern"
|
driveFolderBg: "Hintergrund von Drive-Ordnern"
|
||||||
wallpaperOverlay: "Hintergrundbild-Overlay"
|
|
||||||
badge: "Wappen"
|
badge: "Wappen"
|
||||||
messageBg: "Hintergrund von Chats"
|
messageBg: "Hintergrund von Chats"
|
||||||
accentDarken: "Akzent (Verdunkelt)"
|
|
||||||
accentLighten: "Akzent (Erhellt)"
|
|
||||||
fgHighlighted: "Hervorgehobener Text"
|
fgHighlighted: "Hervorgehobener Text"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Notizen"
|
note: "Notizen"
|
||||||
noteMy: "Meine Notizen"
|
noteMy: "Meine Notizen"
|
||||||
notification: "Benachrichtigungen"
|
notification: "Benachrichtigungen"
|
||||||
reaction: "Auswählen einer Reaktion"
|
reaction: "Auswählen einer Reaktion"
|
||||||
|
chatMessage: "Chat-Nachrichten"
|
||||||
_soundSettings:
|
_soundSettings:
|
||||||
driveFile: "Audiodatei aus dem Drive verwenden"
|
driveFile: "Audiodatei aus dem Drive verwenden"
|
||||||
driveFileWarn: "Wähle eine Audiodatei aus dem Drive"
|
driveFileWarn: "Wähle eine Audiodatei aus dem Drive"
|
||||||
|
@ -2064,6 +2185,10 @@ _timeIn:
|
||||||
seconds: "In {n}s"
|
seconds: "In {n}s"
|
||||||
minutes: "In {n} Min."
|
minutes: "In {n} Min."
|
||||||
hours: "In {n} Std."
|
hours: "In {n} Std."
|
||||||
|
days: "In {n} Tagen"
|
||||||
|
weeks: "In {n} Wochen"
|
||||||
|
months: "In {n} Monaten"
|
||||||
|
years: "In {n} Jahren"
|
||||||
_time:
|
_time:
|
||||||
second: "Sekunde(n)"
|
second: "Sekunde(n)"
|
||||||
minute: "Minute(n)"
|
minute: "Minute(n)"
|
||||||
|
@ -2097,6 +2222,7 @@ _2fa:
|
||||||
backupCodesDescription: "Verwende diese Codes, falls du nicht mehr auf deine App zur Zweifaktorauthentifizierung zugreifen kannst. Jeder Code kann nur einmal verwendet werden. Bewahre sie an einem sicheren Ort auf."
|
backupCodesDescription: "Verwende diese Codes, falls du nicht mehr auf deine App zur Zweifaktorauthentifizierung zugreifen kannst. Jeder Code kann nur einmal verwendet werden. Bewahre sie an einem sicheren Ort auf."
|
||||||
backupCodeUsedWarning: "Ein Backup-Code wurde verwendet. Falls du den Zugriff zu deiner Zweifaktorauthentifizierungsapp verloren hast, konfiguriere diese bitte möglichst bald erneut."
|
backupCodeUsedWarning: "Ein Backup-Code wurde verwendet. Falls du den Zugriff zu deiner Zweifaktorauthentifizierungsapp verloren hast, konfiguriere diese bitte möglichst bald erneut."
|
||||||
backupCodesExhaustedWarning: "Alle Backup-Codes wurden verwendet. Falls du den Zugang zu deiner Zweifaktorauthentifizierungsapp verlierst, wirst du dich nicht mehr in dieses Konto einloggen können. Bitte konfiguriere diese App erneut."
|
backupCodesExhaustedWarning: "Alle Backup-Codes wurden verwendet. Falls du den Zugang zu deiner Zweifaktorauthentifizierungsapp verlierst, wirst du dich nicht mehr in dieses Konto einloggen können. Bitte konfiguriere diese App erneut."
|
||||||
|
moreDetailedGuideHere: "Hier ist eine ausführliche Anleitung"
|
||||||
_permissions:
|
_permissions:
|
||||||
"read:account": "Deine Benutzerkontoinformationen lesen"
|
"read:account": "Deine Benutzerkontoinformationen lesen"
|
||||||
"write:account": "Deine Benutzerkontoinformationen bearbeiten"
|
"write:account": "Deine Benutzerkontoinformationen bearbeiten"
|
||||||
|
@ -2147,8 +2273,12 @@ _permissions:
|
||||||
"read:admin:server-info": "Serverinformationen anzeigen"
|
"read:admin:server-info": "Serverinformationen anzeigen"
|
||||||
"read:admin:show-moderation-log": "Moderationsprotokoll einsehen"
|
"read:admin:show-moderation-log": "Moderationsprotokoll einsehen"
|
||||||
"read:admin:show-user": "Private Benutzerinformationen einsehen"
|
"read:admin:show-user": "Private Benutzerinformationen einsehen"
|
||||||
|
"write:admin:suspend-user": "Benutzer sperren"
|
||||||
"write:admin:unset-user-avatar": "Benutzer-Profilbild entfernen"
|
"write:admin:unset-user-avatar": "Benutzer-Profilbild entfernen"
|
||||||
"write:admin:unset-user-banner": "Benutzer-Banner entfernen"
|
"write:admin:unset-user-banner": "Benutzer-Banner entfernen"
|
||||||
|
"write:admin:unsuspend-user": "Benutzer entsperren"
|
||||||
|
"write:admin:meta": "Metadaten der Instanz verwalten"
|
||||||
|
"write:admin:user-note": "Moderationsvermerke verwalten"
|
||||||
"write:admin:roles": "Rollen verwalten"
|
"write:admin:roles": "Rollen verwalten"
|
||||||
"read:admin:roles": "Rollen anzeigen"
|
"read:admin:roles": "Rollen anzeigen"
|
||||||
"write:admin:relays": "Relays verwalten"
|
"write:admin:relays": "Relays verwalten"
|
||||||
|
@ -2159,12 +2289,14 @@ _permissions:
|
||||||
"read:admin:announcements": "Ankündigungen einsehen"
|
"read:admin:announcements": "Ankündigungen einsehen"
|
||||||
"write:admin:avatar-decorations": "Kann Avatar-Dekorationen verwalten"
|
"write:admin:avatar-decorations": "Kann Avatar-Dekorationen verwalten"
|
||||||
"read:admin:avatar-decorations": "Avatar-Dekorationen ansehen"
|
"read:admin:avatar-decorations": "Avatar-Dekorationen ansehen"
|
||||||
|
"write:admin:federation": "Informationen über Föderationen bearbeiten oder löschen"
|
||||||
"write:admin:account": "Benutzerkonten verwalten"
|
"write:admin:account": "Benutzerkonten verwalten"
|
||||||
"read:admin:account": "Benutzerkonten anzeigen"
|
"read:admin:account": "Benutzerkonten anzeigen"
|
||||||
"write:admin:emoji": "Emojis verwalten"
|
"write:admin:emoji": "Emojis verwalten"
|
||||||
"read:admin:emoji": "Emojis anzeigen"
|
"read:admin:emoji": "Emojis anzeigen"
|
||||||
"write:admin:queue": "Job-Warteschlange verwalten"
|
"write:admin:queue": "Job-Warteschlange verwalten"
|
||||||
"read:admin:queue": "Job-Warteschlange anzeigen"
|
"read:admin:queue": "Job-Warteschlange anzeigen"
|
||||||
|
"write:admin:promo": "Moderationsnotiz hinzufügen"
|
||||||
"write:admin:drive": "Benutzer-Drive verwalten"
|
"write:admin:drive": "Benutzer-Drive verwalten"
|
||||||
"read:admin:drive": "Benutzer-Drive ansehen"
|
"read:admin:drive": "Benutzer-Drive ansehen"
|
||||||
"read:admin:stream": "Verwendung der Websocket-API für Administratoren"
|
"read:admin:stream": "Verwendung der Websocket-API für Administratoren"
|
||||||
|
@ -2172,7 +2304,12 @@ _permissions:
|
||||||
"read:admin:ad": "Werbung ansehen"
|
"read:admin:ad": "Werbung ansehen"
|
||||||
"write:invite-codes": "Einladungscodes erstellen"
|
"write:invite-codes": "Einladungscodes erstellen"
|
||||||
"read:invite-codes": "Einladungscodes anzeigen"
|
"read:invite-codes": "Einladungscodes anzeigen"
|
||||||
|
"write:clip-favorite": "Clip-Likes bearbeiten oder löschen"
|
||||||
|
"read:clip-favorite": "Clip-Likes ansehen"
|
||||||
|
"read:federation": "Informationen zur Föderation einsehen"
|
||||||
|
"write:report-abuse": "Verstöße melden"
|
||||||
"write:chat": "Chats bedienen"
|
"write:chat": "Chats bedienen"
|
||||||
|
"read:chat": "Chats durchsuchen"
|
||||||
_auth:
|
_auth:
|
||||||
shareAccessTitle: "Verteilung von App-Berechtigungen"
|
shareAccessTitle: "Verteilung von App-Berechtigungen"
|
||||||
shareAccess: "Möchtest du „{name}“ authorisieren, auf dieses Benutzerkonto zugreifen zu können?"
|
shareAccess: "Möchtest du „{name}“ authorisieren, auf dieses Benutzerkonto zugreifen zu können?"
|
||||||
|
@ -2183,6 +2320,7 @@ _auth:
|
||||||
callback: "Es wird zur Anwendung zurückgekehrt"
|
callback: "Es wird zur Anwendung zurückgekehrt"
|
||||||
accepted: "Zugriff gewährt"
|
accepted: "Zugriff gewährt"
|
||||||
denied: "Zugriff verweigert"
|
denied: "Zugriff verweigert"
|
||||||
|
scopeUser: "Als folgender Benutzer agieren"
|
||||||
pleaseLogin: "Bitte logge dich ein, um Apps zu authorisieren."
|
pleaseLogin: "Bitte logge dich ein, um Apps zu authorisieren."
|
||||||
byClickingYouWillBeRedirectedToThisUrl: "Wenn der Zugang gewährt wird, wirst du automatisch zu folgender URL weitergeleitet"
|
byClickingYouWillBeRedirectedToThisUrl: "Wenn der Zugang gewährt wird, wirst du automatisch zu folgender URL weitergeleitet"
|
||||||
_antennaSources:
|
_antennaSources:
|
||||||
|
@ -2230,6 +2368,7 @@ _widgets:
|
||||||
chooseList: "Liste auswählen"
|
chooseList: "Liste auswählen"
|
||||||
clicker: "Klickzähler"
|
clicker: "Klickzähler"
|
||||||
birthdayFollowings: "Nutzer, die heute Geburtstag haben"
|
birthdayFollowings: "Nutzer, die heute Geburtstag haben"
|
||||||
|
chat: "Chat"
|
||||||
_cw:
|
_cw:
|
||||||
hide: "Inhalt verbergen"
|
hide: "Inhalt verbergen"
|
||||||
show: "Inhalt anzeigen"
|
show: "Inhalt anzeigen"
|
||||||
|
@ -2295,6 +2434,7 @@ _profile:
|
||||||
avatarDecorationMax: "Du kannst bis zu {max} Dekorationen hinzufügen."
|
avatarDecorationMax: "Du kannst bis zu {max} Dekorationen hinzufügen."
|
||||||
followedMessage: "Nachricht, wenn dir jemand folgt"
|
followedMessage: "Nachricht, wenn dir jemand folgt"
|
||||||
followedMessageDescription: "Du kannst eine kurze Nachricht festlegen, die dem Empfänger angezeigt wird, wenn er dir folgt."
|
followedMessageDescription: "Du kannst eine kurze Nachricht festlegen, die dem Empfänger angezeigt wird, wenn er dir folgt."
|
||||||
|
followedMessageDescriptionForLockedAccount: "Wenn Folgeanfragen deine Genehmigung brauchen, wird dies beim Genehmigen einer Anfrage angezeigt."
|
||||||
_exportOrImport:
|
_exportOrImport:
|
||||||
allNotes: "Alle Notizen"
|
allNotes: "Alle Notizen"
|
||||||
favoritedNotes: "Als Favorit markierte Notizen"
|
favoritedNotes: "Als Favorit markierte Notizen"
|
||||||
|
@ -2352,6 +2492,7 @@ _play:
|
||||||
title: "Titel"
|
title: "Titel"
|
||||||
script: "Skript"
|
script: "Skript"
|
||||||
summary: "Beschreibung"
|
summary: "Beschreibung"
|
||||||
|
visibilityDescription: "Wenn du die Sichtbarkeit auf Privat stellst, wird der Play nicht auf deinem Profil sichtbar sein, aber jeder, der die URL hat, kann ihn trotzdem aufrufen."
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "Seite erstellen"
|
newPage: "Seite erstellen"
|
||||||
editPage: "Seite bearbeiten"
|
editPage: "Seite bearbeiten"
|
||||||
|
@ -2383,6 +2524,7 @@ _pages:
|
||||||
eyeCatchingImageSet: "Vorschaubild festlegen"
|
eyeCatchingImageSet: "Vorschaubild festlegen"
|
||||||
eyeCatchingImageRemove: "Vorschaubild entfernen"
|
eyeCatchingImageRemove: "Vorschaubild entfernen"
|
||||||
chooseBlock: "Block hinzufügen"
|
chooseBlock: "Block hinzufügen"
|
||||||
|
enterSectionTitle: "Titel des Abschnitts eingeben"
|
||||||
selectType: "Typ auswählen"
|
selectType: "Typ auswählen"
|
||||||
contentBlocks: "Inhalt"
|
contentBlocks: "Inhalt"
|
||||||
inputBlocks: "Eingabe"
|
inputBlocks: "Eingabe"
|
||||||
|
@ -2393,6 +2535,8 @@ _pages:
|
||||||
section: "Abschnitt"
|
section: "Abschnitt"
|
||||||
image: "Bild"
|
image: "Bild"
|
||||||
button: "Knopf"
|
button: "Knopf"
|
||||||
|
dynamic: "Dynamische Bausteine"
|
||||||
|
dynamicDescription: "Dieser Baustein wurde abgeschafft. Bitte verwende von nun an {play}."
|
||||||
note: "Eingebettete Notiz"
|
note: "Eingebettete Notiz"
|
||||||
_note:
|
_note:
|
||||||
id: "Notiz-ID"
|
id: "Notiz-ID"
|
||||||
|
@ -2415,6 +2559,7 @@ _notification:
|
||||||
newNote: "Neue Notiz"
|
newNote: "Neue Notiz"
|
||||||
unreadAntennaNote: "Antenne {name}"
|
unreadAntennaNote: "Antenne {name}"
|
||||||
roleAssigned: "Rolle zugewiesen"
|
roleAssigned: "Rolle zugewiesen"
|
||||||
|
chatRoomInvitationReceived: "Du wurdest in einen Chatraum eingeladen"
|
||||||
emptyPushNotificationMessage: "Push-Benachrichtigungen wurden aktualisiert"
|
emptyPushNotificationMessage: "Push-Benachrichtigungen wurden aktualisiert"
|
||||||
achievementEarned: "Errungenschaft freigeschaltet"
|
achievementEarned: "Errungenschaft freigeschaltet"
|
||||||
testNotification: "Testbenachrichtigung"
|
testNotification: "Testbenachrichtigung"
|
||||||
|
@ -2429,6 +2574,7 @@ _notification:
|
||||||
exportOfXCompleted: "Der Export von {x} ist abgeschlossen"
|
exportOfXCompleted: "Der Export von {x} ist abgeschlossen"
|
||||||
login: "Neue Anmeldung erfolgt"
|
login: "Neue Anmeldung erfolgt"
|
||||||
createToken: "Ein Zugangstoken wurde erstellt"
|
createToken: "Ein Zugangstoken wurde erstellt"
|
||||||
|
createTokenDescription: "Wenn Sie keine Ahnung haben, löschen Sie das Zugriffstoken über \"{text}\""
|
||||||
_types:
|
_types:
|
||||||
all: "Alle"
|
all: "Alle"
|
||||||
note: "Neue Notizen"
|
note: "Neue Notizen"
|
||||||
|
@ -2442,9 +2588,11 @@ _notification:
|
||||||
receiveFollowRequest: "Erhaltene Follow-Anfragen"
|
receiveFollowRequest: "Erhaltene Follow-Anfragen"
|
||||||
followRequestAccepted: "Akzeptierte Follow-Anfragen"
|
followRequestAccepted: "Akzeptierte Follow-Anfragen"
|
||||||
roleAssigned: "Rolle zugewiesen"
|
roleAssigned: "Rolle zugewiesen"
|
||||||
|
chatRoomInvitationReceived: "Einladungen zum Chatraum"
|
||||||
achievementEarned: "Errungenschaft freigeschaltet"
|
achievementEarned: "Errungenschaft freigeschaltet"
|
||||||
exportCompleted: "Der Export ist abgeschlossen"
|
exportCompleted: "Der Export ist abgeschlossen"
|
||||||
login: "Anmeldung"
|
login: "Anmeldung"
|
||||||
|
createToken: "Erstellung von Zugriffstokens"
|
||||||
test: "Test-Benachrichtigungen"
|
test: "Test-Benachrichtigungen"
|
||||||
app: "Benachrichtigungen von Apps"
|
app: "Benachrichtigungen von Apps"
|
||||||
_actions:
|
_actions:
|
||||||
|
@ -2454,6 +2602,9 @@ _notification:
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "Hauptspalte immer zeigen"
|
alwaysShowMainColumn: "Hauptspalte immer zeigen"
|
||||||
columnAlign: "Spaltenausrichtung"
|
columnAlign: "Spaltenausrichtung"
|
||||||
|
columnGap: "Spaltenabstand"
|
||||||
|
deckMenuPosition: "Position des Deck-Menüs"
|
||||||
|
navbarPosition: "Position der Navigationsleiste"
|
||||||
addColumn: "Spalte hinzufügen"
|
addColumn: "Spalte hinzufügen"
|
||||||
newNoteNotificationSettings: "Benachrichtigungseinstellungen für neue Notizen"
|
newNoteNotificationSettings: "Benachrichtigungseinstellungen für neue Notizen"
|
||||||
configureColumn: "Spalteneinstellungen"
|
configureColumn: "Spalteneinstellungen"
|
||||||
|
@ -2484,6 +2635,7 @@ _deck:
|
||||||
mentions: "Erwähnungen"
|
mentions: "Erwähnungen"
|
||||||
direct: "Direktnachrichten"
|
direct: "Direktnachrichten"
|
||||||
roleTimeline: "Rollenchronik"
|
roleTimeline: "Rollenchronik"
|
||||||
|
chat: "Chat"
|
||||||
_dialog:
|
_dialog:
|
||||||
charactersExceeded: "Maximallänge überschritten! Momentan {current} von {max}"
|
charactersExceeded: "Maximallänge überschritten! Momentan {current} von {max}"
|
||||||
charactersBelow: "Minimallänge unterschritten! Momentan {current} von {min}"
|
charactersBelow: "Minimallänge unterschritten! Momentan {current} von {min}"
|
||||||
|
@ -2560,6 +2712,7 @@ _moderationLogTypes:
|
||||||
unmarkSensitiveDriveFile: "Datei als nicht sensitiv markiert"
|
unmarkSensitiveDriveFile: "Datei als nicht sensitiv markiert"
|
||||||
resolveAbuseReport: "Meldung bearbeitet"
|
resolveAbuseReport: "Meldung bearbeitet"
|
||||||
forwardAbuseReport: "Meldung weitergeleitet"
|
forwardAbuseReport: "Meldung weitergeleitet"
|
||||||
|
updateAbuseReportNote: "Moderationsnotiz einer Meldung aktualisiert"
|
||||||
createInvitation: "Einladung erstellt"
|
createInvitation: "Einladung erstellt"
|
||||||
createAd: "Werbung erstellt"
|
createAd: "Werbung erstellt"
|
||||||
deleteAd: "Werbung gelöscht"
|
deleteAd: "Werbung gelöscht"
|
||||||
|
@ -2579,6 +2732,8 @@ _moderationLogTypes:
|
||||||
deletePage: "Seite gelöscht"
|
deletePage: "Seite gelöscht"
|
||||||
deleteFlash: "Play gelöscht"
|
deleteFlash: "Play gelöscht"
|
||||||
deleteGalleryPost: "Galeriebeitrag gelöscht"
|
deleteGalleryPost: "Galeriebeitrag gelöscht"
|
||||||
|
deleteChatRoom: "Chatraum gelöscht"
|
||||||
|
updateProxyAccountDescription: "Beschreibung des Proxy-Benutzerkontos aktualisiert"
|
||||||
_fileViewer:
|
_fileViewer:
|
||||||
title: "Dateiinformationen"
|
title: "Dateiinformationen"
|
||||||
type: "Dateityp"
|
type: "Dateityp"
|
||||||
|
@ -2644,6 +2799,7 @@ _hemisphere:
|
||||||
S: "Südliche Erdhalbkugel"
|
S: "Südliche Erdhalbkugel"
|
||||||
caption: "Wird in einigen Client-Einstellungen zur Bestimmung der Jahreszeit verwendet."
|
caption: "Wird in einigen Client-Einstellungen zur Bestimmung der Jahreszeit verwendet."
|
||||||
_reversi:
|
_reversi:
|
||||||
|
reversi: "Reversi"
|
||||||
gameSettings: "Spieleinstellungen"
|
gameSettings: "Spieleinstellungen"
|
||||||
chooseBoard: "Spielbrett auswählen"
|
chooseBoard: "Spielbrett auswählen"
|
||||||
blackOrWhite: "Schwarz/Weiß"
|
blackOrWhite: "Schwarz/Weiß"
|
||||||
|
@ -2661,6 +2817,7 @@ _reversi:
|
||||||
pastTurnOf: "Zug von {name}"
|
pastTurnOf: "Zug von {name}"
|
||||||
surrender: "Aufgeben"
|
surrender: "Aufgeben"
|
||||||
surrendered: "Aufgegeben"
|
surrendered: "Aufgegeben"
|
||||||
|
timeout: "Zeit abgelaufen"
|
||||||
drawn: "Unentschieden"
|
drawn: "Unentschieden"
|
||||||
won: "{name} hat gewonnen"
|
won: "{name} hat gewonnen"
|
||||||
black: "Schwarz"
|
black: "Schwarz"
|
||||||
|
@ -2671,10 +2828,14 @@ _reversi:
|
||||||
allGames: "Alle Runden"
|
allGames: "Alle Runden"
|
||||||
ended: "Beendet"
|
ended: "Beendet"
|
||||||
playing: "Partie läuft"
|
playing: "Partie läuft"
|
||||||
|
isLlotheo: "Der mit weniger Steinen gewinnt (Llotheo)"
|
||||||
|
loopedMap: "Wiederholendes Spielbrett"
|
||||||
|
canPutEverywhere: "Steine können überall platziert werden"
|
||||||
timeLimitForEachTurn: "Zeitlimit eines Zugs"
|
timeLimitForEachTurn: "Zeitlimit eines Zugs"
|
||||||
freeMatch: "Freies Spiel"
|
freeMatch: "Freies Spiel"
|
||||||
lookingForPlayer: "Gegner werden gesucht..."
|
lookingForPlayer: "Gegner werden gesucht..."
|
||||||
gameCanceled: "Das Spiel wurde abgesagt."
|
gameCanceled: "Das Spiel wurde abgesagt."
|
||||||
|
shareToTlTheGameWhenStart: "Spiel in der Chronik teilen, wenn es gestartet wurde"
|
||||||
iStartedAGame: "Das Spiel hat begonnen! #MisskeyReversi"
|
iStartedAGame: "Das Spiel hat begonnen! #MisskeyReversi"
|
||||||
opponentHasSettingsChanged: "Der Gegner hat seine Einstellungen geändert."
|
opponentHasSettingsChanged: "Der Gegner hat seine Einstellungen geändert."
|
||||||
allowIrregularRules: "Irreguläre Regeln (völlig frei)"
|
allowIrregularRules: "Irreguläre Regeln (völlig frei)"
|
||||||
|
@ -2695,7 +2856,9 @@ _urlPreviewSetting:
|
||||||
requireContentLengthDescription: "Wenn der Server keine Content-Length zurückgibt, wird keine Vorschau erzeugt."
|
requireContentLengthDescription: "Wenn der Server keine Content-Length zurückgibt, wird keine Vorschau erzeugt."
|
||||||
userAgent: "User-Agent"
|
userAgent: "User-Agent"
|
||||||
userAgentDescription: "Legt den User-Agent fest, der beim Abrufen der Vorschau verwendet werden soll. Bleibt er leer, wird der Standard-User-Agent verwendet."
|
userAgentDescription: "Legt den User-Agent fest, der beim Abrufen der Vorschau verwendet werden soll. Bleibt er leer, wird der Standard-User-Agent verwendet."
|
||||||
|
summaryProxy: "Proxy-Endpunkte, die Vorschaubilder erzeugen"
|
||||||
summaryProxyDescription: "Generierung von Vorschaubildern mit Summaly Proxy anstelle von Misskey selbst."
|
summaryProxyDescription: "Generierung von Vorschaubildern mit Summaly Proxy anstelle von Misskey selbst."
|
||||||
|
summaryProxyDescription2: "Die folgenden Parameter werden als Abfrage-Strings mit dem Proxy verknüpft. Wenn der Proxy sie nicht unterstützt, werden die Werte ignoriert."
|
||||||
_mediaControls:
|
_mediaControls:
|
||||||
pip: "Bild-in-Bild"
|
pip: "Bild-in-Bild"
|
||||||
playbackRate: "Wiedergabegeschwindigkeit"
|
playbackRate: "Wiedergabegeschwindigkeit"
|
||||||
|
@ -2703,15 +2866,68 @@ _mediaControls:
|
||||||
_contextMenu:
|
_contextMenu:
|
||||||
title: "Kontextmenü"
|
title: "Kontextmenü"
|
||||||
app: "Anwendung"
|
app: "Anwendung"
|
||||||
|
appWithShift: "Anwendung per Umschalttaste"
|
||||||
|
native: "Natives Browsermenü"
|
||||||
_gridComponent:
|
_gridComponent:
|
||||||
_error:
|
_error:
|
||||||
requiredValue: "Dieser Wert ist ein Pflichtfeld"
|
requiredValue: "Dieser Wert ist ein Pflichtfeld"
|
||||||
|
columnTypeNotSupport: "Die Validierung regulärer Ausdrücke wird nur für Spalten vom Typ \"Text\" unterstützt."
|
||||||
|
patternNotMatch: "Dieser Wert stimmt nicht mit dem Schema in {pattern} überein"
|
||||||
notUnique: "Dieser Wert muss eindeutig sein"
|
notUnique: "Dieser Wert muss eindeutig sein"
|
||||||
|
_roleSelectDialog:
|
||||||
|
notSelected: "Nicht ausgewählt"
|
||||||
_customEmojisManager:
|
_customEmojisManager:
|
||||||
|
_gridCommon:
|
||||||
|
copySelectionRows: "Ausgewählte Zeilen kopieren"
|
||||||
|
copySelectionRanges: "Auswahl kopieren"
|
||||||
|
deleteSelectionRows: "Ausgewählte Zeilen löschen"
|
||||||
|
deleteSelectionRanges: "Zeilen in der Auswahl löschen"
|
||||||
|
searchSettings: "Sucheinstellungen"
|
||||||
|
searchSettingCaption: "Detaillierte Suchkriterien festlegen."
|
||||||
|
searchLimit: "Anzahl der Ergebnisse"
|
||||||
|
sortOrder: "Sortierung"
|
||||||
|
registrationLogs: "Registrierungsprotokoll"
|
||||||
|
registrationLogsCaption: "Protokolle werden beim Aktualisieren oder Löschen von Emojis angezeigt. Sie verschwinden nach dem Aktualisieren oder Löschen, dem Wechsel zu einer neuen Seite oder dem Neuladen."
|
||||||
|
alertEmojisRegisterFailedDescription: "Emoji konnte nicht aktualisiert oder gelöscht werden. Bitte prüfe das Registrierungsprotokoll für Details."
|
||||||
_logs:
|
_logs:
|
||||||
|
showSuccessLogSwitch: "Erfolgsprotokoll zeigen"
|
||||||
|
failureLogNothing: "Es gibt kein Fehlerprotokoll."
|
||||||
logNothing: "Keine Protokoll-Einträge."
|
logNothing: "Keine Protokoll-Einträge."
|
||||||
_remote:
|
_remote:
|
||||||
|
selectionRowDetail: "Details der ausgewählten Zeile"
|
||||||
|
importSelectionRows: "Ausgewählte Zeilen importieren"
|
||||||
|
importSelectionRangesRows: "Zeilen in der Auswahl importieren"
|
||||||
|
importEmojisButton: "Ausgewählte Emojis importieren"
|
||||||
confirmImportEmojisTitle: "Emojis importieren"
|
confirmImportEmojisTitle: "Emojis importieren"
|
||||||
|
confirmImportEmojisDescription: "Importiere {count} Emoji(s), die von entfernten Server empfangen wurden. Bitte achte genau auf die Lizenz der Emojis. Bist du sicher, dass du fortfahren möchtest?"
|
||||||
|
_local:
|
||||||
|
tabTitleList: "Hinzugefügte Emojis"
|
||||||
|
tabTitleRegister: "Emojis hinzufügen"
|
||||||
|
_list:
|
||||||
|
emojisNothing: "Es wurden keine Emojis hinzugefügt."
|
||||||
|
markAsDeleteTargetRows: "Ausgewählte Zeilen als zu löschendes Element markieren"
|
||||||
|
markAsDeleteTargetRanges: "Zeilen in der Auswahl als zu löschendes Element markieren"
|
||||||
|
alertUpdateEmojisNothingDescription: "Es wurden keine Emojis geändert."
|
||||||
|
alertDeleteEmojisNothingDescription: "Es gibt keine zu löschenden Emojis."
|
||||||
|
confirmMovePage: "Möchten Sie die Seiten verschieben?"
|
||||||
|
confirmChangeView: "Möchten Sie die Darstellung wechseln?"
|
||||||
|
confirmUpdateEmojisDescription: "Aktualisiere {count} Emoji(s). Willst du fortfahren?"
|
||||||
|
confirmDeleteEmojisDescription: "Lösche {count} ausgewählte Emoji(s). Willst du fortfahren?"
|
||||||
|
confirmResetDescription: "Alle bisher vorgenommenen Änderungen werden zurückgesetzt."
|
||||||
|
confirmMovePageDesciption: "An den Emojis auf dieser Seite wurden Änderungen vorgenommen.\nWenn du die Seite verlässt, ohne zu speichern, werden alle auf dieser Seite vorgenommenen Änderungen verworfen."
|
||||||
|
dialogSelectRoleTitle: "Suche nach dem Rollensatz in Emojis"
|
||||||
|
_register:
|
||||||
|
uploadSettingTitle: "Upload-Einstellungen"
|
||||||
|
uploadSettingDescription: "Hier kannst du das Verhalten beim Hochladen von Emojis konfigurieren."
|
||||||
|
directoryToCategoryLabel: "Gib den Namen des Verzeichnisses in das Feld „Kategorie“ ein"
|
||||||
|
directoryToCategoryCaption: "Wenn du ein Verzeichnis ziehst und ablegst, gib den Verzeichnisnamen in das Feld „Kategorie“ ein."
|
||||||
|
emojiInputAreaCaption: "Wählen Sie die Emojis aus, die Sie mit einer der folgenden Methoden speichern möchten."
|
||||||
|
emojiInputAreaList1: "Ziehe Bilddateien oder Verzeichnisse per Drag-and-drop in diesen Rahmen"
|
||||||
|
emojiInputAreaList2: "Klicke auf diesen Link, um von deinem PC aus zu wählen"
|
||||||
|
emojiInputAreaList3: "Klicke auf diesen Link, um vom Drive aus zu wählen"
|
||||||
|
confirmRegisterEmojisDescription: "Füge die in der Liste aufgeführten Emojis als neue benutzerdefinierte Emojis hinzu. Bist du sicher? (Um eine Überlastung zu vermeiden, können nur {count} Emoji(s) in einem Vorgang hinzugefügt werden)"
|
||||||
|
confirmClearEmojisDescription: "Verwerfe die Bearbeitungen und lösche die Emojis aus der Liste. Bist du sicher, dass du fortfahren möchtest?"
|
||||||
|
confirmUploadEmojisDescription: "Lade die {count} abgelegte(n) Datei(en) in das Drive hoch. Bist du sicher, dass du fortfahren möchtest?"
|
||||||
_embedCodeGen:
|
_embedCodeGen:
|
||||||
title: "Einbettungscode anpassen"
|
title: "Einbettungscode anpassen"
|
||||||
header: "Kopfzeile anzeigen"
|
header: "Kopfzeile anzeigen"
|
||||||
|
@ -2719,6 +2935,9 @@ _embedCodeGen:
|
||||||
maxHeight: "Maximale Höhe"
|
maxHeight: "Maximale Höhe"
|
||||||
maxHeightDescription: "Der Wert 0 deaktiviert die Einstellung der maximalen Höhe. Gib einen Wert an, um zu verhindern, dass das Widget weiterhin vertikal vergrößert wird."
|
maxHeightDescription: "Der Wert 0 deaktiviert die Einstellung der maximalen Höhe. Gib einen Wert an, um zu verhindern, dass das Widget weiterhin vertikal vergrößert wird."
|
||||||
maxHeightWarn: "Die Begrenzung der maximalen Höhe ist deaktiviert (0). Wenn dies nicht beabsichtigt war, setze die maximale Höhe auf einen Wert fest."
|
maxHeightWarn: "Die Begrenzung der maximalen Höhe ist deaktiviert (0). Wenn dies nicht beabsichtigt war, setze die maximale Höhe auf einen Wert fest."
|
||||||
|
previewIsNotActual: "Die Anzeige weicht von der tatsächlichen Einbettung ab, da sie den auf dem Vorschaufenster angezeigten Bereich überschreitet."
|
||||||
|
rounded: "Ecken abrunden"
|
||||||
|
border: "Dem äußeren Rand einen Rahmen hinzufügen"
|
||||||
applyToPreview: "Auf die Vorschau anwenden"
|
applyToPreview: "Auf die Vorschau anwenden"
|
||||||
generateCode: "Einbettungscode generieren"
|
generateCode: "Einbettungscode generieren"
|
||||||
codeGenerated: "Der Code wurde generiert"
|
codeGenerated: "Der Code wurde generiert"
|
||||||
|
@ -2749,8 +2968,17 @@ _remoteLookupErrors:
|
||||||
title: "Nicht gefunden"
|
title: "Nicht gefunden"
|
||||||
description: "Die angeforderte Ressource konnte nicht gefunden werden, bitte überprüfe die URI erneut."
|
description: "Die angeforderte Ressource konnte nicht gefunden werden, bitte überprüfe die URI erneut."
|
||||||
_captcha:
|
_captcha:
|
||||||
|
verify: "Bitte beantworte das CAPTCHA"
|
||||||
|
testSiteKeyMessage: "Du kannst die Vorschau prüfen, indem du die Testwerte für den Site- und Secret-Key eingibst. Weitere Informationen findest du auf der folgenden Seite."
|
||||||
_error:
|
_error:
|
||||||
|
_requestFailed:
|
||||||
|
title: "CAPTCHA-Anfrage fehlgeschlagen."
|
||||||
|
text: "Bitte probiere es später noch einmal oder überprüfe die Einstellungen erneut."
|
||||||
|
_verificationFailed:
|
||||||
|
title: "CAPTCHA-Prüfung fehlgeschlagen"
|
||||||
|
text: "Bitte überprüfe nochmals, ob die Einstellungen korrekt sind."
|
||||||
_unknown:
|
_unknown:
|
||||||
|
title: "CAPTCHA-Fehler"
|
||||||
text: "Es ist ein unerwarteter Fehler aufgetreten."
|
text: "Es ist ein unerwarteter Fehler aufgetreten."
|
||||||
_bootErrors:
|
_bootErrors:
|
||||||
title: "Laden fehlgeschlagen"
|
title: "Laden fehlgeschlagen"
|
||||||
|
|
|
@ -301,6 +301,7 @@ uploadFromUrlMayTakeTime: "It may take some time until the upload is complete."
|
||||||
explore: "Explore"
|
explore: "Explore"
|
||||||
messageRead: "Read"
|
messageRead: "Read"
|
||||||
noMoreHistory: "There is no further history"
|
noMoreHistory: "There is no further history"
|
||||||
|
startChat: "Start chat"
|
||||||
nUsersRead: "read by {n}"
|
nUsersRead: "read by {n}"
|
||||||
agreeTo: "I agree to {0}"
|
agreeTo: "I agree to {0}"
|
||||||
agree: "Agree"
|
agree: "Agree"
|
||||||
|
@ -344,7 +345,7 @@ emptyDrive: "Your Drive is empty"
|
||||||
emptyFolder: "This folder is empty"
|
emptyFolder: "This folder is empty"
|
||||||
unableToDelete: "Unable to delete"
|
unableToDelete: "Unable to delete"
|
||||||
inputNewFileName: "Enter a new filename"
|
inputNewFileName: "Enter a new filename"
|
||||||
inputNewDescription: "Enter new caption"
|
inputNewDescription: "Enter new alt text"
|
||||||
inputNewFolderName: "Enter a new folder name"
|
inputNewFolderName: "Enter a new folder name"
|
||||||
circularReferenceFolder: "The destination folder is a subfolder of the folder you wish to move."
|
circularReferenceFolder: "The destination folder is a subfolder of the folder you wish to move."
|
||||||
hasChildFilesOrFolders: "Since this folder is not empty, it can not be deleted."
|
hasChildFilesOrFolders: "Since this folder is not empty, it can not be deleted."
|
||||||
|
@ -423,6 +424,7 @@ antennaExcludeBots: "Exclude bot accounts"
|
||||||
antennaKeywordsDescription: "Separate with spaces for an AND condition or with line breaks for an OR condition."
|
antennaKeywordsDescription: "Separate with spaces for an AND condition or with line breaks for an OR condition."
|
||||||
notifyAntenna: "Notify about new notes"
|
notifyAntenna: "Notify about new notes"
|
||||||
withFileAntenna: "Only notes with files"
|
withFileAntenna: "Only notes with files"
|
||||||
|
excludeNotesInSensitiveChannel: "Exclude notes from sensitive channels"
|
||||||
enableServiceworker: "Enable Push-Notifications for your Browser"
|
enableServiceworker: "Enable Push-Notifications for your Browser"
|
||||||
antennaUsersDescription: "List one username per line"
|
antennaUsersDescription: "List one username per line"
|
||||||
caseSensitive: "Case sensitive"
|
caseSensitive: "Case sensitive"
|
||||||
|
@ -642,8 +644,8 @@ disablePlayer: "Close video player"
|
||||||
expandTweet: "Expand post"
|
expandTweet: "Expand post"
|
||||||
themeEditor: "Theme editor"
|
themeEditor: "Theme editor"
|
||||||
description: "Description"
|
description: "Description"
|
||||||
describeFile: "Add caption"
|
describeFile: "Add alt text"
|
||||||
enterFileDescription: "Enter caption"
|
enterFileDescription: "Enter alt text"
|
||||||
author: "Author"
|
author: "Author"
|
||||||
leaveConfirm: "There are unsaved changes. Do you want to discard them?"
|
leaveConfirm: "There are unsaved changes. Do you want to discard them?"
|
||||||
manage: "Management"
|
manage: "Management"
|
||||||
|
@ -1013,7 +1015,7 @@ sendPushNotificationReadMessageCaption: "This may increase the power consumption
|
||||||
windowMaximize: "Maximize"
|
windowMaximize: "Maximize"
|
||||||
windowMinimize: "Minimize"
|
windowMinimize: "Minimize"
|
||||||
windowRestore: "Restore"
|
windowRestore: "Restore"
|
||||||
caption: "Caption"
|
caption: "Alt text"
|
||||||
loggedInAsBot: "Currently logged in as bot"
|
loggedInAsBot: "Currently logged in as bot"
|
||||||
tools: "Tools"
|
tools: "Tools"
|
||||||
cannotLoad: "Unable to load"
|
cannotLoad: "Unable to load"
|
||||||
|
@ -1331,12 +1333,63 @@ emojiPalette: "Emoji palette"
|
||||||
postForm: "Posting form"
|
postForm: "Posting form"
|
||||||
textCount: "Character count"
|
textCount: "Character count"
|
||||||
information: "About"
|
information: "About"
|
||||||
|
chat: "Chat"
|
||||||
|
migrateOldSettings: "Migrate old client settings"
|
||||||
|
migrateOldSettings_description: "This should be done automatically but if for some reason the migration was not successful, you can trigger the migration process yourself manually. The current configuration information will be overwritten."
|
||||||
|
compress: "Compress"
|
||||||
|
right: "Right"
|
||||||
|
bottom: "Bottom"
|
||||||
|
top: "Top"
|
||||||
|
embed: "Embed"
|
||||||
|
settingsMigrating: "Settings are being migrated, please wait a moment... (You can also migrate manually later by going to Settings→Others→Migrate old settings)"
|
||||||
|
readonly: "Read only"
|
||||||
|
goToDeck: "Return to Deck"
|
||||||
_chat:
|
_chat:
|
||||||
|
noMessagesYet: "No messages yet"
|
||||||
|
newMessage: "New message"
|
||||||
|
individualChat: "Private Chat"
|
||||||
|
individualChat_description: "Have a private chat with another person."
|
||||||
|
roomChat: "Room Chat"
|
||||||
|
roomChat_description: "A chat room which can have multiple people.\nYou can also invite people who don't allow private chats if they accept the invite."
|
||||||
|
createRoom: "Create Room"
|
||||||
|
inviteUserToChat: "Invite users to start chatting"
|
||||||
|
yourRooms: "Created rooms"
|
||||||
|
joiningRooms: "Joined rooms"
|
||||||
invitations: "Invite"
|
invitations: "Invite"
|
||||||
|
noInvitations: "No invitations"
|
||||||
|
history: "History"
|
||||||
noHistory: "No history available"
|
noHistory: "No history available"
|
||||||
|
noRooms: "No rooms found"
|
||||||
|
inviteUser: "Invite Users"
|
||||||
|
sentInvitations: "Sent Invites"
|
||||||
|
join: "Join"
|
||||||
|
ignore: "Ignore"
|
||||||
|
leave: "Leave room"
|
||||||
members: "Members"
|
members: "Members"
|
||||||
|
searchMessages: "Search messages"
|
||||||
home: "Home"
|
home: "Home"
|
||||||
send: "Send"
|
send: "Send"
|
||||||
|
newline: "New line"
|
||||||
|
muteThisRoom: "Mute room"
|
||||||
|
deleteRoom: "Delete room"
|
||||||
|
chatNotAvailableForThisAccountOrServer: "Chat is not enabled on this server or for this account."
|
||||||
|
chatIsReadOnlyForThisAccountOrServer: "Chat is read-only on this instance or this account. You cannot write new messages or create/join chat rooms."
|
||||||
|
chatNotAvailableInOtherAccount: "The chat function is disabled for the other user."
|
||||||
|
cannotChatWithTheUser: "Cannot start a chat with this user"
|
||||||
|
cannotChatWithTheUser_description: "Chat is either unavailable or the other party has not enabled chat."
|
||||||
|
chatWithThisUser: "Chat with user"
|
||||||
|
thisUserAllowsChatOnlyFromFollowers: "This user accepts chats from followers only."
|
||||||
|
thisUserAllowsChatOnlyFromFollowing: "This user accepts chats only from users they follow."
|
||||||
|
thisUserAllowsChatOnlyFromMutualFollowing: "This user only accepts chats from users who are mutual followers."
|
||||||
|
thisUserNotAllowedChatAnyone: "This user is not accepting chats from anyone."
|
||||||
|
chatAllowedUsers: "Who to allow chatting with"
|
||||||
|
chatAllowedUsers_note: "You can chat with anyone to whom you have sent a chat message regardless of this setting."
|
||||||
|
_chatAllowedUsers:
|
||||||
|
everyone: "Everyone"
|
||||||
|
followers: "Only your followers"
|
||||||
|
following: "Only users you are following"
|
||||||
|
mutual: "Mutual followers only"
|
||||||
|
none: "Nobody"
|
||||||
_emojiPalette:
|
_emojiPalette:
|
||||||
palettes: "Palette"
|
palettes: "Palette"
|
||||||
enableSyncBetweenDevicesForPalettes: "Enable palette sync between devices"
|
enableSyncBetweenDevicesForPalettes: "Enable palette sync between devices"
|
||||||
|
@ -1362,6 +1415,14 @@ _settings:
|
||||||
timelineAndNote: "Timeline and note"
|
timelineAndNote: "Timeline and note"
|
||||||
makeEveryTextElementsSelectable: "Make all text elements selectable"
|
makeEveryTextElementsSelectable: "Make all text elements selectable"
|
||||||
makeEveryTextElementsSelectable_description: "Enabling this may reduce usability in some situations."
|
makeEveryTextElementsSelectable_description: "Enabling this may reduce usability in some situations."
|
||||||
|
useStickyIcons: "Make icons follow while scrolling"
|
||||||
|
showNavbarSubButtons: "Show sub-buttons on the navigation bar"
|
||||||
|
ifOn: "When turned on"
|
||||||
|
ifOff: "When turned off"
|
||||||
|
enableSyncThemesBetweenDevices: "Synchronize installed themes across devices"
|
||||||
|
_chat:
|
||||||
|
showSenderName: "Show sender's name"
|
||||||
|
sendOnEnter: "Press Enter to send"
|
||||||
_preferencesProfile:
|
_preferencesProfile:
|
||||||
profileName: "Profile name"
|
profileName: "Profile name"
|
||||||
profileNameDescription: "Set a name that identifies this device."
|
profileNameDescription: "Set a name that identifies this device."
|
||||||
|
@ -1831,6 +1892,8 @@ _role:
|
||||||
descriptionOfIsExplorable: "This role's timeline and the list of users with this will be made public if enabled."
|
descriptionOfIsExplorable: "This role's timeline and the list of users with this will be made public if enabled."
|
||||||
displayOrder: "Position"
|
displayOrder: "Position"
|
||||||
descriptionOfDisplayOrder: "The higher the number, the higher its UI position."
|
descriptionOfDisplayOrder: "The higher the number, the higher its UI position."
|
||||||
|
preserveAssignmentOnMoveAccount: "Preserve role assignment during migration"
|
||||||
|
preserveAssignmentOnMoveAccount_description: "When turned on, this role will be carried over to the destination account when an account with this role is migrated."
|
||||||
canEditMembersByModerator: "Allow moderators to edit the list of members for this role"
|
canEditMembersByModerator: "Allow moderators to edit the list of members for this role"
|
||||||
descriptionOfCanEditMembersByModerator: "When turned on, moderators as well as administrators will be able to assign and unassign users to this role. When turned off, only administrators will be able to assign users."
|
descriptionOfCanEditMembersByModerator: "When turned on, moderators as well as administrators will be able to assign and unassign users to this role. When turned off, only administrators will be able to assign users."
|
||||||
priority: "Priority"
|
priority: "Priority"
|
||||||
|
@ -1871,6 +1934,7 @@ _role:
|
||||||
canImportFollowing: "Allow importing following"
|
canImportFollowing: "Allow importing following"
|
||||||
canImportMuting: "Allow importing muting"
|
canImportMuting: "Allow importing muting"
|
||||||
canImportUserLists: "Allow importing lists"
|
canImportUserLists: "Allow importing lists"
|
||||||
|
chatAvailability: "Allow Chat"
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "Assigned to manual roles"
|
roleAssignedTo: "Assigned to manual roles"
|
||||||
isLocal: "Local user"
|
isLocal: "Local user"
|
||||||
|
@ -2067,7 +2131,6 @@ _theme:
|
||||||
header: "Header"
|
header: "Header"
|
||||||
navBg: "Sidebar background"
|
navBg: "Sidebar background"
|
||||||
navFg: "Sidebar text"
|
navFg: "Sidebar text"
|
||||||
navHoverFg: "Sidebar text (Hover)"
|
|
||||||
navActive: "Sidebar text (Active)"
|
navActive: "Sidebar text (Active)"
|
||||||
navIndicator: "Sidebar indicator"
|
navIndicator: "Sidebar indicator"
|
||||||
link: "Link"
|
link: "Link"
|
||||||
|
@ -2090,17 +2153,15 @@ _theme:
|
||||||
buttonHoverBg: "Button background (Hover)"
|
buttonHoverBg: "Button background (Hover)"
|
||||||
inputBorder: "Input field border"
|
inputBorder: "Input field border"
|
||||||
driveFolderBg: "Drive folder background"
|
driveFolderBg: "Drive folder background"
|
||||||
wallpaperOverlay: "Wallpaper overlay"
|
|
||||||
badge: "Badge"
|
badge: "Badge"
|
||||||
messageBg: "Chat background"
|
messageBg: "Chat background"
|
||||||
accentDarken: "Accent (Darkened)"
|
|
||||||
accentLighten: "Accent (Lightened)"
|
|
||||||
fgHighlighted: "Highlighted Text"
|
fgHighlighted: "Highlighted Text"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "New note"
|
note: "New note"
|
||||||
noteMy: "Own note"
|
noteMy: "Own note"
|
||||||
notification: "Notifications"
|
notification: "Notifications"
|
||||||
reaction: "On choosing a reaction"
|
reaction: "On choosing a reaction"
|
||||||
|
chatMessage: "Chat Messages"
|
||||||
_soundSettings:
|
_soundSettings:
|
||||||
driveFile: "Use an audio file in Drive."
|
driveFile: "Use an audio file in Drive."
|
||||||
driveFileWarn: "Select an audio file from Drive."
|
driveFileWarn: "Select an audio file from Drive."
|
||||||
|
@ -2248,6 +2309,7 @@ _permissions:
|
||||||
"read:federation": "Get federation data"
|
"read:federation": "Get federation data"
|
||||||
"write:report-abuse": "Report violation"
|
"write:report-abuse": "Report violation"
|
||||||
"write:chat": "Compose or delete chat messages"
|
"write:chat": "Compose or delete chat messages"
|
||||||
|
"read:chat": "Browse Chat"
|
||||||
_auth:
|
_auth:
|
||||||
shareAccessTitle: "Granting application permissions"
|
shareAccessTitle: "Granting application permissions"
|
||||||
shareAccess: "Would you like to authorize \"{name}\" to access this account?"
|
shareAccess: "Would you like to authorize \"{name}\" to access this account?"
|
||||||
|
@ -2306,6 +2368,7 @@ _widgets:
|
||||||
chooseList: "Select a list"
|
chooseList: "Select a list"
|
||||||
clicker: "Clicker"
|
clicker: "Clicker"
|
||||||
birthdayFollowings: "Today's Birthdays"
|
birthdayFollowings: "Today's Birthdays"
|
||||||
|
chat: "Chat"
|
||||||
_cw:
|
_cw:
|
||||||
hide: "Hide"
|
hide: "Hide"
|
||||||
show: "Show content"
|
show: "Show content"
|
||||||
|
@ -2496,6 +2559,7 @@ _notification:
|
||||||
newNote: "New note"
|
newNote: "New note"
|
||||||
unreadAntennaNote: "Antenna {name}"
|
unreadAntennaNote: "Antenna {name}"
|
||||||
roleAssigned: "Role given"
|
roleAssigned: "Role given"
|
||||||
|
chatRoomInvitationReceived: "You have been invited to a chat room"
|
||||||
emptyPushNotificationMessage: "Push notifications have been updated"
|
emptyPushNotificationMessage: "Push notifications have been updated"
|
||||||
achievementEarned: "Achievement unlocked"
|
achievementEarned: "Achievement unlocked"
|
||||||
testNotification: "Test notification"
|
testNotification: "Test notification"
|
||||||
|
@ -2524,6 +2588,7 @@ _notification:
|
||||||
receiveFollowRequest: "Received follow requests"
|
receiveFollowRequest: "Received follow requests"
|
||||||
followRequestAccepted: "Accepted follow requests"
|
followRequestAccepted: "Accepted follow requests"
|
||||||
roleAssigned: "Role given"
|
roleAssigned: "Role given"
|
||||||
|
chatRoomInvitationReceived: "Invited to chat room"
|
||||||
achievementEarned: "Achievement unlocked"
|
achievementEarned: "Achievement unlocked"
|
||||||
exportCompleted: "The export has been completed"
|
exportCompleted: "The export has been completed"
|
||||||
login: "Sign In"
|
login: "Sign In"
|
||||||
|
@ -2537,6 +2602,9 @@ _notification:
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "Always show main column"
|
alwaysShowMainColumn: "Always show main column"
|
||||||
columnAlign: "Align columns"
|
columnAlign: "Align columns"
|
||||||
|
columnGap: "Margin between columns"
|
||||||
|
deckMenuPosition: "Deck menu position"
|
||||||
|
navbarPosition: "Navigation bar position"
|
||||||
addColumn: "Add column"
|
addColumn: "Add column"
|
||||||
newNoteNotificationSettings: "Notification setting for new notes"
|
newNoteNotificationSettings: "Notification setting for new notes"
|
||||||
configureColumn: "Column settings"
|
configureColumn: "Column settings"
|
||||||
|
@ -2550,7 +2618,7 @@ _deck:
|
||||||
newProfile: "New profile"
|
newProfile: "New profile"
|
||||||
deleteProfile: "Delete profile"
|
deleteProfile: "Delete profile"
|
||||||
introduction: "Create the perfect interface for you by arranging columns freely!"
|
introduction: "Create the perfect interface for you by arranging columns freely!"
|
||||||
introduction2: "Click on the + on the right of the screen to add new colums whenever you want."
|
introduction2: "Click on the + on the right of the screen to add new columns whenever you want."
|
||||||
widgetsIntroduction: "Please select \"Edit widgets\" in the column menu and add a widget."
|
widgetsIntroduction: "Please select \"Edit widgets\" in the column menu and add a widget."
|
||||||
useSimpleUiForNonRootPages: "Use simple UI for navigated pages"
|
useSimpleUiForNonRootPages: "Use simple UI for navigated pages"
|
||||||
usedAsMinWidthWhenFlexible: "Minimum width will be used for this when the \"Auto-adjust width\" option is enabled"
|
usedAsMinWidthWhenFlexible: "Minimum width will be used for this when the \"Auto-adjust width\" option is enabled"
|
||||||
|
@ -2567,6 +2635,7 @@ _deck:
|
||||||
mentions: "Mentions"
|
mentions: "Mentions"
|
||||||
direct: "Direct notes"
|
direct: "Direct notes"
|
||||||
roleTimeline: "Role Timeline"
|
roleTimeline: "Role Timeline"
|
||||||
|
chat: "Chat"
|
||||||
_dialog:
|
_dialog:
|
||||||
charactersExceeded: "You've exceeded the maximum character limit! Currently at {current} of {max}."
|
charactersExceeded: "You've exceeded the maximum character limit! Currently at {current} of {max}."
|
||||||
charactersBelow: "You're below the minimum character limit! Currently at {current} of {min}."
|
charactersBelow: "You're below the minimum character limit! Currently at {current} of {min}."
|
||||||
|
@ -2663,6 +2732,7 @@ _moderationLogTypes:
|
||||||
deletePage: "Page deleted"
|
deletePage: "Page deleted"
|
||||||
deleteFlash: "Play deleted"
|
deleteFlash: "Play deleted"
|
||||||
deleteGalleryPost: "Gallery post deleted"
|
deleteGalleryPost: "Gallery post deleted"
|
||||||
|
deleteChatRoom: "Deleted Chat Room"
|
||||||
updateProxyAccountDescription: "Update the description of the proxy account"
|
updateProxyAccountDescription: "Update the description of the proxy account"
|
||||||
_fileViewer:
|
_fileViewer:
|
||||||
title: "File details"
|
title: "File details"
|
||||||
|
|
|
@ -301,6 +301,7 @@ uploadFromUrlMayTakeTime: "Subir el fichero puede tardar un tiempo."
|
||||||
explore: "Explorar"
|
explore: "Explorar"
|
||||||
messageRead: "Ya leído"
|
messageRead: "Ya leído"
|
||||||
noMoreHistory: "El historial se ha acabado"
|
noMoreHistory: "El historial se ha acabado"
|
||||||
|
startChat: "Nuevo Chat"
|
||||||
nUsersRead: "Leído por {n} personas"
|
nUsersRead: "Leído por {n} personas"
|
||||||
agreeTo: "De acuerdo con {0}"
|
agreeTo: "De acuerdo con {0}"
|
||||||
agree: "De acuerdo."
|
agree: "De acuerdo."
|
||||||
|
@ -694,6 +695,7 @@ userSaysSomethingAbout: "{name} dijo algo sobre {word}"
|
||||||
makeActive: "Activar"
|
makeActive: "Activar"
|
||||||
display: "Apariencia"
|
display: "Apariencia"
|
||||||
copy: "Copiar"
|
copy: "Copiar"
|
||||||
|
copiedToClipboard: "Texto copiado al portapapeles"
|
||||||
metrics: "Métricas"
|
metrics: "Métricas"
|
||||||
overview: "Resumen"
|
overview: "Resumen"
|
||||||
logs: "Registros"
|
logs: "Registros"
|
||||||
|
@ -1293,17 +1295,55 @@ passkeyVerificationFailed: "La verificación de la clave de acceso ha fallado."
|
||||||
passkeyVerificationSucceededButPasswordlessLoginDisabled: "La verificación de la clave de acceso ha sido satisfactoria pero se ha deshabilitado el inicio de sesión sin contraseña."
|
passkeyVerificationSucceededButPasswordlessLoginDisabled: "La verificación de la clave de acceso ha sido satisfactoria pero se ha deshabilitado el inicio de sesión sin contraseña."
|
||||||
messageToFollower: "Mensaje a seguidores"
|
messageToFollower: "Mensaje a seguidores"
|
||||||
target: "Para"
|
target: "Para"
|
||||||
|
prohibitedWordsForNameOfUser: "Palabras prohibidas para nombres de usuario"
|
||||||
|
prohibitedWordsForNameOfUserDescription: "Si alguna de las cadenas de esta lista está incluida en el nombre del usuario, el nombre será denegado. Los usuarios con privilegios de moderador no se ven afectados por esta restricción."
|
||||||
|
yourNameContainsProhibitedWords: "Tu nombre contiene palabras prohibidas"
|
||||||
|
yourNameContainsProhibitedWordsDescription: "Si deseas usar este nombre, por favor contacta con tu administrador/a de tu servidor"
|
||||||
|
lockdown: "Bloqueo"
|
||||||
|
pleaseSelectAccount: "Seleccione una cuenta, por favor."
|
||||||
|
availableRoles: "Roles disponibles "
|
||||||
|
acknowledgeNotesAndEnable: "Activar después de comprender las precauciones"
|
||||||
federationSpecified: "Este servidor opera en una federación de listas blancas. No puede interactuar con otros servidores que no sean los especificados por el administrador."
|
federationSpecified: "Este servidor opera en una federación de listas blancas. No puede interactuar con otros servidores que no sean los especificados por el administrador."
|
||||||
federationDisabled: "La federación está desactivada en este servidor. No puede interactuar con usuarios de otros servidores"
|
federationDisabled: "La federación está desactivada en este servidor. No puede interactuar con usuarios de otros servidores"
|
||||||
|
preferences: "Preferencias"
|
||||||
postForm: "Formulario"
|
postForm: "Formulario"
|
||||||
information: "Información"
|
information: "Información"
|
||||||
|
right: "Derecha"
|
||||||
|
bottom: "Abajo"
|
||||||
|
top: "Arriba"
|
||||||
|
embed: "Insertar"
|
||||||
|
settingsMigrating: "La configuración está siendo migrada, por favor espera un momento... (También puedes migrar manualmente más tarde yendo a Ajustes otros migrar configuración antigua"
|
||||||
|
readonly: "Solo Lectura"
|
||||||
_chat:
|
_chat:
|
||||||
|
noMessagesYet: "Aún no hay mensajes"
|
||||||
|
newMessage: "Mensajes nuevos"
|
||||||
|
individualChat: "Chat individual"
|
||||||
|
individualChat_description: "Mantén una conversación privada con otra persona."
|
||||||
invitations: "Invitar"
|
invitations: "Invitar"
|
||||||
noHistory: "No hay datos en el historial"
|
noHistory: "No hay datos en el historial"
|
||||||
members: "Miembros"
|
members: "Miembros"
|
||||||
home: "Inicio"
|
home: "Inicio"
|
||||||
send: "Enviar"
|
send: "Enviar"
|
||||||
|
chatNotAvailableInOtherAccount: "La función de chat está desactivada para el otro usuario."
|
||||||
|
cannotChatWithTheUser: "No se puede iniciar un chat con este usuario"
|
||||||
|
cannotChatWithTheUser_description: "El chat no está disponible o la otra parte no ha habilitado el chat."
|
||||||
|
chatWithThisUser: "Chatear"
|
||||||
|
thisUserAllowsChatOnlyFromFollowers: "Este usuario sólo acepta chats de seguidores."
|
||||||
|
thisUserAllowsChatOnlyFromFollowing: "Este usuario sólo acepta chats de los usuarios a los que sigue."
|
||||||
|
thisUserAllowsChatOnlyFromMutualFollowing: "Este usuario sólo acepta chats de usuarios que son seguidores mutuos."
|
||||||
|
thisUserNotAllowedChatAnyone: "Este usuario no acepta chats de nadie."
|
||||||
|
chatAllowedUsers: "A quién permitir chatear."
|
||||||
|
chatAllowedUsers_note: "Puedes chatear con cualquier persona a la que hayas enviado un mensaje de chat, independientemente de esta configuración."
|
||||||
|
_chatAllowedUsers:
|
||||||
|
everyone: "Todos"
|
||||||
|
followers: "Sólo sus propios seguidores."
|
||||||
|
following: "Solo usuarios que sigues"
|
||||||
|
mutual: "Solo seguidores mutuos"
|
||||||
|
none: "Nadie"
|
||||||
|
_emojiPalette:
|
||||||
|
palettes: "Paleta\n"
|
||||||
_settings:
|
_settings:
|
||||||
|
api: "API"
|
||||||
webhook: "Webhook"
|
webhook: "Webhook"
|
||||||
_accountSettings:
|
_accountSettings:
|
||||||
requireSigninToViewContents: "Se requiere iniciar sesión para ver el contenido"
|
requireSigninToViewContents: "Se requiere iniciar sesión para ver el contenido"
|
||||||
|
@ -1964,7 +2004,6 @@ _theme:
|
||||||
header: "Cabezal"
|
header: "Cabezal"
|
||||||
navBg: "Fondo de la barra lateral"
|
navBg: "Fondo de la barra lateral"
|
||||||
navFg: "Texto de la barra lateral"
|
navFg: "Texto de la barra lateral"
|
||||||
navHoverFg: "Texto de la barra lateral (hover)"
|
|
||||||
navActive: "Texto de la barra lateral (activo)"
|
navActive: "Texto de la barra lateral (activo)"
|
||||||
navIndicator: "Indicador de la barra lateral"
|
navIndicator: "Indicador de la barra lateral"
|
||||||
link: "Vínculo"
|
link: "Vínculo"
|
||||||
|
@ -1987,11 +2026,8 @@ _theme:
|
||||||
buttonHoverBg: "Fondo de botón (hover)"
|
buttonHoverBg: "Fondo de botón (hover)"
|
||||||
inputBorder: "Borde de los campos de entrada"
|
inputBorder: "Borde de los campos de entrada"
|
||||||
driveFolderBg: "Fondo de capeta del drive"
|
driveFolderBg: "Fondo de capeta del drive"
|
||||||
wallpaperOverlay: "Transparencia del fondo de pantalla"
|
|
||||||
badge: "Medalla"
|
badge: "Medalla"
|
||||||
messageBg: "Fondo de chat"
|
messageBg: "Fondo de chat"
|
||||||
accentDarken: "Acento (oscuro)"
|
|
||||||
accentLighten: "Acento (claro)"
|
|
||||||
fgHighlighted: "Texto resaltado"
|
fgHighlighted: "Texto resaltado"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Notas"
|
note: "Notas"
|
||||||
|
|
|
@ -1816,7 +1816,6 @@ _theme:
|
||||||
header: "Entête"
|
header: "Entête"
|
||||||
navBg: "Fond de la barre latérale"
|
navBg: "Fond de la barre latérale"
|
||||||
navFg: "Texte de la barre latérale"
|
navFg: "Texte de la barre latérale"
|
||||||
navHoverFg: "Texte de la barre latérale (survolé)"
|
|
||||||
navActive: "Texte de la barre latérale (actif)"
|
navActive: "Texte de la barre latérale (actif)"
|
||||||
navIndicator: "Indicateur de barre latérale"
|
navIndicator: "Indicateur de barre latérale"
|
||||||
link: "Lien"
|
link: "Lien"
|
||||||
|
@ -1839,11 +1838,8 @@ _theme:
|
||||||
buttonHoverBg: "Arrière-plan du bouton (survolé)"
|
buttonHoverBg: "Arrière-plan du bouton (survolé)"
|
||||||
inputBorder: "Cadre de la zone de texte"
|
inputBorder: "Cadre de la zone de texte"
|
||||||
driveFolderBg: "Arrière-plan du dossier de disque"
|
driveFolderBg: "Arrière-plan du dossier de disque"
|
||||||
wallpaperOverlay: "Superposition de fond d'écran"
|
|
||||||
badge: "Badge"
|
badge: "Badge"
|
||||||
messageBg: "Arrière plan de la discussion"
|
messageBg: "Arrière plan de la discussion"
|
||||||
accentDarken: "Plus sombre"
|
|
||||||
accentLighten: "Plus clair"
|
|
||||||
fgHighlighted: "Texte mis en évidence"
|
fgHighlighted: "Texte mis en évidence"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Nouvelle note"
|
note: "Nouvelle note"
|
||||||
|
|
|
@ -1931,7 +1931,6 @@ _theme:
|
||||||
header: "Header"
|
header: "Header"
|
||||||
navBg: "Latar belakang bilah samping"
|
navBg: "Latar belakang bilah samping"
|
||||||
navFg: "Teks bilah samping"
|
navFg: "Teks bilah samping"
|
||||||
navHoverFg: "Teks bilah samping (Mengambang)"
|
|
||||||
navActive: "Teks bilah samping (Aktif)"
|
navActive: "Teks bilah samping (Aktif)"
|
||||||
navIndicator: "Indikator bilah samping"
|
navIndicator: "Indikator bilah samping"
|
||||||
link: "Tautan"
|
link: "Tautan"
|
||||||
|
@ -1954,11 +1953,8 @@ _theme:
|
||||||
buttonHoverBg: "Latar belakang tombol (Mengambang)"
|
buttonHoverBg: "Latar belakang tombol (Mengambang)"
|
||||||
inputBorder: "Batas bidang masukan"
|
inputBorder: "Batas bidang masukan"
|
||||||
driveFolderBg: "Latar belakang folder drive"
|
driveFolderBg: "Latar belakang folder drive"
|
||||||
wallpaperOverlay: "Lapisan wallpaper"
|
|
||||||
badge: "Lencana"
|
badge: "Lencana"
|
||||||
messageBg: "Latar belakang obrolan"
|
messageBg: "Latar belakang obrolan"
|
||||||
accentDarken: "Aksen (Gelap)"
|
|
||||||
accentLighten: "Aksen (Terang)"
|
|
||||||
fgHighlighted: "Teks yang disorot"
|
fgHighlighted: "Teks yang disorot"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Catatan"
|
note: "Catatan"
|
||||||
|
|
|
@ -1714,6 +1714,10 @@ export interface Locale extends ILocale {
|
||||||
* ファイルが添付されたノートのみ
|
* ファイルが添付されたノートのみ
|
||||||
*/
|
*/
|
||||||
"withFileAntenna": string;
|
"withFileAntenna": string;
|
||||||
|
/**
|
||||||
|
* センシティブなチャンネルのノートを除外
|
||||||
|
*/
|
||||||
|
"excludeNotesInSensitiveChannel": string;
|
||||||
/**
|
/**
|
||||||
* ブラウザへのプッシュ通知を有効にする
|
* ブラウザへのプッシュ通知を有効にする
|
||||||
*/
|
*/
|
||||||
|
@ -3930,6 +3934,10 @@ export interface Locale extends ILocale {
|
||||||
* ログアウトしますか?
|
* ログアウトしますか?
|
||||||
*/
|
*/
|
||||||
"logoutConfirm": string;
|
"logoutConfirm": string;
|
||||||
|
/**
|
||||||
|
* ログアウトするとクライアントの設定情報がブラウザから消去されます。再ログイン時に設定情報を復元できるようにするためには、設定の自動バックアップを有効にしてください。
|
||||||
|
*/
|
||||||
|
"logoutWillClearClientData": string;
|
||||||
/**
|
/**
|
||||||
* 最終利用日時
|
* 最終利用日時
|
||||||
*/
|
*/
|
||||||
|
@ -5362,6 +5370,34 @@ export interface Locale extends ILocale {
|
||||||
* 圧縮
|
* 圧縮
|
||||||
*/
|
*/
|
||||||
"compress": string;
|
"compress": string;
|
||||||
|
/**
|
||||||
|
* 右
|
||||||
|
*/
|
||||||
|
"right": string;
|
||||||
|
/**
|
||||||
|
* 下
|
||||||
|
*/
|
||||||
|
"bottom": string;
|
||||||
|
/**
|
||||||
|
* 上
|
||||||
|
*/
|
||||||
|
"top": string;
|
||||||
|
/**
|
||||||
|
* 埋め込み
|
||||||
|
*/
|
||||||
|
"embed": string;
|
||||||
|
/**
|
||||||
|
* 設定を移行しています。しばらくお待ちください... (後ほど、設定→その他→旧設定情報を移行 で手動で移行することもできます)
|
||||||
|
*/
|
||||||
|
"settingsMigrating": string;
|
||||||
|
/**
|
||||||
|
* 読み取り専用
|
||||||
|
*/
|
||||||
|
"readonly": string;
|
||||||
|
/**
|
||||||
|
* デッキへ戻る
|
||||||
|
*/
|
||||||
|
"goToDeck": string;
|
||||||
"_chat": {
|
"_chat": {
|
||||||
/**
|
/**
|
||||||
* まだメッセージはありません
|
* まだメッセージはありません
|
||||||
|
@ -5476,6 +5512,10 @@ export interface Locale extends ILocale {
|
||||||
* このサーバー、またはこのアカウントでチャットは有効化されていません。
|
* このサーバー、またはこのアカウントでチャットは有効化されていません。
|
||||||
*/
|
*/
|
||||||
"chatNotAvailableForThisAccountOrServer": string;
|
"chatNotAvailableForThisAccountOrServer": string;
|
||||||
|
/**
|
||||||
|
* このサーバー、またはこのアカウントでチャットは読み取り専用となっています。新たに書き込んだり、チャットルームを作成・参加したりすることはできません。
|
||||||
|
*/
|
||||||
|
"chatIsReadOnlyForThisAccountOrServer": string;
|
||||||
/**
|
/**
|
||||||
* 相手のアカウントでチャット機能が使えない状態になっています。
|
* 相手のアカウントでチャット機能が使えない状態になっています。
|
||||||
*/
|
*/
|
||||||
|
@ -5497,7 +5537,7 @@ export interface Locale extends ILocale {
|
||||||
*/
|
*/
|
||||||
"thisUserAllowsChatOnlyFromFollowers": string;
|
"thisUserAllowsChatOnlyFromFollowers": string;
|
||||||
/**
|
/**
|
||||||
* このユーザーはフォローしているユーザーからのみチャットを受け付けています。
|
* このユーザーは、このユーザーがフォローしているユーザーからのみチャットを受け付けています。
|
||||||
*/
|
*/
|
||||||
"thisUserAllowsChatOnlyFromFollowing": string;
|
"thisUserAllowsChatOnlyFromFollowing": string;
|
||||||
/**
|
/**
|
||||||
|
@ -5634,6 +5674,10 @@ export interface Locale extends ILocale {
|
||||||
* 有効にすると、一部のシチュエーションでのユーザビリティが低下する場合があります。
|
* 有効にすると、一部のシチュエーションでのユーザビリティが低下する場合があります。
|
||||||
*/
|
*/
|
||||||
"makeEveryTextElementsSelectable_description": string;
|
"makeEveryTextElementsSelectable_description": string;
|
||||||
|
/**
|
||||||
|
* アイコンをスクロールに追従させる
|
||||||
|
*/
|
||||||
|
"useStickyIcons": string;
|
||||||
/**
|
/**
|
||||||
* ナビゲーションバーに副ボタンを表示
|
* ナビゲーションバーに副ボタンを表示
|
||||||
*/
|
*/
|
||||||
|
@ -5646,6 +5690,10 @@ export interface Locale extends ILocale {
|
||||||
* オフのとき
|
* オフのとき
|
||||||
*/
|
*/
|
||||||
"ifOff": string;
|
"ifOff": string;
|
||||||
|
/**
|
||||||
|
* デバイス間でインストールしたテーマを同期
|
||||||
|
*/
|
||||||
|
"enableSyncThemesBetweenDevices": string;
|
||||||
"_chat": {
|
"_chat": {
|
||||||
/**
|
/**
|
||||||
* 送信者の名前を表示
|
* 送信者の名前を表示
|
||||||
|
@ -7333,6 +7381,14 @@ export interface Locale extends ILocale {
|
||||||
* 数値が大きいほどUI上で先頭に表示されます。
|
* 数値が大きいほどUI上で先頭に表示されます。
|
||||||
*/
|
*/
|
||||||
"descriptionOfDisplayOrder": string;
|
"descriptionOfDisplayOrder": string;
|
||||||
|
/**
|
||||||
|
* アサイン状態を移行先アカウントにも引き継ぐ
|
||||||
|
*/
|
||||||
|
"preserveAssignmentOnMoveAccount": string;
|
||||||
|
/**
|
||||||
|
* オンにすると、このロールが付与されたアカウントが移行された際に、移行先アカウントにもこのロールが引き継がれるようになります。
|
||||||
|
*/
|
||||||
|
"preserveAssignmentOnMoveAccount_description": string;
|
||||||
/**
|
/**
|
||||||
* モデレーターのメンバー編集を許可
|
* モデレーターのメンバー編集を許可
|
||||||
*/
|
*/
|
||||||
|
@ -7491,7 +7547,7 @@ export interface Locale extends ILocale {
|
||||||
/**
|
/**
|
||||||
* チャットを許可
|
* チャットを許可
|
||||||
*/
|
*/
|
||||||
"canChat": string;
|
"chatAvailability": string;
|
||||||
};
|
};
|
||||||
"_condition": {
|
"_condition": {
|
||||||
/**
|
/**
|
||||||
|
@ -8219,23 +8275,19 @@ export interface Locale extends ILocale {
|
||||||
*/
|
*/
|
||||||
"header": string;
|
"header": string;
|
||||||
/**
|
/**
|
||||||
* サイドバーの背景
|
* ナビゲーションバーの背景
|
||||||
*/
|
*/
|
||||||
"navBg": string;
|
"navBg": string;
|
||||||
/**
|
/**
|
||||||
* サイドバーの文字
|
* ナビゲーションバーの文字
|
||||||
*/
|
*/
|
||||||
"navFg": string;
|
"navFg": string;
|
||||||
/**
|
/**
|
||||||
* サイドバー文字(ホバー)
|
* ナビゲーションバー文字(アクティブ)
|
||||||
*/
|
|
||||||
"navHoverFg": string;
|
|
||||||
/**
|
|
||||||
* サイドバー文字(アクティブ)
|
|
||||||
*/
|
*/
|
||||||
"navActive": string;
|
"navActive": string;
|
||||||
/**
|
/**
|
||||||
* サイドバーのインジケーター
|
* ナビゲーションバーのインジケーター
|
||||||
*/
|
*/
|
||||||
"navIndicator": string;
|
"navIndicator": string;
|
||||||
/**
|
/**
|
||||||
|
@ -8255,7 +8307,7 @@ export interface Locale extends ILocale {
|
||||||
*/
|
*/
|
||||||
"mentionMe": string;
|
"mentionMe": string;
|
||||||
/**
|
/**
|
||||||
* Renote
|
* リノート
|
||||||
*/
|
*/
|
||||||
"renote": string;
|
"renote": string;
|
||||||
/**
|
/**
|
||||||
|
@ -8318,10 +8370,6 @@ export interface Locale extends ILocale {
|
||||||
* ドライブフォルダーの背景
|
* ドライブフォルダーの背景
|
||||||
*/
|
*/
|
||||||
"driveFolderBg": string;
|
"driveFolderBg": string;
|
||||||
/**
|
|
||||||
* 壁紙のオーバーレイ
|
|
||||||
*/
|
|
||||||
"wallpaperOverlay": string;
|
|
||||||
/**
|
/**
|
||||||
* バッジ
|
* バッジ
|
||||||
*/
|
*/
|
||||||
|
@ -8330,14 +8378,6 @@ export interface Locale extends ILocale {
|
||||||
* チャットの背景
|
* チャットの背景
|
||||||
*/
|
*/
|
||||||
"messageBg": string;
|
"messageBg": string;
|
||||||
/**
|
|
||||||
* アクセント (暗め)
|
|
||||||
*/
|
|
||||||
"accentDarken": string;
|
|
||||||
/**
|
|
||||||
* アクセント (明るめ)
|
|
||||||
*/
|
|
||||||
"accentLighten": string;
|
|
||||||
/**
|
/**
|
||||||
* 強調された文字
|
* 強調された文字
|
||||||
*/
|
*/
|
||||||
|
@ -9167,6 +9207,10 @@ export interface Locale extends ILocale {
|
||||||
* 今日誕生日のユーザー
|
* 今日誕生日のユーザー
|
||||||
*/
|
*/
|
||||||
"birthdayFollowings": string;
|
"birthdayFollowings": string;
|
||||||
|
/**
|
||||||
|
* チャット
|
||||||
|
*/
|
||||||
|
"chat": string;
|
||||||
};
|
};
|
||||||
"_cw": {
|
"_cw": {
|
||||||
/**
|
/**
|
||||||
|
@ -10061,6 +10105,18 @@ export interface Locale extends ILocale {
|
||||||
* カラムの寄せ
|
* カラムの寄せ
|
||||||
*/
|
*/
|
||||||
"columnAlign": string;
|
"columnAlign": string;
|
||||||
|
/**
|
||||||
|
* カラム間のマージン
|
||||||
|
*/
|
||||||
|
"columnGap": string;
|
||||||
|
/**
|
||||||
|
* デッキメニューの位置
|
||||||
|
*/
|
||||||
|
"deckMenuPosition": string;
|
||||||
|
/**
|
||||||
|
* ナビゲーションバーの位置
|
||||||
|
*/
|
||||||
|
"navbarPosition": string;
|
||||||
/**
|
/**
|
||||||
* カラムを追加
|
* カラムを追加
|
||||||
*/
|
*/
|
||||||
|
@ -10114,7 +10170,7 @@ export interface Locale extends ILocale {
|
||||||
*/
|
*/
|
||||||
"introduction": string;
|
"introduction": string;
|
||||||
/**
|
/**
|
||||||
* 画面の右にある + を押して、いつでもカラムを追加できます。
|
* カラムを追加するには、画面の + をクリックします。
|
||||||
*/
|
*/
|
||||||
"introduction2": string;
|
"introduction2": string;
|
||||||
/**
|
/**
|
||||||
|
@ -10178,6 +10234,10 @@ export interface Locale extends ILocale {
|
||||||
* ロールタイムライン
|
* ロールタイムライン
|
||||||
*/
|
*/
|
||||||
"roleTimeline": string;
|
"roleTimeline": string;
|
||||||
|
/**
|
||||||
|
* チャット
|
||||||
|
*/
|
||||||
|
"chat": string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
"_dialog": {
|
"_dialog": {
|
||||||
|
|
|
@ -424,6 +424,7 @@ antennaExcludeBots: "Escludere i Bot"
|
||||||
antennaKeywordsDescription: "Sparando con uno spazio indichi la condizione E (and). Separando con un a capo, indichi la condizione O (or)."
|
antennaKeywordsDescription: "Sparando con uno spazio indichi la condizione E (and). Separando con un a capo, indichi la condizione O (or)."
|
||||||
notifyAntenna: "Invia notifiche delle nuove note"
|
notifyAntenna: "Invia notifiche delle nuove note"
|
||||||
withFileAntenna: "Solo note con file in allegato"
|
withFileAntenna: "Solo note con file in allegato"
|
||||||
|
excludeNotesInSensitiveChannel: "Escludere le Note dai canali espliciti"
|
||||||
enableServiceworker: "Abilita ServiceWorker"
|
enableServiceworker: "Abilita ServiceWorker"
|
||||||
antennaUsersDescription: "Elenca un nome utente per riga"
|
antennaUsersDescription: "Elenca un nome utente per riga"
|
||||||
caseSensitive: "Sensibile alla distinzione tra maiuscole e minuscole"
|
caseSensitive: "Sensibile alla distinzione tra maiuscole e minuscole"
|
||||||
|
@ -522,7 +523,7 @@ showNoteActionsOnlyHover: "Mostra le azioni delle Note solo al passaggio del mou
|
||||||
showReactionsCount: "Visualizza il numero di reazioni su una nota"
|
showReactionsCount: "Visualizza il numero di reazioni su una nota"
|
||||||
noHistory: "Nessuna cronologia"
|
noHistory: "Nessuna cronologia"
|
||||||
signinHistory: "Storico degli accessi al profilo"
|
signinHistory: "Storico degli accessi al profilo"
|
||||||
enableAdvancedMfm: "Attiva MFM avanzati"
|
enableAdvancedMfm: "Attivare i Misskey Flavoured Markdown (MFM) avanzati"
|
||||||
enableAnimatedMfm: "Attiva MFM animati"
|
enableAnimatedMfm: "Attiva MFM animati"
|
||||||
doing: "In corso..."
|
doing: "In corso..."
|
||||||
category: "Categoria"
|
category: "Categoria"
|
||||||
|
@ -605,7 +606,7 @@ uiInspector: "UI Inspector"
|
||||||
uiInspectorDescription: "Puoi visualizzare un elenco di elementi UI presenti in memoria. I componenti dell'interfaccia utente vengono generati dalle funzioni Ui:C:."
|
uiInspectorDescription: "Puoi visualizzare un elenco di elementi UI presenti in memoria. I componenti dell'interfaccia utente vengono generati dalle funzioni Ui:C:."
|
||||||
output: "Output"
|
output: "Output"
|
||||||
script: "Script"
|
script: "Script"
|
||||||
disablePagesScript: "Disabilita AiScript nelle pagine"
|
disablePagesScript: "Disabilitare AiScript nelle pagine"
|
||||||
updateRemoteUser: "Aggiorna dati dal profilo remoto"
|
updateRemoteUser: "Aggiorna dati dal profilo remoto"
|
||||||
unsetUserAvatar: "Rimozione foto profilo"
|
unsetUserAvatar: "Rimozione foto profilo"
|
||||||
unsetUserAvatarConfirm: "Vuoi davvero rimuovere la foto profilo?"
|
unsetUserAvatarConfirm: "Vuoi davvero rimuovere la foto profilo?"
|
||||||
|
@ -663,7 +664,7 @@ generateAccessToken: "Genera token di accesso"
|
||||||
permission: "Autorizzazioni "
|
permission: "Autorizzazioni "
|
||||||
adminPermission: "Privilegi amministrativi"
|
adminPermission: "Privilegi amministrativi"
|
||||||
enableAll: "Abilita tutto"
|
enableAll: "Abilita tutto"
|
||||||
disableAll: "Disabilita tutto"
|
disableAll: "Disabilitare tutto"
|
||||||
tokenRequested: "Autorizza accesso al profilo"
|
tokenRequested: "Autorizza accesso al profilo"
|
||||||
pluginTokenRequestedDescription: "Il plugin potrà utilizzare le autorizzazioni impostate qui."
|
pluginTokenRequestedDescription: "Il plugin potrà utilizzare le autorizzazioni impostate qui."
|
||||||
notificationType: "Tipo di notifiche"
|
notificationType: "Tipo di notifiche"
|
||||||
|
@ -727,7 +728,7 @@ reporterOrigin: "Segnalazione da"
|
||||||
send: "Inviare"
|
send: "Inviare"
|
||||||
openInNewTab: "Apri in una nuova scheda"
|
openInNewTab: "Apri in una nuova scheda"
|
||||||
openInSideView: "Apri in vista laterale"
|
openInSideView: "Apri in vista laterale"
|
||||||
defaultNavigationBehaviour: "Navigazione preimpostata"
|
defaultNavigationBehaviour: "Tipo di navigazione predefinita"
|
||||||
editTheseSettingsMayBreakAccount: "Modificare queste impostazioni può danneggiare il profilo"
|
editTheseSettingsMayBreakAccount: "Modificare queste impostazioni può danneggiare il profilo"
|
||||||
instanceTicker: "Informazioni sull'istanza da cui vengono le note"
|
instanceTicker: "Informazioni sull'istanza da cui vengono le note"
|
||||||
waitingFor: "Aspettando {x}"
|
waitingFor: "Aspettando {x}"
|
||||||
|
@ -766,7 +767,7 @@ noCrawleDescription: "Richiedi che i motori di ricerca non indicizzino la tua pa
|
||||||
lockedAccountInfo: "A meno che non imposti la visibilità delle tue note su \"Solo ai follower\", le tue note sono visibili da tutti, anche se hai configurato l'account per confermare manualmente le richieste di follow."
|
lockedAccountInfo: "A meno che non imposti la visibilità delle tue note su \"Solo ai follower\", le tue note sono visibili da tutti, anche se hai configurato l'account per confermare manualmente le richieste di follow."
|
||||||
alwaysMarkSensitive: "Segnare automaticamente come espliciti gli allegati"
|
alwaysMarkSensitive: "Segnare automaticamente come espliciti gli allegati"
|
||||||
loadRawImages: "Visualizza le intere immagini allegate invece delle miniature."
|
loadRawImages: "Visualizza le intere immagini allegate invece delle miniature."
|
||||||
disableShowingAnimatedImages: "Disabilita le immagini animate"
|
disableShowingAnimatedImages: "Disabilitare le immagini animate"
|
||||||
highlightSensitiveMedia: "Evidenzia i media espliciti"
|
highlightSensitiveMedia: "Evidenzia i media espliciti"
|
||||||
verificationEmailSent: "Una mail di verifica è stata inviata. Si prega di accedere al collegamento per compiere la verifica."
|
verificationEmailSent: "Una mail di verifica è stata inviata. Si prega di accedere al collegamento per compiere la verifica."
|
||||||
notSet: "Non impostato"
|
notSet: "Non impostato"
|
||||||
|
@ -866,7 +867,7 @@ noBotProtectionWarning: "Non è stata impostata alcuna protezione dai Bot"
|
||||||
configure: "Imposta"
|
configure: "Imposta"
|
||||||
postToGallery: "Pubblicare nella galleria"
|
postToGallery: "Pubblicare nella galleria"
|
||||||
postToHashtag: "Pubblica a questo hashtag"
|
postToHashtag: "Pubblica a questo hashtag"
|
||||||
gallery: "Galleria"
|
gallery: "Gallerie"
|
||||||
recentPosts: "Pubblicazioni recenti"
|
recentPosts: "Pubblicazioni recenti"
|
||||||
popularPosts: "Le più visualizzate"
|
popularPosts: "Le più visualizzate"
|
||||||
shareWithNote: "Condividere in nota"
|
shareWithNote: "Condividere in nota"
|
||||||
|
@ -978,6 +979,7 @@ document: "Documentazione"
|
||||||
numberOfPageCache: "Numero di pagine cache"
|
numberOfPageCache: "Numero di pagine cache"
|
||||||
numberOfPageCacheDescription: "Aumenta l'usabilità, ma aumenta anche il carico e l'utilizzo della memoria."
|
numberOfPageCacheDescription: "Aumenta l'usabilità, ma aumenta anche il carico e l'utilizzo della memoria."
|
||||||
logoutConfirm: "Vuoi davvero uscire da Misskey? "
|
logoutConfirm: "Vuoi davvero uscire da Misskey? "
|
||||||
|
logoutWillClearClientData: "All'uscita, la configurazione del client viene rimossa dal browser. Per ripristinarla quando si effettua nuovamente l'accesso, abilitare il backup automatico."
|
||||||
lastActiveDate: "Data dell'ultimo utilizzo"
|
lastActiveDate: "Data dell'ultimo utilizzo"
|
||||||
statusbar: "Barra di stato"
|
statusbar: "Barra di stato"
|
||||||
pleaseSelect: "Scegli un'opzione"
|
pleaseSelect: "Scegli un'opzione"
|
||||||
|
@ -1192,7 +1194,7 @@ renotes: "Rinota"
|
||||||
loadReplies: "Leggi le risposte"
|
loadReplies: "Leggi le risposte"
|
||||||
loadConversation: "Leggi la conversazione"
|
loadConversation: "Leggi la conversazione"
|
||||||
pinnedList: "Elenco in primo piano"
|
pinnedList: "Elenco in primo piano"
|
||||||
keepScreenOn: "Mantieni lo schermo acceso"
|
keepScreenOn: "Mantenere lo schermo acceso"
|
||||||
verifiedLink: "Abbiamo confermato la validità di questo collegamento"
|
verifiedLink: "Abbiamo confermato la validità di questo collegamento"
|
||||||
notifyNotes: "Notifica nuove Note"
|
notifyNotes: "Notifica nuove Note"
|
||||||
unnotifyNotes: "Interrompi le notifiche di nuove Note"
|
unnotifyNotes: "Interrompi le notifiche di nuove Note"
|
||||||
|
@ -1234,7 +1236,7 @@ flip: "Inverti"
|
||||||
showAvatarDecorations: "Mostra decorazione della foto profilo"
|
showAvatarDecorations: "Mostra decorazione della foto profilo"
|
||||||
releaseToRefresh: "Rilascia per aggiornare"
|
releaseToRefresh: "Rilascia per aggiornare"
|
||||||
refreshing: "Aggiornamento..."
|
refreshing: "Aggiornamento..."
|
||||||
pullDownToRefresh: "Trascina per aggiornare"
|
pullDownToRefresh: "Trascinare per aggiornare"
|
||||||
disableStreamingTimeline: "Disabilitare gli aggiornamenti della TL in tempo reale"
|
disableStreamingTimeline: "Disabilitare gli aggiornamenti della TL in tempo reale"
|
||||||
useGroupedNotifications: "Mostra le notifiche raggruppate"
|
useGroupedNotifications: "Mostra le notifiche raggruppate"
|
||||||
signupPendingError: "Si è verificato un problema durante la verifica del tuo indirizzo email. Potrebbe essere scaduto il collegamento temporaneo."
|
signupPendingError: "Si è verificato un problema durante la verifica del tuo indirizzo email. Potrebbe essere scaduto il collegamento temporaneo."
|
||||||
|
@ -1262,7 +1264,7 @@ backToTitle: "Torna al titolo"
|
||||||
hemisphere: "Geolocalizzazione"
|
hemisphere: "Geolocalizzazione"
|
||||||
withSensitive: "Mostra le Note con allegati espliciti"
|
withSensitive: "Mostra le Note con allegati espliciti"
|
||||||
userSaysSomethingSensitive: "Note da {name} con allegati espliciti"
|
userSaysSomethingSensitive: "Note da {name} con allegati espliciti"
|
||||||
enableHorizontalSwipe: "Trascina per invertire i tab"
|
enableHorizontalSwipe: "Trascinare per invertire le colonne"
|
||||||
loading: "Caricamento"
|
loading: "Caricamento"
|
||||||
surrender: "Annulla"
|
surrender: "Annulla"
|
||||||
gameRetry: "Riprova"
|
gameRetry: "Riprova"
|
||||||
|
@ -1335,6 +1337,14 @@ information: "Informazioni"
|
||||||
chat: "Chat"
|
chat: "Chat"
|
||||||
migrateOldSettings: "Migrare le vecchie impostazioni"
|
migrateOldSettings: "Migrare le vecchie impostazioni"
|
||||||
migrateOldSettings_description: "Di solito, viene fatto automaticamente. Se per qualche motivo non fossero migrate con successo, è possibile avviare il processo di migrazione manualmente, sovrascrivendo le configurazioni attuali."
|
migrateOldSettings_description: "Di solito, viene fatto automaticamente. Se per qualche motivo non fossero migrate con successo, è possibile avviare il processo di migrazione manualmente, sovrascrivendo le configurazioni attuali."
|
||||||
|
compress: "Comprimi"
|
||||||
|
right: "Destra"
|
||||||
|
bottom: "Sotto"
|
||||||
|
top: "Sopra"
|
||||||
|
embed: "Incorporare"
|
||||||
|
settingsMigrating: "Migrazione delle impostazioni. Attendere prego ... (Puoi anche migrare manualmente in un secondo momento, nel menu: Impostazioni → Altro → Migrazione delle impostazioni)"
|
||||||
|
readonly: "Sola lettura"
|
||||||
|
goToDeck: "Torna al Deck"
|
||||||
_chat:
|
_chat:
|
||||||
noMessagesYet: "Ancora nessun messaggio"
|
noMessagesYet: "Ancora nessun messaggio"
|
||||||
newMessage: "Nuovo messaggio"
|
newMessage: "Nuovo messaggio"
|
||||||
|
@ -1363,6 +1373,9 @@ _chat:
|
||||||
newline: "Nuova riga"
|
newline: "Nuova riga"
|
||||||
muteThisRoom: "Silenzia stanza"
|
muteThisRoom: "Silenzia stanza"
|
||||||
deleteRoom: "Elimina stanza"
|
deleteRoom: "Elimina stanza"
|
||||||
|
chatNotAvailableForThisAccountOrServer: "Questo server, o questo profilo ha disabilitato la chat."
|
||||||
|
chatIsReadOnlyForThisAccountOrServer: "Le chat, su questo server o su questo profilo, sono di sola lettura. Impossibile scrivere in chat o creare e partecipare a stanze."
|
||||||
|
chatNotAvailableInOtherAccount: "La chat non è disponibile nel profilo dell'altra persona."
|
||||||
cannotChatWithTheUser: "Impossibile chattare con questa persona"
|
cannotChatWithTheUser: "Impossibile chattare con questa persona"
|
||||||
cannotChatWithTheUser_description: "La chat potrebbe non essere disponibile, oppure l'altra persona potrebbe non esserlo."
|
cannotChatWithTheUser_description: "La chat potrebbe non essere disponibile, oppure l'altra persona potrebbe non esserlo."
|
||||||
chatWithThisUser: "Chatta con questa persona"
|
chatWithThisUser: "Chatta con questa persona"
|
||||||
|
@ -1403,9 +1416,11 @@ _settings:
|
||||||
timelineAndNote: "Note e Timeline"
|
timelineAndNote: "Note e Timeline"
|
||||||
makeEveryTextElementsSelectable: "Imposta ogni elemento come selezionabile"
|
makeEveryTextElementsSelectable: "Imposta ogni elemento come selezionabile"
|
||||||
makeEveryTextElementsSelectable_description: "Potrebbe ridurre l'usabilità in alcune situazioni."
|
makeEveryTextElementsSelectable_description: "Potrebbe ridurre l'usabilità in alcune situazioni."
|
||||||
|
useStickyIcons: "Fissa le icone durante lo scorrimento"
|
||||||
showNavbarSubButtons: "Mostra i pulsanti secondari nella barra di navigazione"
|
showNavbarSubButtons: "Mostra i pulsanti secondari nella barra di navigazione"
|
||||||
ifOn: "Quando attivato"
|
ifOn: "Quando attivato"
|
||||||
ifOff: "Quando disattivato"
|
ifOff: "Quando disattivato"
|
||||||
|
enableSyncThemesBetweenDevices: "Sincronizzare il tema tra i dispositivi"
|
||||||
_chat:
|
_chat:
|
||||||
showSenderName: "Mostra il nome del mittente"
|
showSenderName: "Mostra il nome del mittente"
|
||||||
sendOnEnter: "Invio spedisce"
|
sendOnEnter: "Invio spedisce"
|
||||||
|
@ -1878,6 +1893,8 @@ _role:
|
||||||
descriptionOfIsExplorable: "Selezionandolo, la timeline del ruolo diventerà accessibile pubblicamente. Tranne se il ruolo non è pubblico."
|
descriptionOfIsExplorable: "Selezionandolo, la timeline del ruolo diventerà accessibile pubblicamente. Tranne se il ruolo non è pubblico."
|
||||||
displayOrder: "Ordine di visualizzazione"
|
displayOrder: "Ordine di visualizzazione"
|
||||||
descriptionOfDisplayOrder: "I valori più alti vengono visualizzati per primi"
|
descriptionOfDisplayOrder: "I valori più alti vengono visualizzati per primi"
|
||||||
|
preserveAssignmentOnMoveAccount: "Mantenere l'assegnazione alla migrazione del profilo"
|
||||||
|
preserveAssignmentOnMoveAccount_description: "Attivando, il ruolo verrà portato sul profilo destinatario, durante la migrazione."
|
||||||
canEditMembersByModerator: "Anche i Moderatori assegnano profili a questo ruolo"
|
canEditMembersByModerator: "Anche i Moderatori assegnano profili a questo ruolo"
|
||||||
descriptionOfCanEditMembersByModerator: "Se disattivo, potranno farlo solamente gli Amministratori."
|
descriptionOfCanEditMembersByModerator: "Se disattivo, potranno farlo solamente gli Amministratori."
|
||||||
priority: "Priorità"
|
priority: "Priorità"
|
||||||
|
@ -1918,7 +1935,7 @@ _role:
|
||||||
canImportFollowing: "Può importare Following"
|
canImportFollowing: "Può importare Following"
|
||||||
canImportMuting: "Può importare Silenziati"
|
canImportMuting: "Può importare Silenziati"
|
||||||
canImportUserLists: "Può importare liste di Profili"
|
canImportUserLists: "Può importare liste di Profili"
|
||||||
canChat: "Chat consentita"
|
chatAvailability: "Chat consentita"
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "Assegnato a ruoli manualmente"
|
roleAssignedTo: "Assegnato a ruoli manualmente"
|
||||||
isLocal: "Profilo locale"
|
isLocal: "Profilo locale"
|
||||||
|
@ -2115,14 +2132,13 @@ _theme:
|
||||||
header: "Intestazione"
|
header: "Intestazione"
|
||||||
navBg: "Sfondo della barra laterale"
|
navBg: "Sfondo della barra laterale"
|
||||||
navFg: "Testo della barra laterale"
|
navFg: "Testo della barra laterale"
|
||||||
navHoverFg: "Testo della barra laterale (al passaggio del mouse)"
|
|
||||||
navActive: "Testo della barra laterale (attivo)"
|
navActive: "Testo della barra laterale (attivo)"
|
||||||
navIndicator: "Indicatore di barra laterale"
|
navIndicator: "Indicatore di barra laterale"
|
||||||
link: "Link"
|
link: "Link"
|
||||||
hashtag: "Hashtag"
|
hashtag: "Hashtag"
|
||||||
mention: "Menzioni"
|
mention: "Menzioni"
|
||||||
mentionMe: "Menzioni (di me)"
|
mentionMe: "Menzioni (di me)"
|
||||||
renote: "Rinota"
|
renote: "Renota"
|
||||||
modalBg: "Sfondo modale."
|
modalBg: "Sfondo modale."
|
||||||
divider: "Interruzione di linea"
|
divider: "Interruzione di linea"
|
||||||
scrollbarHandle: "Maniglie della barra di scorrimento"
|
scrollbarHandle: "Maniglie della barra di scorrimento"
|
||||||
|
@ -2138,11 +2154,8 @@ _theme:
|
||||||
buttonHoverBg: "Sfondo del pulsante (sorvolato)"
|
buttonHoverBg: "Sfondo del pulsante (sorvolato)"
|
||||||
inputBorder: "Inquadra casella di testo"
|
inputBorder: "Inquadra casella di testo"
|
||||||
driveFolderBg: "Sfondo della cartella di disco"
|
driveFolderBg: "Sfondo della cartella di disco"
|
||||||
wallpaperOverlay: "Sovrapposizione dello sfondo"
|
|
||||||
badge: "Distintivo"
|
badge: "Distintivo"
|
||||||
messageBg: "Sfondo della chat"
|
messageBg: "Sfondo della chat"
|
||||||
accentDarken: "Temi (scuri)"
|
|
||||||
accentLighten: "Temi (luminosi)"
|
|
||||||
fgHighlighted: "Testo in evidenza."
|
fgHighlighted: "Testo in evidenza."
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Nota"
|
note: "Nota"
|
||||||
|
@ -2356,6 +2369,7 @@ _widgets:
|
||||||
chooseList: "Seleziona una lista"
|
chooseList: "Seleziona una lista"
|
||||||
clicker: "Cliccheria"
|
clicker: "Cliccheria"
|
||||||
birthdayFollowings: "Compleanni del giorno"
|
birthdayFollowings: "Compleanni del giorno"
|
||||||
|
chat: "Chat"
|
||||||
_cw:
|
_cw:
|
||||||
hide: "Nascondere"
|
hide: "Nascondere"
|
||||||
show: "Continua la lettura..."
|
show: "Continua la lettura..."
|
||||||
|
@ -2588,7 +2602,10 @@ _notification:
|
||||||
renote: "Rinota"
|
renote: "Rinota"
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "Mostra sempre la colonna principale"
|
alwaysShowMainColumn: "Mostra sempre la colonna principale"
|
||||||
columnAlign: "Allineare colonne"
|
columnAlign: "Allineamento delle colonne"
|
||||||
|
columnGap: "Spessore del margine tra colonne"
|
||||||
|
deckMenuPosition: "Posizione del menu Deck"
|
||||||
|
navbarPosition: "Posizione barra di navigazione"
|
||||||
addColumn: "Aggiungi colonna"
|
addColumn: "Aggiungi colonna"
|
||||||
newNoteNotificationSettings: "Preferenze per le notifiche di nuove Note"
|
newNoteNotificationSettings: "Preferenze per le notifiche di nuove Note"
|
||||||
configureColumn: "Impostazioni colonna"
|
configureColumn: "Impostazioni colonna"
|
||||||
|
@ -2615,10 +2632,11 @@ _deck:
|
||||||
tl: "Timeline"
|
tl: "Timeline"
|
||||||
antenna: "Antenne"
|
antenna: "Antenne"
|
||||||
list: "Liste"
|
list: "Liste"
|
||||||
channel: "Canale"
|
channel: "Canali"
|
||||||
mentions: "Menzioni"
|
mentions: "Menzioni"
|
||||||
direct: "Note Dirette"
|
direct: "Note Dirette"
|
||||||
roleTimeline: "Timeline Ruolo"
|
roleTimeline: "Timeline Ruolo"
|
||||||
|
chat: "Chat"
|
||||||
_dialog:
|
_dialog:
|
||||||
charactersExceeded: "Hai superato il limite di {max} caratteri! ({current})"
|
charactersExceeded: "Hai superato il limite di {max} caratteri! ({current})"
|
||||||
charactersBelow: "Sei al di sotto del minimo di {min} caratteri! ({current})"
|
charactersBelow: "Sei al di sotto del minimo di {min} caratteri! ({current})"
|
||||||
|
@ -2905,7 +2923,7 @@ _customEmojisManager:
|
||||||
directoryToCategoryLabel: "Inseriscile in una cartella omonima alla categoria"
|
directoryToCategoryLabel: "Inseriscile in una cartella omonima alla categoria"
|
||||||
directoryToCategoryCaption: "Crea il campo categoria in base alla cartella."
|
directoryToCategoryCaption: "Crea il campo categoria in base alla cartella."
|
||||||
emojiInputAreaCaption: "Seleziona l'emoji da registrare utilizzando uno dei metodi."
|
emojiInputAreaCaption: "Seleziona l'emoji da registrare utilizzando uno dei metodi."
|
||||||
emojiInputAreaList1: "Trascina una immagine o una cartella in quest'area"
|
emojiInputAreaList1: "Trascinare una immagine o una cartella in quest'area"
|
||||||
emojiInputAreaList2: "Clicca per scegliere file dal tuo dispositivo"
|
emojiInputAreaList2: "Clicca per scegliere file dal tuo dispositivo"
|
||||||
emojiInputAreaList3: "Clicca per selezionare dal Drive"
|
emojiInputAreaList3: "Clicca per selezionare dal Drive"
|
||||||
confirmRegisterEmojisDescription: "Registrazione delle emoji elencate come nuove emoji personalizzate. Vuoi davvero procedere? (Per evitare sovraccarichi, puoi registrare al massimo {count} emoji per volta)"
|
confirmRegisterEmojisDescription: "Registrazione delle emoji elencate come nuove emoji personalizzate. Vuoi davvero procedere? (Per evitare sovraccarichi, puoi registrare al massimo {count} emoji per volta)"
|
||||||
|
|
|
@ -424,6 +424,7 @@ antennaExcludeBots: "Botアカウントを除外"
|
||||||
antennaKeywordsDescription: "スペースで区切るとAND指定になり、改行で区切るとOR指定になります"
|
antennaKeywordsDescription: "スペースで区切るとAND指定になり、改行で区切るとOR指定になります"
|
||||||
notifyAntenna: "新しいノートを通知する"
|
notifyAntenna: "新しいノートを通知する"
|
||||||
withFileAntenna: "ファイルが添付されたノートのみ"
|
withFileAntenna: "ファイルが添付されたノートのみ"
|
||||||
|
excludeNotesInSensitiveChannel: "センシティブなチャンネルのノートを除外"
|
||||||
enableServiceworker: "ブラウザへのプッシュ通知を有効にする"
|
enableServiceworker: "ブラウザへのプッシュ通知を有効にする"
|
||||||
antennaUsersDescription: "ユーザー名を改行で区切って指定します"
|
antennaUsersDescription: "ユーザー名を改行で区切って指定します"
|
||||||
caseSensitive: "大文字小文字を区別する"
|
caseSensitive: "大文字小文字を区別する"
|
||||||
|
@ -978,6 +979,7 @@ document: "ドキュメント"
|
||||||
numberOfPageCache: "ページキャッシュ数"
|
numberOfPageCache: "ページキャッシュ数"
|
||||||
numberOfPageCacheDescription: "多くすると利便性が向上しますが、負荷とメモリ使用量が増えます。"
|
numberOfPageCacheDescription: "多くすると利便性が向上しますが、負荷とメモリ使用量が増えます。"
|
||||||
logoutConfirm: "ログアウトしますか?"
|
logoutConfirm: "ログアウトしますか?"
|
||||||
|
logoutWillClearClientData: "ログアウトするとクライアントの設定情報がブラウザから消去されます。再ログイン時に設定情報を復元できるようにするためには、設定の自動バックアップを有効にしてください。"
|
||||||
lastActiveDate: "最終利用日時"
|
lastActiveDate: "最終利用日時"
|
||||||
statusbar: "ステータスバー"
|
statusbar: "ステータスバー"
|
||||||
pleaseSelect: "選択してください"
|
pleaseSelect: "選択してください"
|
||||||
|
@ -1336,6 +1338,13 @@ chat: "チャット"
|
||||||
migrateOldSettings: "旧設定情報を移行"
|
migrateOldSettings: "旧設定情報を移行"
|
||||||
migrateOldSettings_description: "通常これは自動で行われていますが、何らかの理由により上手く移行されなかった場合は手動で移行処理をトリガーできます。現在の設定情報は上書きされます。"
|
migrateOldSettings_description: "通常これは自動で行われていますが、何らかの理由により上手く移行されなかった場合は手動で移行処理をトリガーできます。現在の設定情報は上書きされます。"
|
||||||
compress: "圧縮"
|
compress: "圧縮"
|
||||||
|
right: "右"
|
||||||
|
bottom: "下"
|
||||||
|
top: "上"
|
||||||
|
embed: "埋め込み"
|
||||||
|
settingsMigrating: "設定を移行しています。しばらくお待ちください... (後ほど、設定→その他→旧設定情報を移行 で手動で移行することもできます)"
|
||||||
|
readonly: "読み取り専用"
|
||||||
|
goToDeck: "デッキへ戻る"
|
||||||
|
|
||||||
_chat:
|
_chat:
|
||||||
noMessagesYet: "まだメッセージはありません"
|
noMessagesYet: "まだメッセージはありません"
|
||||||
|
@ -1366,12 +1375,13 @@ _chat:
|
||||||
muteThisRoom: "このルームをミュート"
|
muteThisRoom: "このルームをミュート"
|
||||||
deleteRoom: "ルームを削除"
|
deleteRoom: "ルームを削除"
|
||||||
chatNotAvailableForThisAccountOrServer: "このサーバー、またはこのアカウントでチャットは有効化されていません。"
|
chatNotAvailableForThisAccountOrServer: "このサーバー、またはこのアカウントでチャットは有効化されていません。"
|
||||||
|
chatIsReadOnlyForThisAccountOrServer: "このサーバー、またはこのアカウントでチャットは読み取り専用となっています。新たに書き込んだり、チャットルームを作成・参加したりすることはできません。"
|
||||||
chatNotAvailableInOtherAccount: "相手のアカウントでチャット機能が使えない状態になっています。"
|
chatNotAvailableInOtherAccount: "相手のアカウントでチャット機能が使えない状態になっています。"
|
||||||
cannotChatWithTheUser: "このユーザーとのチャットを開始できません"
|
cannotChatWithTheUser: "このユーザーとのチャットを開始できません"
|
||||||
cannotChatWithTheUser_description: "チャットが使えない状態になっているか、相手がチャットを開放していません。"
|
cannotChatWithTheUser_description: "チャットが使えない状態になっているか、相手がチャットを開放していません。"
|
||||||
chatWithThisUser: "チャットする"
|
chatWithThisUser: "チャットする"
|
||||||
thisUserAllowsChatOnlyFromFollowers: "このユーザーはフォロワーからのみチャットを受け付けています。"
|
thisUserAllowsChatOnlyFromFollowers: "このユーザーはフォロワーからのみチャットを受け付けています。"
|
||||||
thisUserAllowsChatOnlyFromFollowing: "このユーザーはフォローしているユーザーからのみチャットを受け付けています。"
|
thisUserAllowsChatOnlyFromFollowing: "このユーザーは、このユーザーがフォローしているユーザーからのみチャットを受け付けています。"
|
||||||
thisUserAllowsChatOnlyFromMutualFollowing: "このユーザーは相互フォローのユーザーからのみチャットを受け付けています。"
|
thisUserAllowsChatOnlyFromMutualFollowing: "このユーザーは相互フォローのユーザーからのみチャットを受け付けています。"
|
||||||
thisUserNotAllowedChatAnyone: "このユーザーは誰からもチャットを受け付けていません。"
|
thisUserNotAllowedChatAnyone: "このユーザーは誰からもチャットを受け付けていません。"
|
||||||
chatAllowedUsers: "チャットを許可する相手"
|
chatAllowedUsers: "チャットを許可する相手"
|
||||||
|
@ -1409,9 +1419,11 @@ _settings:
|
||||||
timelineAndNote: "タイムラインとノート"
|
timelineAndNote: "タイムラインとノート"
|
||||||
makeEveryTextElementsSelectable: "全てのテキスト要素を選択可能にする"
|
makeEveryTextElementsSelectable: "全てのテキスト要素を選択可能にする"
|
||||||
makeEveryTextElementsSelectable_description: "有効にすると、一部のシチュエーションでのユーザビリティが低下する場合があります。"
|
makeEveryTextElementsSelectable_description: "有効にすると、一部のシチュエーションでのユーザビリティが低下する場合があります。"
|
||||||
|
useStickyIcons: "アイコンをスクロールに追従させる"
|
||||||
showNavbarSubButtons: "ナビゲーションバーに副ボタンを表示"
|
showNavbarSubButtons: "ナビゲーションバーに副ボタンを表示"
|
||||||
ifOn: "オンのとき"
|
ifOn: "オンのとき"
|
||||||
ifOff: "オフのとき"
|
ifOff: "オフのとき"
|
||||||
|
enableSyncThemesBetweenDevices: "デバイス間でインストールしたテーマを同期"
|
||||||
|
|
||||||
_chat:
|
_chat:
|
||||||
showSenderName: "送信者の名前を表示"
|
showSenderName: "送信者の名前を表示"
|
||||||
|
@ -1900,6 +1912,8 @@ _role:
|
||||||
descriptionOfIsExplorable: "オンにすると、「みつける」でメンバー一覧が公開されるほか、ロールのタイムラインが利用可能になります。"
|
descriptionOfIsExplorable: "オンにすると、「みつける」でメンバー一覧が公開されるほか、ロールのタイムラインが利用可能になります。"
|
||||||
displayOrder: "表示順"
|
displayOrder: "表示順"
|
||||||
descriptionOfDisplayOrder: "数値が大きいほどUI上で先頭に表示されます。"
|
descriptionOfDisplayOrder: "数値が大きいほどUI上で先頭に表示されます。"
|
||||||
|
preserveAssignmentOnMoveAccount: "アサイン状態を移行先アカウントにも引き継ぐ"
|
||||||
|
preserveAssignmentOnMoveAccount_description: "オンにすると、このロールが付与されたアカウントが移行された際に、移行先アカウントにもこのロールが引き継がれるようになります。"
|
||||||
canEditMembersByModerator: "モデレーターのメンバー編集を許可"
|
canEditMembersByModerator: "モデレーターのメンバー編集を許可"
|
||||||
descriptionOfCanEditMembersByModerator: "オンにすると、管理者に加えてモデレーターもこのロールへユーザーをアサイン/アサイン解除できるようになります。オフにすると管理者のみが行えます。"
|
descriptionOfCanEditMembersByModerator: "オンにすると、管理者に加えてモデレーターもこのロールへユーザーをアサイン/アサイン解除できるようになります。オフにすると管理者のみが行えます。"
|
||||||
priority: "優先度"
|
priority: "優先度"
|
||||||
|
@ -1940,7 +1954,7 @@ _role:
|
||||||
canImportFollowing: "フォローのインポートを許可"
|
canImportFollowing: "フォローのインポートを許可"
|
||||||
canImportMuting: "ミュートのインポートを許可"
|
canImportMuting: "ミュートのインポートを許可"
|
||||||
canImportUserLists: "リストのインポートを許可"
|
canImportUserLists: "リストのインポートを許可"
|
||||||
canChat: "チャットを許可"
|
chatAvailability: "チャットを許可"
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "マニュアルロールにアサイン済み"
|
roleAssignedTo: "マニュアルロールにアサイン済み"
|
||||||
isLocal: "ローカルユーザー"
|
isLocal: "ローカルユーザー"
|
||||||
|
@ -2157,16 +2171,15 @@ _theme:
|
||||||
panel: "パネル"
|
panel: "パネル"
|
||||||
shadow: "影"
|
shadow: "影"
|
||||||
header: "ヘッダー"
|
header: "ヘッダー"
|
||||||
navBg: "サイドバーの背景"
|
navBg: "ナビゲーションバーの背景"
|
||||||
navFg: "サイドバーの文字"
|
navFg: "ナビゲーションバーの文字"
|
||||||
navHoverFg: "サイドバー文字(ホバー)"
|
navActive: "ナビゲーションバー文字(アクティブ)"
|
||||||
navActive: "サイドバー文字(アクティブ)"
|
navIndicator: "ナビゲーションバーのインジケーター"
|
||||||
navIndicator: "サイドバーのインジケーター"
|
|
||||||
link: "リンク"
|
link: "リンク"
|
||||||
hashtag: "ハッシュタグ"
|
hashtag: "ハッシュタグ"
|
||||||
mention: "メンション"
|
mention: "メンション"
|
||||||
mentionMe: "あなた宛てメンション"
|
mentionMe: "あなた宛てメンション"
|
||||||
renote: "Renote"
|
renote: "リノート"
|
||||||
modalBg: "モーダルの背景"
|
modalBg: "モーダルの背景"
|
||||||
divider: "分割線"
|
divider: "分割線"
|
||||||
scrollbarHandle: "スクロールバーの取っ手"
|
scrollbarHandle: "スクロールバーの取っ手"
|
||||||
|
@ -2182,11 +2195,8 @@ _theme:
|
||||||
buttonHoverBg: "ボタンの背景 (ホバー)"
|
buttonHoverBg: "ボタンの背景 (ホバー)"
|
||||||
inputBorder: "入力ボックスの縁取り"
|
inputBorder: "入力ボックスの縁取り"
|
||||||
driveFolderBg: "ドライブフォルダーの背景"
|
driveFolderBg: "ドライブフォルダーの背景"
|
||||||
wallpaperOverlay: "壁紙のオーバーレイ"
|
|
||||||
badge: "バッジ"
|
badge: "バッジ"
|
||||||
messageBg: "チャットの背景"
|
messageBg: "チャットの背景"
|
||||||
accentDarken: "アクセント (暗め)"
|
|
||||||
accentLighten: "アクセント (明るめ)"
|
|
||||||
fgHighlighted: "強調された文字"
|
fgHighlighted: "強調された文字"
|
||||||
|
|
||||||
_sfx:
|
_sfx:
|
||||||
|
@ -2411,6 +2421,7 @@ _widgets:
|
||||||
chooseList: "リストを選択"
|
chooseList: "リストを選択"
|
||||||
clicker: "クリッカー"
|
clicker: "クリッカー"
|
||||||
birthdayFollowings: "今日誕生日のユーザー"
|
birthdayFollowings: "今日誕生日のユーザー"
|
||||||
|
chat: "チャット"
|
||||||
|
|
||||||
_cw:
|
_cw:
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
|
@ -2661,6 +2672,9 @@ _notification:
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "常にメインカラムを表示"
|
alwaysShowMainColumn: "常にメインカラムを表示"
|
||||||
columnAlign: "カラムの寄せ"
|
columnAlign: "カラムの寄せ"
|
||||||
|
columnGap: "カラム間のマージン"
|
||||||
|
deckMenuPosition: "デッキメニューの位置"
|
||||||
|
navbarPosition: "ナビゲーションバーの位置"
|
||||||
addColumn: "カラムを追加"
|
addColumn: "カラムを追加"
|
||||||
newNoteNotificationSettings: "新着ノート通知の設定"
|
newNoteNotificationSettings: "新着ノート通知の設定"
|
||||||
configureColumn: "カラムの設定"
|
configureColumn: "カラムの設定"
|
||||||
|
@ -2674,7 +2688,7 @@ _deck:
|
||||||
newProfile: "新規プロファイル"
|
newProfile: "新規プロファイル"
|
||||||
deleteProfile: "プロファイルを削除"
|
deleteProfile: "プロファイルを削除"
|
||||||
introduction: "カラムを組み合わせて自分だけのインターフェイスを作りましょう!"
|
introduction: "カラムを組み合わせて自分だけのインターフェイスを作りましょう!"
|
||||||
introduction2: "画面の右にある + を押して、いつでもカラムを追加できます。"
|
introduction2: "カラムを追加するには、画面の + をクリックします。"
|
||||||
widgetsIntroduction: "カラムのメニューから、「ウィジェットの編集」を選択してウィジェットを追加してください"
|
widgetsIntroduction: "カラムのメニューから、「ウィジェットの編集」を選択してウィジェットを追加してください"
|
||||||
useSimpleUiForNonRootPages: "非ルートページは簡易UIで表示"
|
useSimpleUiForNonRootPages: "非ルートページは簡易UIで表示"
|
||||||
usedAsMinWidthWhenFlexible: "「幅を自動調整」が有効の場合、これが幅の最小値となります"
|
usedAsMinWidthWhenFlexible: "「幅を自動調整」が有効の場合、これが幅の最小値となります"
|
||||||
|
@ -2692,6 +2706,7 @@ _deck:
|
||||||
mentions: "あなた宛て"
|
mentions: "あなた宛て"
|
||||||
direct: "ダイレクト"
|
direct: "ダイレクト"
|
||||||
roleTimeline: "ロールタイムライン"
|
roleTimeline: "ロールタイムライン"
|
||||||
|
chat: "チャット"
|
||||||
|
|
||||||
_dialog:
|
_dialog:
|
||||||
charactersExceeded: "最大文字数を超えています! 現在 {current} / 制限 {max}"
|
charactersExceeded: "最大文字数を超えています! 現在 {current} / 制限 {max}"
|
||||||
|
|
|
@ -2007,7 +2007,6 @@ _theme:
|
||||||
header: "ヘッダー"
|
header: "ヘッダー"
|
||||||
navBg: "サイドバーの背景"
|
navBg: "サイドバーの背景"
|
||||||
navFg: "サイドバーの文字"
|
navFg: "サイドバーの文字"
|
||||||
navHoverFg: "サイドバー文字(ホバー)"
|
|
||||||
navActive: "サイドバー文字(アクティブ)"
|
navActive: "サイドバー文字(アクティブ)"
|
||||||
navIndicator: "サイドバーのインジケーター"
|
navIndicator: "サイドバーのインジケーター"
|
||||||
link: "リンク"
|
link: "リンク"
|
||||||
|
@ -2030,11 +2029,8 @@ _theme:
|
||||||
buttonHoverBg: "ボタンの背景 (ホバー)"
|
buttonHoverBg: "ボタンの背景 (ホバー)"
|
||||||
inputBorder: "入力ボックスの縁取り"
|
inputBorder: "入力ボックスの縁取り"
|
||||||
driveFolderBg: "ドライブフォルダーの背景"
|
driveFolderBg: "ドライブフォルダーの背景"
|
||||||
wallpaperOverlay: "壁紙のオーバーレイ"
|
|
||||||
badge: "バッジ"
|
badge: "バッジ"
|
||||||
messageBg: "チャットの背景"
|
messageBg: "チャットの背景"
|
||||||
accentDarken: "アクセント (暗め)"
|
|
||||||
accentLighten: "アクセント (明るめ)"
|
|
||||||
fgHighlighted: "強調されとる文字"
|
fgHighlighted: "強調されとる文字"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "ノート"
|
note: "ノート"
|
||||||
|
|
|
@ -747,6 +747,7 @@ _theme:
|
||||||
description: "설멩"
|
description: "설멩"
|
||||||
keys:
|
keys:
|
||||||
mention: "멘션"
|
mention: "멘션"
|
||||||
|
renote: "리노트"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "새 노트"
|
note: "새 노트"
|
||||||
notification: "알림"
|
notification: "알림"
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,6 +5,7 @@ introMisskey: "Welkom! Misskey is een open source, gedecentraliseerde microblogd
|
||||||
poweredByMisskeyDescription: "{name} is één van de services die door het open source platform <b>Misskey</b> wordt geleverd (het wordt ook wel een \"Misskey server genmoemd\")."
|
poweredByMisskeyDescription: "{name} is één van de services die door het open source platform <b>Misskey</b> wordt geleverd (het wordt ook wel een \"Misskey server genmoemd\")."
|
||||||
monthAndDay: "{day} {month}"
|
monthAndDay: "{day} {month}"
|
||||||
search: "Zoeken"
|
search: "Zoeken"
|
||||||
|
reset: "Herstellen"
|
||||||
notifications: "Meldingen"
|
notifications: "Meldingen"
|
||||||
username: "Gebruikersnaam"
|
username: "Gebruikersnaam"
|
||||||
password: "Wachtwoord"
|
password: "Wachtwoord"
|
||||||
|
@ -48,6 +49,7 @@ pin: "Vastmaken aan profielpagina"
|
||||||
unpin: "Losmaken van profielpagina"
|
unpin: "Losmaken van profielpagina"
|
||||||
copyContent: "Kopiëren inhoud"
|
copyContent: "Kopiëren inhoud"
|
||||||
copyLink: "Kopiëren link"
|
copyLink: "Kopiëren link"
|
||||||
|
copyRemoteLink: "Remote-link kopiëren"
|
||||||
copyLinkRenote: ""
|
copyLinkRenote: ""
|
||||||
delete: "Verwijderen"
|
delete: "Verwijderen"
|
||||||
deleteAndEdit: "Verwijderen en bewerken"
|
deleteAndEdit: "Verwijderen en bewerken"
|
||||||
|
@ -63,6 +65,7 @@ copyFileId: "Kopieer veld ID"
|
||||||
copyFolderId: "Kopieer folder ID"
|
copyFolderId: "Kopieer folder ID"
|
||||||
copyProfileUrl: "Kopieer profiel URL"
|
copyProfileUrl: "Kopieer profiel URL"
|
||||||
searchUser: "Zoeken een gebruiker"
|
searchUser: "Zoeken een gebruiker"
|
||||||
|
searchThisUsersNotes: "Notities van deze gebruiker doorzoeken"
|
||||||
reply: "Antwoord"
|
reply: "Antwoord"
|
||||||
loadMore: "Laad meer"
|
loadMore: "Laad meer"
|
||||||
showMore: "Toon meer"
|
showMore: "Toon meer"
|
||||||
|
@ -129,9 +132,12 @@ emojiPicker: "Emoji kiezer"
|
||||||
pinnedEmojisForReactionSettingDescription: "Kies de emojis die als eerste getoond worden tijdens het reageren"
|
pinnedEmojisForReactionSettingDescription: "Kies de emojis die als eerste getoond worden tijdens het reageren"
|
||||||
pinnedEmojisSettingDescription: "Kies de emojis die als eerste getoond worden tijdens het reageren"
|
pinnedEmojisSettingDescription: "Kies de emojis die als eerste getoond worden tijdens het reageren"
|
||||||
emojiPickerDisplay: "Emoji kiezer weergave"
|
emojiPickerDisplay: "Emoji kiezer weergave"
|
||||||
|
overwriteFromPinnedEmojisForReaction: "Overschrijven met reactieinstellingen"
|
||||||
|
overwriteFromPinnedEmojis: "Overschrijven met algemene instellingen"
|
||||||
reactionSettingDescription2: "Sleep om opnieuw te ordenen, Klik om te verwijderen, Druk op \"+\" om toe te voegen"
|
reactionSettingDescription2: "Sleep om opnieuw te ordenen, Klik om te verwijderen, Druk op \"+\" om toe te voegen"
|
||||||
rememberNoteVisibility: "Vergeet niet de notitie zichtbaarheidsinstellingen"
|
rememberNoteVisibility: "Vergeet niet de notitie zichtbaarheidsinstellingen"
|
||||||
attachCancel: "Verwijder bijlage"
|
attachCancel: "Verwijder bijlage"
|
||||||
|
deleteFile: "Bestand verwijderen"
|
||||||
markAsSensitive: "Markeren als NSFW"
|
markAsSensitive: "Markeren als NSFW"
|
||||||
unmarkAsSensitive: "Geen NSFW"
|
unmarkAsSensitive: "Geen NSFW"
|
||||||
enterFileName: "Invoeren bestandsnaam"
|
enterFileName: "Invoeren bestandsnaam"
|
||||||
|
@ -147,6 +153,7 @@ suspendConfirm: "Ben je zeker dat je deze account wil suspenderen?"
|
||||||
unsuspendConfirm: "Ben je zeker dat je deze account wil opnieuw aanstellen?"
|
unsuspendConfirm: "Ben je zeker dat je deze account wil opnieuw aanstellen?"
|
||||||
selectList: "Kies een lijst."
|
selectList: "Kies een lijst."
|
||||||
selectAntenna: "Kies een antenne"
|
selectAntenna: "Kies een antenne"
|
||||||
|
createAntenna: "Antenne aanmaken"
|
||||||
selectWidget: "Kies een widget"
|
selectWidget: "Kies een widget"
|
||||||
editWidgets: "Bewerk widgets"
|
editWidgets: "Bewerk widgets"
|
||||||
editWidgetsExit: "Klaar"
|
editWidgetsExit: "Klaar"
|
||||||
|
@ -158,6 +165,7 @@ emojiUrl: "URL emoji"
|
||||||
addEmoji: "Toevoegen emoji"
|
addEmoji: "Toevoegen emoji"
|
||||||
settingGuide: "Aanbevolen instellingen"
|
settingGuide: "Aanbevolen instellingen"
|
||||||
cacheRemoteFiles: "Externe bestanden cachen"
|
cacheRemoteFiles: "Externe bestanden cachen"
|
||||||
|
cacheRemoteFilesDescription: "Als deze instelling uitgeschakeld is worden bestanden altijd direct van remote servers geladen. Hiermee wordt opslagruimte bespaard, maar doordat er geen thumbnails worden gegenereerd, zal netwerkverkeer toenemen."
|
||||||
flagAsBot: "Markeer dit account als een robot."
|
flagAsBot: "Markeer dit account als een robot."
|
||||||
flagAsBotDescription: "Als dit account van een programma wordt beheerd, zet deze vlag aan. Het aanzetten helpt andere ontwikkelaars om bijvoorbeeld onbedoelde feedback loops te doorbreken of om Misskey meer geschikt te maken."
|
flagAsBotDescription: "Als dit account van een programma wordt beheerd, zet deze vlag aan. Het aanzetten helpt andere ontwikkelaars om bijvoorbeeld onbedoelde feedback loops te doorbreken of om Misskey meer geschikt te maken."
|
||||||
flagAsCat: "Markeer dit account als een kat."
|
flagAsCat: "Markeer dit account als een kat."
|
||||||
|
@ -168,6 +176,10 @@ autoAcceptFollowed: "Accepteer verzoeken om jezelf te volgen vanzelf als je de v
|
||||||
addAccount: "Account toevoegen"
|
addAccount: "Account toevoegen"
|
||||||
loginFailed: "Aanmelding mislukt."
|
loginFailed: "Aanmelding mislukt."
|
||||||
showOnRemote: "Toon op de externe instantie."
|
showOnRemote: "Toon op de externe instantie."
|
||||||
|
continueOnRemote: "Verder op remote server"
|
||||||
|
chooseServerOnMisskeyHub: "Kies een server van de Misskey Hub"
|
||||||
|
specifyServerHost: "Serverhost uitkiezen"
|
||||||
|
inputHostName: "Domein invullen"
|
||||||
general: "Algemeen"
|
general: "Algemeen"
|
||||||
wallpaper: "Achtergrond"
|
wallpaper: "Achtergrond"
|
||||||
setWallpaper: "Achtergrond instellen"
|
setWallpaper: "Achtergrond instellen"
|
||||||
|
@ -178,6 +190,7 @@ followConfirm: "Weet je zeker dat je {name} wilt volgen?"
|
||||||
proxyAccount: "Proxy account"
|
proxyAccount: "Proxy account"
|
||||||
proxyAccountDescription: "Een proxy-account is een account dat onder bepaalde voorwaarden fungeert als externe volger voor gebruikers. Als een gebruiker bijvoorbeeld een externe gebruiker aan de lijst toevoegt, wordt de activiteit van de externe gebruiker niet aan de server geleverd als geen lokale gebruiker die gebruiker volgt, dus het proxy-account volgt in plaats daarvan."
|
proxyAccountDescription: "Een proxy-account is een account dat onder bepaalde voorwaarden fungeert als externe volger voor gebruikers. Als een gebruiker bijvoorbeeld een externe gebruiker aan de lijst toevoegt, wordt de activiteit van de externe gebruiker niet aan de server geleverd als geen lokale gebruiker die gebruiker volgt, dus het proxy-account volgt in plaats daarvan."
|
||||||
host: "Server"
|
host: "Server"
|
||||||
|
selectSelf: "Mezelf kiezen"
|
||||||
selectUser: "Kies een gebruiker"
|
selectUser: "Kies een gebruiker"
|
||||||
recipient: "Ontvanger"
|
recipient: "Ontvanger"
|
||||||
annotation: "Reacties"
|
annotation: "Reacties"
|
||||||
|
@ -192,6 +205,7 @@ perHour: "Per uur"
|
||||||
perDay: "Per dag"
|
perDay: "Per dag"
|
||||||
stopActivityDelivery: "Stop met versturen activiteiten"
|
stopActivityDelivery: "Stop met versturen activiteiten"
|
||||||
blockThisInstance: "Blokkeer deze server"
|
blockThisInstance: "Blokkeer deze server"
|
||||||
|
mediaSilenceThisInstance: "Media van deze server dempen"
|
||||||
operations: "Verwerkingen"
|
operations: "Verwerkingen"
|
||||||
software: "Software"
|
software: "Software"
|
||||||
version: "Versie"
|
version: "Versie"
|
||||||
|
@ -211,6 +225,11 @@ clearCachedFiles: "Cache opschonen"
|
||||||
clearCachedFilesConfirm: "Weet je zeker dat je alle externe bestanden in de cache wilt verwijderen?"
|
clearCachedFilesConfirm: "Weet je zeker dat je alle externe bestanden in de cache wilt verwijderen?"
|
||||||
blockedInstances: "Geblokkeerde servers"
|
blockedInstances: "Geblokkeerde servers"
|
||||||
blockedInstancesDescription: "Maak een lijst van de servers die moeten worden geblokkeerd, gescheiden door regeleinden. Geblokkeerde servers kunnen niet meer communiceren met deze server."
|
blockedInstancesDescription: "Maak een lijst van de servers die moeten worden geblokkeerd, gescheiden door regeleinden. Geblokkeerde servers kunnen niet meer communiceren met deze server."
|
||||||
|
silencedInstancesDescription: "Geef de hostnamen van de servers die je wil dempen op, elk op hun eigen regel. Alle accounts die bij de opgegeven servers horen worden als gedempt behandeld, kunnen alleen maar volgverzoeken maken, en kunnen lokale accounts niet vermelden als ze niet gevolgd worden. Geblokkeerde servers worden hier niet door beïnvloed."
|
||||||
|
mediaSilencedInstances: "Media-gedempte servers"
|
||||||
|
mediaSilencedInstancesDescription: "Geef de hostnamen van de servers die je wil media-dempen op, elk op hun eigen regel. Alle accounts die bij de opgegeven servers horen worden als gedempt behandeld, en kunnen geen eigen emojis gebruiken. Geblokkeerde servers worden hier niet door beïnvloed."
|
||||||
|
federationAllowedHosts: "Servers die mogen federeren "
|
||||||
|
federationAllowedHostsDescription: "Geef de hostnamen van de servers die mogen federeren op, elk op hun eigen regel."
|
||||||
muteAndBlock: "Gedempt en geblokkeerd"
|
muteAndBlock: "Gedempt en geblokkeerd"
|
||||||
mutedUsers: "Gedempte gebruikers"
|
mutedUsers: "Gedempte gebruikers"
|
||||||
blockedUsers: "Geblokkeerde gebruikers"
|
blockedUsers: "Geblokkeerde gebruikers"
|
||||||
|
@ -255,6 +274,7 @@ removed: "Succesvol verwijderd"
|
||||||
removeAreYouSure: "Weet je zeker dat je \"{x}\" wil verwijderen?"
|
removeAreYouSure: "Weet je zeker dat je \"{x}\" wil verwijderen?"
|
||||||
deleteAreYouSure: "Weet je zeker dat je \"{x}\" wil verwijderen?"
|
deleteAreYouSure: "Weet je zeker dat je \"{x}\" wil verwijderen?"
|
||||||
resetAreYouSure: "Resetten?"
|
resetAreYouSure: "Resetten?"
|
||||||
|
areYouSure: "Weet je het zeker?"
|
||||||
saved: "Opgeslagen"
|
saved: "Opgeslagen"
|
||||||
upload: "Uploaden"
|
upload: "Uploaden"
|
||||||
keepOriginalUploading: "Origineel beeld behouden."
|
keepOriginalUploading: "Origineel beeld behouden."
|
||||||
|
@ -268,6 +288,7 @@ uploadFromUrlMayTakeTime: "Het kan even duren voordat het uploaden voltooid is."
|
||||||
explore: "Verkennen"
|
explore: "Verkennen"
|
||||||
messageRead: "Lezen"
|
messageRead: "Lezen"
|
||||||
noMoreHistory: "Er is geen verdere geschiedenis"
|
noMoreHistory: "Er is geen verdere geschiedenis"
|
||||||
|
startChat: "Chat starten"
|
||||||
nUsersRead: "gelezen door {n}"
|
nUsersRead: "gelezen door {n}"
|
||||||
agreeTo: "Ik stem in met {0}"
|
agreeTo: "Ik stem in met {0}"
|
||||||
start: "Aan de slag"
|
start: "Aan de slag"
|
||||||
|
@ -294,12 +315,15 @@ selectFile: "Kies een bestand"
|
||||||
selectFiles: "Selecteer bestanden"
|
selectFiles: "Selecteer bestanden"
|
||||||
selectFolder: "Kies een map"
|
selectFolder: "Kies een map"
|
||||||
selectFolders: "Kies mappen"
|
selectFolders: "Kies mappen"
|
||||||
|
fileNotSelected: "Geen bestand geselecteerd"
|
||||||
renameFile: "Wijzig bestandsnaam"
|
renameFile: "Wijzig bestandsnaam"
|
||||||
folderName: "Mapnaam"
|
folderName: "Mapnaam"
|
||||||
createFolder: "Map aanmaken"
|
createFolder: "Map aanmaken"
|
||||||
renameFolder: "Map hernoemen"
|
renameFolder: "Map hernoemen"
|
||||||
deleteFolder: "Map verwijderen"
|
deleteFolder: "Map verwijderen"
|
||||||
|
folder: "Map"
|
||||||
addFile: "Bestand toevoegen"
|
addFile: "Bestand toevoegen"
|
||||||
|
showFile: "Bestanden weergeven"
|
||||||
emptyDrive: "Jouw Drive is leeg."
|
emptyDrive: "Jouw Drive is leeg."
|
||||||
emptyFolder: "Deze map is leeg"
|
emptyFolder: "Deze map is leeg"
|
||||||
unableToDelete: "Kan niet worden verwijderd"
|
unableToDelete: "Kan niet worden verwijderd"
|
||||||
|
@ -355,8 +379,11 @@ hcaptcha: "hCaptcha"
|
||||||
enableHcaptcha: "Inschakelen hCaptcha"
|
enableHcaptcha: "Inschakelen hCaptcha"
|
||||||
hcaptchaSiteKey: "Site sleutel"
|
hcaptchaSiteKey: "Site sleutel"
|
||||||
hcaptchaSecretKey: "Geheime sleutel"
|
hcaptchaSecretKey: "Geheime sleutel"
|
||||||
|
mcaptcha: "mCaptcha"
|
||||||
|
enableMcaptcha: "mCaptcha activeren"
|
||||||
mcaptchaSiteKey: "Site sleutel"
|
mcaptchaSiteKey: "Site sleutel"
|
||||||
mcaptchaSecretKey: "Geheime sleutel"
|
mcaptchaSecretKey: "Geheime sleutel"
|
||||||
|
mcaptchaInstanceUrl: "mCaptcha server-URL"
|
||||||
recaptcha: "reCAPTCHA"
|
recaptcha: "reCAPTCHA"
|
||||||
enableRecaptcha: "Inschakelen reCAPTCHA"
|
enableRecaptcha: "Inschakelen reCAPTCHA"
|
||||||
recaptchaSiteKey: "Site sleutel"
|
recaptchaSiteKey: "Site sleutel"
|
||||||
|
@ -371,6 +398,7 @@ name: "Naam"
|
||||||
antennaSource: "Bron antenne"
|
antennaSource: "Bron antenne"
|
||||||
antennaKeywords: "Sleutelwoorden"
|
antennaKeywords: "Sleutelwoorden"
|
||||||
antennaExcludeKeywords: "Blokkeerwoorden"
|
antennaExcludeKeywords: "Blokkeerwoorden"
|
||||||
|
antennaExcludeBots: "Bot-accounts uitsluiten"
|
||||||
withReplies: "Antwoorden toevoegen"
|
withReplies: "Antwoorden toevoegen"
|
||||||
connectedTo: "De volgende accounts zijn verbonden"
|
connectedTo: "De volgende accounts zijn verbonden"
|
||||||
notesAndReplies: "Berichten en reacties"
|
notesAndReplies: "Berichten en reacties"
|
||||||
|
@ -421,7 +449,13 @@ retype: "Opnieuw invoeren"
|
||||||
noteOf: "Notitie van {user}"
|
noteOf: "Notitie van {user}"
|
||||||
quoteAttached: "Citaat"
|
quoteAttached: "Citaat"
|
||||||
quoteQuestion: "Toevoegen als citaat?"
|
quoteQuestion: "Toevoegen als citaat?"
|
||||||
|
signinOrContinueOnRemote: "Ga naar je eigen instantie of registreer je/log in op deze server om door te gaan."
|
||||||
invitations: "Uitnodigen"
|
invitations: "Uitnodigen"
|
||||||
|
menuStyle: "Menustijl"
|
||||||
|
style: "Stijl"
|
||||||
|
drawer: "Lade"
|
||||||
|
popup: "Pop-up"
|
||||||
|
showReactionsCount: "Zie het aantal reacties op notities"
|
||||||
dashboard: "Overzicht"
|
dashboard: "Overzicht"
|
||||||
local: "Lokaal"
|
local: "Lokaal"
|
||||||
remote: "Remote"
|
remote: "Remote"
|
||||||
|
@ -437,16 +471,41 @@ numberOfDays: "Aantal dagen"
|
||||||
hideThisNote: "Verberg deze notitie"
|
hideThisNote: "Verberg deze notitie"
|
||||||
showFeaturedNotesInTimeline: "Laat featured notities in tijdlijn zien"
|
showFeaturedNotesInTimeline: "Laat featured notities in tijdlijn zien"
|
||||||
sound: "Geluid"
|
sound: "Geluid"
|
||||||
|
notUseSound: "Geluid uitschakelen"
|
||||||
|
useSoundOnlyWhenActive: "Geluid alleen inschakelen wanneer Misskey actief is"
|
||||||
|
uiInspector: "UI-inspecteur"
|
||||||
|
unsetUserAvatar: "Avatar verwijderen"
|
||||||
|
unsetUserAvatarConfirm: "Weet je zeker dat je je avatar wil verwijderen?"
|
||||||
|
unsetUserBanner: "Banner verwijderen"
|
||||||
|
unsetUserBannerConfirm: "Weet je zeker dat je je banner wil verwijderen?"
|
||||||
|
expandTweet: "Notitie uitklappen"
|
||||||
|
adminPermission: "Administratorrechten"
|
||||||
smtpHost: "Server"
|
smtpHost: "Server"
|
||||||
smtpUser: "Gebruikersnaam"
|
smtpUser: "Gebruikersnaam"
|
||||||
smtpPass: "Wachtwoord"
|
smtpPass: "Wachtwoord"
|
||||||
|
wordMuteDescription: "Minimaliseert notities die het gespecificeerde woord of zin bevatten. Geminimaliseerde notities kunnen worden weergegeven door er op te klikken."
|
||||||
|
hardWordMute: "Harde woorddemping"
|
||||||
|
showMutedWord: "Gedempte woorden weergeven"
|
||||||
|
hardWordMuteDescription: "Verbert notities die het gespecificeerde woord of zin bevatten. In tegenstelling tot woorddemping wordt de notitie volledig verborgen."
|
||||||
|
userSaysSomethingAbout: "{name} zei iets over '{word}'"
|
||||||
|
copiedToClipboard: "Naar het klembord gekopieerd"
|
||||||
|
theKeywordWhenSearchingForCustomEmoji: "Dit is het keyword dat gebruikt wordt bij het zoeken naar eigen emojis."
|
||||||
|
fillAbuseReportDescription: "Vul s.v.p. de details in over deze melding. Geef, als het over een specifieke notitie gaat, ook de URL op."
|
||||||
|
reloadToApplySetting: "Deze instelling gaat pas in nadat de pagina herladen is. Nu herladen?"
|
||||||
clearCache: "Cache opschonen"
|
clearCache: "Cache opschonen"
|
||||||
info: "Over"
|
info: "Over"
|
||||||
user: "Gebruikers"
|
user: "Gebruikers"
|
||||||
|
noInquiryUrlWarning: "Contact-URL niet opgegeven"
|
||||||
muteThread: "Discussies dempen "
|
muteThread: "Discussies dempen "
|
||||||
unmuteThread: "Dempen van discussie ongedaan maken"
|
unmuteThread: "Dempen van discussie ongedaan maken"
|
||||||
|
followingVisibility: "Zichtbaarheid van gevolgden"
|
||||||
|
followersVisibility: "Zichtbaarheid van volgers"
|
||||||
|
incorrectTotp: "Het eenmalige wachtwoord is incorrect of verlopen"
|
||||||
hide: "Verbergen"
|
hide: "Verbergen"
|
||||||
searchByGoogle: "Zoeken"
|
searchByGoogle: "Zoeken"
|
||||||
|
threeMonths: "3 maanden"
|
||||||
|
oneYear: "1 jaar"
|
||||||
|
threeDays: "3 dagen"
|
||||||
cropImage: "Afbeelding bijsnijden"
|
cropImage: "Afbeelding bijsnijden"
|
||||||
cropImageAsk: "Bijsnijdengevraagd"
|
cropImageAsk: "Bijsnijdengevraagd"
|
||||||
file: "Bestanden"
|
file: "Bestanden"
|
||||||
|
@ -457,9 +516,28 @@ pushNotificationAlreadySubscribed: "Pushberichtrn al ingeschakeld"
|
||||||
windowMaximize: "Maximaliseren"
|
windowMaximize: "Maximaliseren"
|
||||||
windowRestore: "Herstellen"
|
windowRestore: "Herstellen"
|
||||||
loggedInAsBot: "Momenteel als bot ingelogd"
|
loggedInAsBot: "Momenteel als bot ingelogd"
|
||||||
|
correspondingSourceIsAvailable: "De bijbehorende broncode is beschikbaar bij {anchor}"
|
||||||
|
invalidParamErrorDescription: "De aanvraagparameters zijn ongeldig. Dit komt meestal door een bug, maar kan ook omdat de invoer te lang is of iets dergelijks."
|
||||||
|
collapseRenotes: "Renotes die je al gezien hebt, inklappen"
|
||||||
|
collapseRenotesDescription: "Klapt notities in waar je al op gereageerd hebt of die je al gerenotet hebt."
|
||||||
|
prohibitedWords: "Verboden woorden"
|
||||||
|
prohibitedWordsDescription: "Activeert een foutmelding als er geprobeerd wordt een notitie met de ingestelde woorden te plaatsen. Meerdere woorden kunnen worden ingesteld, elk op hun eigen regel."
|
||||||
|
hiddenTags: "Verborgen hashtags"
|
||||||
|
hiddenTagsDescription: "Selecteer tags die niet worden weergegeven in de trends. Meerdere tags kunnen worden geregistreerd, elk op hun eigen regel."
|
||||||
|
enableStatsForFederatedInstances: "Statistieken van remote servers ontvangen"
|
||||||
|
limitWidthOfReaction: "Limiteert de maximale breedte van reacties en geef ze verkleind weer"
|
||||||
|
audio: "Audio"
|
||||||
|
audioFiles: "Audio"
|
||||||
|
archived: "Gearchiveerd"
|
||||||
|
unarchive: "Dearchiveren"
|
||||||
|
lookupConfirm: "Weet je zeker dat je dit wil opzoeken?"
|
||||||
|
openTagPageConfirm: "Wil je deze hashtagpagina openen?"
|
||||||
|
specifyHost: "Specificeer host"
|
||||||
icon: "Avatar"
|
icon: "Avatar"
|
||||||
replies: "Antwoord"
|
replies: "Antwoord"
|
||||||
renotes: "Herdelen"
|
renotes: "Herdelen"
|
||||||
|
followingOrFollower: "Gevolgd of volger"
|
||||||
|
confirmShowRepliesAll: "Dit is een onomkeerbare operatie. Weet je zeker dat reacties op anderen van iedereen die je volgt, wil weergeven in je tijdlijn?"
|
||||||
information: "Over"
|
information: "Over"
|
||||||
_chat:
|
_chat:
|
||||||
invitations: "Uitnodigen"
|
invitations: "Uitnodigen"
|
||||||
|
|
|
@ -1212,7 +1212,6 @@ _theme:
|
||||||
header: "Nagłówek"
|
header: "Nagłówek"
|
||||||
navBg: "Tło paska bocznego"
|
navBg: "Tło paska bocznego"
|
||||||
navFg: "Tekst paska bocznego"
|
navFg: "Tekst paska bocznego"
|
||||||
navHoverFg: "Tekst paska bocznego (zbliżenie)"
|
|
||||||
navActive: "Tekst paska bocznego (aktywny)"
|
navActive: "Tekst paska bocznego (aktywny)"
|
||||||
navIndicator: "Wskaźnik paska bocznego"
|
navIndicator: "Wskaźnik paska bocznego"
|
||||||
link: "Odnośnik"
|
link: "Odnośnik"
|
||||||
|
@ -1235,11 +1234,8 @@ _theme:
|
||||||
buttonHoverBg: "Tło przycisku (po najechaniu)"
|
buttonHoverBg: "Tło przycisku (po najechaniu)"
|
||||||
inputBorder: "Obramowanie pola wejścia"
|
inputBorder: "Obramowanie pola wejścia"
|
||||||
driveFolderBg: "Tło folderu na dysku"
|
driveFolderBg: "Tło folderu na dysku"
|
||||||
wallpaperOverlay: "Nakładka tapety"
|
|
||||||
badge: "Odznaka"
|
badge: "Odznaka"
|
||||||
messageBg: "Tło czatu"
|
messageBg: "Tło czatu"
|
||||||
accentDarken: "Akcent (ciemniejszy)"
|
|
||||||
accentLighten: "Akcent (jaśniejszy)"
|
|
||||||
fgHighlighted: "Wyróżniony tekst"
|
fgHighlighted: "Wyróżniony tekst"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Wpisy"
|
note: "Wpisy"
|
||||||
|
|
|
@ -1997,7 +1997,6 @@ _theme:
|
||||||
header: "Cabeçalho"
|
header: "Cabeçalho"
|
||||||
navBg: "Plano de fundo da barra lateral"
|
navBg: "Plano de fundo da barra lateral"
|
||||||
navFg: "Texto da barra lateral"
|
navFg: "Texto da barra lateral"
|
||||||
navHoverFg: "Texto da coluna lateral (Selecionado)"
|
|
||||||
navActive: "Texto da coluna lateral (Ativa)"
|
navActive: "Texto da coluna lateral (Ativa)"
|
||||||
navIndicator: "Indicador da coluna lateral"
|
navIndicator: "Indicador da coluna lateral"
|
||||||
link: "Link"
|
link: "Link"
|
||||||
|
@ -2020,11 +2019,8 @@ _theme:
|
||||||
buttonHoverBg: "Plano de fundo de botão (Selecionado)"
|
buttonHoverBg: "Plano de fundo de botão (Selecionado)"
|
||||||
inputBorder: "Borda de campo digitável"
|
inputBorder: "Borda de campo digitável"
|
||||||
driveFolderBg: "Plano de fundo da pasta no Drive"
|
driveFolderBg: "Plano de fundo da pasta no Drive"
|
||||||
wallpaperOverlay: "Sobreposição do papel de parede."
|
|
||||||
badge: "Emblema"
|
badge: "Emblema"
|
||||||
messageBg: "Plano de fundo do chat"
|
messageBg: "Plano de fundo do chat"
|
||||||
accentDarken: "Cor de destaque (Escurecida)"
|
|
||||||
accentLighten: "Cor de destaque (Esclarecida)"
|
|
||||||
fgHighlighted: "Texto Destacado"
|
fgHighlighted: "Texto Destacado"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Posts"
|
note: "Posts"
|
||||||
|
|
|
@ -1689,7 +1689,6 @@ _theme:
|
||||||
header: "Заголовок"
|
header: "Заголовок"
|
||||||
navBg: "Фон боковой панели"
|
navBg: "Фон боковой панели"
|
||||||
navFg: "Текст на боковой панели"
|
navFg: "Текст на боковой панели"
|
||||||
navHoverFg: "Текст на боковой панели (под указателем)"
|
|
||||||
navActive: "Текст на боковой панели (активирован)"
|
navActive: "Текст на боковой панели (активирован)"
|
||||||
navIndicator: "Индикатор на боковой панели"
|
navIndicator: "Индикатор на боковой панели"
|
||||||
link: "Ссылка"
|
link: "Ссылка"
|
||||||
|
@ -1712,11 +1711,8 @@ _theme:
|
||||||
buttonHoverBg: "Текст кнопки"
|
buttonHoverBg: "Текст кнопки"
|
||||||
inputBorder: "Рамка поля ввода"
|
inputBorder: "Рамка поля ввода"
|
||||||
driveFolderBg: "Фон папки «Диска»"
|
driveFolderBg: "Фон папки «Диска»"
|
||||||
wallpaperOverlay: "Слой обоев"
|
|
||||||
badge: "Значок"
|
badge: "Значок"
|
||||||
messageBg: "Фон беседы"
|
messageBg: "Фон беседы"
|
||||||
accentDarken: "Фон (затемнённый)"
|
|
||||||
accentLighten: "Фон (осветлённый)"
|
|
||||||
fgHighlighted: "Подсвеченный текст"
|
fgHighlighted: "Подсвеченный текст"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Заметки"
|
note: "Заметки"
|
||||||
|
|
|
@ -1089,7 +1089,6 @@ _theme:
|
||||||
header: "Hlavička"
|
header: "Hlavička"
|
||||||
navBg: "Pozadie bočného panela"
|
navBg: "Pozadie bočného panela"
|
||||||
navFg: "Text bočného panela"
|
navFg: "Text bočného panela"
|
||||||
navHoverFg: "Text bočného panela (pod kurzorom)"
|
|
||||||
navActive: "Text bočného panela (aktívny)"
|
navActive: "Text bočného panela (aktívny)"
|
||||||
navIndicator: "Indikátor bočného panela"
|
navIndicator: "Indikátor bočného panela"
|
||||||
link: "Odkaz"
|
link: "Odkaz"
|
||||||
|
@ -1112,11 +1111,8 @@ _theme:
|
||||||
buttonHoverBg: "Pozadie tlačidla (pod kurzorom)"
|
buttonHoverBg: "Pozadie tlačidla (pod kurzorom)"
|
||||||
inputBorder: "Okraj vstupného poľa"
|
inputBorder: "Okraj vstupného poľa"
|
||||||
driveFolderBg: "Pozadie priečinu disku"
|
driveFolderBg: "Pozadie priečinu disku"
|
||||||
wallpaperOverlay: "Vrstvenie pozadia"
|
|
||||||
badge: "Odznak"
|
badge: "Odznak"
|
||||||
messageBg: "Pozadie chatu"
|
messageBg: "Pozadie chatu"
|
||||||
accentDarken: "Akcent (stmavené)"
|
|
||||||
accentLighten: "Akcent (zosvetlené)"
|
|
||||||
fgHighlighted: "Zvýraznený text"
|
fgHighlighted: "Zvýraznený text"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Poznámky"
|
note: "Poznámky"
|
||||||
|
|
|
@ -1974,7 +1974,6 @@ _theme:
|
||||||
header: "ส่วนหัว"
|
header: "ส่วนหัว"
|
||||||
navBg: "พื้นหลังแถบด้านข้าง"
|
navBg: "พื้นหลังแถบด้านข้าง"
|
||||||
navFg: "ข้อความแถบด้านข้าง"
|
navFg: "ข้อความแถบด้านข้าง"
|
||||||
navHoverFg: "ข้อความแถบด้านข้าง (โฮเวอร์)"
|
|
||||||
navActive: "ข้อความแถบด้านข้าง (ใช้งานอยู่)"
|
navActive: "ข้อความแถบด้านข้าง (ใช้งานอยู่)"
|
||||||
navIndicator: "ตัวระบุแถบด้านข้าง"
|
navIndicator: "ตัวระบุแถบด้านข้าง"
|
||||||
link: "ลิงก์"
|
link: "ลิงก์"
|
||||||
|
@ -1997,11 +1996,8 @@ _theme:
|
||||||
buttonHoverBg: "ปุ่มพื้นหลัง (โฮเวอร์)"
|
buttonHoverBg: "ปุ่มพื้นหลัง (โฮเวอร์)"
|
||||||
inputBorder: "เส้นขอบของช่องป้อนข้อมูล"
|
inputBorder: "เส้นขอบของช่องป้อนข้อมูล"
|
||||||
driveFolderBg: "พื้นหลังโฟลเดอร์ไดรฟ์"
|
driveFolderBg: "พื้นหลังโฟลเดอร์ไดรฟ์"
|
||||||
wallpaperOverlay: "วอลล์เปเปอร์ซ้อนทับ"
|
|
||||||
badge: "ตรา"
|
badge: "ตรา"
|
||||||
messageBg: "พื้นหลังแชท"
|
messageBg: "พื้นหลังแชท"
|
||||||
accentDarken: "สีหลัก (มืด)"
|
|
||||||
accentLighten: "สีหลัก (สว่าง)"
|
|
||||||
fgHighlighted: "ข้อความที่ไฮไลต์"
|
fgHighlighted: "ข้อความที่ไฮไลต์"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "โน้ต"
|
note: "โน้ต"
|
||||||
|
|
|
@ -1283,7 +1283,6 @@ _theme:
|
||||||
header: "Заголовок"
|
header: "Заголовок"
|
||||||
navBg: "Фон бокової панелі"
|
navBg: "Фон бокової панелі"
|
||||||
navFg: "Текст бокової панелі"
|
navFg: "Текст бокової панелі"
|
||||||
navHoverFg: "Текст бокової панелі (під курсором)"
|
|
||||||
navActive: "Текст бокової панелі (активне)"
|
navActive: "Текст бокової панелі (активне)"
|
||||||
navIndicator: "Індикатор бокової панелі"
|
navIndicator: "Індикатор бокової панелі"
|
||||||
link: "Посилання"
|
link: "Посилання"
|
||||||
|
@ -1306,11 +1305,8 @@ _theme:
|
||||||
buttonHoverBg: "Фон кнопки (при наведенні)"
|
buttonHoverBg: "Фон кнопки (при наведенні)"
|
||||||
inputBorder: "Край поля вводу"
|
inputBorder: "Край поля вводу"
|
||||||
driveFolderBg: "Фон папки на диску"
|
driveFolderBg: "Фон папки на диску"
|
||||||
wallpaperOverlay: "Накладання шпалер"
|
|
||||||
badge: "Значок"
|
badge: "Значок"
|
||||||
messageBg: "Фон переписки"
|
messageBg: "Фон переписки"
|
||||||
accentDarken: "Акцент (Затемлений)"
|
|
||||||
accentLighten: "Акцент (Освітлений)"
|
|
||||||
fgHighlighted: "Виділений текст"
|
fgHighlighted: "Виділений текст"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Нотатки"
|
note: "Нотатки"
|
||||||
|
|
|
@ -907,8 +907,6 @@ _theme:
|
||||||
mention: "Murojat"
|
mention: "Murojat"
|
||||||
renote: "Qayta qayd etish"
|
renote: "Qayta qayd etish"
|
||||||
divider: "Ajratrmoq"
|
divider: "Ajratrmoq"
|
||||||
accentDarken: "Urg'u (Qoraytirilgan)"
|
|
||||||
accentLighten: "Urg'u (Yoritilgan)"
|
|
||||||
fgHighlighted: "Belgilangan matn"
|
fgHighlighted: "Belgilangan matn"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Qaydlar"
|
note: "Qaydlar"
|
||||||
|
|
|
@ -1530,7 +1530,6 @@ _theme:
|
||||||
header: "Ảnh bìa"
|
header: "Ảnh bìa"
|
||||||
navBg: "Nền thanh bên"
|
navBg: "Nền thanh bên"
|
||||||
navFg: "Chữ thanh bên"
|
navFg: "Chữ thanh bên"
|
||||||
navHoverFg: "Chữ thanh bên (Khi chạm)"
|
|
||||||
navActive: "Chữ thanh bên (Khi chọn)"
|
navActive: "Chữ thanh bên (Khi chọn)"
|
||||||
navIndicator: "Chỉ báo thanh bên"
|
navIndicator: "Chỉ báo thanh bên"
|
||||||
link: "Đường dẫn"
|
link: "Đường dẫn"
|
||||||
|
@ -1553,11 +1552,8 @@ _theme:
|
||||||
buttonHoverBg: "Nền nút (Chạm)"
|
buttonHoverBg: "Nền nút (Chạm)"
|
||||||
inputBorder: "Đường viền khung soạn thảo"
|
inputBorder: "Đường viền khung soạn thảo"
|
||||||
driveFolderBg: "Nền thư mục Ổ đĩa"
|
driveFolderBg: "Nền thư mục Ổ đĩa"
|
||||||
wallpaperOverlay: "Lớp phủ hình nền"
|
|
||||||
badge: "Huy hiệu"
|
badge: "Huy hiệu"
|
||||||
messageBg: "Nền chat"
|
messageBg: "Nền chat"
|
||||||
accentDarken: "Màu phụ (Tối)"
|
|
||||||
accentLighten: "Màu phụ (Sáng)"
|
|
||||||
fgHighlighted: "Chữ nổi bật"
|
fgHighlighted: "Chữ nổi bật"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Tút"
|
note: "Tút"
|
||||||
|
|
|
@ -424,6 +424,7 @@ antennaExcludeBots: "排除机器人账户"
|
||||||
antennaKeywordsDescription: "AND 条件用空格分隔,OR 条件用换行符分隔。"
|
antennaKeywordsDescription: "AND 条件用空格分隔,OR 条件用换行符分隔。"
|
||||||
notifyAntenna: "开启通知"
|
notifyAntenna: "开启通知"
|
||||||
withFileAntenna: "仅带有附件的帖子"
|
withFileAntenna: "仅带有附件的帖子"
|
||||||
|
excludeNotesInSensitiveChannel: "排除敏感频道内的帖子"
|
||||||
enableServiceworker: "启用 ServiceWorker"
|
enableServiceworker: "启用 ServiceWorker"
|
||||||
antennaUsersDescription: "指定用户名,一行一个"
|
antennaUsersDescription: "指定用户名,一行一个"
|
||||||
caseSensitive: "区分大小写"
|
caseSensitive: "区分大小写"
|
||||||
|
@ -978,6 +979,7 @@ document: "文档"
|
||||||
numberOfPageCache: "缓存页数"
|
numberOfPageCache: "缓存页数"
|
||||||
numberOfPageCacheDescription: "设置较高的值会更方便用户,但设备的负载和内存使用量会增加。"
|
numberOfPageCacheDescription: "设置较高的值会更方便用户,但设备的负载和内存使用量会增加。"
|
||||||
logoutConfirm: "是否确认登出?"
|
logoutConfirm: "是否确认登出?"
|
||||||
|
logoutWillClearClientData: "登出时将会从浏览器中删除客户端的设置信息。如果想要在再次登入时恢复设置信息,请在设置里打开自动备份。"
|
||||||
lastActiveDate: "最后活跃时间"
|
lastActiveDate: "最后活跃时间"
|
||||||
statusbar: "状态栏"
|
statusbar: "状态栏"
|
||||||
pleaseSelect: "请选择"
|
pleaseSelect: "请选择"
|
||||||
|
@ -1335,6 +1337,14 @@ information: "关于"
|
||||||
chat: "聊天"
|
chat: "聊天"
|
||||||
migrateOldSettings: "迁移旧设置信息"
|
migrateOldSettings: "迁移旧设置信息"
|
||||||
migrateOldSettings_description: "通常设置信息将自动迁移。但如果由于某种原因迁移不成功,则可以手动触发迁移过程。当前的配置信息将被覆盖。"
|
migrateOldSettings_description: "通常设置信息将自动迁移。但如果由于某种原因迁移不成功,则可以手动触发迁移过程。当前的配置信息将被覆盖。"
|
||||||
|
compress: "压缩"
|
||||||
|
right: "右"
|
||||||
|
bottom: "下"
|
||||||
|
top: "上"
|
||||||
|
embed: "嵌入"
|
||||||
|
settingsMigrating: "正在迁移设置,请稍候。(之后也可以在设置 → 其它 → 迁移旧设置来手动迁移)"
|
||||||
|
readonly: "只读"
|
||||||
|
goToDeck: "返回至 Deck"
|
||||||
_chat:
|
_chat:
|
||||||
noMessagesYet: "还没有消息"
|
noMessagesYet: "还没有消息"
|
||||||
newMessage: "新消息"
|
newMessage: "新消息"
|
||||||
|
@ -1363,6 +1373,9 @@ _chat:
|
||||||
newline: "换行"
|
newline: "换行"
|
||||||
muteThisRoom: "静音此房间"
|
muteThisRoom: "静音此房间"
|
||||||
deleteRoom: "删除房间"
|
deleteRoom: "删除房间"
|
||||||
|
chatNotAvailableForThisAccountOrServer: "此服务器或者账户还未开启聊天功能。"
|
||||||
|
chatIsReadOnlyForThisAccountOrServer: "此服务器或者账户内的聊天为只读。无法发布新信息或创建及加入群聊。"
|
||||||
|
chatNotAvailableInOtherAccount: "对方账户目前处于无法使用聊天的状态。"
|
||||||
cannotChatWithTheUser: "无法与此用户聊天"
|
cannotChatWithTheUser: "无法与此用户聊天"
|
||||||
cannotChatWithTheUser_description: "可能现在无法使用聊天,或者对方未开启聊天。"
|
cannotChatWithTheUser_description: "可能现在无法使用聊天,或者对方未开启聊天。"
|
||||||
chatWithThisUser: "聊天"
|
chatWithThisUser: "聊天"
|
||||||
|
@ -1403,6 +1416,7 @@ _settings:
|
||||||
timelineAndNote: "时间线和帖子"
|
timelineAndNote: "时间线和帖子"
|
||||||
makeEveryTextElementsSelectable: "使所有的文字均可选择"
|
makeEveryTextElementsSelectable: "使所有的文字均可选择"
|
||||||
makeEveryTextElementsSelectable_description: "若开启,在某些情况下可能降低用户体验。"
|
makeEveryTextElementsSelectable_description: "若开启,在某些情况下可能降低用户体验。"
|
||||||
|
useStickyIcons: "使图标跟随滚动"
|
||||||
showNavbarSubButtons: "在导航栏中显示副按钮"
|
showNavbarSubButtons: "在导航栏中显示副按钮"
|
||||||
ifOn: "启用时"
|
ifOn: "启用时"
|
||||||
ifOff: "关闭时"
|
ifOff: "关闭时"
|
||||||
|
@ -1878,6 +1892,8 @@ _role:
|
||||||
descriptionOfIsExplorable: "打开后将公开角色时间线。如果角色不是公开的,就无法公开时间线。"
|
descriptionOfIsExplorable: "打开后将公开角色时间线。如果角色不是公开的,就无法公开时间线。"
|
||||||
displayOrder: "显示顺序"
|
displayOrder: "显示顺序"
|
||||||
descriptionOfDisplayOrder: "数字越大,显示位置越靠前。"
|
descriptionOfDisplayOrder: "数字越大,显示位置越靠前。"
|
||||||
|
preserveAssignmentOnMoveAccount: "将分配状态继承到目标账户"
|
||||||
|
preserveAssignmentOnMoveAccount_description: "启用后,当迁移具有该角色的账户时,目标账户也会继承该角色。"
|
||||||
canEditMembersByModerator: "允许监察员编辑成员"
|
canEditMembersByModerator: "允许监察员编辑成员"
|
||||||
descriptionOfCanEditMembersByModerator: "如果选中,监察员和管理员都能够为用户分配/取消分配角色。如果未选中,则只有管理员可以执行此操作。"
|
descriptionOfCanEditMembersByModerator: "如果选中,监察员和管理员都能够为用户分配/取消分配角色。如果未选中,则只有管理员可以执行此操作。"
|
||||||
priority: "优先级"
|
priority: "优先级"
|
||||||
|
@ -1918,7 +1934,7 @@ _role:
|
||||||
canImportFollowing: "允许导入关注列表"
|
canImportFollowing: "允许导入关注列表"
|
||||||
canImportMuting: "允许导入隐藏列表"
|
canImportMuting: "允许导入隐藏列表"
|
||||||
canImportUserLists: "允许导入用户列表"
|
canImportUserLists: "允许导入用户列表"
|
||||||
canChat: "允许聊天"
|
chatAvailability: "允许聊天"
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "已分配给手动角色"
|
roleAssignedTo: "已分配给手动角色"
|
||||||
isLocal: "是本地用户"
|
isLocal: "是本地用户"
|
||||||
|
@ -2115,7 +2131,6 @@ _theme:
|
||||||
header: "顶栏"
|
header: "顶栏"
|
||||||
navBg: "侧边栏背景"
|
navBg: "侧边栏背景"
|
||||||
navFg: "侧栏文本"
|
navFg: "侧栏文本"
|
||||||
navHoverFg: "侧栏文本(悬停)"
|
|
||||||
navActive: "侧栏文本(活动)"
|
navActive: "侧栏文本(活动)"
|
||||||
navIndicator: "侧栏标记"
|
navIndicator: "侧栏标记"
|
||||||
link: "链接"
|
link: "链接"
|
||||||
|
@ -2138,11 +2153,8 @@ _theme:
|
||||||
buttonHoverBg: "按钮背景(悬停)"
|
buttonHoverBg: "按钮背景(悬停)"
|
||||||
inputBorder: "输入框边框"
|
inputBorder: "输入框边框"
|
||||||
driveFolderBg: "网盘的文件夹背景"
|
driveFolderBg: "网盘的文件夹背景"
|
||||||
wallpaperOverlay: "壁纸叠加层"
|
|
||||||
badge: "徽章"
|
badge: "徽章"
|
||||||
messageBg: "聊天背景"
|
messageBg: "聊天背景"
|
||||||
accentDarken: "强调色(深)"
|
|
||||||
accentLighten: "强调色(浅)"
|
|
||||||
fgHighlighted: "高亮显示文本"
|
fgHighlighted: "高亮显示文本"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "帖子"
|
note: "帖子"
|
||||||
|
@ -2356,6 +2368,7 @@ _widgets:
|
||||||
chooseList: "选择列表"
|
chooseList: "选择列表"
|
||||||
clicker: "点击器"
|
clicker: "点击器"
|
||||||
birthdayFollowings: "今天是他们的生日"
|
birthdayFollowings: "今天是他们的生日"
|
||||||
|
chat: "聊天"
|
||||||
_cw:
|
_cw:
|
||||||
hide: "隐藏"
|
hide: "隐藏"
|
||||||
show: "查看更多"
|
show: "查看更多"
|
||||||
|
@ -2589,6 +2602,9 @@ _notification:
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "总是显示主列"
|
alwaysShowMainColumn: "总是显示主列"
|
||||||
columnAlign: "列对齐"
|
columnAlign: "列对齐"
|
||||||
|
columnGap: "列间距"
|
||||||
|
deckMenuPosition: "Deck 菜单位置"
|
||||||
|
navbarPosition: "导航栏位置"
|
||||||
addColumn: "添加列"
|
addColumn: "添加列"
|
||||||
newNoteNotificationSettings: "新帖子通知设定"
|
newNoteNotificationSettings: "新帖子通知设定"
|
||||||
configureColumn: "列设置"
|
configureColumn: "列设置"
|
||||||
|
@ -2602,7 +2618,7 @@ _deck:
|
||||||
newProfile: "新建配置文件"
|
newProfile: "新建配置文件"
|
||||||
deleteProfile: "删除配置文件"
|
deleteProfile: "删除配置文件"
|
||||||
introduction: "将各列进行组合以创建您自己的界面!"
|
introduction: "将各列进行组合以创建您自己的界面!"
|
||||||
introduction2: "您可以随时通过屏幕右侧的 + 来添加列"
|
introduction2: "可以随时通过屏幕右侧的 + 来添加列"
|
||||||
widgetsIntroduction: "从列菜单中,选择“小工具编辑”来添加小工具"
|
widgetsIntroduction: "从列菜单中,选择“小工具编辑”来添加小工具"
|
||||||
useSimpleUiForNonRootPages: "用简易UI表示非根页面"
|
useSimpleUiForNonRootPages: "用简易UI表示非根页面"
|
||||||
usedAsMinWidthWhenFlexible: "「自适应宽度」被启用的时候,这就是最小的宽度"
|
usedAsMinWidthWhenFlexible: "「自适应宽度」被启用的时候,这就是最小的宽度"
|
||||||
|
@ -2619,6 +2635,7 @@ _deck:
|
||||||
mentions: "提及"
|
mentions: "提及"
|
||||||
direct: "指定用户"
|
direct: "指定用户"
|
||||||
roleTimeline: "角色时间线"
|
roleTimeline: "角色时间线"
|
||||||
|
chat: "聊天"
|
||||||
_dialog:
|
_dialog:
|
||||||
charactersExceeded: "已经超过了最大字符数! 当前字符数 {current} / 限制字符数 {max}"
|
charactersExceeded: "已经超过了最大字符数! 当前字符数 {current} / 限制字符数 {max}"
|
||||||
charactersBelow: "低于最小字符数!当前字符数 {current} / 限制字符数 {min}"
|
charactersBelow: "低于最小字符数!当前字符数 {current} / 限制字符数 {min}"
|
||||||
|
|
|
@ -424,6 +424,7 @@ antennaExcludeBots: "排除機器人帳戶"
|
||||||
antennaKeywordsDescription: "空格代表「以及」(AND),換行代表「或者」(OR)"
|
antennaKeywordsDescription: "空格代表「以及」(AND),換行代表「或者」(OR)"
|
||||||
notifyAntenna: "通知有新貼文"
|
notifyAntenna: "通知有新貼文"
|
||||||
withFileAntenna: "僅帶有附件的貼文"
|
withFileAntenna: "僅帶有附件的貼文"
|
||||||
|
excludeNotesInSensitiveChannel: "排除敏感頻道的貼文"
|
||||||
enableServiceworker: "啟用瀏覽器的推播通知"
|
enableServiceworker: "啟用瀏覽器的推播通知"
|
||||||
antennaUsersDescription: "填寫使用者名稱,以換行分隔"
|
antennaUsersDescription: "填寫使用者名稱,以換行分隔"
|
||||||
caseSensitive: "區分大小寫"
|
caseSensitive: "區分大小寫"
|
||||||
|
@ -978,6 +979,7 @@ document: "文件"
|
||||||
numberOfPageCache: "快取頁面數"
|
numberOfPageCache: "快取頁面數"
|
||||||
numberOfPageCacheDescription: "增加數量會提高便利性,但也會增加負荷與記憶體使用量。"
|
numberOfPageCacheDescription: "增加數量會提高便利性,但也會增加負荷與記憶體使用量。"
|
||||||
logoutConfirm: "確定要登出嗎?"
|
logoutConfirm: "確定要登出嗎?"
|
||||||
|
logoutWillClearClientData: "當您登出時,客戶端的設定資訊將從瀏覽器中清除。為了能夠在重新登入時恢復您的設定資訊,請啟用設定內的自動備份選項。"
|
||||||
lastActiveDate: "上次使用日期及時間"
|
lastActiveDate: "上次使用日期及時間"
|
||||||
statusbar: "狀態列"
|
statusbar: "狀態列"
|
||||||
pleaseSelect: "請選擇"
|
pleaseSelect: "請選擇"
|
||||||
|
@ -1307,7 +1309,7 @@ availableRoles: "可用角色"
|
||||||
acknowledgeNotesAndEnable: "了解注意事項後再開啟。"
|
acknowledgeNotesAndEnable: "了解注意事項後再開啟。"
|
||||||
federationSpecified: "此伺服器以白名單聯邦的方式運作。除了管理員指定的伺服器外,它無法與其他伺服器互動。"
|
federationSpecified: "此伺服器以白名單聯邦的方式運作。除了管理員指定的伺服器外,它無法與其他伺服器互動。"
|
||||||
federationDisabled: "此伺服器未開啟站台聯邦。無法與其他伺服器上的使用者互動。"
|
federationDisabled: "此伺服器未開啟站台聯邦。無法與其他伺服器上的使用者互動。"
|
||||||
confirmOnReact: "反應時確認"
|
confirmOnReact: "在做出反應前先確認"
|
||||||
reactAreYouSure: "用「 {emoji} 」反應嗎?"
|
reactAreYouSure: "用「 {emoji} 」反應嗎?"
|
||||||
markAsSensitiveConfirm: "要將這個媒體設定為敏感嗎?"
|
markAsSensitiveConfirm: "要將這個媒體設定為敏感嗎?"
|
||||||
unmarkAsSensitiveConfirm: "要解除這個媒體的敏感設定嗎?"
|
unmarkAsSensitiveConfirm: "要解除這個媒體的敏感設定嗎?"
|
||||||
|
@ -1335,6 +1337,13 @@ information: "關於"
|
||||||
chat: "聊天"
|
chat: "聊天"
|
||||||
migrateOldSettings: "遷移舊設定資訊"
|
migrateOldSettings: "遷移舊設定資訊"
|
||||||
migrateOldSettings_description: "通常情況下,這會自動進行,但若因某些原因未能順利遷移,您可以手動觸發遷移處理。請注意,當前的設定資訊將會被覆寫。"
|
migrateOldSettings_description: "通常情況下,這會自動進行,但若因某些原因未能順利遷移,您可以手動觸發遷移處理。請注意,當前的設定資訊將會被覆寫。"
|
||||||
|
compress: "壓縮"
|
||||||
|
right: "右"
|
||||||
|
bottom: "下"
|
||||||
|
top: "上"
|
||||||
|
embed: "嵌入"
|
||||||
|
settingsMigrating: "正在移轉設定。請稍候……(之後也可以到「設定 → 其他 → 舊設定資訊移轉」中手動進行移轉)"
|
||||||
|
readonly: "唯讀"
|
||||||
_chat:
|
_chat:
|
||||||
noMessagesYet: "尚無訊息"
|
noMessagesYet: "尚無訊息"
|
||||||
newMessage: "新訊息"
|
newMessage: "新訊息"
|
||||||
|
@ -1363,6 +1372,9 @@ _chat:
|
||||||
newline: "換行"
|
newline: "換行"
|
||||||
muteThisRoom: "此聊天室已靜音"
|
muteThisRoom: "此聊天室已靜音"
|
||||||
deleteRoom: "刪除聊天室"
|
deleteRoom: "刪除聊天室"
|
||||||
|
chatNotAvailableForThisAccountOrServer: "這個伺服器或這個帳號的聊天功能尚未啟用。"
|
||||||
|
chatIsReadOnlyForThisAccountOrServer: "在此伺服器或此帳戶上的聊天是唯讀的。您無法發布新訊息、建立或加入聊天室。"
|
||||||
|
chatNotAvailableInOtherAccount: "對方的帳號無法使用聊天功能。"
|
||||||
cannotChatWithTheUser: "無法與此使用者聊天"
|
cannotChatWithTheUser: "無法與此使用者聊天"
|
||||||
cannotChatWithTheUser_description: "聊天功能目前無法使用,或對方尚未開放聊天功能。"
|
cannotChatWithTheUser_description: "聊天功能目前無法使用,或對方尚未開放聊天功能。"
|
||||||
chatWithThisUser: "聊天"
|
chatWithThisUser: "聊天"
|
||||||
|
@ -1403,9 +1415,11 @@ _settings:
|
||||||
timelineAndNote: "時間軸及貼文"
|
timelineAndNote: "時間軸及貼文"
|
||||||
makeEveryTextElementsSelectable: "允許選取所有文字"
|
makeEveryTextElementsSelectable: "允許選取所有文字"
|
||||||
makeEveryTextElementsSelectable_description: "啟用此功能後,可能會在某些情境下降低可用性。"
|
makeEveryTextElementsSelectable_description: "啟用此功能後,可能會在某些情境下降低可用性。"
|
||||||
|
useStickyIcons: "使大頭貼跟隨捲動"
|
||||||
showNavbarSubButtons: "在導覽列顯示輔助按鈕"
|
showNavbarSubButtons: "在導覽列顯示輔助按鈕"
|
||||||
ifOn: "開啟時"
|
ifOn: "開啟時"
|
||||||
ifOff: "關閉時"
|
ifOff: "關閉時"
|
||||||
|
enableSyncThemesBetweenDevices: "在裝置之間同步已安裝的主題"
|
||||||
_chat:
|
_chat:
|
||||||
showSenderName: "顯示發送者的名稱"
|
showSenderName: "顯示發送者的名稱"
|
||||||
sendOnEnter: "按下 Enter 發送訊息"
|
sendOnEnter: "按下 Enter 發送訊息"
|
||||||
|
@ -1425,14 +1439,14 @@ _preferencesBackup:
|
||||||
_accountSettings:
|
_accountSettings:
|
||||||
requireSigninToViewContents: "須登入以顯示內容"
|
requireSigninToViewContents: "須登入以顯示內容"
|
||||||
requireSigninToViewContentsDescription1: "必須登入才會顯示您建立的貼文等內容。可望有效防止資訊被爬蟲蒐集。"
|
requireSigninToViewContentsDescription1: "必須登入才會顯示您建立的貼文等內容。可望有效防止資訊被爬蟲蒐集。"
|
||||||
requireSigninToViewContentsDescription2: "來自不支援 URL 預覽 (OGP)、 網頁嵌入和引用貼文的伺服器,也將停止顯示。"
|
requireSigninToViewContentsDescription2: "針對您貼文的 URL 預覽 (OGP) 與網頁嵌入功能將會無法使用。而不支援引用貼文的伺服器,也將停止顯示。"
|
||||||
requireSigninToViewContentsDescription3: "這些限制可能不適用於被聯邦發送至遠端伺服器的內容。"
|
requireSigninToViewContentsDescription3: "這些限制可能不適用於被聯邦發送至遠端伺服器的內容。"
|
||||||
makeNotesFollowersOnlyBefore: "讓過去的貼文僅對追隨者顯示"
|
makeNotesFollowersOnlyBefore: "讓過去的貼文僅對追隨者顯示"
|
||||||
makeNotesFollowersOnlyBeforeDescription: "啟用此功能後,超過設定的日期和時間或超過設定時間的貼文將僅對追隨者顯示。 如果您再次停用它,貼文的公開狀態也會恢復原狀。"
|
makeNotesFollowersOnlyBeforeDescription: "啟用此功能後,超過設定的日期和時間或超過設定時間的貼文將僅對追隨者顯示。 如果您再次停用它,貼文的公開狀態也會恢復原狀。"
|
||||||
makeNotesHiddenBefore: "隱藏過去的貼文"
|
makeNotesHiddenBefore: "隱藏過去的貼文"
|
||||||
makeNotesHiddenBeforeDescription: "啟用此功能後,超過設定的日期和時間或超過設定時間的貼文將僅對自己顯示(私密化)。 如果您再次停用它,貼文的公開狀態也會恢復原狀。"
|
makeNotesHiddenBeforeDescription: "啟用此功能後,超過設定的日期和時間或超過設定時間的貼文將僅對自己顯示(私密化)。 如果您再次停用它,貼文的公開狀態也會恢復原狀。"
|
||||||
mayNotEffectForFederatedNotes: "聯邦發送至遠端伺服器的貼文可能會不受影響。"
|
mayNotEffectForFederatedNotes: "聯邦發送至遠端伺服器的貼文可能會不受影響。"
|
||||||
mayNotEffectSomeSituations: "這些限制已經簡化。它們可能不適用於某些情況,例如在遠端伺服器上檢視或管理時。"
|
mayNotEffectSomeSituations: "這些限制僅是簡化版本。在某些情況下,例如在遠端伺服器上瀏覽或進行審核時,可能不會套用這些限制。"
|
||||||
notesHavePassedSpecifiedPeriod: "早於指定時間的貼文"
|
notesHavePassedSpecifiedPeriod: "早於指定時間的貼文"
|
||||||
notesOlderThanSpecifiedDateAndTime: "指定時間和日期之前的貼文"
|
notesOlderThanSpecifiedDateAndTime: "指定時間和日期之前的貼文"
|
||||||
_abuseUserReport:
|
_abuseUserReport:
|
||||||
|
@ -1878,6 +1892,8 @@ _role:
|
||||||
descriptionOfIsExplorable: "若開啟則公開角色時間軸。若角色不是公開的,則無法公開時間軸。"
|
descriptionOfIsExplorable: "若開啟則公開角色時間軸。若角色不是公開的,則無法公開時間軸。"
|
||||||
displayOrder: "顯示順序"
|
displayOrder: "顯示順序"
|
||||||
descriptionOfDisplayOrder: "數字越大,顯示在UI上的越上面。"
|
descriptionOfDisplayOrder: "數字越大,顯示在UI上的越上面。"
|
||||||
|
preserveAssignmentOnMoveAccount: "將指派狀態承接至轉移後的帳戶"
|
||||||
|
preserveAssignmentOnMoveAccount_description: "開啟此選項後,當具備此角色的帳戶被移轉時,該角色也會承接至轉移後的帳戶。"
|
||||||
canEditMembersByModerator: "允許編輯審查員的成員"
|
canEditMembersByModerator: "允許編輯審查員的成員"
|
||||||
descriptionOfCanEditMembersByModerator: "如果開啟,管理員與審查員都可以為使用者指派/解除指派該角色。如果關閉,則只有管理員可以執行。"
|
descriptionOfCanEditMembersByModerator: "如果開啟,管理員與審查員都可以為使用者指派/解除指派該角色。如果關閉,則只有管理員可以執行。"
|
||||||
priority: "優先級"
|
priority: "優先級"
|
||||||
|
@ -1918,7 +1934,7 @@ _role:
|
||||||
canImportFollowing: "允許匯入追隨名單"
|
canImportFollowing: "允許匯入追隨名單"
|
||||||
canImportMuting: "允許匯入靜音名單"
|
canImportMuting: "允許匯入靜音名單"
|
||||||
canImportUserLists: "允許匯入清單"
|
canImportUserLists: "允許匯入清單"
|
||||||
canChat: "允許聊天"
|
chatAvailability: "允許聊天"
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "手動指派角色完成"
|
roleAssignedTo: "手動指派角色完成"
|
||||||
isLocal: "本地使用者"
|
isLocal: "本地使用者"
|
||||||
|
@ -2115,7 +2131,6 @@ _theme:
|
||||||
header: "標題"
|
header: "標題"
|
||||||
navBg: "側邊欄的背景 "
|
navBg: "側邊欄的背景 "
|
||||||
navFg: "側邊欄的文字"
|
navFg: "側邊欄的文字"
|
||||||
navHoverFg: "側邊欄文字(懸浮) "
|
|
||||||
navActive: "側邊欄文字(活動)"
|
navActive: "側邊欄文字(活動)"
|
||||||
navIndicator: "側邊欄指示符"
|
navIndicator: "側邊欄指示符"
|
||||||
link: "連結"
|
link: "連結"
|
||||||
|
@ -2138,11 +2153,8 @@ _theme:
|
||||||
buttonHoverBg: "按鈕背景 (漂浮)"
|
buttonHoverBg: "按鈕背景 (漂浮)"
|
||||||
inputBorder: "輸入框邊框"
|
inputBorder: "輸入框邊框"
|
||||||
driveFolderBg: "雲端硬碟文件夾背景"
|
driveFolderBg: "雲端硬碟文件夾背景"
|
||||||
wallpaperOverlay: "壁紙覆蓋層"
|
|
||||||
badge: "徽章"
|
badge: "徽章"
|
||||||
messageBg: "私訊背景"
|
messageBg: "私訊背景"
|
||||||
accentDarken: "強調色(黑暗)"
|
|
||||||
accentLighten: "強調色(明亮)"
|
|
||||||
fgHighlighted: "突顯文字"
|
fgHighlighted: "突顯文字"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "貼文"
|
note: "貼文"
|
||||||
|
@ -2356,6 +2368,7 @@ _widgets:
|
||||||
chooseList: "選擇清單"
|
chooseList: "選擇清單"
|
||||||
clicker: "點擊器"
|
clicker: "點擊器"
|
||||||
birthdayFollowings: "今天生日的使用者"
|
birthdayFollowings: "今天生日的使用者"
|
||||||
|
chat: "聊天"
|
||||||
_cw:
|
_cw:
|
||||||
hide: "隱藏"
|
hide: "隱藏"
|
||||||
show: "顯示內容"
|
show: "顯示內容"
|
||||||
|
@ -2589,6 +2602,9 @@ _notification:
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "總是顯示主欄"
|
alwaysShowMainColumn: "總是顯示主欄"
|
||||||
columnAlign: "對齊欄位"
|
columnAlign: "對齊欄位"
|
||||||
|
columnGap: "欄與欄之間的邊距"
|
||||||
|
deckMenuPosition: "多欄模式的選單位置"
|
||||||
|
navbarPosition: "導覽列位置"
|
||||||
addColumn: "新增欄位"
|
addColumn: "新增欄位"
|
||||||
newNoteNotificationSettings: "新貼文通知的設定"
|
newNoteNotificationSettings: "新貼文通知的設定"
|
||||||
configureColumn: "欄位的設定"
|
configureColumn: "欄位的設定"
|
||||||
|
@ -2619,6 +2635,7 @@ _deck:
|
||||||
mentions: "提及"
|
mentions: "提及"
|
||||||
direct: "指定使用者"
|
direct: "指定使用者"
|
||||||
roleTimeline: "角色時間軸"
|
roleTimeline: "角色時間軸"
|
||||||
|
chat: "聊天"
|
||||||
_dialog:
|
_dialog:
|
||||||
charactersExceeded: "您的貼文太長了!現時字數 {current}/限制字數 {max}"
|
charactersExceeded: "您的貼文太長了!現時字數 {current}/限制字數 {max}"
|
||||||
charactersBelow: "您的貼文太短了!現時字數 {current}/限制字數 {min}"
|
charactersBelow: "您的貼文太短了!現時字數 {current}/限制字數 {min}"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "2025.3.2-beta.15",
|
"version": "2025.4.1-alpha.1",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -24,7 +24,6 @@
|
||||||
"build": "pnpm build-pre && pnpm -r build && pnpm build-assets",
|
"build": "pnpm build-pre && pnpm -r build && pnpm build-assets",
|
||||||
"build-storybook": "pnpm --filter frontend build-storybook",
|
"build-storybook": "pnpm --filter frontend build-storybook",
|
||||||
"build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
|
"build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
|
||||||
"build-frontend-search-index": "pnpm --filter frontend build-search-index",
|
|
||||||
"start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js",
|
"start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js",
|
||||||
"start:test": "ncp ./.github/misskey/test.yml ./.config/test.yml && cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js",
|
"start:test": "ncp ./.github/misskey/test.yml ./.config/test.yml && cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js",
|
||||||
"init": "pnpm migrate",
|
"init": "pnpm migrate",
|
||||||
|
@ -85,7 +84,8 @@
|
||||||
"@aiscript-dev/aiscript-languageserver": "-"
|
"@aiscript-dev/aiscript-languageserver": "-"
|
||||||
},
|
},
|
||||||
"patchedDependencies": {
|
"patchedDependencies": {
|
||||||
"re2": "scripts/dependency-patches/re2.patch"
|
"re2": "scripts/dependency-patches/re2.patch",
|
||||||
|
"vite": "scripts/dependency-patches/vite.patch"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class AddAntennaHideNotesInSensitiveChannel1736230492103 {
|
||||||
|
name = 'AddAntennaHideNotesInSensitiveChannel1736230492103'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "antenna" ADD "hideNotesInSensitiveChannel" boolean NOT NULL DEFAULT false`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "hideNotesInSensitiveChannel"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class RoleCopyOnMoveAccount1743558299182 {
|
||||||
|
name = 'RoleCopyOnMoveAccount1743558299182'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "role" ADD "preserveAssignmentOnMoveAccount" boolean NOT NULL DEFAULT false`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "role" DROP COLUMN "preserveAssignmentOnMoveAccount"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class ExcludeNotesInSensitiveChannel1744075766000 {
|
||||||
|
name = 'ExcludeNotesInSensitiveChannel1744075766000'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "antenna" RENAME COLUMN "hideNotesInSensitiveChannel" TO "excludeNotesInSensitiveChannel"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "antenna" RENAME COLUMN "excludeNotesInSensitiveChannel" TO "hideNotesInSensitiveChannel"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,17 +37,17 @@
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@swc/core-android-arm64": "1.3.11",
|
"@swc/core-android-arm64": "1.3.11",
|
||||||
"@swc/core-darwin-arm64": "1.11.11",
|
"@swc/core-darwin-arm64": "1.11.18",
|
||||||
"@swc/core-darwin-x64": "1.11.11",
|
"@swc/core-darwin-x64": "1.11.18",
|
||||||
"@swc/core-freebsd-x64": "1.3.11",
|
"@swc/core-freebsd-x64": "1.3.11",
|
||||||
"@swc/core-linux-arm-gnueabihf": "1.11.11",
|
"@swc/core-linux-arm-gnueabihf": "1.11.18",
|
||||||
"@swc/core-linux-arm64-gnu": "1.11.11",
|
"@swc/core-linux-arm64-gnu": "1.11.18",
|
||||||
"@swc/core-linux-arm64-musl": "1.11.11",
|
"@swc/core-linux-arm64-musl": "1.11.18",
|
||||||
"@swc/core-linux-x64-gnu": "1.11.11",
|
"@swc/core-linux-x64-gnu": "1.11.18",
|
||||||
"@swc/core-linux-x64-musl": "1.11.11",
|
"@swc/core-linux-x64-musl": "1.11.18",
|
||||||
"@swc/core-win32-arm64-msvc": "1.11.11",
|
"@swc/core-win32-arm64-msvc": "1.11.18",
|
||||||
"@swc/core-win32-ia32-msvc": "1.11.11",
|
"@swc/core-win32-ia32-msvc": "1.11.18",
|
||||||
"@swc/core-win32-x64-msvc": "1.11.11",
|
"@swc/core-win32-x64-msvc": "1.11.18",
|
||||||
"@tensorflow/tfjs": "4.22.0",
|
"@tensorflow/tfjs": "4.22.0",
|
||||||
"@tensorflow/tfjs-node": "4.22.0",
|
"@tensorflow/tfjs-node": "4.22.0",
|
||||||
"bufferutil": "4.0.9",
|
"bufferutil": "4.0.9",
|
||||||
|
@ -67,8 +67,8 @@
|
||||||
"utf-8-validate": "6.0.5"
|
"utf-8-validate": "6.0.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "3.772.0",
|
"@aws-sdk/client-s3": "3.782.0",
|
||||||
"@aws-sdk/lib-storage": "3.772.0",
|
"@aws-sdk/lib-storage": "3.782.0",
|
||||||
"@discordapp/twemoji": "15.1.0",
|
"@discordapp/twemoji": "15.1.0",
|
||||||
"@fastify/accepts": "5.0.2",
|
"@fastify/accepts": "5.0.2",
|
||||||
"@fastify/cookie": "11.0.2",
|
"@fastify/cookie": "11.0.2",
|
||||||
|
@ -78,12 +78,12 @@
|
||||||
"@fastify/multipart": "9.0.3",
|
"@fastify/multipart": "9.0.3",
|
||||||
"@fastify/static": "8.1.1",
|
"@fastify/static": "8.1.1",
|
||||||
"@fastify/view": "10.0.2",
|
"@fastify/view": "10.0.2",
|
||||||
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
"@misskey-dev/sharp-read-bmp": "1.3.0",
|
||||||
"@misskey-dev/summaly": "5.2.0",
|
"@misskey-dev/summaly": "5.2.0",
|
||||||
"@napi-rs/canvas": "0.1.68",
|
"@napi-rs/canvas": "0.1.69",
|
||||||
"@nestjs/common": "11.0.12",
|
"@nestjs/common": "11.0.16",
|
||||||
"@nestjs/core": "11.0.12",
|
"@nestjs/core": "11.0.15",
|
||||||
"@nestjs/testing": "11.0.12",
|
"@nestjs/testing": "11.0.15",
|
||||||
"@peertube/http-signature": "1.7.0",
|
"@peertube/http-signature": "1.7.0",
|
||||||
"@sentry/node": "8.55.0",
|
"@sentry/node": "8.55.0",
|
||||||
"@sentry/profiling-node": "8.55.0",
|
"@sentry/profiling-node": "8.55.0",
|
||||||
|
@ -91,7 +91,7 @@
|
||||||
"@sinonjs/fake-timers": "11.3.1",
|
"@sinonjs/fake-timers": "11.3.1",
|
||||||
"@smithy/node-http-handler": "2.5.0",
|
"@smithy/node-http-handler": "2.5.0",
|
||||||
"@swc/cli": "0.6.0",
|
"@swc/cli": "0.6.0",
|
||||||
"@swc/core": "1.11.11",
|
"@swc/core": "1.11.18",
|
||||||
"@twemoji/parser": "15.1.1",
|
"@twemoji/parser": "15.1.1",
|
||||||
"accepts": "1.3.8",
|
"accepts": "1.3.8",
|
||||||
"ajv": "8.17.1",
|
"ajv": "8.17.1",
|
||||||
|
@ -100,7 +100,7 @@
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"blurhash": "2.0.5",
|
"blurhash": "2.0.5",
|
||||||
"body-parser": "1.20.3",
|
"body-parser": "1.20.3",
|
||||||
"bullmq": "5.44.1",
|
"bullmq": "5.48.1",
|
||||||
"cacheable-lookup": "7.0.0",
|
"cacheable-lookup": "7.0.0",
|
||||||
"cbor": "9.0.2",
|
"cbor": "9.0.2",
|
||||||
"chalk": "5.4.1",
|
"chalk": "5.4.1",
|
||||||
|
@ -111,13 +111,13 @@
|
||||||
"content-disposition": "0.5.4",
|
"content-disposition": "0.5.4",
|
||||||
"date-fns": "2.30.0",
|
"date-fns": "2.30.0",
|
||||||
"deep-email-validator": "0.1.21",
|
"deep-email-validator": "0.1.21",
|
||||||
"fastify": "5.2.1",
|
"fastify": "5.2.2",
|
||||||
"fastify-raw-body": "5.0.0",
|
"fastify-raw-body": "5.0.0",
|
||||||
"feed": "4.2.2",
|
"feed": "4.2.2",
|
||||||
"file-type": "19.6.0",
|
"file-type": "19.6.0",
|
||||||
"fluent-ffmpeg": "2.1.3",
|
"fluent-ffmpeg": "2.1.3",
|
||||||
"form-data": "4.0.2",
|
"form-data": "4.0.2",
|
||||||
"got": "14.4.6",
|
"got": "14.4.7",
|
||||||
"happy-dom": "16.8.1",
|
"happy-dom": "16.8.1",
|
||||||
"hpagent": "1.2.0",
|
"hpagent": "1.2.0",
|
||||||
"htmlescape": "1.1.1",
|
"htmlescape": "1.1.1",
|
||||||
|
@ -148,7 +148,7 @@
|
||||||
"oauth2orize": "1.12.0",
|
"oauth2orize": "1.12.0",
|
||||||
"oauth2orize-pkce": "0.1.2",
|
"oauth2orize-pkce": "0.1.2",
|
||||||
"os-utils": "0.0.14",
|
"os-utils": "0.0.14",
|
||||||
"otpauth": "9.3.6",
|
"otpauth": "9.4.0",
|
||||||
"parse5": "7.2.1",
|
"parse5": "7.2.1",
|
||||||
"pg": "8.14.1",
|
"pg": "8.14.1",
|
||||||
"pkce-challenge": "4.1.0",
|
"pkce-challenge": "4.1.0",
|
||||||
|
@ -166,17 +166,17 @@
|
||||||
"rxjs": "7.8.2",
|
"rxjs": "7.8.2",
|
||||||
"sanitize-html": "2.15.0",
|
"sanitize-html": "2.15.0",
|
||||||
"secure-json-parse": "3.0.2",
|
"secure-json-parse": "3.0.2",
|
||||||
"sharp": "0.33.5",
|
"sharp": "0.34.1",
|
||||||
"slacc": "0.0.10",
|
"slacc": "0.0.10",
|
||||||
"strict-event-emitter-types": "2.0.0",
|
"strict-event-emitter-types": "2.0.0",
|
||||||
"stringz": "2.1.0",
|
"stringz": "2.1.0",
|
||||||
"systeminformation": "5.25.11",
|
"systeminformation": "5.25.11",
|
||||||
"tinycolor2": "1.6.0",
|
"tinycolor2": "1.6.0",
|
||||||
"tmp": "0.2.3",
|
"tmp": "0.2.3",
|
||||||
"tsc-alias": "1.8.11",
|
"tsc-alias": "1.8.15",
|
||||||
"tsconfig-paths": "4.2.0",
|
"tsconfig-paths": "4.2.0",
|
||||||
"typeorm": "0.3.21",
|
"typeorm": "0.3.22",
|
||||||
"typescript": "5.8.2",
|
"typescript": "5.8.3",
|
||||||
"ulid": "2.4.0",
|
"ulid": "2.4.0",
|
||||||
"vary": "1.1.2",
|
"vary": "1.1.2",
|
||||||
"web-push": "3.6.7",
|
"web-push": "3.6.7",
|
||||||
|
@ -186,6 +186,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@jest/globals": "29.7.0",
|
"@jest/globals": "29.7.0",
|
||||||
"@nestjs/platform-express": "10.4.15",
|
"@nestjs/platform-express": "10.4.15",
|
||||||
|
"@sentry/vue": "9.12.0",
|
||||||
"@simplewebauthn/types": "12.0.0",
|
"@simplewebauthn/types": "12.0.0",
|
||||||
"@swc/jest": "0.2.37",
|
"@swc/jest": "0.2.37",
|
||||||
"@types/accepts": "1.3.7",
|
"@types/accepts": "1.3.7",
|
||||||
|
@ -204,7 +205,7 @@
|
||||||
"@types/jsrsasign": "10.5.15",
|
"@types/jsrsasign": "10.5.15",
|
||||||
"@types/mime-types": "2.1.4",
|
"@types/mime-types": "2.1.4",
|
||||||
"@types/ms": "0.7.34",
|
"@types/ms": "0.7.34",
|
||||||
"@types/node": "22.13.10",
|
"@types/node": "22.14.0",
|
||||||
"@types/nodemailer": "6.4.17",
|
"@types/nodemailer": "6.4.17",
|
||||||
"@types/oauth": "0.9.6",
|
"@types/oauth": "0.9.6",
|
||||||
"@types/oauth2orize": "1.11.5",
|
"@types/oauth2orize": "1.11.5",
|
||||||
|
@ -215,17 +216,17 @@
|
||||||
"@types/random-seed": "0.3.5",
|
"@types/random-seed": "0.3.5",
|
||||||
"@types/ratelimiter": "3.4.6",
|
"@types/ratelimiter": "3.4.6",
|
||||||
"@types/rename": "1.0.7",
|
"@types/rename": "1.0.7",
|
||||||
"@types/sanitize-html": "2.13.0",
|
"@types/sanitize-html": "2.15.0",
|
||||||
"@types/semver": "7.5.8",
|
"@types/semver": "7.7.0",
|
||||||
"@types/simple-oauth2": "5.0.7",
|
"@types/simple-oauth2": "5.0.7",
|
||||||
"@types/sinonjs__fake-timers": "8.1.5",
|
"@types/sinonjs__fake-timers": "8.1.5",
|
||||||
"@types/tinycolor2": "1.4.6",
|
"@types/tinycolor2": "1.4.6",
|
||||||
"@types/tmp": "0.2.6",
|
"@types/tmp": "0.2.6",
|
||||||
"@types/vary": "1.1.3",
|
"@types/vary": "1.1.3",
|
||||||
"@types/web-push": "3.6.4",
|
"@types/web-push": "3.6.4",
|
||||||
"@types/ws": "8.18.0",
|
"@types/ws": "8.18.1",
|
||||||
"@typescript-eslint/eslint-plugin": "8.27.0",
|
"@typescript-eslint/eslint-plugin": "8.29.1",
|
||||||
"@typescript-eslint/parser": "8.27.0",
|
"@typescript-eslint/parser": "8.29.1",
|
||||||
"aws-sdk-client-mock": "4.1.0",
|
"aws-sdk-client-mock": "4.1.0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"eslint-plugin-import": "2.31.0",
|
"eslint-plugin-import": "2.31.0",
|
||||||
|
|
|
@ -7,7 +7,8 @@ import * as fs from 'node:fs';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { dirname, resolve } from 'node:path';
|
import { dirname, resolve } from 'node:path';
|
||||||
import * as yaml from 'js-yaml';
|
import * as yaml from 'js-yaml';
|
||||||
import * as Sentry from '@sentry/node';
|
import type * as Sentry from '@sentry/node';
|
||||||
|
import type * as SentryVue from '@sentry/vue';
|
||||||
import type { RedisOptions } from 'ioredis';
|
import type { RedisOptions } from 'ioredis';
|
||||||
|
|
||||||
type RedisOptionsSource = Partial<RedisOptions> & {
|
type RedisOptionsSource = Partial<RedisOptions> & {
|
||||||
|
@ -62,7 +63,12 @@ type Source = {
|
||||||
scope?: 'local' | 'global' | string[];
|
scope?: 'local' | 'global' | string[];
|
||||||
};
|
};
|
||||||
sentryForBackend?: { options: Partial<Sentry.NodeOptions>; enableNodeProfiling: boolean; };
|
sentryForBackend?: { options: Partial<Sentry.NodeOptions>; enableNodeProfiling: boolean; };
|
||||||
sentryForFrontend?: { options: Partial<Sentry.NodeOptions> };
|
sentryForFrontend?: {
|
||||||
|
options: Partial<SentryVue.BrowserOptions> & { dsn: string };
|
||||||
|
vueIntegration?: SentryVue.VueIntegrationOptions | null;
|
||||||
|
browserTracingIntegration?: Parameters<typeof SentryVue.browserTracingIntegration>[0] | null;
|
||||||
|
replayIntegration?: Parameters<typeof SentryVue.replayIntegration>[0] | null;
|
||||||
|
};
|
||||||
|
|
||||||
publishTarballInsteadOfProvideRepositoryUrl?: boolean;
|
publishTarballInsteadOfProvideRepositoryUrl?: boolean;
|
||||||
|
|
||||||
|
@ -198,7 +204,12 @@ export type Config = {
|
||||||
redisForTimelines: RedisOptions & RedisOptionsSource;
|
redisForTimelines: RedisOptions & RedisOptionsSource;
|
||||||
redisForReactions: RedisOptions & RedisOptionsSource;
|
redisForReactions: RedisOptions & RedisOptionsSource;
|
||||||
sentryForBackend: { options: Partial<Sentry.NodeOptions>; enableNodeProfiling: boolean; } | undefined;
|
sentryForBackend: { options: Partial<Sentry.NodeOptions>; enableNodeProfiling: boolean; } | undefined;
|
||||||
sentryForFrontend: { options: Partial<Sentry.NodeOptions> } | undefined;
|
sentryForFrontend: {
|
||||||
|
options: Partial<SentryVue.BrowserOptions> & { dsn: string };
|
||||||
|
vueIntegration?: SentryVue.VueIntegrationOptions | null;
|
||||||
|
browserTracingIntegration?: Parameters<typeof SentryVue.browserTracingIntegration>[0] | null;
|
||||||
|
replayIntegration?: Parameters<typeof SentryVue.replayIntegration>[0] | null;
|
||||||
|
} | undefined;
|
||||||
perChannelMaxNoteCacheCount: number;
|
perChannelMaxNoteCacheCount: number;
|
||||||
perUserNotificationsMaxCount: number;
|
perUserNotificationsMaxCount: number;
|
||||||
deactivateAntennaThreshold: number;
|
deactivateAntennaThreshold: number;
|
||||||
|
|
|
@ -24,6 +24,8 @@ import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
|
||||||
import InstanceChart from '@/core/chart/charts/instance.js';
|
import InstanceChart from '@/core/chart/charts/instance.js';
|
||||||
import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js';
|
import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js';
|
||||||
import { SystemAccountService } from '@/core/SystemAccountService.js';
|
import { SystemAccountService } from '@/core/SystemAccountService.js';
|
||||||
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
|
import { AntennaService } from '@/core/AntennaService.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AccountMoveService {
|
export class AccountMoveService {
|
||||||
|
@ -61,6 +63,8 @@ export class AccountMoveService {
|
||||||
private relayService: RelayService,
|
private relayService: RelayService,
|
||||||
private queueService: QueueService,
|
private queueService: QueueService,
|
||||||
private systemAccountService: SystemAccountService,
|
private systemAccountService: SystemAccountService,
|
||||||
|
private roleService: RoleService,
|
||||||
|
private antennaService: AntennaService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +123,9 @@ export class AccountMoveService {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.copyBlocking(src, dst),
|
this.copyBlocking(src, dst),
|
||||||
this.copyMutings(src, dst),
|
this.copyMutings(src, dst),
|
||||||
|
this.copyRoles(src, dst),
|
||||||
this.updateLists(src, dst),
|
this.updateLists(src, dst),
|
||||||
|
this.antennaService.onMoveAccount(src, dst),
|
||||||
]);
|
]);
|
||||||
} catch {
|
} catch {
|
||||||
/* skip if any error happens */
|
/* skip if any error happens */
|
||||||
|
@ -201,6 +207,32 @@ export class AccountMoveService {
|
||||||
await this.mutingsRepository.insert(arrayToInsert);
|
await this.mutingsRepository.insert(arrayToInsert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async copyRoles(src: ThinUser, dst: ThinUser): Promise<void> {
|
||||||
|
// Insert new roles with the same values except userId
|
||||||
|
// role service may have cache for roles so retrieve roles from service
|
||||||
|
const [oldRoleAssignments, roles] = await Promise.all([
|
||||||
|
this.roleService.getUserAssigns(src.id),
|
||||||
|
this.roleService.getRoles(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (oldRoleAssignments.length === 0) return;
|
||||||
|
|
||||||
|
// No promise all since the only async operation is writing to the database
|
||||||
|
for (const oldRoleAssignment of oldRoleAssignments) {
|
||||||
|
const role = roles.find(x => x.id === oldRoleAssignment.roleId);
|
||||||
|
if (role == null) continue; // Very unlikely however removing role may cause this case
|
||||||
|
if (!role.preserveAssignmentOnMoveAccount) continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.roleService.assign(dst.id, role.id, oldRoleAssignment.expiresAt);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof RoleService.AlreadyAssignedError) continue;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update lists while moving accounts.
|
* Update lists while moving accounts.
|
||||||
* - No removal of the old account from the lists
|
* - No removal of the old account from the lists
|
||||||
|
|
|
@ -5,18 +5,20 @@
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import * as Redis from 'ioredis';
|
import * as Redis from 'ioredis';
|
||||||
|
import { In } from 'typeorm';
|
||||||
|
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
|
||||||
|
import type { GlobalEvents } from '@/core/GlobalEventService.js';
|
||||||
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import * as Acct from '@/misc/acct.js';
|
||||||
|
import type { Packed } from '@/misc/json-schema.js';
|
||||||
|
import type { AntennasRepository, UserListMembershipsRepository } from '@/models/_.js';
|
||||||
import type { MiAntenna } from '@/models/Antenna.js';
|
import type { MiAntenna } from '@/models/Antenna.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { CacheService } from './CacheService.js';
|
||||||
import * as Acct from '@/misc/acct.js';
|
|
||||||
import type { Packed } from '@/misc/json-schema.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
|
||||||
import type { AntennasRepository, UserListMembershipsRepository } from '@/models/_.js';
|
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import type { GlobalEvents } from '@/core/GlobalEventService.js';
|
|
||||||
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
|
|
||||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -37,6 +39,7 @@ export class AntennaService implements OnApplicationShutdown {
|
||||||
@Inject(DI.userListMembershipsRepository)
|
@Inject(DI.userListMembershipsRepository)
|
||||||
private userListMembershipsRepository: UserListMembershipsRepository,
|
private userListMembershipsRepository: UserListMembershipsRepository,
|
||||||
|
|
||||||
|
private cacheService: CacheService,
|
||||||
private utilityService: UtilityService,
|
private utilityService: UtilityService,
|
||||||
private globalEventService: GlobalEventService,
|
private globalEventService: GlobalEventService,
|
||||||
private fanoutTimelineService: FanoutTimelineService,
|
private fanoutTimelineService: FanoutTimelineService,
|
||||||
|
@ -111,8 +114,7 @@ export class AntennaService implements OnApplicationShutdown {
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async checkHitAntenna(antenna: MiAntenna, note: (MiNote | Packed<'Note'>), noteUser: { id: MiUser['id']; username: string; host: string | null; isBot: boolean; }): Promise<boolean> {
|
public async checkHitAntenna(antenna: MiAntenna, note: (MiNote | Packed<'Note'>), noteUser: { id: MiUser['id']; username: string; host: string | null; isBot: boolean; }): Promise<boolean> {
|
||||||
if (note.visibility === 'specified') return false;
|
if (antenna.excludeNotesInSensitiveChannel && note.channel?.isSensitive) return false;
|
||||||
if (note.visibility === 'followers') return false;
|
|
||||||
|
|
||||||
if (antenna.excludeBots && noteUser.isBot) return false;
|
if (antenna.excludeBots && noteUser.isBot) return false;
|
||||||
|
|
||||||
|
@ -120,6 +122,18 @@ export class AntennaService implements OnApplicationShutdown {
|
||||||
|
|
||||||
if (!antenna.withReplies && note.replyId != null) return false;
|
if (!antenna.withReplies && note.replyId != null) return false;
|
||||||
|
|
||||||
|
if (note.visibility === 'specified') {
|
||||||
|
if (note.userId !== antenna.userId) {
|
||||||
|
if (note.visibleUserIds == null) return false;
|
||||||
|
if (!note.visibleUserIds.includes(antenna.userId)) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (note.visibility === 'followers') {
|
||||||
|
const isFollowing = Object.hasOwn(await this.cacheService.userFollowingsCache.fetch(antenna.userId), note.userId);
|
||||||
|
if (!isFollowing && antenna.userId !== note.userId) return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (antenna.src === 'home') {
|
if (antenna.src === 'home') {
|
||||||
// TODO
|
// TODO
|
||||||
} else if (antenna.src === 'list') {
|
} else if (antenna.src === 'list') {
|
||||||
|
@ -206,6 +220,41 @@ export class AntennaService implements OnApplicationShutdown {
|
||||||
return this.antennas;
|
return this.antennas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async onMoveAccount(src: MiUser, dst: MiUser): Promise<void> {
|
||||||
|
// There is a possibility for users to add the srcUser to their antennas, but it's low, so we don't check it.
|
||||||
|
|
||||||
|
// Get MiAntenna[] from cache and filter to select antennas with the src user is in the users list
|
||||||
|
const srcUserAcct = this.utilityService.getFullApAccount(src.username, src.host).toLowerCase();
|
||||||
|
const antennasToMigrate = (await this.getAntennas()).filter(antenna => {
|
||||||
|
return antenna.users.some(user => {
|
||||||
|
const { username, host } = Acct.parse(user);
|
||||||
|
return this.utilityService.getFullApAccount(username, host).toLowerCase() === srcUserAcct;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (antennasToMigrate.length === 0) return;
|
||||||
|
|
||||||
|
const antennaIds = antennasToMigrate.map(x => x.id);
|
||||||
|
|
||||||
|
// Update the antennas by appending dst users acct to the users list
|
||||||
|
const dstUserAcct = '@' + Acct.toString({ username: dst.username, host: dst.host });
|
||||||
|
|
||||||
|
await this.antennasRepository.createQueryBuilder('antenna')
|
||||||
|
.update()
|
||||||
|
.set({
|
||||||
|
users: () => 'array_append(antenna.users, :dstUserAcct)',
|
||||||
|
})
|
||||||
|
.where('antenna.id IN (:...antennaIds)', { antennaIds })
|
||||||
|
.setParameters({ dstUserAcct })
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
// announce update to event
|
||||||
|
for (const newAntenna of await this.antennasRepository.findBy({ id: In(antennaIds) })) {
|
||||||
|
this.globalEventService.publishInternalEvent('antennaUpdated', newAntenna);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
this.redisForSub.off('message', this.onRedisMessage);
|
this.redisForSub.off('message', this.onRedisMessage);
|
||||||
|
|
|
@ -94,12 +94,46 @@ export class ChatService {
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async getChatAvailability(userId: MiUser['id']): Promise<{ read: boolean; write: boolean; }> {
|
||||||
|
const policies = await this.roleService.getUserPolicies(userId);
|
||||||
|
|
||||||
|
switch (policies.chatAvailability) {
|
||||||
|
case 'available':
|
||||||
|
return {
|
||||||
|
read: true,
|
||||||
|
write: true,
|
||||||
|
};
|
||||||
|
case 'readonly':
|
||||||
|
return {
|
||||||
|
read: true,
|
||||||
|
write: false,
|
||||||
|
};
|
||||||
|
case 'unavailable':
|
||||||
|
return {
|
||||||
|
read: false,
|
||||||
|
write: false,
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
throw new Error('invalid chat availability (unreachable)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** getChatAvailabilityの糖衣。主にAPI呼び出し時に走らせて、権限的に問題ない場合はそのまま続行する */
|
||||||
|
@bindThis
|
||||||
|
public async checkChatAvailability(userId: MiUser['id'], permission: 'read' | 'write') {
|
||||||
|
const policy = await this.getChatAvailability(userId);
|
||||||
|
if (policy[permission] === false) {
|
||||||
|
throw new Error('ROLE_PERMISSION_DENIED');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async createMessageToUser(fromUser: { id: MiUser['id']; host: MiUser['host']; }, toUser: MiUser, params: {
|
public async createMessageToUser(fromUser: { id: MiUser['id']; host: MiUser['host']; }, toUser: MiUser, params: {
|
||||||
text?: string | null;
|
text?: string | null;
|
||||||
file?: MiDriveFile | null;
|
file?: MiDriveFile | null;
|
||||||
uri?: string | null;
|
uri?: string | null;
|
||||||
}): Promise<Packed<'ChatMessageLite'>> {
|
}): Promise<Packed<'ChatMessageLiteFor1on1'>> {
|
||||||
if (fromUser.id === toUser.id) {
|
if (fromUser.id === toUser.id) {
|
||||||
throw new Error('yourself');
|
throw new Error('yourself');
|
||||||
}
|
}
|
||||||
|
@ -140,7 +174,7 @@ export class ChatService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(await this.roleService.getUserPolicies(toUser.id)).canChat) {
|
if (!(await this.getChatAvailability(toUser.id)).write) {
|
||||||
throw new Error('recipient is cannot chat (policy)');
|
throw new Error('recipient is cannot chat (policy)');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +232,7 @@ export class ChatService {
|
||||||
|
|
||||||
const packedMessageForTo = await this.chatEntityService.packMessageDetailed(inserted, toUser);
|
const packedMessageForTo = await this.chatEntityService.packMessageDetailed(inserted, toUser);
|
||||||
this.globalEventService.publishMainStream(toUser.id, 'newChatMessage', packedMessageForTo);
|
this.globalEventService.publishMainStream(toUser.id, 'newChatMessage', packedMessageForTo);
|
||||||
//this.pushNotificationService.pushNotification(toUser.id, 'newChatMessage', packedMessageForTo);
|
this.pushNotificationService.pushNotification(toUser.id, 'newChatMessage', packedMessageForTo);
|
||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,10 +244,16 @@ export class ChatService {
|
||||||
text?: string | null;
|
text?: string | null;
|
||||||
file?: MiDriveFile | null;
|
file?: MiDriveFile | null;
|
||||||
uri?: string | null;
|
uri?: string | null;
|
||||||
}): Promise<Packed<'ChatMessageLite'>> {
|
}): Promise<Packed<'ChatMessageLiteForRoom'>> {
|
||||||
const memberships = await this.chatRoomMembershipsRepository.findBy({ roomId: toRoom.id });
|
const memberships = (await this.chatRoomMembershipsRepository.findBy({ roomId: toRoom.id })).map(m => ({
|
||||||
|
userId: m.userId,
|
||||||
|
isMuted: m.isMuted,
|
||||||
|
})).concat({ // ownerはmembershipレコードを作らないため
|
||||||
|
userId: toRoom.ownerId,
|
||||||
|
isMuted: false,
|
||||||
|
});
|
||||||
|
|
||||||
if (toRoom.ownerId !== fromUser.id && !memberships.some(member => member.userId === fromUser.id)) {
|
if (!memberships.some(member => member.userId === fromUser.id)) {
|
||||||
throw new Error('you are not a member of the room');
|
throw new Error('you are not a member of the room');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +302,7 @@ export class ChatService {
|
||||||
if (marker == null) continue;
|
if (marker == null) continue;
|
||||||
|
|
||||||
this.globalEventService.publishMainStream(membershipsOtherThanMe[i].userId, 'newChatMessage', packedMessageForTo);
|
this.globalEventService.publishMainStream(membershipsOtherThanMe[i].userId, 'newChatMessage', packedMessageForTo);
|
||||||
//this.pushNotificationService.pushNotification(membershipsOtherThanMe[i].userId, 'newChatMessage', packedMessageForTo);
|
this.pushNotificationService.pushNotification(membershipsOtherThanMe[i].userId, 'newChatMessage', packedMessageForTo);
|
||||||
}
|
}
|
||||||
}, 3000);
|
}, 3000);
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ export class FanoutTimelineEndpointService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async getMiNotes(ps: TimelineOptions): Promise<MiNote[]> {
|
async getMiNotes(ps: TimelineOptions): Promise<MiNote[]> {
|
||||||
// 呼び出し元と以下の処理をシンプルにするためにdbFallbackを置き換える
|
// 呼び出し元と以下の処理をシンプルにするためにdbFallbackを置き換える
|
||||||
if (!ps.useDbFallback) ps.dbFallback = () => Promise.resolve([]);
|
if (!ps.useDbFallback) ps.dbFallback = () => Promise.resolve([]);
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,13 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { ulid } from 'ulid';
|
import { ulid } from 'ulid';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { genAid, isSafeAidT, parseAid } from '@/misc/id/aid.js';
|
import { genAid, isSafeAidT, parseAid, parseAidFull } from '@/misc/id/aid.js';
|
||||||
import { genAidx, isSafeAidxT, parseAidx } from '@/misc/id/aidx.js';
|
import { genAidx, isSafeAidxT, parseAidx, parseAidxFull } from '@/misc/id/aidx.js';
|
||||||
import { genMeid, isSafeMeidT, parseMeid } from '@/misc/id/meid.js';
|
import { genMeid, isSafeMeidT, parseMeid, parseMeidFull } from '@/misc/id/meid.js';
|
||||||
import { genMeidg, isSafeMeidgT, parseMeidg } from '@/misc/id/meidg.js';
|
import { genMeidg, isSafeMeidgT, parseMeidg, parseMeidgFull } from '@/misc/id/meidg.js';
|
||||||
import { genObjectId, isSafeObjectIdT, parseObjectId } from '@/misc/id/object-id.js';
|
import { genObjectId, isSafeObjectIdT, parseObjectId, parseObjectIdFull } from '@/misc/id/object-id.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { parseUlid } from '@/misc/id/ulid.js';
|
import { parseUlid, parseUlidFull } from '@/misc/id/ulid.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class IdService {
|
export class IdService {
|
||||||
|
@ -70,4 +70,18 @@ export class IdService {
|
||||||
default: throw new Error('unrecognized id generation method');
|
default: throw new Error('unrecognized id generation method');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: additional is at most 64 bits
|
||||||
|
@bindThis
|
||||||
|
public parseFull(id: string): { date: number; additional: bigint; } {
|
||||||
|
switch (this.method) {
|
||||||
|
case 'aid': return parseAidFull(id);
|
||||||
|
case 'aidx': return parseAidxFull(id);
|
||||||
|
case 'objectid': return parseObjectIdFull(id);
|
||||||
|
case 'meid': return parseMeidFull(id);
|
||||||
|
case 'meidg': return parseMeidgFull(id);
|
||||||
|
case 'ulid': return parseUlidFull(id);
|
||||||
|
default: throw new Error('unrecognized id generation method');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
import { URL } from 'node:url';
|
import { URL } from 'node:url';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import * as parse5 from 'parse5';
|
import * as parse5 from 'parse5';
|
||||||
import { Window, XMLSerializer } from 'happy-dom';
|
import { type Document, type HTMLParagraphElement, Window, XMLSerializer } from 'happy-dom';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { intersperse } from '@/misc/prelude/array.js';
|
import { intersperse } from '@/misc/prelude/array.js';
|
||||||
|
@ -23,6 +23,8 @@ type ChildNode = DefaultTreeAdapterMap['childNode'];
|
||||||
const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/;
|
const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/;
|
||||||
const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/;
|
const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/;
|
||||||
|
|
||||||
|
export type Appender = (document: Document, body: HTMLParagraphElement) => void;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MfmService {
|
export class MfmService {
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -267,7 +269,7 @@ export class MfmService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public toHtml(nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMentionedRemoteUsers = []) {
|
public toHtml(nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMentionedRemoteUsers = [], additionalAppenders: Appender[] = []) {
|
||||||
if (nodes == null) {
|
if (nodes == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -492,6 +494,10 @@ export class MfmService {
|
||||||
|
|
||||||
appendChildren(nodes, body);
|
appendChildren(nodes, body);
|
||||||
|
|
||||||
|
for (const additionalAppender of additionalAppenders) {
|
||||||
|
additionalAppender(doc, body);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove the unnecessary namespace
|
// Remove the unnecessary namespace
|
||||||
const serialized = new XMLSerializer().serializeToString(body).replace(/^\s*<p xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">/, '<p>');
|
const serialized = new XMLSerializer().serializeToString(body).replace(/^\s*<p xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">/, '<p>');
|
||||||
|
|
||||||
|
|
|
@ -532,7 +532,10 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
|
|
||||||
this.pushToTl(note, user);
|
this.pushToTl(note, user);
|
||||||
|
|
||||||
this.antennaService.addNoteToAntennas(note, user);
|
this.antennaService.addNoteToAntennas({
|
||||||
|
...note,
|
||||||
|
channel: data.channel ?? null,
|
||||||
|
}, user);
|
||||||
|
|
||||||
if (data.reply) {
|
if (data.reply) {
|
||||||
this.saveReply(data.reply, note);
|
this.saveReply(data.reply, note);
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { setTimeout } from 'node:timers/promises';
|
||||||
import * as Redis from 'ioredis';
|
import * as Redis from 'ioredis';
|
||||||
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
|
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
|
import { ReplyError } from 'ioredis';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { UsersRepository } from '@/models/_.js';
|
import type { UsersRepository } from '@/models/_.js';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
|
@ -19,7 +20,7 @@ import { IdService } from '@/core/IdService.js';
|
||||||
import { CacheService } from '@/core/CacheService.js';
|
import { CacheService } from '@/core/CacheService.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { UserListService } from '@/core/UserListService.js';
|
import { UserListService } from '@/core/UserListService.js';
|
||||||
import type { FilterUnionByProperty } from '@/types.js';
|
import { FilterUnionByProperty, groupedNotificationTypes, obsoleteNotificationTypes } from '@/types.js';
|
||||||
import { trackPromise } from '@/misc/promise-tracker.js';
|
import { trackPromise } from '@/misc/promise-tracker.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -145,21 +146,36 @@ export class NotificationService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const notification = {
|
const createdAt = new Date();
|
||||||
id: this.idService.gen(),
|
let notification: FilterUnionByProperty<MiNotification, 'type', T>;
|
||||||
createdAt: new Date(),
|
let redisId: string;
|
||||||
type: type,
|
|
||||||
...(notifierId ? {
|
|
||||||
notifierId,
|
|
||||||
} : {}),
|
|
||||||
...data,
|
|
||||||
} as any as FilterUnionByProperty<MiNotification, 'type', T>;
|
|
||||||
|
|
||||||
const redisIdPromise = this.redisClient.xadd(
|
do {
|
||||||
`notificationTimeline:${notifieeId}`,
|
notification = {
|
||||||
'MAXLEN', '~', this.config.perUserNotificationsMaxCount.toString(),
|
id: this.idService.gen(),
|
||||||
'*',
|
createdAt,
|
||||||
'data', JSON.stringify(notification));
|
type: type,
|
||||||
|
...(notifierId ? {
|
||||||
|
notifierId,
|
||||||
|
} : {}),
|
||||||
|
...data,
|
||||||
|
} as unknown as FilterUnionByProperty<MiNotification, 'type', T>;
|
||||||
|
|
||||||
|
try {
|
||||||
|
redisId = (await this.redisClient.xadd(
|
||||||
|
`notificationTimeline:${notifieeId}`,
|
||||||
|
'MAXLEN', '~', this.config.perUserNotificationsMaxCount.toString(),
|
||||||
|
this.toXListId(notification.id),
|
||||||
|
'data', JSON.stringify(notification)))!;
|
||||||
|
} catch (e) {
|
||||||
|
// The ID specified in XADD is equal or smaller than the target stream top item で失敗することがあるのでリトライ
|
||||||
|
if (e instanceof ReplyError) continue;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
|
} while (true);
|
||||||
|
|
||||||
const packed = await this.notificationEntityService.pack(notification, notifieeId, {});
|
const packed = await this.notificationEntityService.pack(notification, notifieeId, {});
|
||||||
|
|
||||||
|
@ -173,7 +189,7 @@ export class NotificationService implements OnApplicationShutdown {
|
||||||
const interval = notification.type === 'test' ? 0 : 2000;
|
const interval = notification.type === 'test' ? 0 : 2000;
|
||||||
setTimeout(interval, 'unread notification', { signal: this.#shutdownController.signal }).then(async () => {
|
setTimeout(interval, 'unread notification', { signal: this.#shutdownController.signal }).then(async () => {
|
||||||
const latestReadNotificationId = await this.redisClient.get(`latestReadNotification:${notifieeId}`);
|
const latestReadNotificationId = await this.redisClient.get(`latestReadNotification:${notifieeId}`);
|
||||||
if (latestReadNotificationId && (latestReadNotificationId >= (await redisIdPromise)!)) return;
|
if (latestReadNotificationId && (latestReadNotificationId >= redisId)) return;
|
||||||
|
|
||||||
this.globalEventService.publishMainStream(notifieeId, 'unreadNotification', packed);
|
this.globalEventService.publishMainStream(notifieeId, 'unreadNotification', packed);
|
||||||
this.pushNotificationService.pushNotification(notifieeId, 'notification', packed);
|
this.pushNotificationService.pushNotification(notifieeId, 'notification', packed);
|
||||||
|
@ -228,6 +244,79 @@ export class NotificationService implements OnApplicationShutdown {
|
||||||
this.#shutdownController.abort();
|
this.#shutdownController.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private toXListId(id: string): string {
|
||||||
|
const { date, additional } = this.idService.parseFull(id);
|
||||||
|
return date.toString() + '-' + additional.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async getNotifications(
|
||||||
|
userId: MiUser['id'],
|
||||||
|
{
|
||||||
|
sinceId,
|
||||||
|
untilId,
|
||||||
|
limit = 20,
|
||||||
|
includeTypes,
|
||||||
|
excludeTypes,
|
||||||
|
}: {
|
||||||
|
sinceId?: string,
|
||||||
|
untilId?: string,
|
||||||
|
limit?: number,
|
||||||
|
// any extra types are allowed, those are no-op
|
||||||
|
includeTypes?: (MiNotification['type'] | string)[],
|
||||||
|
excludeTypes?: (MiNotification['type'] | string)[],
|
||||||
|
},
|
||||||
|
): Promise<MiNotification[]> {
|
||||||
|
let sinceTime = sinceId ? this.toXListId(sinceId) : null;
|
||||||
|
let untilTime = untilId ? this.toXListId(untilId) : null;
|
||||||
|
|
||||||
|
let notifications: MiNotification[];
|
||||||
|
for (;;) {
|
||||||
|
let notificationsRes: [id: string, fields: string[]][];
|
||||||
|
|
||||||
|
// sinceidのみの場合は古い順、そうでない場合は新しい順。 QueryService.makePaginationQueryも参照
|
||||||
|
if (sinceTime && !untilTime) {
|
||||||
|
notificationsRes = await this.redisClient.xrange(
|
||||||
|
`notificationTimeline:${userId}`,
|
||||||
|
'(' + sinceTime,
|
||||||
|
'+',
|
||||||
|
'COUNT', limit);
|
||||||
|
} else {
|
||||||
|
notificationsRes = await this.redisClient.xrevrange(
|
||||||
|
`notificationTimeline:${userId}`,
|
||||||
|
untilTime ? '(' + untilTime : '+',
|
||||||
|
sinceTime ? '(' + sinceTime : '-',
|
||||||
|
'COUNT', limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notificationsRes.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
notifications = notificationsRes.map(x => JSON.parse(x[1][1])) as MiNotification[];
|
||||||
|
|
||||||
|
if (includeTypes && includeTypes.length > 0) {
|
||||||
|
notifications = notifications.filter(notification => includeTypes.includes(notification.type));
|
||||||
|
} else if (excludeTypes && excludeTypes.length > 0) {
|
||||||
|
notifications = notifications.filter(notification => !excludeTypes.includes(notification.type));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notifications.length !== 0) {
|
||||||
|
// 通知が1件以上ある場合は返す
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// フィルタしたことで通知が0件になった場合、次のページを取得する
|
||||||
|
if (sinceId && !untilId) {
|
||||||
|
sinceTime = notificationsRes[notificationsRes.length - 1][0];
|
||||||
|
} else {
|
||||||
|
untilTime = notificationsRes[notificationsRes.length - 1][0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return notifications;
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public onApplicationShutdown(signal?: string | undefined): void {
|
public onApplicationShutdown(signal?: string | undefined): void {
|
||||||
this.dispose();
|
this.dispose();
|
||||||
|
|
|
@ -22,6 +22,7 @@ type PushNotificationsTypes = {
|
||||||
note: Packed<'Note'>;
|
note: Packed<'Note'>;
|
||||||
};
|
};
|
||||||
'readAllNotifications': undefined;
|
'readAllNotifications': undefined;
|
||||||
|
newChatMessage: Packed<'ChatMessage'>;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reduce length because push message servers have character limits
|
// Reduce length because push message servers have character limits
|
||||||
|
|
|
@ -63,7 +63,7 @@ export type RolePolicies = {
|
||||||
canImportFollowing: boolean;
|
canImportFollowing: boolean;
|
||||||
canImportMuting: boolean;
|
canImportMuting: boolean;
|
||||||
canImportUserLists: boolean;
|
canImportUserLists: boolean;
|
||||||
canChat: boolean;
|
chatAvailability: 'available' | 'readonly' | 'unavailable';
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_POLICIES: RolePolicies = {
|
export const DEFAULT_POLICIES: RolePolicies = {
|
||||||
|
@ -98,7 +98,7 @@ export const DEFAULT_POLICIES: RolePolicies = {
|
||||||
canImportFollowing: true,
|
canImportFollowing: true,
|
||||||
canImportMuting: true,
|
canImportMuting: true,
|
||||||
canImportUserLists: true,
|
canImportUserLists: true,
|
||||||
canChat: true,
|
chatAvailability: 'available',
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -370,6 +370,12 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||||
return aggregate(policies.map(policy => policy.useDefault ? basePolicies[name] : policy.value));
|
return aggregate(policies.map(policy => policy.useDefault ? basePolicies[name] : policy.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function aggregateChatAvailability(vs: RolePolicies['chatAvailability'][]) {
|
||||||
|
if (vs.some(v => v === 'available')) return 'available';
|
||||||
|
if (vs.some(v => v === 'readonly')) return 'readonly';
|
||||||
|
return 'unavailable';
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
gtlAvailable: calc('gtlAvailable', vs => vs.some(v => v === true)),
|
gtlAvailable: calc('gtlAvailable', vs => vs.some(v => v === true)),
|
||||||
ltlAvailable: calc('ltlAvailable', vs => vs.some(v => v === true)),
|
ltlAvailable: calc('ltlAvailable', vs => vs.some(v => v === true)),
|
||||||
|
@ -402,7 +408,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||||
canImportFollowing: calc('canImportFollowing', vs => vs.some(v => v === true)),
|
canImportFollowing: calc('canImportFollowing', vs => vs.some(v => v === true)),
|
||||||
canImportMuting: calc('canImportMuting', vs => vs.some(v => v === true)),
|
canImportMuting: calc('canImportMuting', vs => vs.some(v => v === true)),
|
||||||
canImportUserLists: calc('canImportUserLists', vs => vs.some(v => v === true)),
|
canImportUserLists: calc('canImportUserLists', vs => vs.some(v => v === true)),
|
||||||
canChat: calc('canChat', vs => vs.some(v => v === true)),
|
chatAvailability: calc('chatAvailability', aggregateChatAvailability),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,6 +636,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||||
isModerator: values.isModerator,
|
isModerator: values.isModerator,
|
||||||
isExplorable: values.isExplorable,
|
isExplorable: values.isExplorable,
|
||||||
asBadge: values.asBadge,
|
asBadge: values.asBadge,
|
||||||
|
preserveAssignmentOnMoveAccount: values.preserveAssignmentOnMoveAccount,
|
||||||
canEditMembersByModerator: values.canEditMembersByModerator,
|
canEditMembersByModerator: values.canEditMembersByModerator,
|
||||||
displayOrder: values.displayOrder,
|
displayOrder: values.displayOrder,
|
||||||
policies: values.policies,
|
policies: values.policies,
|
||||||
|
|
|
@ -5,11 +5,14 @@
|
||||||
|
|
||||||
import { randomUUID } from 'node:crypto';
|
import { randomUUID } from 'node:crypto';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||||
import { DataSource, IsNull } from 'typeorm';
|
import { DataSource, IsNull } from 'typeorm';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import bcrypt from 'bcryptjs';
|
import bcrypt from 'bcryptjs';
|
||||||
import { MiLocalUser, MiUser } from '@/models/User.js';
|
import { MiLocalUser, MiUser } from '@/models/User.js';
|
||||||
import { MiSystemAccount, MiUsedUsername, MiUserKeypair, MiUserProfile, type UsersRepository, type SystemAccountsRepository } from '@/models/_.js';
|
import { MiSystemAccount, MiUsedUsername, MiUserKeypair, MiUserProfile, type UsersRepository, type SystemAccountsRepository } from '@/models/_.js';
|
||||||
import type { MiMeta, UserProfilesRepository } from '@/models/_.js';
|
import type { MiMeta, UserProfilesRepository } from '@/models/_.js';
|
||||||
|
import type { GlobalEvents } from '@/core/GlobalEventService.js';
|
||||||
import { MemoryKVCache } from '@/misc/cache.js';
|
import { MemoryKVCache } from '@/misc/cache.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
@ -20,10 +23,13 @@ import { genRsaKeyPair } from '@/misc/gen-key-pair.js';
|
||||||
export const SYSTEM_ACCOUNT_TYPES = ['actor', 'relay', 'proxy'] as const;
|
export const SYSTEM_ACCOUNT_TYPES = ['actor', 'relay', 'proxy'] as const;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SystemAccountService {
|
export class SystemAccountService implements OnApplicationShutdown {
|
||||||
private cache: MemoryKVCache<MiLocalUser>;
|
private cache: MemoryKVCache<MiLocalUser>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@Inject(DI.redisForSub)
|
||||||
|
private redisForSub: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
|
||||||
|
@ -42,6 +48,31 @@ export class SystemAccountService {
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
) {
|
) {
|
||||||
this.cache = new MemoryKVCache<MiLocalUser>(1000 * 60 * 10); // 10m
|
this.cache = new MemoryKVCache<MiLocalUser>(1000 * 60 * 10); // 10m
|
||||||
|
|
||||||
|
this.redisForSub.on('message', this.onMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
private async onMessage(_: string, data: string): Promise<void> {
|
||||||
|
const obj = JSON.parse(data);
|
||||||
|
|
||||||
|
if (obj.channel === 'internal') {
|
||||||
|
const { type, body } = obj.message as GlobalEvents['internal']['payload'];
|
||||||
|
switch (type) {
|
||||||
|
case 'metaUpdated': {
|
||||||
|
if (body.before != null && body.before.name !== body.after.name) {
|
||||||
|
for (const account of SYSTEM_ACCOUNT_TYPES) {
|
||||||
|
await this.updateCorrespondingUserProfile(account, {
|
||||||
|
name: body.after.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@ -145,7 +176,7 @@ export class SystemAccountService {
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async updateCorrespondingUserProfile(type: typeof SYSTEM_ACCOUNT_TYPES[number], extra: {
|
public async updateCorrespondingUserProfile(type: typeof SYSTEM_ACCOUNT_TYPES[number], extra: {
|
||||||
name?: string;
|
name?: string | null;
|
||||||
description?: MiUserProfile['description'];
|
description?: MiUserProfile['description'];
|
||||||
}): Promise<MiLocalUser> {
|
}): Promise<MiLocalUser> {
|
||||||
const user = await this.fetch(type);
|
const user = await this.fetch(type);
|
||||||
|
@ -169,4 +200,15 @@ export class SystemAccountService {
|
||||||
|
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public dispose(): void {
|
||||||
|
this.redisForSub.off('message', this.onMessage);
|
||||||
|
this.cache.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public onApplicationShutdown(signal?: string): void {
|
||||||
|
this.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -411,8 +411,8 @@ export class WebhookTestService {
|
||||||
name: user.name,
|
name: user.name,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
host: user.host,
|
host: user.host,
|
||||||
avatarUrl: user.avatarUrl,
|
avatarUrl: user.avatarId == null ? null : user.avatarUrl,
|
||||||
avatarBlurhash: user.avatarBlurhash,
|
avatarBlurhash: user.avatarId == null ? null : user.avatarBlurhash,
|
||||||
avatarDecorations: user.avatarDecorations.map(it => ({
|
avatarDecorations: user.avatarDecorations.map(it => ({
|
||||||
id: it.id,
|
id: it.id,
|
||||||
angle: it.angle,
|
angle: it.angle,
|
||||||
|
@ -441,8 +441,8 @@ export class WebhookTestService {
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
updatedAt: user.updatedAt?.toISOString() ?? null,
|
updatedAt: user.updatedAt?.toISOString() ?? null,
|
||||||
lastFetchedAt: user.lastFetchedAt?.toISOString() ?? null,
|
lastFetchedAt: user.lastFetchedAt?.toISOString() ?? null,
|
||||||
bannerUrl: user.bannerUrl,
|
bannerUrl: user.bannerId == null ? null : user.bannerUrl,
|
||||||
bannerBlurhash: user.bannerBlurhash,
|
bannerBlurhash: user.bannerId == null ? null : user.bannerBlurhash,
|
||||||
isLocked: user.isLocked,
|
isLocked: user.isLocked,
|
||||||
isSilenced: false,
|
isSilenced: false,
|
||||||
isSuspended: user.isSuspended,
|
isSuspended: user.isSuspended,
|
||||||
|
@ -463,6 +463,7 @@ export class WebhookTestService {
|
||||||
followersVisibility: 'public',
|
followersVisibility: 'public',
|
||||||
followingVisibility: 'public',
|
followingVisibility: 'public',
|
||||||
chatScope: 'mutual',
|
chatScope: 'mutual',
|
||||||
|
canChat: true,
|
||||||
twoFactorEnabled: false,
|
twoFactorEnabled: false,
|
||||||
usePasswordLessLogin: false,
|
usePasswordLessLogin: false,
|
||||||
securityKeys: false,
|
securityKeys: false,
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import * as mfm from 'mfm-js';
|
import * as mfm from 'mfm-js';
|
||||||
import { MfmService } from '@/core/MfmService.js';
|
import { MfmService, Appender } from '@/core/MfmService.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { extractApHashtagObjects } from './models/tag.js';
|
import { extractApHashtagObjects } from './models/tag.js';
|
||||||
|
@ -25,17 +25,17 @@ export class ApMfmService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public getNoteHtml(note: Pick<MiNote, 'text' | 'mentionedRemoteUsers'>, apAppend?: string) {
|
public getNoteHtml(note: Pick<MiNote, 'text' | 'mentionedRemoteUsers'>, additionalAppender: Appender[] = []) {
|
||||||
let noMisskeyContent = false;
|
let noMisskeyContent = false;
|
||||||
const srcMfm = (note.text ?? '') + (apAppend ?? '');
|
const srcMfm = (note.text ?? '');
|
||||||
|
|
||||||
const parsed = mfm.parse(srcMfm);
|
const parsed = mfm.parse(srcMfm);
|
||||||
|
|
||||||
if (!apAppend && parsed?.every(n => ['text', 'unicodeEmoji', 'emojiCode', 'mention', 'hashtag', 'url'].includes(n.type))) {
|
if (!additionalAppender.length && parsed.every(n => ['text', 'unicodeEmoji', 'emojiCode', 'mention', 'hashtag', 'url'].includes(n.type))) {
|
||||||
noMisskeyContent = true;
|
noMisskeyContent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = this.mfmService.toHtml(parsed, JSON.parse(note.mentionedRemoteUsers));
|
const content = this.mfmService.toHtml(parsed, JSON.parse(note.mentionedRemoteUsers), additionalAppender);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content,
|
content,
|
||||||
|
|
|
@ -19,7 +19,7 @@ import type { MiEmoji } from '@/models/Emoji.js';
|
||||||
import type { MiPoll } from '@/models/Poll.js';
|
import type { MiPoll } from '@/models/Poll.js';
|
||||||
import type { MiPollVote } from '@/models/PollVote.js';
|
import type { MiPollVote } from '@/models/PollVote.js';
|
||||||
import { UserKeypairService } from '@/core/UserKeypairService.js';
|
import { UserKeypairService } from '@/core/UserKeypairService.js';
|
||||||
import { MfmService } from '@/core/MfmService.js';
|
import { MfmService, type Appender } from '@/core/MfmService.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
||||||
import type { MiUserKeypair } from '@/models/UserKeypair.js';
|
import type { MiUserKeypair } from '@/models/UserKeypair.js';
|
||||||
|
@ -430,10 +430,24 @@ export class ApRendererService {
|
||||||
poll = await this.pollsRepository.findOneBy({ noteId: note.id });
|
poll = await this.pollsRepository.findOneBy({ noteId: note.id });
|
||||||
}
|
}
|
||||||
|
|
||||||
let apAppend = '';
|
const apAppend: Appender[] = [];
|
||||||
|
|
||||||
if (quote) {
|
if (quote) {
|
||||||
apAppend += `\n\nRE: ${quote}`;
|
// Append quote link as `<br><br><span class="quote-inline">RE: <a href="...">...</a></span>`
|
||||||
|
// the claas name `quote-inline` is used in non-misskey clients for styling quote notes.
|
||||||
|
// For compatibility, the span part should be kept as possible.
|
||||||
|
apAppend.push((doc, body) => {
|
||||||
|
body.appendChild(doc.createElement('br'));
|
||||||
|
body.appendChild(doc.createElement('br'));
|
||||||
|
const span = doc.createElement('span');
|
||||||
|
span.className = 'quote-inline';
|
||||||
|
span.appendChild(doc.createTextNode('RE: '));
|
||||||
|
const link = doc.createElement('a');
|
||||||
|
link.setAttribute('href', quote);
|
||||||
|
link.textContent = quote;
|
||||||
|
span.appendChild(link);
|
||||||
|
body.appendChild(span);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const summary = note.cw === '' ? String.fromCharCode(0x200B) : note.cw;
|
const summary = note.cw === '' ? String.fromCharCode(0x200B) : note.cw;
|
||||||
|
@ -509,7 +523,7 @@ export class ApRendererService {
|
||||||
const urlPart = match[0];
|
const urlPart = match[0];
|
||||||
const urlPartParsed = new URL(urlPart);
|
const urlPartParsed = new URL(urlPart);
|
||||||
const restPart = maybeUrl.slice(match[0].length);
|
const restPart = maybeUrl.slice(match[0].length);
|
||||||
|
|
||||||
return `<a href="${urlPartParsed.href}" rel="me nofollow noopener" target="_blank">${urlPart}</a>${restPart}`;
|
return `<a href="${urlPartParsed.href}" rel="me nofollow noopener" target="_blank">${urlPart}</a>${restPart}`;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return maybeUrl;
|
return maybeUrl;
|
||||||
|
|
|
@ -41,6 +41,7 @@ export class AntennaEntityService {
|
||||||
excludeBots: antenna.excludeBots,
|
excludeBots: antenna.excludeBots,
|
||||||
withReplies: antenna.withReplies,
|
withReplies: antenna.withReplies,
|
||||||
withFile: antenna.withFile,
|
withFile: antenna.withFile,
|
||||||
|
excludeNotesInSensitiveChannel: antenna.excludeNotesInSensitiveChannel,
|
||||||
isActive: antenna.isActive,
|
isActive: antenna.isActive,
|
||||||
hasUnreadNote: false, // TODO
|
hasUnreadNote: false, // TODO
|
||||||
notify: false, // 後方互換性のため
|
notify: false, // 後方互換性のため
|
||||||
|
|
|
@ -128,7 +128,7 @@ export class ChatEntityService {
|
||||||
packedFiles: Map<MiChatMessage['fileId'], Packed<'DriveFile'> | null>;
|
packedFiles: Map<MiChatMessage['fileId'], Packed<'DriveFile'> | null>;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
): Promise<Packed<'ChatMessageLite'>> {
|
): Promise<Packed<'ChatMessageLiteFor1on1'>> {
|
||||||
const packedFiles = options?._hint_?.packedFiles;
|
const packedFiles = options?._hint_?.packedFiles;
|
||||||
|
|
||||||
const message = typeof src === 'object' ? src : await this.chatMessagesRepository.findOneByOrFail({ id: src });
|
const message = typeof src === 'object' ? src : await this.chatMessagesRepository.findOneByOrFail({ id: src });
|
||||||
|
@ -147,7 +147,7 @@ export class ChatEntityService {
|
||||||
createdAt: this.idService.parse(message.id).date.toISOString(),
|
createdAt: this.idService.parse(message.id).date.toISOString(),
|
||||||
text: message.text,
|
text: message.text,
|
||||||
fromUserId: message.fromUserId,
|
fromUserId: message.fromUserId,
|
||||||
toUserId: message.toUserId,
|
toUserId: message.toUserId!,
|
||||||
fileId: message.fileId,
|
fileId: message.fileId,
|
||||||
file: message.fileId ? (packedFiles?.get(message.fileId) ?? await this.driveFileEntityService.pack(message.file ?? message.fileId)) : null,
|
file: message.fileId ? (packedFiles?.get(message.fileId) ?? await this.driveFileEntityService.pack(message.file ?? message.fileId)) : null,
|
||||||
reactions,
|
reactions,
|
||||||
|
@ -177,7 +177,7 @@ export class ChatEntityService {
|
||||||
packedUsers: Map<MiUser['id'], Packed<'UserLite'>>;
|
packedUsers: Map<MiUser['id'], Packed<'UserLite'>>;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
): Promise<Packed<'ChatMessageLite'>> {
|
): Promise<Packed<'ChatMessageLiteForRoom'>> {
|
||||||
const packedFiles = options?._hint_?.packedFiles;
|
const packedFiles = options?._hint_?.packedFiles;
|
||||||
const packedUsers = options?._hint_?.packedUsers;
|
const packedUsers = options?._hint_?.packedUsers;
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ export class ChatEntityService {
|
||||||
text: message.text,
|
text: message.text,
|
||||||
fromUserId: message.fromUserId,
|
fromUserId: message.fromUserId,
|
||||||
fromUser: packedUsers?.get(message.fromUserId) ?? await this.userEntityService.pack(message.fromUser ?? message.fromUserId),
|
fromUser: packedUsers?.get(message.fromUserId) ?? await this.userEntityService.pack(message.fromUser ?? message.fromUserId),
|
||||||
toRoomId: message.toRoomId,
|
toRoomId: message.toRoomId!,
|
||||||
fileId: message.fileId,
|
fileId: message.fileId,
|
||||||
file: message.fileId ? (packedFiles?.get(message.fileId) ?? await this.driveFileEntityService.pack(message.file ?? message.fileId)) : null,
|
file: message.fileId ? (packedFiles?.get(message.fileId) ?? await this.driveFileEntityService.pack(message.file ?? message.fileId)) : null,
|
||||||
reactions,
|
reactions,
|
||||||
|
|
|
@ -127,6 +127,7 @@ export class MetaEntityService {
|
||||||
|
|
||||||
policies: { ...DEFAULT_POLICIES, ...instance.policies },
|
policies: { ...DEFAULT_POLICIES, ...instance.policies },
|
||||||
|
|
||||||
|
sentryForFrontend: this.config.sentryForFrontend ?? null,
|
||||||
mediaProxy: this.config.mediaProxy,
|
mediaProxy: this.config.mediaProxy,
|
||||||
enableUrlPreview: instance.urlPreviewEnabled,
|
enableUrlPreview: instance.urlPreviewEnabled,
|
||||||
noteSearchableScope: (this.config.meilisearch == null || this.config.meilisearch.scope !== 'local') ? 'global' : 'local',
|
noteSearchableScope: (this.config.meilisearch == null || this.config.meilisearch.scope !== 'local') ? 'global' : 'local',
|
||||||
|
|
|
@ -13,6 +13,7 @@ import type { MiRole } from '@/models/Role.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
import { Packed } from '@/misc/json-schema.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RoleEntityService {
|
export class RoleEntityService {
|
||||||
|
@ -31,7 +32,7 @@ export class RoleEntityService {
|
||||||
public async pack(
|
public async pack(
|
||||||
src: MiRole['id'] | MiRole,
|
src: MiRole['id'] | MiRole,
|
||||||
me?: { id: MiUser['id'] } | null | undefined,
|
me?: { id: MiUser['id'] } | null | undefined,
|
||||||
) {
|
): Promise<Packed<'Role'>> {
|
||||||
const role = typeof src === 'object' ? src : await this.rolesRepository.findOneByOrFail({ id: src });
|
const role = typeof src === 'object' ? src : await this.rolesRepository.findOneByOrFail({ id: src });
|
||||||
|
|
||||||
const assignedCount = await this.roleAssignmentsRepository.createQueryBuilder('assign')
|
const assignedCount = await this.roleAssignmentsRepository.createQueryBuilder('assign')
|
||||||
|
@ -67,6 +68,7 @@ export class RoleEntityService {
|
||||||
isModerator: role.isModerator,
|
isModerator: role.isModerator,
|
||||||
isExplorable: role.isExplorable,
|
isExplorable: role.isExplorable,
|
||||||
asBadge: role.asBadge,
|
asBadge: role.asBadge,
|
||||||
|
preserveAssignmentOnMoveAccount: role.preserveAssignmentOnMoveAccount,
|
||||||
canEditMembersByModerator: role.canEditMembersByModerator,
|
canEditMembersByModerator: role.canEditMembersByModerator,
|
||||||
displayOrder: role.displayOrder,
|
displayOrder: role.displayOrder,
|
||||||
policies: policies,
|
policies: policies,
|
||||||
|
|
|
@ -486,8 +486,8 @@ export class UserEntityService implements OnModuleInit {
|
||||||
name: user.name,
|
name: user.name,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
host: user.host,
|
host: user.host,
|
||||||
avatarUrl: user.avatarUrl ?? this.getIdenticonUrl(user),
|
avatarUrl: (user.avatarId == null ? null : user.avatarUrl) ?? this.getIdenticonUrl(user),
|
||||||
avatarBlurhash: user.avatarBlurhash,
|
avatarBlurhash: (user.avatarId == null ? null : user.avatarBlurhash),
|
||||||
avatarDecorations: user.avatarDecorations.length > 0 ? this.avatarDecorationService.getAll().then(decorations => user.avatarDecorations.filter(ud => decorations.some(d => d.id === ud.id)).map(ud => ({
|
avatarDecorations: user.avatarDecorations.length > 0 ? this.avatarDecorationService.getAll().then(decorations => user.avatarDecorations.filter(ud => decorations.some(d => d.id === ud.id)).map(ud => ({
|
||||||
id: ud.id,
|
id: ud.id,
|
||||||
angle: ud.angle || undefined,
|
angle: ud.angle || undefined,
|
||||||
|
@ -533,8 +533,8 @@ export class UserEntityService implements OnModuleInit {
|
||||||
createdAt: this.idService.parse(user.id).date.toISOString(),
|
createdAt: this.idService.parse(user.id).date.toISOString(),
|
||||||
updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null,
|
updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null,
|
||||||
lastFetchedAt: user.lastFetchedAt ? user.lastFetchedAt.toISOString() : null,
|
lastFetchedAt: user.lastFetchedAt ? user.lastFetchedAt.toISOString() : null,
|
||||||
bannerUrl: user.bannerUrl,
|
bannerUrl: user.bannerId == null ? null : user.bannerUrl,
|
||||||
bannerBlurhash: user.bannerBlurhash,
|
bannerBlurhash: user.bannerId == null ? null : user.bannerBlurhash,
|
||||||
isLocked: user.isLocked,
|
isLocked: user.isLocked,
|
||||||
isSilenced: this.roleService.getUserPolicies(user.id).then(r => !r.canPublicNote),
|
isSilenced: this.roleService.getUserPolicies(user.id).then(r => !r.canPublicNote),
|
||||||
isSuspended: user.isSuspended,
|
isSuspended: user.isSuspended,
|
||||||
|
@ -557,7 +557,7 @@ export class UserEntityService implements OnModuleInit {
|
||||||
followersVisibility: profile!.followersVisibility,
|
followersVisibility: profile!.followersVisibility,
|
||||||
followingVisibility: profile!.followingVisibility,
|
followingVisibility: profile!.followingVisibility,
|
||||||
chatScope: user.chatScope,
|
chatScope: user.chatScope,
|
||||||
canChat: this.roleService.getUserPolicies(user.id).then(r => r.canChat),
|
canChat: this.roleService.getUserPolicies(user.id).then(r => r.chatAvailability === 'available'),
|
||||||
roles: this.roleService.getUserRoles(user.id).then(roles => roles.filter(role => role.isPublic).sort((a, b) => b.displayOrder - a.displayOrder).map(role => ({
|
roles: this.roleService.getUserRoles(user.id).then(roles => roles.filter(role => role.isPublic).sort((a, b) => b.displayOrder - a.displayOrder).map(role => ({
|
||||||
id: role.id,
|
id: role.id,
|
||||||
name: role.name,
|
name: role.name,
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
function parseBigIntChunked(str: string, base: number, chunkSize: number, powerOfChunkSize: bigint): bigint {
|
||||||
|
const chunks = [];
|
||||||
|
while (str.length > 0) {
|
||||||
|
chunks.unshift(str.slice(-chunkSize));
|
||||||
|
str = str.slice(0, -chunkSize);
|
||||||
|
}
|
||||||
|
let result = 0n;
|
||||||
|
for (const chunk of chunks) {
|
||||||
|
result *= powerOfChunkSize;
|
||||||
|
const int = parseInt(chunk, base);
|
||||||
|
if (Number.isNaN(int)) {
|
||||||
|
throw new Error('Invalid base36 string');
|
||||||
|
}
|
||||||
|
result += BigInt(int);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseBigInt36(str: string): bigint {
|
||||||
|
// log_36(Number.MAX_SAFE_INTEGER) => 10.251599391715352
|
||||||
|
// so we process 10 chars at once
|
||||||
|
return parseBigIntChunked(str, 36, 10, 36n ** 10n);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseBigInt16(str: string): bigint {
|
||||||
|
// log_16(Number.MAX_SAFE_INTEGER) => 13.25
|
||||||
|
// so we process 13 chars at once
|
||||||
|
return parseBigIntChunked(str, 16, 13, 16n ** 13n);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseBigInt32(str: string): bigint {
|
||||||
|
// log_32(Number.MAX_SAFE_INTEGER) => 10.6
|
||||||
|
// so we process 10 chars at once
|
||||||
|
return parseBigIntChunked(str, 32, 10, 32n ** 10n);
|
||||||
|
}
|
|
@ -7,6 +7,7 @@
|
||||||
// 長さ8の[2000年1月1日からの経過ミリ秒をbase36でエンコードしたもの] + 長さ2の[ノイズ文字列]
|
// 長さ8の[2000年1月1日からの経過ミリ秒をbase36でエンコードしたもの] + 長さ2の[ノイズ文字列]
|
||||||
|
|
||||||
import * as crypto from 'node:crypto';
|
import * as crypto from 'node:crypto';
|
||||||
|
import { parseBigInt36 } from '@/misc/bigint.js';
|
||||||
|
|
||||||
export const aidRegExp = /^[0-9a-z]{10}$/;
|
export const aidRegExp = /^[0-9a-z]{10}$/;
|
||||||
|
|
||||||
|
@ -35,6 +36,12 @@ export function parseAid(id: string): { date: Date; } {
|
||||||
return { date: new Date(time) };
|
return { date: new Date(time) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseAidFull(id: string): { date: number; additional: bigint; } {
|
||||||
|
const date = parseInt(id.slice(0, 8), 36) + TIME2000;
|
||||||
|
const additional = parseBigInt36(id.slice(8, 10));
|
||||||
|
return { date, additional };
|
||||||
|
}
|
||||||
|
|
||||||
export function isSafeAidT(t: number): boolean {
|
export function isSafeAidT(t: number): boolean {
|
||||||
return t > TIME2000;
|
return t > TIME2000;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// https://misskey.m544.net/notes/71899acdcc9859ec5708ac24
|
// https://misskey.m544.net/notes/71899acdcc9859ec5708ac24
|
||||||
|
|
||||||
import { customAlphabet } from 'nanoid';
|
import { customAlphabet } from 'nanoid';
|
||||||
|
import { parseBigInt36 } from '@/misc/bigint.js';
|
||||||
|
|
||||||
export const aidxRegExp = /^[0-9a-z]{16}$/;
|
export const aidxRegExp = /^[0-9a-z]{16}$/;
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ const TIME2000 = 946684800000;
|
||||||
const TIME_LENGTH = 8;
|
const TIME_LENGTH = 8;
|
||||||
const NODE_LENGTH = 4;
|
const NODE_LENGTH = 4;
|
||||||
const NOISE_LENGTH = 4;
|
const NOISE_LENGTH = 4;
|
||||||
|
const AIDX_LENGTH = TIME_LENGTH + NODE_LENGTH + NOISE_LENGTH;
|
||||||
|
|
||||||
const nodeId = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', NODE_LENGTH)();
|
const nodeId = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', NODE_LENGTH)();
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
|
@ -42,6 +44,12 @@ export function parseAidx(id: string): { date: Date; } {
|
||||||
return { date: new Date(time) };
|
return { date: new Date(time) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseAidxFull(id: string): { date: number; additional: bigint; } {
|
||||||
|
const date = parseInt(id.slice(0, TIME_LENGTH), 36) + TIME2000;
|
||||||
|
const additional = parseBigInt36(id.slice(TIME_LENGTH, AIDX_LENGTH));
|
||||||
|
return { date, additional };
|
||||||
|
}
|
||||||
|
|
||||||
export function isSafeAidxT(t: number): boolean {
|
export function isSafeAidxT(t: number): boolean {
|
||||||
return t > TIME2000;
|
return t > TIME2000;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { parseBigInt16 } from '@/misc/bigint.js';
|
||||||
|
|
||||||
const CHARS = '0123456789abcdef';
|
const CHARS = '0123456789abcdef';
|
||||||
|
|
||||||
// same as object-id
|
// same as object-id
|
||||||
|
@ -39,6 +41,13 @@ export function parseMeid(id: string): { date: Date; } {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseMeidFull(id: string): { date: number; additional: bigint; } {
|
||||||
|
return {
|
||||||
|
date: parseInt(id.slice(0, 12), 16) - 0x800000000000,
|
||||||
|
additional: parseBigInt16(id.slice(12, 24)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function isSafeMeidT(t: number): boolean {
|
export function isSafeMeidT(t: number): boolean {
|
||||||
return t > 0;
|
return t > 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { parseBigInt16 } from '@/misc/bigint.js';
|
||||||
|
|
||||||
const CHARS = '0123456789abcdef';
|
const CHARS = '0123456789abcdef';
|
||||||
|
|
||||||
// 4bit Fixed hex value 'g'
|
// 4bit Fixed hex value 'g'
|
||||||
|
@ -39,6 +41,13 @@ export function parseMeidg(id: string): { date: Date; } {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseMeidgFull(id: string): { date: number; additional: bigint; } {
|
||||||
|
return {
|
||||||
|
date: parseInt(id.slice(1, 12), 16),
|
||||||
|
additional: parseBigInt16(id.slice(12, 24)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function isSafeMeidgT(t: number): boolean {
|
export function isSafeMeidgT(t: number): boolean {
|
||||||
return t > 0;
|
return t > 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { parseBigInt16 } from '@/misc/bigint.js';
|
||||||
|
|
||||||
const CHARS = '0123456789abcdef';
|
const CHARS = '0123456789abcdef';
|
||||||
|
|
||||||
// same as meid
|
// same as meid
|
||||||
|
@ -39,6 +41,13 @@ export function parseObjectId(id: string): { date: Date; } {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseObjectIdFull(id: string): { date: number; additional: bigint; } {
|
||||||
|
return {
|
||||||
|
date: parseInt(id.slice(0, 8), 16) * 1000,
|
||||||
|
additional: parseBigInt16(id.slice(8, 24)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function isSafeObjectIdT(t: number): boolean {
|
export function isSafeObjectIdT(t: number): boolean {
|
||||||
return t > 0;
|
return t > 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,27 @@
|
||||||
|
|
||||||
// Crockford's Base32
|
// Crockford's Base32
|
||||||
// https://github.com/ulid/spec#encoding
|
// https://github.com/ulid/spec#encoding
|
||||||
|
import { parseBigInt32 } from '@/misc/bigint.js';
|
||||||
|
|
||||||
const CHARS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
const CHARS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
||||||
|
|
||||||
export const ulidRegExp = /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$/;
|
export const ulidRegExp = /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$/;
|
||||||
|
|
||||||
export function parseUlid(id: string): { date: Date; } {
|
function parseBase32(timestamp: string) {
|
||||||
const timestamp = id.slice(0, 10);
|
|
||||||
let time = 0;
|
let time = 0;
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < timestamp.length; i++) {
|
||||||
time = time * 32 + CHARS.indexOf(timestamp[i]);
|
time = time * 32 + CHARS.indexOf(timestamp[i]);
|
||||||
}
|
}
|
||||||
return { date: new Date(time) };
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseUlid(id: string): { date: Date; } {
|
||||||
|
return { date: new Date(parseBase32(id.slice(0, 10))) };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseUlidFull(id: string): { date: number; additional: bigint; } {
|
||||||
|
return {
|
||||||
|
date: parseBase32(id.slice(0, 10)),
|
||||||
|
additional: parseBigInt32(id.slice(10, 26)),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ import {
|
||||||
} from '@/models/json-schema/meta.js';
|
} from '@/models/json-schema/meta.js';
|
||||||
import { packedSystemWebhookSchema } from '@/models/json-schema/system-webhook.js';
|
import { packedSystemWebhookSchema } from '@/models/json-schema/system-webhook.js';
|
||||||
import { packedAbuseReportNotificationRecipientSchema } from '@/models/json-schema/abuse-report-notification-recipient.js';
|
import { packedAbuseReportNotificationRecipientSchema } from '@/models/json-schema/abuse-report-notification-recipient.js';
|
||||||
import { packedChatMessageSchema, packedChatMessageLiteSchema } from '@/models/json-schema/chat-message.js';
|
import { packedChatMessageSchema, packedChatMessageLiteSchema, packedChatMessageLiteForRoomSchema, packedChatMessageLiteFor1on1Schema } from '@/models/json-schema/chat-message.js';
|
||||||
import { packedChatRoomSchema } from '@/models/json-schema/chat-room.js';
|
import { packedChatRoomSchema } from '@/models/json-schema/chat-room.js';
|
||||||
import { packedChatRoomInvitationSchema } from '@/models/json-schema/chat-room-invitation.js';
|
import { packedChatRoomInvitationSchema } from '@/models/json-schema/chat-room-invitation.js';
|
||||||
import { packedChatRoomMembershipSchema } from '@/models/json-schema/chat-room-membership.js';
|
import { packedChatRoomMembershipSchema } from '@/models/json-schema/chat-room-membership.js';
|
||||||
|
@ -126,6 +126,8 @@ export const refs = {
|
||||||
AbuseReportNotificationRecipient: packedAbuseReportNotificationRecipientSchema,
|
AbuseReportNotificationRecipient: packedAbuseReportNotificationRecipientSchema,
|
||||||
ChatMessage: packedChatMessageSchema,
|
ChatMessage: packedChatMessageSchema,
|
||||||
ChatMessageLite: packedChatMessageLiteSchema,
|
ChatMessageLite: packedChatMessageLiteSchema,
|
||||||
|
ChatMessageLiteFor1on1: packedChatMessageLiteFor1on1Schema,
|
||||||
|
ChatMessageLiteForRoom: packedChatMessageLiteForRoomSchema,
|
||||||
ChatRoom: packedChatRoomSchema,
|
ChatRoom: packedChatRoomSchema,
|
||||||
ChatRoomInvitation: packedChatRoomInvitationSchema,
|
ChatRoomInvitation: packedChatRoomInvitationSchema,
|
||||||
ChatRoomMembership: packedChatRoomMembershipSchema,
|
ChatRoomMembership: packedChatRoomMembershipSchema,
|
||||||
|
|
|
@ -100,4 +100,9 @@ export class MiAntenna {
|
||||||
default: false,
|
default: false,
|
||||||
})
|
})
|
||||||
public localOnly: boolean;
|
public localOnly: boolean;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
public excludeNotesInSensitiveChannel: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,6 +248,11 @@ export class MiRole {
|
||||||
})
|
})
|
||||||
public isExplorable: boolean;
|
public isExplorable: boolean;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
public preserveAssignmentOnMoveAccount: boolean;
|
||||||
|
|
||||||
@Column('boolean', {
|
@Column('boolean', {
|
||||||
default: false,
|
default: false,
|
||||||
})
|
})
|
||||||
|
|
|
@ -118,21 +118,25 @@ export class MiUser {
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
public banner: MiDriveFile | null;
|
public banner: MiDriveFile | null;
|
||||||
|
|
||||||
|
// avatarId が null になったとしてもこれが null でない可能性があるため、このフィールドを使うときは avatarId の non-null チェックをすること
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 512, nullable: true,
|
length: 512, nullable: true,
|
||||||
})
|
})
|
||||||
public avatarUrl: string | null;
|
public avatarUrl: string | null;
|
||||||
|
|
||||||
|
// bannerId が null になったとしてもこれが null でない可能性があるため、このフィールドを使うときは bannerId の non-null チェックをすること
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 512, nullable: true,
|
length: 512, nullable: true,
|
||||||
})
|
})
|
||||||
public bannerUrl: string | null;
|
public bannerUrl: string | null;
|
||||||
|
|
||||||
|
// avatarId が null になったとしてもこれが null でない可能性があるため、このフィールドを使うときは avatarId の non-null チェックをすること
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 128, nullable: true,
|
length: 128, nullable: true,
|
||||||
})
|
})
|
||||||
public avatarBlurhash: string | null;
|
public avatarBlurhash: string | null;
|
||||||
|
|
||||||
|
// bannerId が null になったとしてもこれが null でない可能性があるため、このフィールドを使うときは bannerId の non-null チェックをすること
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 128, nullable: true,
|
length: 128, nullable: true,
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,29 +3,48 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { FindOneOptions, InsertQueryBuilder, ObjectLiteral, Repository, SelectQueryBuilder } from 'typeorm';
|
import {
|
||||||
|
FindOneOptions,
|
||||||
|
InsertQueryBuilder,
|
||||||
|
ObjectLiteral,
|
||||||
|
QueryRunner,
|
||||||
|
Repository,
|
||||||
|
SelectQueryBuilder,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions.js';
|
||||||
import { RelationCountLoader } from 'typeorm/query-builder/relation-count/RelationCountLoader.js';
|
import { RelationCountLoader } from 'typeorm/query-builder/relation-count/RelationCountLoader.js';
|
||||||
import { RelationIdLoader } from 'typeorm/query-builder/relation-id/RelationIdLoader.js';
|
import { RelationIdLoader } from 'typeorm/query-builder/relation-id/RelationIdLoader.js';
|
||||||
import { RawSqlResultsToEntityTransformer } from 'typeorm/query-builder/transformer/RawSqlResultsToEntityTransformer.js';
|
import {
|
||||||
import { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
|
RawSqlResultsToEntityTransformer,
|
||||||
|
} from 'typeorm/query-builder/transformer/RawSqlResultsToEntityTransformer.js';
|
||||||
import { MiAbuseReportNotificationRecipient } from '@/models/AbuseReportNotificationRecipient.js';
|
import { MiAbuseReportNotificationRecipient } from '@/models/AbuseReportNotificationRecipient.js';
|
||||||
|
import { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
|
||||||
import { MiAccessToken } from '@/models/AccessToken.js';
|
import { MiAccessToken } from '@/models/AccessToken.js';
|
||||||
import { MiAd } from '@/models/Ad.js';
|
import { MiAd } from '@/models/Ad.js';
|
||||||
import { MiAnnouncement } from '@/models/Announcement.js';
|
import { MiAnnouncement } from '@/models/Announcement.js';
|
||||||
import { MiAnnouncementRead } from '@/models/AnnouncementRead.js';
|
import { MiAnnouncementRead } from '@/models/AnnouncementRead.js';
|
||||||
import { MiAntenna } from '@/models/Antenna.js';
|
import { MiAntenna } from '@/models/Antenna.js';
|
||||||
import { MiApp } from '@/models/App.js';
|
import { MiApp } from '@/models/App.js';
|
||||||
import { MiAvatarDecoration } from '@/models/AvatarDecoration.js';
|
|
||||||
import { MiAuthSession } from '@/models/AuthSession.js';
|
import { MiAuthSession } from '@/models/AuthSession.js';
|
||||||
|
import { MiAvatarDecoration } from '@/models/AvatarDecoration.js';
|
||||||
import { MiBlocking } from '@/models/Blocking.js';
|
import { MiBlocking } from '@/models/Blocking.js';
|
||||||
import { MiChannelFollowing } from '@/models/ChannelFollowing.js';
|
import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
|
||||||
|
import { MiChannel } from '@/models/Channel.js';
|
||||||
import { MiChannelFavorite } from '@/models/ChannelFavorite.js';
|
import { MiChannelFavorite } from '@/models/ChannelFavorite.js';
|
||||||
|
import { MiChannelFollowing } from '@/models/ChannelFollowing.js';
|
||||||
|
import { MiChatApproval } from '@/models/ChatApproval.js';
|
||||||
|
import { MiChatMessage } from '@/models/ChatMessage.js';
|
||||||
|
import { MiChatRoom } from '@/models/ChatRoom.js';
|
||||||
|
import { MiChatRoomInvitation } from '@/models/ChatRoomInvitation.js';
|
||||||
|
import { MiChatRoomMembership } from '@/models/ChatRoomMembership.js';
|
||||||
import { MiClip } from '@/models/Clip.js';
|
import { MiClip } from '@/models/Clip.js';
|
||||||
import { MiClipNote } from '@/models/ClipNote.js';
|
|
||||||
import { MiClipFavorite } from '@/models/ClipFavorite.js';
|
import { MiClipFavorite } from '@/models/ClipFavorite.js';
|
||||||
|
import { MiClipNote } from '@/models/ClipNote.js';
|
||||||
import { MiDriveFile } from '@/models/DriveFile.js';
|
import { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import { MiDriveFolder } from '@/models/DriveFolder.js';
|
import { MiDriveFolder } from '@/models/DriveFolder.js';
|
||||||
import { MiEmoji } from '@/models/Emoji.js';
|
import { MiEmoji } from '@/models/Emoji.js';
|
||||||
|
import { MiFlash } from '@/models/Flash.js';
|
||||||
|
import { MiFlashLike } from '@/models/FlashLike.js';
|
||||||
import { MiFollowing } from '@/models/Following.js';
|
import { MiFollowing } from '@/models/Following.js';
|
||||||
import { MiFollowRequest } from '@/models/FollowRequest.js';
|
import { MiFollowRequest } from '@/models/FollowRequest.js';
|
||||||
import { MiGalleryLike } from '@/models/GalleryLike.js';
|
import { MiGalleryLike } from '@/models/GalleryLike.js';
|
||||||
|
@ -35,7 +54,6 @@ import { MiInstance } from '@/models/Instance.js';
|
||||||
import { MiMeta } from '@/models/Meta.js';
|
import { MiMeta } from '@/models/Meta.js';
|
||||||
import { MiModerationLog } from '@/models/ModerationLog.js';
|
import { MiModerationLog } from '@/models/ModerationLog.js';
|
||||||
import { MiMuting } from '@/models/Muting.js';
|
import { MiMuting } from '@/models/Muting.js';
|
||||||
import { MiRenoteMuting } from '@/models/RenoteMuting.js';
|
|
||||||
import { MiNote } from '@/models/Note.js';
|
import { MiNote } from '@/models/Note.js';
|
||||||
import { MiNoteFavorite } from '@/models/NoteFavorite.js';
|
import { MiNoteFavorite } from '@/models/NoteFavorite.js';
|
||||||
import { MiNoteReaction } from '@/models/NoteReaction.js';
|
import { MiNoteReaction } from '@/models/NoteReaction.js';
|
||||||
|
@ -50,42 +68,38 @@ import { MiPromoRead } from '@/models/PromoRead.js';
|
||||||
import { MiRegistrationTicket } from '@/models/RegistrationTicket.js';
|
import { MiRegistrationTicket } from '@/models/RegistrationTicket.js';
|
||||||
import { MiRegistryItem } from '@/models/RegistryItem.js';
|
import { MiRegistryItem } from '@/models/RegistryItem.js';
|
||||||
import { MiRelay } from '@/models/Relay.js';
|
import { MiRelay } from '@/models/Relay.js';
|
||||||
|
import { MiRenoteMuting } from '@/models/RenoteMuting.js';
|
||||||
|
import { MiRetentionAggregation } from '@/models/RetentionAggregation.js';
|
||||||
|
import { MiReversiGame } from '@/models/ReversiGame.js';
|
||||||
|
import { MiRole } from '@/models/Role.js';
|
||||||
|
import { MiRoleAssignment } from '@/models/RoleAssignment.js';
|
||||||
import { MiSignin } from '@/models/Signin.js';
|
import { MiSignin } from '@/models/Signin.js';
|
||||||
import { MiSwSubscription } from '@/models/SwSubscription.js';
|
import { MiSwSubscription } from '@/models/SwSubscription.js';
|
||||||
import { MiSystemAccount } from '@/models/SystemAccount.js';
|
import { MiSystemAccount } from '@/models/SystemAccount.js';
|
||||||
|
import { MiSystemWebhook } from '@/models/SystemWebhook.js';
|
||||||
import { MiUsedUsername } from '@/models/UsedUsername.js';
|
import { MiUsedUsername } from '@/models/UsedUsername.js';
|
||||||
import { MiUser } from '@/models/User.js';
|
import { MiUser } from '@/models/User.js';
|
||||||
import { MiUserIp } from '@/models/UserIp.js';
|
import { MiUserIp } from '@/models/UserIp.js';
|
||||||
import { MiUserKeypair } from '@/models/UserKeypair.js';
|
import { MiUserKeypair } from '@/models/UserKeypair.js';
|
||||||
import { MiUserList } from '@/models/UserList.js';
|
import { MiUserList } from '@/models/UserList.js';
|
||||||
|
import { MiUserListFavorite } from '@/models/UserListFavorite.js';
|
||||||
import { MiUserListMembership } from '@/models/UserListMembership.js';
|
import { MiUserListMembership } from '@/models/UserListMembership.js';
|
||||||
|
import { MiUserMemo } from '@/models/UserMemo.js';
|
||||||
import { MiUserNotePining } from '@/models/UserNotePining.js';
|
import { MiUserNotePining } from '@/models/UserNotePining.js';
|
||||||
import { MiUserPending } from '@/models/UserPending.js';
|
import { MiUserPending } from '@/models/UserPending.js';
|
||||||
import { MiUserProfile } from '@/models/UserProfile.js';
|
import { MiUserProfile } from '@/models/UserProfile.js';
|
||||||
import { MiUserPublickey } from '@/models/UserPublickey.js';
|
import { MiUserPublickey } from '@/models/UserPublickey.js';
|
||||||
import { MiUserSecurityKey } from '@/models/UserSecurityKey.js';
|
import { MiUserSecurityKey } from '@/models/UserSecurityKey.js';
|
||||||
import { MiUserMemo } from '@/models/UserMemo.js';
|
|
||||||
import { MiWebhook } from '@/models/Webhook.js';
|
import { MiWebhook } from '@/models/Webhook.js';
|
||||||
import { MiSystemWebhook } from '@/models/SystemWebhook.js';
|
|
||||||
import { MiChannel } from '@/models/Channel.js';
|
|
||||||
import { MiRetentionAggregation } from '@/models/RetentionAggregation.js';
|
|
||||||
import { MiRole } from '@/models/Role.js';
|
|
||||||
import { MiRoleAssignment } from '@/models/RoleAssignment.js';
|
|
||||||
import { MiFlash } from '@/models/Flash.js';
|
|
||||||
import { MiFlashLike } from '@/models/FlashLike.js';
|
|
||||||
import { MiUserListFavorite } from '@/models/UserListFavorite.js';
|
|
||||||
import { MiChatMessage } from '@/models/ChatMessage.js';
|
|
||||||
import { MiChatRoom } from '@/models/ChatRoom.js';
|
|
||||||
import { MiChatRoomMembership } from '@/models/ChatRoomMembership.js';
|
|
||||||
import { MiChatRoomInvitation } from '@/models/ChatRoomInvitation.js';
|
|
||||||
import { MiChatApproval } from '@/models/ChatApproval.js';
|
|
||||||
import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
|
|
||||||
import { MiReversiGame } from '@/models/ReversiGame.js';
|
|
||||||
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
|
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
|
||||||
|
|
||||||
export interface MiRepository<T extends ObjectLiteral> {
|
export interface MiRepository<T extends ObjectLiteral> {
|
||||||
createTableColumnNames(this: Repository<T> & MiRepository<T>): string[];
|
createTableColumnNames(this: Repository<T> & MiRepository<T>): string[];
|
||||||
|
|
||||||
insertOne(this: Repository<T> & MiRepository<T>, entity: QueryDeepPartialEntity<T>, findOptions?: Pick<FindOneOptions<T>, 'relations'>): Promise<T>;
|
insertOne(this: Repository<T> & MiRepository<T>, entity: QueryDeepPartialEntity<T>, findOptions?: Pick<FindOneOptions<T>, 'relations'>): Promise<T>;
|
||||||
|
|
||||||
|
insertOneImpl(this: Repository<T> & MiRepository<T>, entity: QueryDeepPartialEntity<T>, findOptions?: Pick<FindOneOptions<T>, 'relations'>, queryRunner?: QueryRunner): Promise<T>;
|
||||||
|
|
||||||
selectAliasColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>, builder: SelectQueryBuilder<T>): void;
|
selectAliasColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>, builder: SelectQueryBuilder<T>): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +108,21 @@ export const miRepository = {
|
||||||
return this.metadata.columns.filter(column => column.isSelect && !column.isVirtual).map(column => column.databaseName);
|
return this.metadata.columns.filter(column => column.isSelect && !column.isVirtual).map(column => column.databaseName);
|
||||||
},
|
},
|
||||||
async insertOne(entity, findOptions?) {
|
async insertOne(entity, findOptions?) {
|
||||||
|
const opt = this.manager.connection.options as PostgresConnectionOptions;
|
||||||
|
if (opt.replication) {
|
||||||
|
const queryRunner = this.manager.connection.createQueryRunner('master');
|
||||||
|
try {
|
||||||
|
return this.insertOneImpl(entity, findOptions, queryRunner);
|
||||||
|
} finally {
|
||||||
|
await queryRunner.release();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return this.insertOneImpl(entity, findOptions);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async insertOneImpl(entity, findOptions?, queryRunner?) {
|
||||||
|
// ---- insert + returningの結果を共通テーブル式(CTE)に保持するクエリを生成 ----
|
||||||
|
|
||||||
const queryBuilder = this.createQueryBuilder().insert().values(entity);
|
const queryBuilder = this.createQueryBuilder().insert().values(entity);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
const mainAlias = queryBuilder.expressionMap.mainAlias!;
|
const mainAlias = queryBuilder.expressionMap.mainAlias!;
|
||||||
|
@ -101,7 +130,9 @@ export const miRepository = {
|
||||||
mainAlias.name = 't';
|
mainAlias.name = 't';
|
||||||
const columnNames = this.createTableColumnNames();
|
const columnNames = this.createTableColumnNames();
|
||||||
queryBuilder.returning(columnNames.reduce((a, c) => `${a}, ${queryBuilder.escape(c)}`, '').slice(2));
|
queryBuilder.returning(columnNames.reduce((a, c) => `${a}, ${queryBuilder.escape(c)}`, '').slice(2));
|
||||||
const builder = this.createQueryBuilder().addCommonTableExpression(queryBuilder, 'cte', { columnNames });
|
|
||||||
|
// ---- 共通テーブル式(CTE)から結果を取得 ----
|
||||||
|
const builder = this.createQueryBuilder(undefined, queryRunner).addCommonTableExpression(queryBuilder, 'cte', { columnNames });
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
builder.expressionMap.mainAlias!.tablePath = 'cte';
|
builder.expressionMap.mainAlias!.tablePath = 'cte';
|
||||||
this.selectAliasColumnNames(queryBuilder, builder);
|
this.selectAliasColumnNames(queryBuilder, builder);
|
||||||
|
@ -204,7 +235,9 @@ export {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AbuseUserReportsRepository = Repository<MiAbuseUserReport> & MiRepository<MiAbuseUserReport>;
|
export type AbuseUserReportsRepository = Repository<MiAbuseUserReport> & MiRepository<MiAbuseUserReport>;
|
||||||
export type AbuseReportNotificationRecipientRepository = Repository<MiAbuseReportNotificationRecipient> & MiRepository<MiAbuseReportNotificationRecipient>;
|
export type AbuseReportNotificationRecipientRepository =
|
||||||
|
Repository<MiAbuseReportNotificationRecipient>
|
||||||
|
& MiRepository<MiAbuseReportNotificationRecipient>;
|
||||||
export type AccessTokensRepository = Repository<MiAccessToken> & MiRepository<MiAccessToken>;
|
export type AccessTokensRepository = Repository<MiAccessToken> & MiRepository<MiAccessToken>;
|
||||||
export type AdsRepository = Repository<MiAd> & MiRepository<MiAd>;
|
export type AdsRepository = Repository<MiAd> & MiRepository<MiAd>;
|
||||||
export type AnnouncementsRepository = Repository<MiAnnouncement> & MiRepository<MiAnnouncement>;
|
export type AnnouncementsRepository = Repository<MiAnnouncement> & MiRepository<MiAnnouncement>;
|
||||||
|
|
|
@ -100,5 +100,10 @@ export const packedAntennaSchema = {
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
excludeNotesInSensitiveChannel: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -72,7 +72,7 @@ export const packedChatMessageSchema = {
|
||||||
},
|
},
|
||||||
user: {
|
user: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: true, nullable: true,
|
optional: false, nullable: false,
|
||||||
ref: 'UserLite',
|
ref: 'UserLite',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -144,3 +144,113 @@ export const packedChatMessageLiteSchema = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
export const packedChatMessageLiteFor1on1Schema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
createdAt: {
|
||||||
|
type: 'string',
|
||||||
|
format: 'date-time',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
fromUserId: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
toUserId: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
type: 'string',
|
||||||
|
optional: true, nullable: true,
|
||||||
|
},
|
||||||
|
fileId: {
|
||||||
|
type: 'string',
|
||||||
|
optional: true, nullable: true,
|
||||||
|
},
|
||||||
|
file: {
|
||||||
|
type: 'object',
|
||||||
|
optional: true, nullable: true,
|
||||||
|
ref: 'DriveFile',
|
||||||
|
},
|
||||||
|
reactions: {
|
||||||
|
type: 'array',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
properties: {
|
||||||
|
reaction: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const packedChatMessageLiteForRoomSchema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
createdAt: {
|
||||||
|
type: 'string',
|
||||||
|
format: 'date-time',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
fromUserId: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
fromUser: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
ref: 'UserLite',
|
||||||
|
},
|
||||||
|
toRoomId: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
type: 'string',
|
||||||
|
optional: true, nullable: true,
|
||||||
|
},
|
||||||
|
fileId: {
|
||||||
|
type: 'string',
|
||||||
|
optional: true, nullable: true,
|
||||||
|
},
|
||||||
|
file: {
|
||||||
|
type: 'object',
|
||||||
|
optional: true, nullable: true,
|
||||||
|
ref: 'DriveFile',
|
||||||
|
},
|
||||||
|
reactions: {
|
||||||
|
type: 'array',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
properties: {
|
||||||
|
reaction: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
ref: 'UserLite',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
|
@ -211,6 +211,38 @@ export const packedMetaLiteSchema = {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
|
sentryForFrontend: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
properties: {
|
||||||
|
options: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
properties: {
|
||||||
|
dsn: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
additionalProperties: true,
|
||||||
|
},
|
||||||
|
vueIntegration: {
|
||||||
|
type: 'object',
|
||||||
|
optional: true, nullable: true,
|
||||||
|
additionalProperties: true,
|
||||||
|
},
|
||||||
|
browserTracingIntegration: {
|
||||||
|
type: 'object',
|
||||||
|
optional: true, nullable: true,
|
||||||
|
additionalProperties: true,
|
||||||
|
},
|
||||||
|
replayIntegration: {
|
||||||
|
type: 'object',
|
||||||
|
optional: true, nullable: true,
|
||||||
|
additionalProperties: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
mediaProxy: {
|
mediaProxy: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
|
|
@ -292,9 +292,10 @@ export const packedRolePoliciesSchema = {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
canChat: {
|
chatAvailability: {
|
||||||
type: 'boolean',
|
type: 'string',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
enum: ['available', 'readonly', 'unavailable'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -389,6 +390,11 @@ export const packedRoleSchema = {
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
example: false,
|
example: false,
|
||||||
},
|
},
|
||||||
|
preserveAssignmentOnMoveAccount: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
example: false,
|
||||||
|
},
|
||||||
canEditMembersByModerator: {
|
canEditMembersByModerator: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
// https://github.com/typeorm/typeorm/issues/2400
|
// https://github.com/typeorm/typeorm/issues/2400
|
||||||
import pg from 'pg';
|
import pg from 'pg';
|
||||||
import { DataSource, Logger } from 'typeorm';
|
import { DataSource, Logger, type QueryRunner } from 'typeorm';
|
||||||
import * as highlight from 'cli-highlight';
|
import * as highlight from 'cli-highlight';
|
||||||
import { entities as charts } from '@/core/chart/entities.js';
|
import { entities as charts } from '@/core/chart/entities.js';
|
||||||
import { Config } from '@/config.js';
|
import { Config } from '@/config.js';
|
||||||
|
@ -96,6 +96,7 @@ const sqlLogger = dbLogger.createSubLogger('sql', 'gray');
|
||||||
export type LoggerProps = {
|
export type LoggerProps = {
|
||||||
disableQueryTruncation?: boolean;
|
disableQueryTruncation?: boolean;
|
||||||
enableQueryParamLogging?: boolean;
|
enableQueryParamLogging?: boolean;
|
||||||
|
printReplicationMode?: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
function highlightSql(sql: string) {
|
function highlightSql(sql: string) {
|
||||||
|
@ -121,8 +122,10 @@ class MyCustomLogger implements Logger {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private transformQueryLog(sql: string) {
|
private transformQueryLog(sql: string, opts?: {
|
||||||
let modded = sql;
|
prefix?: string;
|
||||||
|
}) {
|
||||||
|
let modded = opts?.prefix ? opts.prefix + sql : sql;
|
||||||
if (!this.props.disableQueryTruncation) {
|
if (!this.props.disableQueryTruncation) {
|
||||||
modded = truncateSql(modded);
|
modded = truncateSql(modded);
|
||||||
}
|
}
|
||||||
|
@ -140,18 +143,27 @@ class MyCustomLogger implements Logger {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public logQuery(query: string, parameters?: any[]) {
|
public logQuery(query: string, parameters?: any[], queryRunner?: QueryRunner) {
|
||||||
sqlLogger.info(this.transformQueryLog(query), this.transformParameters(parameters));
|
const prefix = (this.props.printReplicationMode && queryRunner)
|
||||||
|
? `[${queryRunner.getReplicationMode()}] `
|
||||||
|
: undefined;
|
||||||
|
sqlLogger.info(this.transformQueryLog(query, { prefix }), this.transformParameters(parameters));
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public logQueryError(error: string, query: string, parameters?: any[]) {
|
public logQueryError(error: string, query: string, parameters?: any[], queryRunner?: QueryRunner) {
|
||||||
sqlLogger.error(this.transformQueryLog(query), this.transformParameters(parameters));
|
const prefix = (this.props.printReplicationMode && queryRunner)
|
||||||
|
? `[${queryRunner.getReplicationMode()}] `
|
||||||
|
: undefined;
|
||||||
|
sqlLogger.error(this.transformQueryLog(query, { prefix }), this.transformParameters(parameters));
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public logQuerySlow(time: number, query: string, parameters?: any[]) {
|
public logQuerySlow(time: number, query: string, parameters?: any[], queryRunner?: QueryRunner) {
|
||||||
sqlLogger.warn(this.transformQueryLog(query), this.transformParameters(parameters));
|
const prefix = (this.props.printReplicationMode && queryRunner)
|
||||||
|
? `[${queryRunner.getReplicationMode()}] `
|
||||||
|
: undefined;
|
||||||
|
sqlLogger.warn(this.transformQueryLog(query, { prefix }), this.transformParameters(parameters));
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@ -298,6 +310,7 @@ export function createPostgresDataSource(config: Config) {
|
||||||
? new MyCustomLogger({
|
? new MyCustomLogger({
|
||||||
disableQueryTruncation: config.logging?.sql?.disableQueryTruncation,
|
disableQueryTruncation: config.logging?.sql?.disableQueryTruncation,
|
||||||
enableQueryParamLogging: config.logging?.sql?.enableQueryParamLogging,
|
enableQueryParamLogging: config.logging?.sql?.enableQueryParamLogging,
|
||||||
|
printReplicationMode: !!config.dbReplications,
|
||||||
})
|
})
|
||||||
: undefined,
|
: undefined,
|
||||||
maxQueryExecutionTime: 300,
|
maxQueryExecutionTime: 300,
|
||||||
|
|
|
@ -32,6 +32,7 @@ import { isQuote, isRenote } from '@/misc/is-renote.js';
|
||||||
import * as Acct from '@/misc/acct.js';
|
import * as Acct from '@/misc/acct.js';
|
||||||
import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions, FastifyBodyParser } from 'fastify';
|
import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions, FastifyBodyParser } from 'fastify';
|
||||||
import type { FindOptionsWhere } from 'typeorm';
|
import type { FindOptionsWhere } from 'typeorm';
|
||||||
|
import { FanoutTimelineEndpointService } from '@/core/FanoutTimelineEndpointService.js';
|
||||||
|
|
||||||
const ACTIVITY_JSON = 'application/activity+json; charset=utf-8';
|
const ACTIVITY_JSON = 'application/activity+json; charset=utf-8';
|
||||||
const LD_JSON = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"; charset=utf-8';
|
const LD_JSON = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"; charset=utf-8';
|
||||||
|
@ -75,6 +76,7 @@ export class ActivityPubServerService {
|
||||||
private queueService: QueueService,
|
private queueService: QueueService,
|
||||||
private userKeypairService: UserKeypairService,
|
private userKeypairService: UserKeypairService,
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
|
private fanoutTimelineEndpointService: FanoutTimelineEndpointService,
|
||||||
) {
|
) {
|
||||||
//this.createServer = this.createServer.bind(this);
|
//this.createServer = this.createServer.bind(this);
|
||||||
}
|
}
|
||||||
|
@ -461,16 +463,28 @@ export class ActivityPubServerService {
|
||||||
const partOf = `${this.config.url}/users/${userId}/outbox`;
|
const partOf = `${this.config.url}/users/${userId}/outbox`;
|
||||||
|
|
||||||
if (page) {
|
if (page) {
|
||||||
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), sinceId, untilId)
|
const notes = this.meta.enableFanoutTimeline ? await this.fanoutTimelineEndpointService.getMiNotes({
|
||||||
.andWhere('note.userId = :userId', { userId: user.id })
|
sinceId: sinceId ?? null,
|
||||||
.andWhere(new Brackets(qb => {
|
untilId: untilId ?? null,
|
||||||
qb
|
limit: limit,
|
||||||
.where('note.visibility = \'public\'')
|
allowPartial: false, // Possibly true? IDK it's OK for ordered collection.
|
||||||
.orWhere('note.visibility = \'home\'');
|
me: null,
|
||||||
}))
|
redisTimelines: [
|
||||||
.andWhere('note.localOnly = FALSE');
|
`userTimeline:${user.id}`,
|
||||||
|
`userTimelineWithReplies:${user.id}`,
|
||||||
const notes = await query.limit(limit).getMany();
|
],
|
||||||
|
useDbFallback: true,
|
||||||
|
ignoreAuthorFromMute: true,
|
||||||
|
excludePureRenotes: false,
|
||||||
|
noteFilter: (note) => {
|
||||||
|
if (note.visibility !== 'home' && note.visibility !== 'public') return false;
|
||||||
|
if (note.localOnly) return false;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
dbFallback: async (untilId, sinceId, limit) => {
|
||||||
|
return await this.getUserNotesFromDb(sinceId, untilId, limit, user.id);
|
||||||
|
},
|
||||||
|
}) : await this.getUserNotesFromDb(sinceId ?? null, untilId ?? null, limit, user.id);
|
||||||
|
|
||||||
if (sinceId) notes.reverse();
|
if (sinceId) notes.reverse();
|
||||||
|
|
||||||
|
@ -508,6 +522,20 @@ export class ActivityPubServerService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
private async getUserNotesFromDb(untilId: string | null, sinceId: string | null, limit: number, userId: MiUser['id']) {
|
||||||
|
return await this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), sinceId, untilId)
|
||||||
|
.andWhere('note.userId = :userId', { userId })
|
||||||
|
.andWhere(new Brackets(qb => {
|
||||||
|
qb
|
||||||
|
.where('note.visibility = \'public\'')
|
||||||
|
.orWhere('note.visibility = \'home\'');
|
||||||
|
}))
|
||||||
|
.andWhere('note.localOnly = FALSE')
|
||||||
|
.limit(limit)
|
||||||
|
.getMany();
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async userInfo(request: FastifyRequest, reply: FastifyReply, user: MiUser | null) {
|
private async userInfo(request: FastifyRequest, reply: FastifyReply, user: MiUser | null) {
|
||||||
if (this.meta.federation === 'none') {
|
if (this.meta.federation === 'none') {
|
||||||
|
@ -735,7 +763,7 @@ export class ActivityPubServerService {
|
||||||
const acct = Acct.parse(request.params.acct);
|
const acct = Acct.parse(request.params.acct);
|
||||||
|
|
||||||
const user = await this.usersRepository.findOneBy({
|
const user = await this.usersRepository.findOneBy({
|
||||||
usernameLower: acct.username,
|
usernameLower: acct.username.toLowerCase(),
|
||||||
host: acct.host ?? IsNull(),
|
host: acct.host ?? IsNull(),
|
||||||
isSuspended: false,
|
isSuspended: false,
|
||||||
});
|
});
|
||||||
|
|
|
@ -221,7 +221,7 @@ export class ServerService implements OnApplicationShutdown {
|
||||||
reply.header('Cache-Control', 'public, max-age=86400');
|
reply.header('Cache-Control', 'public, max-age=86400');
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
reply.redirect(user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user));
|
reply.redirect((user.avatarId == null ? null : user.avatarUrl) ?? this.userEntityService.getIdenticonUrl(user));
|
||||||
} else {
|
} else {
|
||||||
reply.redirect('/static-assets/user-unknown.png');
|
reply.redirect('/static-assets/user-unknown.png');
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,7 +138,7 @@ fastify.get('/.well-known/change-password', async (request, reply) => {
|
||||||
|
|
||||||
const fromAcct = (acct: Acct.Acct): FindOptionsWhere<MiUser> | number =>
|
const fromAcct = (acct: Acct.Acct): FindOptionsWhere<MiUser> | number =>
|
||||||
!acct.host || acct.host === this.config.host.toLowerCase() ? {
|
!acct.host || acct.host === this.config.host.toLowerCase() ? {
|
||||||
usernameLower: acct.username,
|
usernameLower: acct.username.toLowerCase(),
|
||||||
host: IsNull(),
|
host: IsNull(),
|
||||||
isSuspended: false,
|
isSuspended: false,
|
||||||
} : 422;
|
} : 422;
|
||||||
|
|
|
@ -36,6 +36,7 @@ export const paramDef = {
|
||||||
isAdministrator: { type: 'boolean' },
|
isAdministrator: { type: 'boolean' },
|
||||||
isExplorable: { type: 'boolean', default: false }, // optional for backward compatibility
|
isExplorable: { type: 'boolean', default: false }, // optional for backward compatibility
|
||||||
asBadge: { type: 'boolean' },
|
asBadge: { type: 'boolean' },
|
||||||
|
preserveAssignmentOnMoveAccount: { type: 'boolean' },
|
||||||
canEditMembersByModerator: { type: 'boolean' },
|
canEditMembersByModerator: { type: 'boolean' },
|
||||||
displayOrder: { type: 'number' },
|
displayOrder: { type: 'number' },
|
||||||
policies: {
|
policies: {
|
||||||
|
|
|
@ -41,6 +41,7 @@ export const paramDef = {
|
||||||
isAdministrator: { type: 'boolean' },
|
isAdministrator: { type: 'boolean' },
|
||||||
isExplorable: { type: 'boolean' },
|
isExplorable: { type: 'boolean' },
|
||||||
asBadge: { type: 'boolean' },
|
asBadge: { type: 'boolean' },
|
||||||
|
preserveAssignmentOnMoveAccount: { type: 'boolean' },
|
||||||
canEditMembersByModerator: { type: 'boolean' },
|
canEditMembersByModerator: { type: 'boolean' },
|
||||||
displayOrder: { type: 'number' },
|
displayOrder: { type: 'number' },
|
||||||
policies: {
|
policies: {
|
||||||
|
@ -78,6 +79,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
isAdministrator: ps.isAdministrator,
|
isAdministrator: ps.isAdministrator,
|
||||||
isExplorable: ps.isExplorable,
|
isExplorable: ps.isExplorable,
|
||||||
asBadge: ps.asBadge,
|
asBadge: ps.asBadge,
|
||||||
|
preserveAssignmentOnMoveAccount: ps.preserveAssignmentOnMoveAccount,
|
||||||
canEditMembersByModerator: ps.canEditMembersByModerator,
|
canEditMembersByModerator: ps.canEditMembersByModerator,
|
||||||
displayOrder: ps.displayOrder,
|
displayOrder: ps.displayOrder,
|
||||||
policies: ps.policies,
|
policies: ps.policies,
|
||||||
|
|
|
@ -73,6 +73,7 @@ export const paramDef = {
|
||||||
excludeBots: { type: 'boolean' },
|
excludeBots: { type: 'boolean' },
|
||||||
withReplies: { type: 'boolean' },
|
withReplies: { type: 'boolean' },
|
||||||
withFile: { type: 'boolean' },
|
withFile: { type: 'boolean' },
|
||||||
|
excludeNotesInSensitiveChannel: { type: 'boolean' },
|
||||||
},
|
},
|
||||||
required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile'],
|
required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile'],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -133,6 +134,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
excludeBots: ps.excludeBots,
|
excludeBots: ps.excludeBots,
|
||||||
withReplies: ps.withReplies,
|
withReplies: ps.withReplies,
|
||||||
withFile: ps.withFile,
|
withFile: ps.withFile,
|
||||||
|
excludeNotesInSensitiveChannel: ps.excludeNotesInSensitiveChannel,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.globalEventService.publishInternalEvent('antennaCreated', antenna);
|
this.globalEventService.publishInternalEvent('antennaCreated', antenna);
|
||||||
|
|
|
@ -108,6 +108,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser')
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser');
|
.leftJoinAndSelect('renote.user', 'renoteUser');
|
||||||
|
|
||||||
|
// NOTE: センシティブ除外の設定はこのエンドポイントでは無視する。
|
||||||
|
// https://github.com/misskey-dev/misskey/pull/15346#discussion_r1929950255
|
||||||
|
|
||||||
this.queryService.generateVisibilityQuery(query, me);
|
this.queryService.generateVisibilityQuery(query, me);
|
||||||
this.queryService.generateMutedUserQueryForNotes(query, me);
|
this.queryService.generateMutedUserQueryForNotes(query, me);
|
||||||
this.queryService.generateBlockedUserQueryForNotes(query, me);
|
this.queryService.generateBlockedUserQueryForNotes(query, me);
|
||||||
|
|
|
@ -72,6 +72,7 @@ export const paramDef = {
|
||||||
excludeBots: { type: 'boolean' },
|
excludeBots: { type: 'boolean' },
|
||||||
withReplies: { type: 'boolean' },
|
withReplies: { type: 'boolean' },
|
||||||
withFile: { type: 'boolean' },
|
withFile: { type: 'boolean' },
|
||||||
|
excludeNotesInSensitiveChannel: { type: 'boolean' },
|
||||||
},
|
},
|
||||||
required: ['antennaId'],
|
required: ['antennaId'],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -129,6 +130,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
excludeBots: ps.excludeBots,
|
excludeBots: ps.excludeBots,
|
||||||
withReplies: ps.withReplies,
|
withReplies: ps.withReplies,
|
||||||
withFile: ps.withFile,
|
withFile: ps.withFile,
|
||||||
|
excludeNotesInSensitiveChannel: ps.excludeNotesInSensitiveChannel,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
lastUsedAt: new Date(),
|
lastUsedAt: new Date(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -46,6 +46,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private chatService: ChatService,
|
private chatService: ChatService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
await this.chatService.checkChatAvailability(me.id, 'read');
|
||||||
|
|
||||||
const history = ps.room ? await this.chatService.roomHistory(me.id, ps.limit) : await this.chatService.userHistory(me.id, ps.limit);
|
const history = ps.room ? await this.chatService.roomHistory(me.id, ps.limit) : await this.chatService.userHistory(me.id, ps.limit);
|
||||||
|
|
||||||
const packedMessages = await this.chatEntityService.packMessagesDetailed(history, me);
|
const packedMessages = await this.chatEntityService.packMessagesDetailed(history, me);
|
||||||
|
|
|
@ -16,7 +16,6 @@ export const meta = {
|
||||||
tags: ['chat'],
|
tags: ['chat'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requiredRolePolicy: 'canChat',
|
|
||||||
|
|
||||||
prohibitMoved: true,
|
prohibitMoved: true,
|
||||||
|
|
||||||
|
@ -30,7 +29,7 @@ export const meta = {
|
||||||
res: {
|
res: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
ref: 'ChatMessageLite',
|
ref: 'ChatMessageLiteForRoom',
|
||||||
},
|
},
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
|
@ -74,6 +73,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private chatService: ChatService,
|
private chatService: ChatService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
await this.chatService.checkChatAvailability(me.id, 'write');
|
||||||
|
|
||||||
const room = await this.chatService.findRoomById(ps.toRoomId);
|
const room = await this.chatService.findRoomById(ps.toRoomId);
|
||||||
if (room == null) {
|
if (room == null) {
|
||||||
throw new ApiError(meta.errors.noSuchRoom);
|
throw new ApiError(meta.errors.noSuchRoom);
|
||||||
|
|
|
@ -16,7 +16,6 @@ export const meta = {
|
||||||
tags: ['chat'],
|
tags: ['chat'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requiredRolePolicy: 'canChat',
|
|
||||||
|
|
||||||
prohibitMoved: true,
|
prohibitMoved: true,
|
||||||
|
|
||||||
|
@ -30,7 +29,7 @@ export const meta = {
|
||||||
res: {
|
res: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
ref: 'ChatMessageLite',
|
ref: 'ChatMessageLiteFor1on1',
|
||||||
},
|
},
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
|
@ -86,6 +85,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private chatService: ChatService,
|
private chatService: ChatService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
await this.chatService.checkChatAvailability(me.id, 'write');
|
||||||
|
|
||||||
let file = null;
|
let file = null;
|
||||||
if (ps.fileId != null) {
|
if (ps.fileId != null) {
|
||||||
file = await this.driveFilesRepository.findOneBy({
|
file = await this.driveFilesRepository.findOneBy({
|
||||||
|
|
|
@ -42,6 +42,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private chatService: ChatService,
|
private chatService: ChatService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
await this.chatService.checkChatAvailability(me.id, 'write');
|
||||||
|
|
||||||
const message = await this.chatService.findMyMessageById(me.id, ps.messageId);
|
const message = await this.chatService.findMyMessageById(me.id, ps.messageId);
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
throw new ApiError(meta.errors.noSuchMessage);
|
throw new ApiError(meta.errors.noSuchMessage);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue