mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-27 10:20:27 +01:00
Merge branch 'develop' into fix-ptr-event-handling
This commit is contained in:
commit
73b359bce8
229 changed files with 6384 additions and 4558 deletions
|
@ -5,7 +5,7 @@
|
||||||
"workspaceFolder": "/workspace",
|
"workspaceFolder": "/workspace",
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/node:1": {
|
"ghcr.io/devcontainers/features/node:1": {
|
||||||
"version": "20.16.0"
|
"version": "22.11.0"
|
||||||
},
|
},
|
||||||
"ghcr.io/devcontainers-contrib/features/corepack:1": {}
|
"ghcr.io/devcontainers-contrib/features/corepack:1": {}
|
||||||
},
|
},
|
||||||
|
|
2
.github/workflows/get-api-diff.yml
vendored
2
.github/workflows/get-api-diff.yml
vendored
|
@ -17,7 +17,7 @@ jobs:
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [20.16.0]
|
node-version: [22.11.0]
|
||||||
api-json-name: [api-base.json, api-head.json]
|
api-json-name: [api-base.json, api-head.json]
|
||||||
include:
|
include:
|
||||||
- api-json-name: api-base.json
|
- api-json-name: api-base.json
|
||||||
|
|
2
.github/workflows/on-release-created.yml
vendored
2
.github/workflows/on-release-created.yml
vendored
|
@ -17,7 +17,7 @@ jobs:
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [20.16.0]
|
node-version: [22.11.0]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.1.1
|
||||||
|
|
8
.github/workflows/test-backend.yml
vendored
8
.github/workflows/test-backend.yml
vendored
|
@ -22,7 +22,7 @@ jobs:
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [20.16.0]
|
node-version: [22.11.0]
|
||||||
|
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
|
@ -61,7 +61,7 @@ jobs:
|
||||||
- name: Test
|
- name: Test
|
||||||
run: pnpm --filter backend test-and-coverage
|
run: pnpm --filter backend test-and-coverage
|
||||||
- name: Upload to Codecov
|
- name: Upload to Codecov
|
||||||
uses: codecov/codecov-action@v4
|
uses: codecov/codecov-action@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
files: ./packages/backend/coverage/coverage-final.json
|
files: ./packages/backend/coverage/coverage-final.json
|
||||||
|
@ -71,7 +71,7 @@ jobs:
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [20.16.0]
|
node-version: [22.11.0]
|
||||||
|
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
|
@ -108,7 +108,7 @@ jobs:
|
||||||
- name: Test
|
- name: Test
|
||||||
run: pnpm --filter backend test-and-coverage:e2e
|
run: pnpm --filter backend test-and-coverage:e2e
|
||||||
- name: Upload to Codecov
|
- name: Upload to Codecov
|
||||||
uses: codecov/codecov-action@v4
|
uses: codecov/codecov-action@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
files: ./packages/backend/coverage/coverage-final.json
|
files: ./packages/backend/coverage/coverage-final.json
|
||||||
|
|
2
.github/workflows/test-federation.yml
vendored
2
.github/workflows/test-federation.yml
vendored
|
@ -20,7 +20,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [20.16.0]
|
node-version: [22.11.0]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
|
|
6
.github/workflows/test-frontend.yml
vendored
6
.github/workflows/test-frontend.yml
vendored
|
@ -26,7 +26,7 @@ jobs:
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [20.16.0]
|
node-version: [22.11.0]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.1.1
|
||||||
|
@ -50,7 +50,7 @@ jobs:
|
||||||
- name: Test
|
- name: Test
|
||||||
run: pnpm --filter frontend test-and-coverage
|
run: pnpm --filter frontend test-and-coverage
|
||||||
- name: Upload Coverage
|
- name: Upload Coverage
|
||||||
uses: codecov/codecov-action@v4
|
uses: codecov/codecov-action@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
files: ./packages/frontend/coverage/coverage-final.json
|
files: ./packages/frontend/coverage/coverage-final.json
|
||||||
|
@ -61,7 +61,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [20.16.0]
|
node-version: [22.11.0]
|
||||||
browser: [chrome]
|
browser: [chrome]
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|
4
.github/workflows/test-misskey-js.yml
vendored
4
.github/workflows/test-misskey-js.yml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [20.16.0]
|
node-version: [22.11.0]
|
||||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
@ -51,7 +51,7 @@ jobs:
|
||||||
CI: true
|
CI: true
|
||||||
|
|
||||||
- name: Upload Coverage
|
- name: Upload Coverage
|
||||||
uses: codecov/codecov-action@v4
|
uses: codecov/codecov-action@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
files: ./packages/misskey-js/coverage/coverage-final.json
|
files: ./packages/misskey-js/coverage/coverage-final.json
|
||||||
|
|
2
.github/workflows/test-production.yml
vendored
2
.github/workflows/test-production.yml
vendored
|
@ -16,7 +16,7 @@ jobs:
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [20.16.0]
|
node-version: [22.11.0]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.1.1
|
||||||
|
|
2
.github/workflows/validate-api-json.yml
vendored
2
.github/workflows/validate-api-json.yml
vendored
|
@ -18,7 +18,7 @@ jobs:
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [20.16.0]
|
node-version: [22.11.0]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.1
|
- uses: actions/checkout@v4.1.1
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -68,6 +68,8 @@ misskey-assets
|
||||||
# Vite temporary files
|
# Vite temporary files
|
||||||
vite.config.js.timestamp-*
|
vite.config.js.timestamp-*
|
||||||
vite.config.ts.timestamp-*
|
vite.config.ts.timestamp-*
|
||||||
|
vite.config.local-dev.js.timestamp-*
|
||||||
|
vite.config.local-dev.ts.timestamp-*
|
||||||
|
|
||||||
# blender backups
|
# blender backups
|
||||||
*.blend1
|
*.blend1
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
20.16.0
|
22.11.0
|
||||||
|
|
55
CHANGELOG.md
55
CHANGELOG.md
|
@ -1,25 +1,78 @@
|
||||||
## 2024.10.2
|
## 2024.11.0
|
||||||
|
|
||||||
|
### Note
|
||||||
|
- Node.js 20.xは非推奨になりました。Node.js 22.x (LTS)の利用を推奨します。
|
||||||
|
- なお、Node.js 23.xは対応していません。
|
||||||
|
- DockerのNode.jsが22.11.0に更新されました
|
||||||
|
|
||||||
### General
|
### General
|
||||||
- Feat: コンテンツの表示にログインを必須にできるように
|
- Feat: コンテンツの表示にログインを必須にできるように
|
||||||
- Feat: 過去のノートを非公開化/フォロワーのみ表示可能にできるように
|
- Feat: 過去のノートを非公開化/フォロワーのみ表示可能にできるように
|
||||||
|
- Enhance: 依存関係の更新
|
||||||
|
- Enhance: l10nの更新
|
||||||
|
- Fix: お知らせ作成時に画像URL入力欄を空欄に変更できないのを修正 ( #14976 )
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
- Enhance: Bull DashboardでRelationship Queueの状態も確認できるように
|
- Enhance: Bull DashboardでRelationship Queueの状態も確認できるように
|
||||||
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/751)
|
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/751)
|
||||||
- Enhance: ドライブでソートができるように
|
- Enhance: ドライブでソートができるように
|
||||||
|
- Enhance: アイコンデコレーション管理画面の改善
|
||||||
- Enhance: 「単なるラッキー」の取得条件を変更
|
- Enhance: 「単なるラッキー」の取得条件を変更
|
||||||
- Enhance: 投稿フォームでEscキーを押したときIME入力中ならフォームを閉じないように( #10866 )
|
- Enhance: 投稿フォームでEscキーを押したときIME入力中ならフォームを閉じないように( #10866 )
|
||||||
|
- Enhance: MiAuth, OAuthの認可画面の改善
|
||||||
|
- どのアカウントで認証しようとしているのかがわかるように
|
||||||
|
- 認証するアカウントを切り替えられるように
|
||||||
|
- Enhance: Self-XSS防止用の警告を追加
|
||||||
|
- Enhance: カタルーニャ語 (ca-ES) に対応
|
||||||
|
- Enhance: 個別お知らせページではMetaタグを出力するように
|
||||||
|
- Enhance: ノート詳細画面にロールのバッジを表示
|
||||||
|
- Enhance: 過去に送信したフォローリクエストを確認できるように
|
||||||
|
(Based on https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/663)
|
||||||
|
- Enhance: サイドバーを簡単に展開・折りたたみできるように ( #14981 )
|
||||||
|
- Enhance: リノートメニューに「リノートの詳細」を追加
|
||||||
|
- Enhance: 非ログイン状態でMisskeyを開いた際のパフォーマンスを向上
|
||||||
- Fix: 通知の範囲指定の設定項目が必要ない通知設定でも範囲指定の設定がでている問題を修正
|
- Fix: 通知の範囲指定の設定項目が必要ない通知設定でも範囲指定の設定がでている問題を修正
|
||||||
- Fix: Turnstileが失敗・期限切れした際にも成功扱いとなってしまう問題を修正
|
- Fix: Turnstileが失敗・期限切れした際にも成功扱いとなってしまう問題を修正
|
||||||
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/768)
|
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/768)
|
||||||
- Fix: デッキのタイムラインカラムで「センシティブなファイルを含むノートを表示」設定が使用できなかった問題を修正
|
- Fix: デッキのタイムラインカラムで「センシティブなファイルを含むノートを表示」設定が使用できなかった問題を修正
|
||||||
|
- Fix: Encode RSS urls with escape sequences before fetching allowing query parameters to be used
|
||||||
|
- Fix: リンク切れを修正
|
||||||
|
= Fix: ノート投稿ボタンにホバー時のスタイルが適用されていないのを修正
|
||||||
|
(Cherry-picked from https://github.com/taiyme/misskey/pull/305)
|
||||||
|
- Fix: メールアドレス登録有効化時の「完了」ダイアログボックスの表示条件を修正
|
||||||
|
- Fix: 画面幅が狭い環境でデザインが崩れる問題を修正
|
||||||
|
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/815)
|
||||||
|
- Fix: TypeScriptの型チェック対象ファイルを限定してビルドを高速化するように
|
||||||
|
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/725)
|
||||||
- Fix: ごくまれに上方向へのスクロールができなくなる問題を抑制
|
- Fix: ごくまれに上方向へのスクロールができなくなる問題を抑制
|
||||||
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/244)
|
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/244)
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
|
- Enhance: DockerのNode.jsを22.11.0に更新
|
||||||
|
- Enhance: 起動前の疎通チェックで、DBとメイン以外のRedisの疎通確認も行うように
|
||||||
|
(Based on https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/588)
|
||||||
|
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/715)
|
||||||
|
- Enhance: リモートユーザーの照会をオリジナルにリダイレクトするように
|
||||||
|
- Fix: sharedInboxが無いActorに紐づくリモートユーザーを照会できない
|
||||||
|
- Fix: Aproving request from GtS appears with some delay
|
||||||
|
- Fix: フォロワーへのメッセージの絵文字をemojisに含めるように
|
||||||
- Fix: Nested proxy requestsを検出した際にブロックするように
|
- Fix: Nested proxy requestsを検出した際にブロックするように
|
||||||
[ghsa-gq5q-c77c-v236](https://github.com/misskey-dev/misskey/security/advisories/ghsa-gq5q-c77c-v236)
|
[ghsa-gq5q-c77c-v236](https://github.com/misskey-dev/misskey/security/advisories/ghsa-gq5q-c77c-v236)
|
||||||
|
- Fix: 招待コードの発行可能な残り数算出に使用すべきロールポリシーの値が違う問題を修正
|
||||||
|
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/706)
|
||||||
|
- Fix: 連合への配信時に、acctの大小文字が区別されてしまい正しくメンションが処理されないことがある問題を修正
|
||||||
|
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/711)
|
||||||
|
- Fix: ローカルユーザーへのメンションを含むノートが連合される際に正しいURLに変換されないことがある問題を修正
|
||||||
|
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/712)
|
||||||
|
- Fix: FTT無効時にユーザーリストタイムラインが使用できない問題を修正
|
||||||
|
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/709)
|
||||||
|
- Fix: User Webhookテスト機能のMock Payloadを修正
|
||||||
|
- Fix: アカウント削除のモデレーションログが動作していないのを修正 (#14996)
|
||||||
|
- Fix: リノートミュートが新規投稿通知に対して作用していなかった問題を修正
|
||||||
|
- Fix: セキュリティに関する修正
|
||||||
|
|
||||||
|
### Misskey.js
|
||||||
|
- Fix: Stream初期化時、別途WebSocketを指定する場合の型定義を修正
|
||||||
|
|
||||||
## 2024.10.1
|
## 2024.10.1
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,10 @@ One should not add property that has defined before by other implementation, or
|
||||||
## Reviewers guide
|
## Reviewers guide
|
||||||
Be willing to comment on the good points and not just the things you want fixed 💯
|
Be willing to comment on the good points and not just the things you want fixed 💯
|
||||||
|
|
||||||
|
読んでおくといいやつ
|
||||||
|
- https://blog.lacolaco.net/posts/1e2cf439b3c2/
|
||||||
|
- https://konifar-zatsu.hatenadiary.jp/entry/2024/11/05/192421
|
||||||
|
|
||||||
### Review perspective
|
### Review perspective
|
||||||
- Scope
|
- Scope
|
||||||
- Are the goals of the PR clear?
|
- Are the goals of the PR clear?
|
||||||
|
@ -97,6 +101,22 @@ Be willing to comment on the good points and not just the things you want fixed
|
||||||
- Are there any omissions or gaps?
|
- Are there any omissions or gaps?
|
||||||
- Does it check for anomalies?
|
- Does it check for anomalies?
|
||||||
|
|
||||||
|
## Security Advisory
|
||||||
|
### For reporter
|
||||||
|
Thank you for your reporting!
|
||||||
|
|
||||||
|
If you can also create a patch to fix the vulnerability, please create a PR on the private fork.
|
||||||
|
|
||||||
|
> [!note]
|
||||||
|
> There is a GitHub bug that prevents merging if a PR not following the develop branch of upstream, so please keep follow the develop branch.
|
||||||
|
|
||||||
|
### For misskey-dev member
|
||||||
|
修正PRがdevelopに追従されていないとマージできないので、マージできなかったら
|
||||||
|
|
||||||
|
> Could you merge or rebase onto upstream develop branch?
|
||||||
|
|
||||||
|
などと伝える。
|
||||||
|
|
||||||
## Deploy
|
## Deploy
|
||||||
The `/deploy` command by issue comment can be used to deploy the contents of a PR to the preview environment.
|
The `/deploy` command by issue comment can be used to deploy the contents of a PR to the preview environment.
|
||||||
```
|
```
|
||||||
|
@ -132,7 +152,8 @@ You can improve our translations with your Crowdin account.
|
||||||
Your changes in Crowdin are automatically submitted as a PR (with the title "New Crowdin translations") to the repository.
|
Your changes in Crowdin are automatically submitted as a PR (with the title "New Crowdin translations") to the repository.
|
||||||
The owner [@syuilo](https://github.com/syuilo) merges the PR into the develop branch before the next release.
|
The owner [@syuilo](https://github.com/syuilo) merges the PR into the develop branch before the next release.
|
||||||
|
|
||||||
If your language is not listed in Crowdin, please open an issue.
|
If your language is not listed in Crowdin, please open an issue. We will add it to Crowdin.
|
||||||
|
For newly added languages, once the translation progress per language exceeds 70%, it will be officially introduced into Misskey and made available to users.
|
||||||
|
|
||||||
![Crowdin](https://d322cqt584bo4o.cloudfront.net/misskey/localized.svg)
|
![Crowdin](https://d322cqt584bo4o.cloudfront.net/misskey/localized.svg)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# syntax = docker/dockerfile:1.4
|
# syntax = docker/dockerfile:1.4
|
||||||
|
|
||||||
ARG NODE_VERSION=20.16.0-bullseye
|
ARG NODE_VERSION=22.11.0-bullseye
|
||||||
|
|
||||||
# build assets & compile TypeScript
|
# build assets & compile TypeScript
|
||||||
|
|
||||||
|
|
|
@ -6,3 +6,10 @@ This will allow us to assess the risk, and make a fix available before we add a
|
||||||
bug report to the GitHub repository.
|
bug report to the GitHub repository.
|
||||||
|
|
||||||
Thanks for helping make Misskey safe for everyone.
|
Thanks for helping make Misskey safe for everyone.
|
||||||
|
|
||||||
|
## When create a patch
|
||||||
|
|
||||||
|
If you can also create a patch to fix the vulnerability, please create a PR on the private fork.
|
||||||
|
|
||||||
|
> [!note]
|
||||||
|
> There is a GitHub bug that prevents merging if a PR not following the develop branch of upstream, so please keep follow the develop branch.
|
||||||
|
|
|
@ -343,7 +343,6 @@ enableLocalTimeline: "تفعيل الخيط المحلي"
|
||||||
enableGlobalTimeline: "تفعيل الخيط الزمني الشامل"
|
enableGlobalTimeline: "تفعيل الخيط الزمني الشامل"
|
||||||
disablingTimelinesInfo: "سيتمكن المديرون والمشرفون من الوصول إلى كل الخيوط الزمنية حتى وإن لم تفعّل."
|
disablingTimelinesInfo: "سيتمكن المديرون والمشرفون من الوصول إلى كل الخيوط الزمنية حتى وإن لم تفعّل."
|
||||||
registration: "إنشاء حساب"
|
registration: "إنشاء حساب"
|
||||||
enableRegistration: "تفعيل إنشاء الحسابات الجديدة"
|
|
||||||
invite: "دعوة"
|
invite: "دعوة"
|
||||||
driveCapacityPerLocalAccount: "حصة التخزين لكل مستخدم محلي"
|
driveCapacityPerLocalAccount: "حصة التخزين لكل مستخدم محلي"
|
||||||
driveCapacityPerRemoteAccount: "حصة التخزين لكل مستخدم بعيد"
|
driveCapacityPerRemoteAccount: "حصة التخزين لكل مستخدم بعيد"
|
||||||
|
|
|
@ -339,7 +339,6 @@ enableLocalTimeline: "স্থানীয় টাইমলাইন চাল
|
||||||
enableGlobalTimeline: "গ্লোবাল টাইমলাইন চালু করুন"
|
enableGlobalTimeline: "গ্লোবাল টাইমলাইন চালু করুন"
|
||||||
disablingTimelinesInfo: "আপনি এই টাইমলাইনগুলি বন্ধ করলেও প্রশাসক এবং মডারেটররা এই টাইমলাইনগুলি ব্যাবহার করতে পারবে"
|
disablingTimelinesInfo: "আপনি এই টাইমলাইনগুলি বন্ধ করলেও প্রশাসক এবং মডারেটররা এই টাইমলাইনগুলি ব্যাবহার করতে পারবে"
|
||||||
registration: "নিবন্ধন"
|
registration: "নিবন্ধন"
|
||||||
enableRegistration: "নতুন ব্যাবহারকারী নিবন্ধন চালু করুন"
|
|
||||||
invite: "আমন্ত্রণ"
|
invite: "আমন্ত্রণ"
|
||||||
driveCapacityPerLocalAccount: "প্রত্যেক স্থানীয় ব্যাবহারকারীর জন্য ড্রাইভের জায়গা"
|
driveCapacityPerLocalAccount: "প্রত্যেক স্থানীয় ব্যাবহারকারীর জন্য ড্রাইভের জায়গা"
|
||||||
driveCapacityPerRemoteAccount: "প্রত্যেক রিমোট ব্যাবহারকারীর জন্য ড্রাইভের জায়গা"
|
driveCapacityPerRemoteAccount: "প্রত্যেক রিমোট ব্যাবহারকারীর জন্য ড্রাইভের জায়গা"
|
||||||
|
|
|
@ -2,42 +2,43 @@
|
||||||
_lang_: "Català"
|
_lang_: "Català"
|
||||||
headlineMisskey: "Una xarxa connectada per notes"
|
headlineMisskey: "Una xarxa connectada per notes"
|
||||||
introMisskey: "Benvingut! Misskey és un servei de microblogging descentralitzat de codi obert.\nCrea \"notes\" per compartir els teus pensaments amb tots els que t'envolten. 📡\nAmb \"reaccions\", també pots expressar ràpidament els teus sentiments sobre les notes de tothom. 👍\nExplorem un món nou! 🚀"
|
introMisskey: "Benvingut! Misskey és un servei de microblogging descentralitzat de codi obert.\nCrea \"notes\" per compartir els teus pensaments amb tots els que t'envolten. 📡\nAmb \"reaccions\", també pots expressar ràpidament els teus sentiments sobre les notes de tothom. 👍\nExplorem un món nou! 🚀"
|
||||||
poweredByMisskeyDescription: "{name} És un del serveis (anomenats instàncies de Misskey) que utilitzen la plataforma de codi obert <b>Misskey</b>."
|
poweredByMisskeyDescription: "{name} És un dels serveis (anomenats instàncies de Misskey) que utilitzen la plataforma de codi obert <b>Misskey</b>."
|
||||||
monthAndDay: "{day}/{month}"
|
monthAndDay: "{day}/{month}"
|
||||||
search: "Cercar"
|
search: "Cercar"
|
||||||
notifications: "Notificacions"
|
notifications: "Notificacions"
|
||||||
username: "Nom d'usuari"
|
username: "Nom d'usuari"
|
||||||
password: "Contrasenya"
|
password: "Contrasenya"
|
||||||
initialPasswordForSetup: "Contrasenya inicial per la configuració inicial"
|
initialPasswordForSetup: "Contrasenya inicial per fer la primera configuració "
|
||||||
initialPasswordIsIncorrect: "La contrasenya no és correcta."
|
initialPasswordIsIncorrect: "La contrasenya no és correcta."
|
||||||
forgotPassword: "Contrasenya oblidada"
|
initialPasswordForSetupDescription: "Fes servir la contrasenya que has fet servir al fitxer de configuració, si tu mateix has instal·lat Misskey.\nSi fas servir una empresa d'allotjament de Misskey, fes servir la contrasenya que t'han donat.\nSi no has posat cap contrasenya deixar l'espai en blanc."
|
||||||
fetchingAsApObject: "Cercant en el Fediverse..."
|
forgotPassword: "Restableix la contrasenya "
|
||||||
|
fetchingAsApObject: "Cercant al Fediverse..."
|
||||||
ok: "OK"
|
ok: "OK"
|
||||||
gotIt: "Ho he entès!"
|
gotIt: "D'acord "
|
||||||
cancel: "Cancel·lar"
|
cancel: "Cancel·lar"
|
||||||
noThankYou: "No, gràcies"
|
noThankYou: "No, gràcies"
|
||||||
enterUsername: "Introdueix el teu nom d'usuari"
|
enterUsername: "Introdueix el teu nom d'usuari"
|
||||||
renotedBy: "Impulsat per {usuari}"
|
renotedBy: "Impulsat per {user}"
|
||||||
noNotes: "Cap nota"
|
noNotes: "Cap nota"
|
||||||
noNotifications: "Cap notificació"
|
noNotifications: "Cap notificació"
|
||||||
instance: "Servidor"
|
instance: "Instància "
|
||||||
settings: "Preferències"
|
settings: "Preferències"
|
||||||
notificationSettings: "Paràmetres de notificacions"
|
notificationSettings: "Configurar les notificacions"
|
||||||
basicSettings: "Configuració bàsica"
|
basicSettings: "Configuració bàsica"
|
||||||
otherSettings: "Configuració avançada"
|
otherSettings: "Altres configuracions"
|
||||||
openInWindow: "Obrir en una nova finestra"
|
openInWindow: "Obrir en una finestra nova"
|
||||||
profile: "Perfil"
|
profile: "Perfil"
|
||||||
timeline: "Línia de temps"
|
timeline: "Línia de temps"
|
||||||
noAccountDescription: "Aquest usuari encara no ha escrit la seva biografia."
|
noAccountDescription: "Aquest usuari encara no ha escrit la seva biografia."
|
||||||
login: "Iniciar sessió"
|
login: "Iniciar sessió"
|
||||||
loggingIn: "Identificant-se"
|
loggingIn: "Iniciar la sessió "
|
||||||
logout: "Tancar la sessió"
|
logout: "Tancar la sessió"
|
||||||
signup: "Registrar-se"
|
signup: "Registrar-se"
|
||||||
uploading: "Pujant..."
|
uploading: "Pujant..."
|
||||||
save: "Desa"
|
save: "Desa"
|
||||||
users: "Usuaris"
|
users: "Usuaris"
|
||||||
addUser: "Afegir un usuari"
|
addUser: "Afegir un usuari"
|
||||||
favorite: "Afegir a preferits"
|
favorite: "Afegeix als preferits"
|
||||||
favorites: "Favorits"
|
favorites: "Favorits"
|
||||||
unfavorite: "Eliminar dels preferits"
|
unfavorite: "Eliminar dels preferits"
|
||||||
favorited: "Afegit als preferits."
|
favorited: "Afegit als preferits."
|
||||||
|
@ -49,26 +50,26 @@ copyContent: "Copiar el contingut"
|
||||||
copyLink: "Copiar l'enllaç"
|
copyLink: "Copiar l'enllaç"
|
||||||
copyLinkRenote: "Copiar l'enllaç de la renota"
|
copyLinkRenote: "Copiar l'enllaç de la renota"
|
||||||
delete: "Elimina"
|
delete: "Elimina"
|
||||||
deleteAndEdit: "Elimina i edita"
|
deleteAndEdit: "Eliminar i editar"
|
||||||
deleteAndEditConfirm: "Segur que vols eliminar aquesta publicació i editar-la? Perdràs totes les reaccions, impulsos i respostes."
|
deleteAndEditConfirm: "Segur que vols eliminar aquesta publicació i editar-la? Perdràs totes les reaccions, impulsos i respostes."
|
||||||
addToList: "Afegir a una llista"
|
addToList: "Afegir a una llista"
|
||||||
addToAntenna: "Afegir a l'antena"
|
addToAntenna: "Afegir a una antena"
|
||||||
sendMessage: "Enviar un missatge"
|
sendMessage: "Enviar un missatge"
|
||||||
copyRSS: "Copiar RSS"
|
copyRSS: "Copiar RSS"
|
||||||
copyUsername: "Copiar nom d'usuari"
|
copyUsername: "Copiar nom d'usuari"
|
||||||
copyUserId: "Copiar ID d'usuari"
|
copyUserId: "Copiar ID d'usuari"
|
||||||
copyNoteId: "Copiar ID de nota"
|
copyNoteId: "Copiar ID de la nota"
|
||||||
copyFileId: "Copiar ID d'arxiu"
|
copyFileId: "Copiar ID de l'arxiu"
|
||||||
copyFolderId: "Copiar ID de carpeta"
|
copyFolderId: "Copiar ID de la carpeta"
|
||||||
copyProfileUrl: "Copiar URL del perfil"
|
copyProfileUrl: "Copiar adreça URL del perfil"
|
||||||
searchUser: "Cercar un usuari"
|
searchUser: "Cercar un usuari"
|
||||||
searchThisUsersNotes: "Cerca les publicacions de l'usuari"
|
searchThisUsersNotes: "Cercar les publicacions de l'usuari"
|
||||||
reply: "Respondre"
|
reply: "Respon"
|
||||||
loadMore: "Carregar més"
|
loadMore: "Carregar més"
|
||||||
showMore: "Veure més"
|
showMore: "Veure més"
|
||||||
showLess: "Mostra menys"
|
showLess: "Mostrar menys"
|
||||||
youGotNewFollower: "t'ha seguit"
|
youGotNewFollower: "t'ha seguit"
|
||||||
receiveFollowRequest: "Sol·licitud de seguiment rebuda"
|
receiveFollowRequest: "Has rebut una sol·licitud de seguiment"
|
||||||
followRequestAccepted: "Sol·licitud de seguiment acceptada"
|
followRequestAccepted: "Sol·licitud de seguiment acceptada"
|
||||||
mention: "Menció"
|
mention: "Menció"
|
||||||
mentions: "Mencions"
|
mentions: "Mencions"
|
||||||
|
@ -77,25 +78,25 @@ importAndExport: "Importar / Exportar"
|
||||||
import: "Importar"
|
import: "Importar"
|
||||||
export: "Exporta"
|
export: "Exporta"
|
||||||
files: "Fitxers"
|
files: "Fitxers"
|
||||||
download: "Baixar"
|
download: "Descarregar"
|
||||||
driveFileDeleteConfirm: "Estàs segur que vols suprimir el fitxer \"{name}\"? Les notes associades a aquest fitxer adjunt també se suprimiran."
|
driveFileDeleteConfirm: "Estàs segur que vols suprimir el fitxer \"{name}\"? Les notes associades a aquest fitxer també seran esborrades."
|
||||||
unfollowConfirm: "Estàs segur que vols deixar de seguir {name}?"
|
unfollowConfirm: "Segur que vols deixar de seguir a {name}?"
|
||||||
exportRequested: "Has sol·licitat una exportació. Això pot trigar una estona. S'afegirà a la teva unitat un cop completat."
|
exportRequested: "Has sol·licitat una exportació de dades. Això pot trigar una estona. S'afegirà a la teva unitat de disc un cop estigui completada."
|
||||||
importRequested: "Has sol·licitat una importació. Això pot trigar una estona."
|
importRequested: "Has sol·licitat una importació de dades. Això pot trigar una estona."
|
||||||
lists: "Llistes"
|
lists: "Llistes"
|
||||||
noLists: "No tens cap llista"
|
noLists: "No tens cap llista"
|
||||||
note: "Nota"
|
note: "Nota"
|
||||||
notes: "Notes"
|
notes: "Notes"
|
||||||
following: "Seguint"
|
following: "Segueixes "
|
||||||
followers: "Seguidors"
|
followers: "Seguidors"
|
||||||
followsYou: "Et segueix"
|
followsYou: "Et segueix"
|
||||||
createList: "Crear llista"
|
createList: "Crear llista"
|
||||||
manageLists: "Gestionar les llistes"
|
manageLists: "Gestionar les llistes"
|
||||||
error: "Error"
|
error: "Error"
|
||||||
somethingHappened: "S'ha produït un error"
|
somethingHappened: "S'ha produït un error"
|
||||||
retry: "Torna-ho a intentar"
|
retry: "Torna-ho a provar"
|
||||||
pageLoadError: "S'ha produït un error en carregar la pàgina"
|
pageLoadError: "S'ha produït un error en carregar la pàgina"
|
||||||
pageLoadErrorDescription: "Això normalment es deu a errors de xarxa o a la memòria cau del navegador. Prova d'esborrar la memòria cau i torna-ho a provar després d'esperar una estona."
|
pageLoadErrorDescription: "Això normalment és a causa d'errors a la xarxa o a la memòria cau del navegador. Prova d'esborrar la memòria cau i torna-ho a provar després d'esperar un temps."
|
||||||
serverIsDead: "Aquest servidor no respon. Espera una estona i torna-ho a provar."
|
serverIsDead: "Aquest servidor no respon. Espera una estona i torna-ho a provar."
|
||||||
youShouldUpgradeClient: "Per veure aquesta pàgina, actualitzeu-la per actualitzar el vostre client."
|
youShouldUpgradeClient: "Per veure aquesta pàgina, actualitzeu-la per actualitzar el vostre client."
|
||||||
enterListName: "Introdueix un nom per a la llista"
|
enterListName: "Introdueix un nom per a la llista"
|
||||||
|
@ -103,52 +104,52 @@ privacy: "Privadesa"
|
||||||
makeFollowManuallyApprove: "Les sol·licituds de seguiment requereixen aprovació"
|
makeFollowManuallyApprove: "Les sol·licituds de seguiment requereixen aprovació"
|
||||||
defaultNoteVisibility: "Visibilitat per defecte"
|
defaultNoteVisibility: "Visibilitat per defecte"
|
||||||
follow: "Seguint"
|
follow: "Seguint"
|
||||||
followRequest: "Enviar la sol·licitud de seguiment"
|
followRequest: "Enviar sol·licitud de seguiment"
|
||||||
followRequests: "Sol·licituds de seguiment"
|
followRequests: "Sol·licituds de seguiment"
|
||||||
unfollow: "Deixar de seguir"
|
unfollow: "Deixar de seguir"
|
||||||
followRequestPending: "Sol·licituds de seguiment pendents"
|
followRequestPending: "Sol·licituds de seguiment pendents"
|
||||||
enterEmoji: "Introduir un emoji"
|
enterEmoji: "Introduir un emoji"
|
||||||
renote: "Impulsa"
|
renote: "Impulsar "
|
||||||
unrenote: "Anul·la l'impuls"
|
unrenote: "Anul·la l'impuls"
|
||||||
renoted: "S'ha impulsat"
|
renoted: "S'ha impulsat"
|
||||||
renotedToX: "Impulsat per {name}."
|
renotedToX: "Impulsat per {name}."
|
||||||
cantRenote: "No es pot impulsar aquesta publicació"
|
cantRenote: "No es pot impulsar aquesta publicació"
|
||||||
cantReRenote: "No es pot impulsar l'impuls."
|
cantReRenote: "No es pot impulsar un impuls."
|
||||||
quote: "Cita"
|
quote: "Cita"
|
||||||
inChannelRenote: "Renotar només al Canal"
|
inChannelRenote: "Impulsar només a un canal"
|
||||||
inChannelQuote: "Citar només al Canal"
|
inChannelQuote: "Citar només a un canal"
|
||||||
renoteToChannel: "Impulsa a un canal"
|
renoteToChannel: "Impulsar a un canal"
|
||||||
renoteToOtherChannel: "Impulsa a un altre canal"
|
renoteToOtherChannel: "Impulsar a un altre canal"
|
||||||
pinnedNote: "Nota fixada"
|
pinnedNote: "Nota fixada"
|
||||||
pinned: "Fixar al perfil"
|
pinned: "Fixar al perfil"
|
||||||
you: "Tu"
|
you: "Tu"
|
||||||
clickToShow: "Fes clic per mostrar"
|
clickToShow: "Fes clic per mostrar"
|
||||||
sensitive: "NSFW"
|
sensitive: "Sensible"
|
||||||
add: "Afegir"
|
add: "Afegir"
|
||||||
reaction: "Reaccions"
|
reaction: "Reacció "
|
||||||
reactions: "Reaccions"
|
reactions: "Reaccions"
|
||||||
emojiPicker: "Selecció d'emojis"
|
emojiPicker: "Selector d'emojis"
|
||||||
pinnedEmojisForReactionSettingDescription: "Selecciona l'emoji amb el qual reaccionar"
|
pinnedEmojisForReactionSettingDescription: "Selecciona l'emoji amb qui vols reaccionar"
|
||||||
pinnedEmojisSettingDescription: "Selecciona l'emoji amb el qual reaccionar"
|
pinnedEmojisSettingDescription: "Selecciona quins emojis vols deixar fixats i es mostrin en obrir el selector d'emojis"
|
||||||
emojiPickerDisplay: "Visualitza el selector d'emojis"
|
emojiPickerDisplay: "Mostrar el selector d'emojis"
|
||||||
overwriteFromPinnedEmojisForReaction: "Reemplaça els emojis de la reacció"
|
overwriteFromPinnedEmojisForReaction: "Reemplaça els emojis de la reacció"
|
||||||
overwriteFromPinnedEmojis: "Sobreescriu des dels emojis fixats"
|
overwriteFromPinnedEmojis: "Sobreescriu els emojis fixats al panel de reaccions"
|
||||||
reactionSettingDescription2: "Arrossega per reordenar, fes clic per suprimir, prem \"+\" per afegir."
|
reactionSettingDescription2: "Arrossega per reordenar, fes clic per suprimir, prem \"+\" per afegir."
|
||||||
rememberNoteVisibility: "Recorda la configuració de visibilitat de les notes"
|
rememberNoteVisibility: "Recorda la configuració de visibilitat de les notes"
|
||||||
attachCancel: "Eliminar el fitxer adjunt"
|
attachCancel: "Eliminar el fitxer adjunt"
|
||||||
deleteFile: "Esborrar l'arxiu "
|
deleteFile: "Esborrar l'arxiu "
|
||||||
markAsSensitive: "Marcar com a NSFW"
|
markAsSensitive: "Marcar com a sensible"
|
||||||
unmarkAsSensitive: "Deixar de marcar com a sensible"
|
unmarkAsSensitive: "Deixar de marcar com a sensible"
|
||||||
enterFileName: "Defineix nom del fitxer"
|
enterFileName: "Defineix nom del fitxer"
|
||||||
mute: "Silencia"
|
mute: "Silencia"
|
||||||
unmute: "Deixa de silenciar"
|
unmute: "Deixa de silenciar"
|
||||||
renoteMute: "Silenciar Renotes"
|
renoteMute: "Silenciar impulsos"
|
||||||
renoteUnmute: "Treure el silenci de les renotes"
|
renoteUnmute: "Treure el silenci dels impulsos"
|
||||||
block: "Bloqueja"
|
block: "Bloqueja"
|
||||||
unblock: "Desbloqueja"
|
unblock: "Desbloqueja"
|
||||||
suspend: "Suspèn"
|
suspend: "Suspèn"
|
||||||
unsuspend: "Deixa de suspendre"
|
unsuspend: "Deixa de suspendre"
|
||||||
blockConfirm: "Vols bloquejar?"
|
blockConfirm: "Vols bloquejar-lo?"
|
||||||
unblockConfirm: "Vols desbloquejar-lo?"
|
unblockConfirm: "Vols desbloquejar-lo?"
|
||||||
suspendConfirm: "Estàs segur que vols suspendre aquest compte?"
|
suspendConfirm: "Estàs segur que vols suspendre aquest compte?"
|
||||||
unsuspendConfirm: "Estàs segur que vols treure la suspensió d'aquest compte?"
|
unsuspendConfirm: "Estàs segur que vols treure la suspensió d'aquest compte?"
|
||||||
|
@ -174,11 +175,11 @@ youCanCleanRemoteFilesCache: "Pots netejar la memòria cau fent clic al botó de
|
||||||
cacheRemoteSensitiveFiles: "Posar a la memòria cau arxius remots sensibles"
|
cacheRemoteSensitiveFiles: "Posar a la memòria cau arxius remots sensibles"
|
||||||
cacheRemoteSensitiveFilesDescription: "Quan aquesta opció és desactiva, els arxius remots sensibles es carregant directament del servidor d'origen sense que es guardin a la memòria cau."
|
cacheRemoteSensitiveFilesDescription: "Quan aquesta opció és desactiva, els arxius remots sensibles es carregant directament del servidor d'origen sense que es guardin a la memòria cau."
|
||||||
flagAsBot: "Marca aquest compte com a bot"
|
flagAsBot: "Marca aquest compte com a bot"
|
||||||
flagAsBotDescription: "Marca aquest compte com a bot"
|
flagAsBotDescription: "Activa aquesta opció si el compte el controla un programa. Si s'activa, actuarà com un senyal per altres desenvolupadors per prevenir cadenes d'interacció sense fi i ajustar els paràmetres interns de Misskey pe tractar el compte com un bot."
|
||||||
flagAsCat: "Marca aquest compte com a gat"
|
flagAsCat: "Marca aquest compte com a gat"
|
||||||
flagAsCatDescription: "Activeu aquesta opció per marcar aquest compte com a gat."
|
flagAsCatDescription: "Activeu aquesta opció per marcar aquest compte com a gat."
|
||||||
flagShowTimelineReplies: "Mostra les respostes a la línia de temps"
|
flagShowTimelineReplies: "Mostra les respostes a la línia de temps"
|
||||||
flagShowTimelineRepliesDescription: "Mostra les respostes a la línia de temps"
|
flagShowTimelineRepliesDescription: "Mostra les respostes dels usuaris a les notes d'altres usuaris a la línia de temps."
|
||||||
autoAcceptFollowed: "Aprova automàticament les sol·licituds de seguiment dels usuaris que segueixes"
|
autoAcceptFollowed: "Aprova automàticament les sol·licituds de seguiment dels usuaris que segueixes"
|
||||||
addAccount: "Afegeix un compte"
|
addAccount: "Afegeix un compte"
|
||||||
reloadAccountsList: "Recarregar la llista de contactes"
|
reloadAccountsList: "Recarregar la llista de contactes"
|
||||||
|
@ -203,7 +204,7 @@ selectUser: "Selecciona usuari/a"
|
||||||
recipient: "Destinatari"
|
recipient: "Destinatari"
|
||||||
annotation: "Comentaris"
|
annotation: "Comentaris"
|
||||||
federation: "Federació"
|
federation: "Federació"
|
||||||
instances: "Servidors"
|
instances: "Instàncies "
|
||||||
registeredAt: "Registrat a"
|
registeredAt: "Registrat a"
|
||||||
latestRequestReceivedAt: "Última petició rebuda"
|
latestRequestReceivedAt: "Última petició rebuda"
|
||||||
latestStatus: "Últim estat"
|
latestStatus: "Últim estat"
|
||||||
|
@ -212,7 +213,7 @@ charts: "Gràfics"
|
||||||
perHour: "Per hora"
|
perHour: "Per hora"
|
||||||
perDay: "Per dia"
|
perDay: "Per dia"
|
||||||
stopActivityDelivery: "Deixa d'enviar activitats"
|
stopActivityDelivery: "Deixa d'enviar activitats"
|
||||||
blockThisInstance: "Deixa d'enviar activitats"
|
blockThisInstance: "Bloca aquesta instància "
|
||||||
silenceThisInstance: "Silencia aquesta instància "
|
silenceThisInstance: "Silencia aquesta instància "
|
||||||
mediaSilenceThisInstance: "Silenciar els arxius d'aquesta instància "
|
mediaSilenceThisInstance: "Silenciar els arxius d'aquesta instància "
|
||||||
operations: "Accions"
|
operations: "Accions"
|
||||||
|
@ -227,7 +228,7 @@ network: "Xarxa"
|
||||||
disk: "Disc"
|
disk: "Disc"
|
||||||
instanceInfo: "Informació del fitxer d'instal·lació"
|
instanceInfo: "Informació del fitxer d'instal·lació"
|
||||||
statistics: "Estadístiques"
|
statistics: "Estadístiques"
|
||||||
clearQueue: "Esborrar la cua"
|
clearQueue: "Esborra la cua de feina"
|
||||||
clearQueueConfirmTitle: "Esteu segur que voleu esborrar la cua?"
|
clearQueueConfirmTitle: "Esteu segur que voleu esborrar la cua?"
|
||||||
clearQueueConfirmText: "Les notes no lliurades que quedin a la cua no es federaran. Normalment aquesta operació no és necessària."
|
clearQueueConfirmText: "Les notes no lliurades que quedin a la cua no es federaran. Normalment aquesta operació no és necessària."
|
||||||
clearCachedFiles: "Esborra la memòria cau"
|
clearCachedFiles: "Esborra la memòria cau"
|
||||||
|
@ -253,7 +254,7 @@ processing: "S'està processant..."
|
||||||
preview: "Vista prèvia"
|
preview: "Vista prèvia"
|
||||||
default: "Per defecte"
|
default: "Per defecte"
|
||||||
defaultValueIs: "Per defecte: {value}"
|
defaultValueIs: "Per defecte: {value}"
|
||||||
noCustomEmojis: "Cap emoji personalitzat"
|
noCustomEmojis: "No hi ha emojis personalitzats"
|
||||||
noJobs: "No hi ha feines"
|
noJobs: "No hi ha feines"
|
||||||
federating: "Federant"
|
federating: "Federant"
|
||||||
blocked: "Bloquejat"
|
blocked: "Bloquejat"
|
||||||
|
@ -267,11 +268,11 @@ instanceFollowers: "Seguidors del servidor"
|
||||||
instanceUsers: "Usuaris del servidor"
|
instanceUsers: "Usuaris del servidor"
|
||||||
changePassword: "Canvia la contrasenya"
|
changePassword: "Canvia la contrasenya"
|
||||||
security: "Seguretat"
|
security: "Seguretat"
|
||||||
retypedNotMatch: "L'entrada no coincideix"
|
retypedNotMatch: "Les entrades no coincideix"
|
||||||
currentPassword: "Contrasenya actual"
|
currentPassword: "Contrasenya actual"
|
||||||
newPassword: "Contrasenya nova"
|
newPassword: "Contrasenya nova"
|
||||||
newPasswordRetype: "Contrasenya nou (repeteix-la)"
|
newPasswordRetype: "Contrasenya nova (repeteix-la)"
|
||||||
attachFile: "Adjunta fitxers"
|
attachFile: "Afegeix un arxiu"
|
||||||
more: "Més"
|
more: "Més"
|
||||||
featured: "Destacat"
|
featured: "Destacat"
|
||||||
usernameOrUserId: "Nom o ID d'usuari"
|
usernameOrUserId: "Nom o ID d'usuari"
|
||||||
|
@ -281,25 +282,25 @@ announcements: "Anuncis"
|
||||||
imageUrl: "URL de la imatge"
|
imageUrl: "URL de la imatge"
|
||||||
remove: "Eliminar"
|
remove: "Eliminar"
|
||||||
removed: "Eliminat"
|
removed: "Eliminat"
|
||||||
removeAreYouSure: "Segur que voleu retirar «{x}»?"
|
removeAreYouSure: "Segur que vols esborrar «{x}»?"
|
||||||
deleteAreYouSure: "Segur que voleu retirar «{x}»?"
|
deleteAreYouSure: "Segur que vols esborrar «{x}»?"
|
||||||
resetAreYouSure: "Segur que voleu restablir-ho?"
|
resetAreYouSure: "Segur que vols restablir-ho?"
|
||||||
areYouSure: "Està segur?"
|
areYouSure: "Estàs segur?"
|
||||||
saved: "S'ha desat"
|
saved: "S'ha desat"
|
||||||
messaging: "Xat"
|
messaging: "Xat"
|
||||||
upload: "Puja"
|
upload: "Puja"
|
||||||
keepOriginalUploading: "Guarda la imatge original"
|
keepOriginalUploading: "Guarda la imatge original"
|
||||||
keepOriginalUploadingDescription: "Guarda la imatge pujada com hi és. Si està apagat, una versió per a la visualització a la xarxa serà generada quan sigui pujada."
|
keepOriginalUploadingDescription: "Guarda la imatge pujada sense modificar. Si està desactivat, es generarà una versió per visualitzar a la web en pujar la imatge."
|
||||||
fromDrive: "Des de la unitat"
|
fromDrive: "Des del Disc"
|
||||||
fromUrl: "Des d'un enllaç"
|
fromUrl: "Des d'un enllaç"
|
||||||
uploadFromUrl: "Carrega des d'un enllaç"
|
uploadFromUrl: "Carrega des d'un enllaç"
|
||||||
uploadFromUrlDescription: "Enllaç del fitxer que vols carregar"
|
uploadFromUrlDescription: "Enllaç del fitxer que vols carregar"
|
||||||
uploadFromUrlRequested: "Càrrega sol·licitada"
|
uploadFromUrlRequested: "Càrrega sol·licitada"
|
||||||
uploadFromUrlMayTakeTime: "La càrrega des de l'enllaç pot prendre un temps"
|
uploadFromUrlMayTakeTime: "La càrrega des de l'enllaç pot trigar un temps"
|
||||||
explore: "Explora"
|
explore: "Explora"
|
||||||
messageRead: "Vist"
|
messageRead: "Vist"
|
||||||
noMoreHistory: "No hi resta més per veure"
|
noMoreHistory: "No hi ha res més per veure"
|
||||||
startMessaging: "Començar a xatejar"
|
startMessaging: "Comença a xatejar"
|
||||||
nUsersRead: "Vist per {n}"
|
nUsersRead: "Vist per {n}"
|
||||||
agreeTo: "Accepto que {0}"
|
agreeTo: "Accepto que {0}"
|
||||||
agree: "Hi estic d'acord"
|
agree: "Hi estic d'acord"
|
||||||
|
@ -311,7 +312,7 @@ home: "Inici"
|
||||||
remoteUserCaution: "Ja que aquest usuari resideix a una instància remota, la informació mostrada es podria trobar incompleta."
|
remoteUserCaution: "Ja que aquest usuari resideix a una instància remota, la informació mostrada es podria trobar incompleta."
|
||||||
activity: "Activitat"
|
activity: "Activitat"
|
||||||
images: "Imatges"
|
images: "Imatges"
|
||||||
image: "Imatges"
|
image: "Imatge"
|
||||||
birthday: "Aniversari"
|
birthday: "Aniversari"
|
||||||
yearsOld: "{age} anys"
|
yearsOld: "{age} anys"
|
||||||
registeredDate: "Data de registre"
|
registeredDate: "Data de registre"
|
||||||
|
@ -326,10 +327,10 @@ darkThemes: "Temes foscos"
|
||||||
syncDeviceDarkMode: "Sincronitza el mode fosc amb la configuració del dispositiu"
|
syncDeviceDarkMode: "Sincronitza el mode fosc amb la configuració del dispositiu"
|
||||||
drive: "Unitat"
|
drive: "Unitat"
|
||||||
fileName: "Nom del Fitxer"
|
fileName: "Nom del Fitxer"
|
||||||
selectFile: "Selecciona fitxers"
|
selectFile: "Selecciona un fitxer"
|
||||||
selectFiles: "Selecciona fitxers"
|
selectFiles: "Selecciona fitxers"
|
||||||
selectFolder: "Selecció de carpeta"
|
selectFolder: "Selecció de carpeta"
|
||||||
selectFolders: "Selecció de carpeta"
|
selectFolders: "Selecció de carpetes"
|
||||||
fileNotSelected: "Cap fitxer seleccionat"
|
fileNotSelected: "Cap fitxer seleccionat"
|
||||||
renameFile: "Canvia el nom del fitxer"
|
renameFile: "Canvia el nom del fitxer"
|
||||||
folderName: "Nom de la carpeta"
|
folderName: "Nom de la carpeta"
|
||||||
|
@ -358,9 +359,9 @@ reload: "Actualitza"
|
||||||
doNothing: "Ignora"
|
doNothing: "Ignora"
|
||||||
reloadConfirm: "Vols recarregar?"
|
reloadConfirm: "Vols recarregar?"
|
||||||
watch: "Veure"
|
watch: "Veure"
|
||||||
unwatch: "Deixar de veure"
|
unwatch: "Deixa de veure"
|
||||||
accept: "Acceptar"
|
accept: "Acceptar"
|
||||||
reject: "Denegar"
|
reject: "Denega"
|
||||||
normal: "Normal"
|
normal: "Normal"
|
||||||
instanceName: "Nom del servidor"
|
instanceName: "Nom del servidor"
|
||||||
instanceDescription: "Descripció del servidor"
|
instanceDescription: "Descripció del servidor"
|
||||||
|
@ -381,7 +382,6 @@ enableLocalTimeline: "Activa la línia de temps local"
|
||||||
enableGlobalTimeline: "Activa la línia de temps global"
|
enableGlobalTimeline: "Activa la línia de temps global"
|
||||||
disablingTimelinesInfo: "Fins i tot si aquestes línies de temps són desactivades, els administradors i els moderadors poden continuar visualitzant per conveniència."
|
disablingTimelinesInfo: "Fins i tot si aquestes línies de temps són desactivades, els administradors i els moderadors poden continuar visualitzant per conveniència."
|
||||||
registration: "Registre"
|
registration: "Registre"
|
||||||
enableRegistration: "Permet els registres d'usuaris"
|
|
||||||
invite: "Convida"
|
invite: "Convida"
|
||||||
driveCapacityPerLocalAccount: "Capacitat del disc per usuaris locals"
|
driveCapacityPerLocalAccount: "Capacitat del disc per usuaris locals"
|
||||||
driveCapacityPerRemoteAccount: "Capacitat del disc per usuaris remots"
|
driveCapacityPerRemoteAccount: "Capacitat del disc per usuaris remots"
|
||||||
|
@ -392,20 +392,20 @@ basicInfo: "Informació bàsica"
|
||||||
pinnedUsers: "Usuaris fixats"
|
pinnedUsers: "Usuaris fixats"
|
||||||
pinnedUsersDescription: "Llista d'usuaris, separats per salts de línia, que seran fixats a la pestanya \"Explorar\"."
|
pinnedUsersDescription: "Llista d'usuaris, separats per salts de línia, que seran fixats a la pestanya \"Explorar\"."
|
||||||
pinnedPages: "Pàgines fixades"
|
pinnedPages: "Pàgines fixades"
|
||||||
pinnedPagesDescription: "Escriu els camins de les pàgines que vols fixar a la pàgina d'inici d'aquesta instància. Separades per salts de línia."
|
pinnedPagesDescription: "Escriu les adreces de les pàgines que vols fixar a la pàgina d'inici d'aquesta instància. Separades per salts de línia."
|
||||||
pinnedClipId: "ID del retall fixat"
|
pinnedClipId: "ID del retall fixat"
|
||||||
pinnedNotes: "Nota fixada"
|
pinnedNotes: "Nota fixada"
|
||||||
hcaptcha: "hCaptcha"
|
hcaptcha: "hCaptcha"
|
||||||
enableHcaptcha: "Activar hCaptcha"
|
enableHcaptcha: "Activa hCaptcha"
|
||||||
hcaptchaSiteKey: "Clau del lloc"
|
hcaptchaSiteKey: "Clau del lloc"
|
||||||
hcaptchaSecretKey: "Clau secreta"
|
hcaptchaSecretKey: "Clau secreta"
|
||||||
mcaptcha: "mCaptcha"
|
mcaptcha: "mCaptcha"
|
||||||
enableMcaptcha: "Activar mCaptcha"
|
enableMcaptcha: "Activa mCaptcha"
|
||||||
mcaptchaSiteKey: "Clau del lloc"
|
mcaptchaSiteKey: "Clau del lloc"
|
||||||
mcaptchaSecretKey: "Clau secreta"
|
mcaptchaSecretKey: "Clau secreta"
|
||||||
mcaptchaInstanceUrl: "Adreça URL del servidor mCaptcha"
|
mcaptchaInstanceUrl: "Adreça URL del servidor mCaptcha"
|
||||||
recaptcha: "reCAPTCHA"
|
recaptcha: "reCAPTCHA"
|
||||||
enableRecaptcha: "Activar reCAPTCHA"
|
enableRecaptcha: "Activa reCAPTCHA"
|
||||||
recaptchaSiteKey: "Clau del lloc"
|
recaptchaSiteKey: "Clau del lloc"
|
||||||
recaptchaSecretKey: "Clau secreta"
|
recaptchaSecretKey: "Clau secreta"
|
||||||
turnstile: "Turnstile"
|
turnstile: "Turnstile"
|
||||||
|
@ -447,14 +447,14 @@ aboutMisskey: "Quant a Misskey"
|
||||||
administrator: "Administrador/a"
|
administrator: "Administrador/a"
|
||||||
token: "Codi de verificació"
|
token: "Codi de verificació"
|
||||||
2fa: "Autenticació de doble factor"
|
2fa: "Autenticació de doble factor"
|
||||||
setupOf2fa: "Configurar l'autenticació de doble factor"
|
setupOf2fa: "Configura l'autenticació de doble factor"
|
||||||
totp: "Aplicació d'autenticació"
|
totp: "Aplicació d'autenticació"
|
||||||
totpDescription: "Escriu una contrasenya d'un sol us fent servir l'aplicació d'autenticació"
|
totpDescription: "Escriu una contrasenya d'un sol us fent servir l'aplicació d'autenticació"
|
||||||
moderator: "Moderador/a"
|
moderator: "Moderador/a"
|
||||||
moderation: "Moderació"
|
moderation: "Moderació"
|
||||||
moderationNote: "Nota de moderació "
|
moderationNote: "Nota de moderació "
|
||||||
moderationNoteDescription: "Pots escriure notes que es compartiran entre els moderadors."
|
moderationNoteDescription: "Pots escriure notes que es compartiran entre els moderadors."
|
||||||
addModerationNote: "Afegir una nota de moderació "
|
addModerationNote: "Afegeix una nota de moderació "
|
||||||
moderationLogs: "Registre de moderació "
|
moderationLogs: "Registre de moderació "
|
||||||
nUsersMentioned: "{n} usuaris mencionats"
|
nUsersMentioned: "{n} usuaris mencionats"
|
||||||
securityKeyAndPasskey: "Clau de seguretat / Clau de pas"
|
securityKeyAndPasskey: "Clau de seguretat / Clau de pas"
|
||||||
|
@ -470,13 +470,13 @@ reduceUiAnimation: "Redueix les animacions de la interfície"
|
||||||
share: "Comparteix"
|
share: "Comparteix"
|
||||||
notFound: "No s'ha trobat"
|
notFound: "No s'ha trobat"
|
||||||
notFoundDescription: "No es troba cap pàgina que correspongui a aquesta adreça"
|
notFoundDescription: "No es troba cap pàgina que correspongui a aquesta adreça"
|
||||||
uploadFolder: "Carpeta per defecte per pujades"
|
uploadFolder: "Carpeta per defecte on desar els arxius pujats"
|
||||||
markAsReadAllNotifications: "Marca totes les notificacions com a llegides"
|
markAsReadAllNotifications: "Marca totes les notificacions com a llegides"
|
||||||
markAsReadAllUnreadNotes: "Marca-ho tot com a llegit"
|
markAsReadAllUnreadNotes: "Marca-ho tot com a llegit"
|
||||||
markAsReadAllTalkMessages: "Marcar tots els missatges com llegits"
|
markAsReadAllTalkMessages: "Marcar tots els missatges com llegits"
|
||||||
help: "Ajuda"
|
help: "Ajuda"
|
||||||
inputMessageHere: "Escriu aquí el teu missatge "
|
inputMessageHere: "Escriu aquí el teu missatge "
|
||||||
close: "Tancar"
|
close: "Tanca"
|
||||||
invites: "Convida"
|
invites: "Convida"
|
||||||
members: "Membres"
|
members: "Membres"
|
||||||
transfer: "Transferir"
|
transfer: "Transferir"
|
||||||
|
@ -507,7 +507,7 @@ normalPassword: "Bona contrasenya"
|
||||||
strongPassword: "Contrasenya segura"
|
strongPassword: "Contrasenya segura"
|
||||||
passwordMatched: "Correcte!"
|
passwordMatched: "Correcte!"
|
||||||
passwordNotMatched: "No coincideix"
|
passwordNotMatched: "No coincideix"
|
||||||
signinWith: "Inicia sessió amb amb {x}"
|
signinWith: "Inicia sessió amb {x}"
|
||||||
signinFailed: "Autenticació sense èxit. Intenta-ho un altre cop utilitzant la contrasenya i el nom correctes."
|
signinFailed: "Autenticació sense èxit. Intenta-ho un altre cop utilitzant la contrasenya i el nom correctes."
|
||||||
or: "O"
|
or: "O"
|
||||||
language: "Idioma"
|
language: "Idioma"
|
||||||
|
@ -586,11 +586,12 @@ masterVolume: "Volum principal"
|
||||||
notUseSound: "Sense so"
|
notUseSound: "Sense so"
|
||||||
useSoundOnlyWhenActive: "Reproduir sons només quan Misskey estigui actiu"
|
useSoundOnlyWhenActive: "Reproduir sons només quan Misskey estigui actiu"
|
||||||
details: "Detalls"
|
details: "Detalls"
|
||||||
|
renoteDetails: "Més informació sobre l'impuls "
|
||||||
chooseEmoji: "Tria un emoji"
|
chooseEmoji: "Tria un emoji"
|
||||||
unableToProcess: "L'operació no pot ser completada "
|
unableToProcess: "L'operació no pot ser completada "
|
||||||
recentUsed: "Utilitzat recentment"
|
recentUsed: "Utilitzat recentment"
|
||||||
install: "Instal·lació "
|
install: "Instal·lació "
|
||||||
uninstall: "Desinstal·lar "
|
uninstall: "Desinstal·la"
|
||||||
installedApps: "Aplicacions autoritzades "
|
installedApps: "Aplicacions autoritzades "
|
||||||
nothing: "No hi ha res per veure aquí "
|
nothing: "No hi ha res per veure aquí "
|
||||||
installedDate: "Data d'instal·lació"
|
installedDate: "Data d'instal·lació"
|
||||||
|
@ -607,13 +608,13 @@ output: "Sortida"
|
||||||
script: "Script"
|
script: "Script"
|
||||||
disablePagesScript: "Desactivar AiScript a les pàgines "
|
disablePagesScript: "Desactivar AiScript a les pàgines "
|
||||||
updateRemoteUser: "Actualitzar la informació de l'usuari remot"
|
updateRemoteUser: "Actualitzar la informació de l'usuari remot"
|
||||||
unsetUserAvatar: "Desactivar l'avatar "
|
unsetUserAvatar: "Desactiva l'avatar "
|
||||||
unsetUserAvatarConfirm: "Segur que vols desactivar l'avatar?"
|
unsetUserAvatarConfirm: "Segur que vols desactivar l'avatar?"
|
||||||
unsetUserBanner: "Desactivar el bàner "
|
unsetUserBanner: "Desactiva el bàner "
|
||||||
unsetUserBannerConfirm: "Segur que vols desactivar el bàner?"
|
unsetUserBannerConfirm: "Segur que vols desactivar el bàner?"
|
||||||
deleteAllFiles: "Esborrar tots els arxius"
|
deleteAllFiles: "Esborra tots els arxius"
|
||||||
deleteAllFilesConfirm: "Segur que vols esborrar tots els arxius?"
|
deleteAllFilesConfirm: "Segur que vols esborrar tots els arxius?"
|
||||||
removeAllFollowing: "Deixar de seguir tots els usuaris seguits"
|
removeAllFollowing: "Deixa de seguir tots els usuaris seguits"
|
||||||
removeAllFollowingDescription: "El fet d'executar això, et farà deixar de seguir a tots els usuaris de {host}. Si us plau, executa això si l'amfitrió, per exemple, ja no existeix."
|
removeAllFollowingDescription: "El fet d'executar això, et farà deixar de seguir a tots els usuaris de {host}. Si us plau, executa això si l'amfitrió, per exemple, ja no existeix."
|
||||||
userSuspended: "Aquest usuari ha sigut suspès"
|
userSuspended: "Aquest usuari ha sigut suspès"
|
||||||
userSilenced: "Aquest usuari està sent silenciat"
|
userSilenced: "Aquest usuari està sent silenciat"
|
||||||
|
@ -946,6 +947,9 @@ oneHour: "1 hora"
|
||||||
oneDay: "Un dia"
|
oneDay: "Un dia"
|
||||||
oneWeek: "Una setmana"
|
oneWeek: "Una setmana"
|
||||||
oneMonth: "Un mes"
|
oneMonth: "Un mes"
|
||||||
|
threeMonths: "3 mesos"
|
||||||
|
oneYear: "1 any"
|
||||||
|
threeDays: "3 dies"
|
||||||
reflectMayTakeTime: "Això pot trigar una estona a tenir efecte"
|
reflectMayTakeTime: "Això pot trigar una estona a tenir efecte"
|
||||||
failedToFetchAccountInformation: "No es pot obtenir la informació del compte"
|
failedToFetchAccountInformation: "No es pot obtenir la informació del compte"
|
||||||
rateLimitExceeded: "S'ha arribat al màxim de peticions"
|
rateLimitExceeded: "S'ha arribat al màxim de peticions"
|
||||||
|
@ -1086,6 +1090,7 @@ retryAllQueuesConfirmTitle: "Tornar a intentar-ho tot?"
|
||||||
retryAllQueuesConfirmText: "Això farà que la càrrega del servidor augmenti temporalment."
|
retryAllQueuesConfirmText: "Això farà que la càrrega del servidor augmenti temporalment."
|
||||||
enableChartsForRemoteUser: "Generar gràfiques d'usuaris remots"
|
enableChartsForRemoteUser: "Generar gràfiques d'usuaris remots"
|
||||||
enableChartsForFederatedInstances: "Generar gràfiques d'instàncies remotes"
|
enableChartsForFederatedInstances: "Generar gràfiques d'instàncies remotes"
|
||||||
|
enableStatsForFederatedInstances: "Activa les estadístiques de les instàncies remotes federades"
|
||||||
showClipButtonInNoteFooter: "Afegir \"Retall\" al menú d'acció de la nota"
|
showClipButtonInNoteFooter: "Afegir \"Retall\" al menú d'acció de la nota"
|
||||||
reactionsDisplaySize: "Mida de les reaccions"
|
reactionsDisplaySize: "Mida de les reaccions"
|
||||||
limitWidthOfReaction: "Limitar l'amplada màxima de la reacció i mostrar-les en una mida reduïda "
|
limitWidthOfReaction: "Limitar l'amplada màxima de la reacció i mostrar-les en una mida reduïda "
|
||||||
|
@ -1178,8 +1183,8 @@ currentAnnouncements: "Informes actuals"
|
||||||
pastAnnouncements: "Informes passats"
|
pastAnnouncements: "Informes passats"
|
||||||
youHaveUnreadAnnouncements: "Tens informes per llegir."
|
youHaveUnreadAnnouncements: "Tens informes per llegir."
|
||||||
useSecurityKey: "Segueix les instruccions del teu navegador O dispositiu per fer servir el teu passkey."
|
useSecurityKey: "Segueix les instruccions del teu navegador O dispositiu per fer servir el teu passkey."
|
||||||
replies: "Respondre"
|
replies: "Respon"
|
||||||
renotes: "Impulsa"
|
renotes: "Impulsar "
|
||||||
loadReplies: "Mostrar les respostes"
|
loadReplies: "Mostrar les respostes"
|
||||||
loadConversation: "Mostrar la conversació "
|
loadConversation: "Mostrar la conversació "
|
||||||
pinnedList: "Llista fixada"
|
pinnedList: "Llista fixada"
|
||||||
|
@ -1287,6 +1292,27 @@ passkeyVerificationSucceededButPasswordlessLoginDisabled: "La verificació de la
|
||||||
messageToFollower: "Missatge als meus seguidors"
|
messageToFollower: "Missatge als meus seguidors"
|
||||||
target: "Assumpte "
|
target: "Assumpte "
|
||||||
testCaptchaWarning: "És una característica dissenyada per a la prova de CAPTCHA. <strong>No l'utilitzes en l'entorn real.</strong>"
|
testCaptchaWarning: "És una característica dissenyada per a la prova de CAPTCHA. <strong>No l'utilitzes en l'entorn real.</strong>"
|
||||||
|
prohibitedWordsForNameOfUser: "Noms prohibits per escollir noms d'usuari "
|
||||||
|
prohibitedWordsForNameOfUserDescription: "Si qualsevol d'aquestes paraules es troben a un nom d'usuari la creació de l'usuari no es durà a terme. Als moderadors no els afecta aquesta restricció."
|
||||||
|
yourNameContainsProhibitedWords: "El nom conté paraules prohibides "
|
||||||
|
yourNameContainsProhibitedWordsDescription: "Si de veritat vols fer servir aquest nom posat en contacte amb l'administrador."
|
||||||
|
thisContentsAreMarkedAsSigninRequiredByAuthor: "L'autor requereix l'inici de sessió per poder veure"
|
||||||
|
lockdown: "Bloquejat"
|
||||||
|
pleaseSelectAccount: "Seleccionar un compte"
|
||||||
|
availableRoles: "Roles disponibles "
|
||||||
|
acknowledgeNotesAndEnable: "Activa'l després de comprendre els possibles perills."
|
||||||
|
_accountSettings:
|
||||||
|
requireSigninToViewContents: "És obligatori l'inici de sessió per poder veure el contingut"
|
||||||
|
requireSigninToViewContentsDescription1: "Es requereix l'inici de sessió per poder veure totes les notes i el contingut que has creat. Amb això esperem evitar que els rastrejadors recopilin informació."
|
||||||
|
requireSigninToViewContentsDescription2: "També es desactivaran les vistes prèvies d'URLS (OGP), la incrustació a pàgines web i la visualització des de servidors que no admetin la citació de notes."
|
||||||
|
requireSigninToViewContentsDescription3: "Aquestes restriccions pot ser que no s'apliquin als continguts federats en servidors remots."
|
||||||
|
makeNotesFollowersOnlyBefore: "Permetre que les notes antigues només es mostrin als seguidors."
|
||||||
|
makeNotesFollowersOnlyBeforeDescription: "Mentre aquesta funció estigui activada, les notes que hagin passat la data i hora fixada o hagi passat els temps establert seran visibles només per als teus seguidors. Quan es desactivi, també es restableix l'estat públic de la nota."
|
||||||
|
makeNotesHiddenBefore: "Fes que les notes antigues siguin privades"
|
||||||
|
makeNotesHiddenBeforeDescription: "Mentres aquesta funció estigui activada les notes que hagin superat una data i hora fixada o hagi passat el temps establert només seran visibles per a tu. Si la desactives es restablirà també l'estat públic de les notes."
|
||||||
|
mayNotEffectForFederatedNotes: "Això pot ser que no afecti les notes federades."
|
||||||
|
notesHavePassedSpecifiedPeriod: "Notes publicades durant un període de temps especificat."
|
||||||
|
notesOlderThanSpecifiedDateAndTime: "Notes més antigues de la data i temps especificat "
|
||||||
_abuseUserReport:
|
_abuseUserReport:
|
||||||
forward: "Reenviar "
|
forward: "Reenviar "
|
||||||
forwardDescription: "Reenvia l'informe a una altra instància com un compte del sistema anònima."
|
forwardDescription: "Reenvia l'informe a una altra instància com un compte del sistema anònima."
|
||||||
|
@ -1431,6 +1457,8 @@ _serverSettings:
|
||||||
reactionsBufferingDescription: "Quan s'activa aquesta opció millora bastant el rendiment en recuperar les línies de temps reduint la càrrega de la base. Com a contrapunt, augmentarà l'ús de memòria de Redís. Desactiva aquesta opció en cas de tenir un servidor amb poca memòria o si tens problemes d'inestabilitat."
|
reactionsBufferingDescription: "Quan s'activa aquesta opció millora bastant el rendiment en recuperar les línies de temps reduint la càrrega de la base. Com a contrapunt, augmentarà l'ús de memòria de Redís. Desactiva aquesta opció en cas de tenir un servidor amb poca memòria o si tens problemes d'inestabilitat."
|
||||||
inquiryUrl: "URL de consulta "
|
inquiryUrl: "URL de consulta "
|
||||||
inquiryUrlDescription: "Escriu adreça URL per al formulari de consulta per al mantenidor del servidor o una pàgina web amb el contacte d'informació."
|
inquiryUrlDescription: "Escriu adreça URL per al formulari de consulta per al mantenidor del servidor o una pàgina web amb el contacte d'informació."
|
||||||
|
openRegistration: "Registres oberts"
|
||||||
|
openRegistrationWarning: "Obrir els registres és arriscat. Es recomana obrir-los només si el servidor és monitorat constantment i per respondre immediatament davant qualsevol problema."
|
||||||
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "Si no es detecta activitat per part del moderador durant un període de temps, aquesta opció es desactiva automàticament per evitar el correu brossa."
|
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "Si no es detecta activitat per part del moderador durant un període de temps, aquesta opció es desactiva automàticament per evitar el correu brossa."
|
||||||
_accountMigration:
|
_accountMigration:
|
||||||
moveFrom: "Migrar un altre compte a aquest"
|
moveFrom: "Migrar un altre compte a aquest"
|
||||||
|
@ -2151,8 +2179,11 @@ _auth:
|
||||||
permissionAsk: "Aquesta aplicació demana els següents permisos"
|
permissionAsk: "Aquesta aplicació demana els següents permisos"
|
||||||
pleaseGoBack: "Si us plau, torna a l'aplicació"
|
pleaseGoBack: "Si us plau, torna a l'aplicació"
|
||||||
callback: "Tornant a l'aplicació"
|
callback: "Tornant a l'aplicació"
|
||||||
|
accepted: "Accés garantit"
|
||||||
denied: "Accés denegat"
|
denied: "Accés denegat"
|
||||||
|
scopeUser: "Opera com si fossis aquest usuari"
|
||||||
pleaseLogin: "Si us plau, identificat per autoritzar l'aplicació."
|
pleaseLogin: "Si us plau, identificat per autoritzar l'aplicació."
|
||||||
|
byClickingYouWillBeRedirectedToThisUrl: "Si es garanteix l'accés, seràs redirigit automàticament a la següent adreça URL"
|
||||||
_antennaSources:
|
_antennaSources:
|
||||||
all: "Totes les publicacions"
|
all: "Totes les publicacions"
|
||||||
homeTimeline: "Publicacions dels usuaris seguits"
|
homeTimeline: "Publicacions dels usuaris seguits"
|
||||||
|
@ -2402,7 +2433,8 @@ _notification:
|
||||||
renotedBySomeUsers: "L'han impulsat {n} usuaris"
|
renotedBySomeUsers: "L'han impulsat {n} usuaris"
|
||||||
followedBySomeUsers: "Et segueixen {n} usuaris"
|
followedBySomeUsers: "Et segueixen {n} usuaris"
|
||||||
flushNotification: "Netejar notificacions"
|
flushNotification: "Netejar notificacions"
|
||||||
exportOfXCompleted: "Completada l'exportació de {n}"
|
exportOfXCompleted: "Completada l'exportació de {x}"
|
||||||
|
login: "Algú ha iniciat sessió "
|
||||||
_types:
|
_types:
|
||||||
all: "Tots"
|
all: "Tots"
|
||||||
note: "Notes noves"
|
note: "Notes noves"
|
||||||
|
@ -2485,6 +2517,8 @@ _webhookSettings:
|
||||||
abuseReport: "Quan reps un nou informe de moderació "
|
abuseReport: "Quan reps un nou informe de moderació "
|
||||||
abuseReportResolved: "Quan resols un informe de moderació "
|
abuseReportResolved: "Quan resols un informe de moderació "
|
||||||
userCreated: "Quan es crea un usuari"
|
userCreated: "Quan es crea un usuari"
|
||||||
|
inactiveModeratorsWarning: "Quan el compte d'un moderador no té activitat durant un temps"
|
||||||
|
inactiveModeratorsInvitationOnlyChanged: "Quan el compte d'un moderador no té activitat durant un temps, i el servidor es canvia a registre per invitacions"
|
||||||
deleteConfirm: "Segur que vols esborrar el webhook?"
|
deleteConfirm: "Segur que vols esborrar el webhook?"
|
||||||
testRemarks: "Si feu clic al botó a la dreta de l'interruptor, podeu enviar un webhook de prova amb dades dummy."
|
testRemarks: "Si feu clic al botó a la dreta de l'interruptor, podeu enviar un webhook de prova amb dades dummy."
|
||||||
_abuseReport:
|
_abuseReport:
|
||||||
|
@ -2612,8 +2646,81 @@ _dataSaver:
|
||||||
description: "Les imatges en miniatura que serveixen com a vista prèvia de les URLs no es tornaran a carregar."
|
description: "Les imatges en miniatura que serveixen com a vista prèvia de les URLs no es tornaran a carregar."
|
||||||
_code:
|
_code:
|
||||||
title: "Ressaltat del codi "
|
title: "Ressaltat del codi "
|
||||||
|
description: "Quan s'utilitza codi MFM, no es llegeix fins que es copiï. En els punts destacats del codi s'han de llegir els fitxers definits per a cada llengua que resulti alt, però no es poden llegir automàticament, per la qual cosa es poden reduir les quantitats de comunicació."
|
||||||
|
_hemisphere:
|
||||||
|
N: "Hemisferi Nord "
|
||||||
|
S: "Hemisferi Sud"
|
||||||
|
caption: "El fan servir alguns clients per determinar l'estació de l'any."
|
||||||
_reversi:
|
_reversi:
|
||||||
|
reversi: "Reversi"
|
||||||
|
gameSettings: "Opcions del joc"
|
||||||
|
chooseBoard: "Escull un taulell"
|
||||||
|
blackOrWhite: "Negres/Blanques"
|
||||||
|
blackIs: "{name} juga amb negres "
|
||||||
|
rules: "Regles"
|
||||||
|
thisGameIsStartedSoon: "El joc començarà en breu"
|
||||||
|
waitingForOther: "Esperant la tirada de l'oponent "
|
||||||
|
waitingForMe: "Esperant el teu torn"
|
||||||
|
waitingBoth: "Prepara't "
|
||||||
|
ready: "Preparat "
|
||||||
|
cancelReady: " No preparat "
|
||||||
|
opponentTurn: "Torn de l'oponent "
|
||||||
|
myTurn: "El teu torn"
|
||||||
|
turnOf: "Li toca a {name}"
|
||||||
|
pastTurnOf: "Torn de {name}"
|
||||||
|
surrender: "Rendeix-te"
|
||||||
|
surrendered: "T'has rendit"
|
||||||
|
timeout: "Temps esgotat"
|
||||||
|
drawn: "Empat"
|
||||||
|
won: "{name} ha guanyat"
|
||||||
|
black: "Negres"
|
||||||
|
white: "Blanques"
|
||||||
total: "Total"
|
total: "Total"
|
||||||
|
turnCount: "Torn {count}"
|
||||||
|
myGames: "Jugades"
|
||||||
|
allGames: "Totes les jugades"
|
||||||
|
ended: "Acabat"
|
||||||
|
playing: "Jugant"
|
||||||
|
isLlotheo: "Qui tingui menys pedres guanya (Llotheo)"
|
||||||
|
loopedMap: "Mapa de recursiu"
|
||||||
|
canPutEverywhere: "Les fitxes es poden posar a qualsevol lloc"
|
||||||
|
timeLimitForEachTurn: "Temps límit per jugada"
|
||||||
|
freeMatch: "Partida lliure"
|
||||||
|
lookingForPlayer: "Buscant contrincant..."
|
||||||
|
gameCanceled: "La partida s'ha cancel·lat "
|
||||||
|
shareToTlTheGameWhenStart: "Compartir la partida a la línia de temps quan comenci"
|
||||||
|
iStartedAGame: "La partida ha començat! #MisskeyReversi"
|
||||||
|
opponentHasSettingsChanged: "L'oponent h canviat la seva configuració "
|
||||||
|
allowIrregularRules: "Regles irregulars (totalment lliure)"
|
||||||
|
disallowIrregularRules: "Sense regles irregulars"
|
||||||
|
showBoardLabels: "Mostrar el número de línia i columna al tauler de joc"
|
||||||
|
useAvatarAsStone: "Fer servir els avatars dels usuaris com a fitxes"
|
||||||
|
_offlineScreen:
|
||||||
|
title: "Fora de línia - No es pot connectar amb el servidor"
|
||||||
|
header: "Impossible connectar amb el servidor"
|
||||||
|
_urlPreviewSetting:
|
||||||
|
title: "Configuració per a la previsualització de l'URL"
|
||||||
|
enable: "Activa la previsualització de l'URL"
|
||||||
|
timeout: "Temps màxim per carregar la previsualització de l'URL (ms)"
|
||||||
|
timeoutDescription: "Si l'obtenció de la previsualització triga més que el temps establert, no es generarà la vista prèvia."
|
||||||
|
maximumContentLength: "Longitud màxima del contingut (bytes)"
|
||||||
|
maximumContentLengthDescription: "Si la màxima longitud és més gran que aquest valor, la previsualització no es generarà."
|
||||||
|
requireContentLength: "Generar la previsualització només si es pot obtenir la longitud màxima "
|
||||||
|
requireContentLengthDescription: "Si l'altre servidor no proporciona la longitud màxima, la previsualització no es generarà."
|
||||||
|
userAgent: "User-Agent"
|
||||||
|
userAgentDescription: "Estableix l'User-Agent que és farà servir per a la recuperació de la vista prèvia. Si és deixa en blanc es farà servir l'User-Agent per defecte."
|
||||||
|
summaryProxy: "Proxy endpoints per generar vistes prèvies"
|
||||||
|
summaryProxyDescription: "La vista prèvia es genera fent servir Summaly proxy, no la genera el mateix Misskey."
|
||||||
|
summaryProxyDescription2: "Els següents paràmetres són passats al proxy com cadenes de consulta. Si el proxy no els admet, s'ignoren els valors configurats."
|
||||||
|
_mediaControls:
|
||||||
|
pip: "Imatge sobre impressionada "
|
||||||
|
playbackRate: "Velocitat de reproducció "
|
||||||
|
loop: "Reproducció en bucle"
|
||||||
|
_contextMenu:
|
||||||
|
title: "Menú contextual"
|
||||||
|
app: "Aplicació "
|
||||||
|
appWithShift: "Aplicació amb la tecla shift"
|
||||||
|
native: "Interfície del navegador"
|
||||||
_embedCodeGen:
|
_embedCodeGen:
|
||||||
title: "Personalitza el codi per incrustar"
|
title: "Personalitza el codi per incrustar"
|
||||||
header: "Mostrar la capçalera"
|
header: "Mostrar la capçalera"
|
||||||
|
@ -2628,3 +2735,12 @@ _embedCodeGen:
|
||||||
generateCode: "Crea el codi per incrustar"
|
generateCode: "Crea el codi per incrustar"
|
||||||
codeGenerated: "Codi generat"
|
codeGenerated: "Codi generat"
|
||||||
codeGeneratedDescription: "Si us plau, enganxeu el codi generat al lloc web."
|
codeGeneratedDescription: "Si us plau, enganxeu el codi generat al lloc web."
|
||||||
|
_selfXssPrevention:
|
||||||
|
warning: "Advertència "
|
||||||
|
title: "\"Enganxa qualsevol cosa en aquesta finestra\" És tot un engany."
|
||||||
|
description1: "Si posa alguna cosa al seu compte, un usuari malintencionat podria segrestar-la o robar-li les dades."
|
||||||
|
description2: "Si no entens que estàs fent %cpara ara mateix i tanca la finestra."
|
||||||
|
description3: "Per obtenir més informació. {link}"
|
||||||
|
_followRequest:
|
||||||
|
recieved: "Sol·licituds rebudes"
|
||||||
|
sent: "Sol·licituds enviades"
|
||||||
|
|
|
@ -348,7 +348,6 @@ enableLocalTimeline: "Povolit lokální čas"
|
||||||
enableGlobalTimeline: "Povolit globální čas"
|
enableGlobalTimeline: "Povolit globální čas"
|
||||||
disablingTimelinesInfo: "Administrátoři a Moderátoři budou mít stálý přístup ke všem časovým osám i přes to že nejsou zapnuté."
|
disablingTimelinesInfo: "Administrátoři a Moderátoři budou mít stálý přístup ke všem časovým osám i přes to že nejsou zapnuté."
|
||||||
registration: "Registrace"
|
registration: "Registrace"
|
||||||
enableRegistration: "Povolit registraci novým uživatelům"
|
|
||||||
invite: "Pozvat"
|
invite: "Pozvat"
|
||||||
driveCapacityPerLocalAccount: "Kapacita disku na lokálního uživatele"
|
driveCapacityPerLocalAccount: "Kapacita disku na lokálního uživatele"
|
||||||
driveCapacityPerRemoteAccount: "Kapacita disku na vzdáleného uživatele"
|
driveCapacityPerRemoteAccount: "Kapacita disku na vzdáleného uživatele"
|
||||||
|
|
|
@ -8,6 +8,9 @@ search: "Suchen"
|
||||||
notifications: "Benachrichtigungen"
|
notifications: "Benachrichtigungen"
|
||||||
username: "Benutzername"
|
username: "Benutzername"
|
||||||
password: "Passwort"
|
password: "Passwort"
|
||||||
|
initialPasswordForSetup: "Initiales Passwort für die Einrichtung"
|
||||||
|
initialPasswordIsIncorrect: "Das initiale Passwort für die Einrichtung ist falsch"
|
||||||
|
initialPasswordForSetupDescription: "Verwende das in der Konfigurationsdatei angegebene Passwort, wenn du Misskey selbst installiert hast.\nWenn du einen Misskey-Hostingdienst o.ä. nutzt, verwende das dort angegebene Kennwort.\nWenn du kein Passwort festgelegt hast, lasse es leer, um fortzufahren."
|
||||||
forgotPassword: "Passwort vergessen"
|
forgotPassword: "Passwort vergessen"
|
||||||
fetchingAsApObject: "Wird aus dem Fediverse angefragt …"
|
fetchingAsApObject: "Wird aus dem Fediverse angefragt …"
|
||||||
ok: "OK"
|
ok: "OK"
|
||||||
|
@ -60,6 +63,7 @@ copyFileId: "Datei-ID kopieren"
|
||||||
copyFolderId: "Ordner-ID kopieren"
|
copyFolderId: "Ordner-ID kopieren"
|
||||||
copyProfileUrl: "Profil-URL kopieren"
|
copyProfileUrl: "Profil-URL kopieren"
|
||||||
searchUser: "Nach einem Benutzer suchen"
|
searchUser: "Nach einem Benutzer suchen"
|
||||||
|
searchThisUsersNotes: "Notizen dieses Benutzers suchen"
|
||||||
reply: "Antworten"
|
reply: "Antworten"
|
||||||
loadMore: "Mehr laden"
|
loadMore: "Mehr laden"
|
||||||
showMore: "Mehr anzeigen"
|
showMore: "Mehr anzeigen"
|
||||||
|
@ -108,11 +112,14 @@ enterEmoji: "Gib ein Emoji ein"
|
||||||
renote: "Renote"
|
renote: "Renote"
|
||||||
unrenote: "Renote zurücknehmen"
|
unrenote: "Renote zurücknehmen"
|
||||||
renoted: "Renote getätigt."
|
renoted: "Renote getätigt."
|
||||||
|
renotedToX: "Renoted zu {name}."
|
||||||
cantRenote: "Renote dieses Beitrags nicht möglich."
|
cantRenote: "Renote dieses Beitrags nicht möglich."
|
||||||
cantReRenote: "Renote einer Renote nicht möglich."
|
cantReRenote: "Renote einer Renote nicht möglich."
|
||||||
quote: "Zitieren"
|
quote: "Zitieren"
|
||||||
inChannelRenote: "Kanal-interner Renote"
|
inChannelRenote: "Kanal-interner Renote"
|
||||||
inChannelQuote: "Kanal-internes Zitat"
|
inChannelQuote: "Kanal-internes Zitat"
|
||||||
|
renoteToChannel: "Renote zu Kanal"
|
||||||
|
renoteToOtherChannel: "Renote zu anderem Kanal"
|
||||||
pinnedNote: "Angeheftete Notiz"
|
pinnedNote: "Angeheftete Notiz"
|
||||||
pinned: "Angeheftet"
|
pinned: "Angeheftet"
|
||||||
you: "Du"
|
you: "Du"
|
||||||
|
@ -124,12 +131,13 @@ reactions: "Reaktionen"
|
||||||
emojiPicker: "Emoji auswählen"
|
emojiPicker: "Emoji auswählen"
|
||||||
pinnedEmojisForReactionSettingDescription: "Lege Emojis fest, die angepinnt werden sollen, um sie beim Reagieren als Erstes anzuzeigen."
|
pinnedEmojisForReactionSettingDescription: "Lege Emojis fest, die angepinnt werden sollen, um sie beim Reagieren als Erstes anzuzeigen."
|
||||||
pinnedEmojisSettingDescription: "Lege Emojis fest, die angepinnt werden sollen, um sie in der Emoji-Auswahl als Erstes anzuzeigen"
|
pinnedEmojisSettingDescription: "Lege Emojis fest, die angepinnt werden sollen, um sie in der Emoji-Auswahl als Erstes anzuzeigen"
|
||||||
|
emojiPickerDisplay: "Anzeige der Emoji-Auswahl"
|
||||||
overwriteFromPinnedEmojisForReaction: "Überschreiben mit den Reaktions-Einstellungen"
|
overwriteFromPinnedEmojisForReaction: "Überschreiben mit den Reaktions-Einstellungen"
|
||||||
overwriteFromPinnedEmojis: "Überschreiben mit den allgemeinen Einstellungen"
|
overwriteFromPinnedEmojis: "Überschreiben mit den allgemeinen Einstellungen"
|
||||||
reactionSettingDescription2: "Ziehe um Anzuordnen, klicke um zu löschen, drücke „+“ um hinzuzufügen"
|
reactionSettingDescription2: "Ziehe um Anzuordnen, klicke um zu löschen, drücke „+“ um hinzuzufügen"
|
||||||
rememberNoteVisibility: "Notizsichtbarkeit merken"
|
rememberNoteVisibility: "Notizsichtbarkeit merken"
|
||||||
attachCancel: "Anhang entfernen"
|
attachCancel: "Anhang entfernen"
|
||||||
deleteFile: "Datei gelöscht"
|
deleteFile: "Datei löschen"
|
||||||
markAsSensitive: "Als sensibel markieren"
|
markAsSensitive: "Als sensibel markieren"
|
||||||
unmarkAsSensitive: "Als nicht sensibel markieren"
|
unmarkAsSensitive: "Als nicht sensibel markieren"
|
||||||
enterFileName: "Dateinamen eingeben"
|
enterFileName: "Dateinamen eingeben"
|
||||||
|
@ -150,6 +158,7 @@ editList: "Liste bearbeiten"
|
||||||
selectChannel: "Kanal auswählen"
|
selectChannel: "Kanal auswählen"
|
||||||
selectAntenna: "Antenne auswählen"
|
selectAntenna: "Antenne auswählen"
|
||||||
editAntenna: "Antenne bearbeiten"
|
editAntenna: "Antenne bearbeiten"
|
||||||
|
createAntenna: "Erstelle eine Antenne"
|
||||||
selectWidget: "Widget auswählen"
|
selectWidget: "Widget auswählen"
|
||||||
editWidgets: "Widgets bearbeiten"
|
editWidgets: "Widgets bearbeiten"
|
||||||
editWidgetsExit: "Fertig"
|
editWidgetsExit: "Fertig"
|
||||||
|
@ -176,6 +185,8 @@ addAccount: "Benutzerkonto hinzufügen"
|
||||||
reloadAccountsList: "Benutzerkontoliste aktualisieren"
|
reloadAccountsList: "Benutzerkontoliste aktualisieren"
|
||||||
loginFailed: "Anmeldung fehlgeschlagen"
|
loginFailed: "Anmeldung fehlgeschlagen"
|
||||||
showOnRemote: "Auf Ursprungsinstanz ansehen"
|
showOnRemote: "Auf Ursprungsinstanz ansehen"
|
||||||
|
chooseServerOnMisskeyHub: "Wähle einen Server aus dem Misskey Hub"
|
||||||
|
inputHostName: "Gib die Domain an"
|
||||||
general: "Allgemein"
|
general: "Allgemein"
|
||||||
wallpaper: "Hintergrund"
|
wallpaper: "Hintergrund"
|
||||||
setWallpaper: "Hintergrund festlegen"
|
setWallpaper: "Hintergrund festlegen"
|
||||||
|
@ -186,6 +197,7 @@ followConfirm: "Möchtest du {name} wirklich folgen?"
|
||||||
proxyAccount: "Proxy-Benutzerkonto"
|
proxyAccount: "Proxy-Benutzerkonto"
|
||||||
proxyAccountDescription: "Ein Proxy-Konto ist ein Benutzerkonto, das unter bestimmten Bedingungen als Follower für Benutzer fremder Instanzen fungiert. Wenn zum Beispiel ein Benutzer einen Benutzer einer fremden Instanz zu einer Liste hinzufügt, werden die Aktivitäten des entfernten Benutzers nicht an die Instanz übermittelt, wenn kein lokaler Benutzer diesem Benutzer folgt; stattdessen folgt das Proxy-Konto."
|
proxyAccountDescription: "Ein Proxy-Konto ist ein Benutzerkonto, das unter bestimmten Bedingungen als Follower für Benutzer fremder Instanzen fungiert. Wenn zum Beispiel ein Benutzer einen Benutzer einer fremden Instanz zu einer Liste hinzufügt, werden die Aktivitäten des entfernten Benutzers nicht an die Instanz übermittelt, wenn kein lokaler Benutzer diesem Benutzer folgt; stattdessen folgt das Proxy-Konto."
|
||||||
host: "Hostname"
|
host: "Hostname"
|
||||||
|
selectSelf: "Mich auswählen"
|
||||||
selectUser: "Benutzer auswählen"
|
selectUser: "Benutzer auswählen"
|
||||||
recipient: "Empfänger"
|
recipient: "Empfänger"
|
||||||
annotation: "Anmerkung"
|
annotation: "Anmerkung"
|
||||||
|
@ -201,6 +213,7 @@ perDay: "Pro Tag"
|
||||||
stopActivityDelivery: "Senden von Aktivitäten einstellen"
|
stopActivityDelivery: "Senden von Aktivitäten einstellen"
|
||||||
blockThisInstance: "Diese Instanz blockieren"
|
blockThisInstance: "Diese Instanz blockieren"
|
||||||
silenceThisInstance: "Instanz stummschalten"
|
silenceThisInstance: "Instanz stummschalten"
|
||||||
|
mediaSilenceThisInstance: "Medien dieses Servers stummschalten"
|
||||||
operations: "Aktionen"
|
operations: "Aktionen"
|
||||||
software: "Software"
|
software: "Software"
|
||||||
version: "Version"
|
version: "Version"
|
||||||
|
@ -222,6 +235,8 @@ blockedInstances: "Blockierte Instanzen"
|
||||||
blockedInstancesDescription: "Gib die Hostnamen der Instanzen, welche blockiert werden sollen, durch Zeilenumbrüche getrennt an. Blockierte Instanzen können mit dieser instanz nicht mehr kommunizieren."
|
blockedInstancesDescription: "Gib die Hostnamen der Instanzen, welche blockiert werden sollen, durch Zeilenumbrüche getrennt an. Blockierte Instanzen können mit dieser instanz nicht mehr kommunizieren."
|
||||||
silencedInstances: "Stummgeschaltete Instanzen"
|
silencedInstances: "Stummgeschaltete Instanzen"
|
||||||
silencedInstancesDescription: "Gib die Hostnamen der Instanzen, welche stummgeschaltet werden sollen, durch Zeilenumbrüche getrennt an. Alle Konten dieser Instanzen werden als stummgeschaltet behandelt, können nur noch Follow-Anfragen stellen und wenn nicht gefolgt keine lokalen Konten erwähnen. Blockierte Instanzen sind davon nicht betroffen."
|
silencedInstancesDescription: "Gib die Hostnamen der Instanzen, welche stummgeschaltet werden sollen, durch Zeilenumbrüche getrennt an. Alle Konten dieser Instanzen werden als stummgeschaltet behandelt, können nur noch Follow-Anfragen stellen und wenn nicht gefolgt keine lokalen Konten erwähnen. Blockierte Instanzen sind davon nicht betroffen."
|
||||||
|
mediaSilencedInstances: "Medien-stummgeschaltete Server"
|
||||||
|
mediaSilencedInstancesDescription: "Gib pro Zeile die Hostnamen der Server ein, dessen Medien du stummschalten möchtest. Alle Benutzerkonten der aufgeführten Server werden als sensibel behandelt und können keine benutzerdefinierten Emojis verwenden. Gesperrte Server sind davon nicht betroffen."
|
||||||
muteAndBlock: "Stummschaltungen und Blockierungen"
|
muteAndBlock: "Stummschaltungen und Blockierungen"
|
||||||
mutedUsers: "Stummgeschaltete Benutzer"
|
mutedUsers: "Stummgeschaltete Benutzer"
|
||||||
blockedUsers: "Blockierte Benutzer"
|
blockedUsers: "Blockierte Benutzer"
|
||||||
|
@ -312,6 +327,7 @@ selectFile: "Datei auswählen"
|
||||||
selectFiles: "Dateien auswählen"
|
selectFiles: "Dateien auswählen"
|
||||||
selectFolder: "Ordner auswählen"
|
selectFolder: "Ordner auswählen"
|
||||||
selectFolders: "Ordner auswählen"
|
selectFolders: "Ordner auswählen"
|
||||||
|
fileNotSelected: "Keine Datei ausgewählt"
|
||||||
renameFile: "Datei umbenennen"
|
renameFile: "Datei umbenennen"
|
||||||
folderName: "Ordnername"
|
folderName: "Ordnername"
|
||||||
createFolder: "Ordner erstellen"
|
createFolder: "Ordner erstellen"
|
||||||
|
@ -319,6 +335,7 @@ renameFolder: "Ordner umbenennen"
|
||||||
deleteFolder: "Ordner löschen"
|
deleteFolder: "Ordner löschen"
|
||||||
folder: "Ordner"
|
folder: "Ordner"
|
||||||
addFile: "Datei hinzufügen"
|
addFile: "Datei hinzufügen"
|
||||||
|
showFile: "Datei anzeigen"
|
||||||
emptyDrive: "Deine Drive ist leer"
|
emptyDrive: "Deine Drive ist leer"
|
||||||
emptyFolder: "Dieser Ordner ist leer"
|
emptyFolder: "Dieser Ordner ist leer"
|
||||||
unableToDelete: "Nicht löschbar"
|
unableToDelete: "Nicht löschbar"
|
||||||
|
@ -361,7 +378,6 @@ enableLocalTimeline: "Lokale Chronik aktivieren"
|
||||||
enableGlobalTimeline: "Globale Chronik aktivieren"
|
enableGlobalTimeline: "Globale Chronik aktivieren"
|
||||||
disablingTimelinesInfo: "Administratoren und Moderatoren haben immer Zugriff auf alle Chroniken, auch wenn diese deaktiviert sind."
|
disablingTimelinesInfo: "Administratoren und Moderatoren haben immer Zugriff auf alle Chroniken, auch wenn diese deaktiviert sind."
|
||||||
registration: "Registrieren"
|
registration: "Registrieren"
|
||||||
enableRegistration: "Registrierung neuer Benutzer erlauben"
|
|
||||||
invite: "Einladen"
|
invite: "Einladen"
|
||||||
driveCapacityPerLocalAccount: "Drive-Kapazität pro lokalem Benutzerkonto"
|
driveCapacityPerLocalAccount: "Drive-Kapazität pro lokalem Benutzerkonto"
|
||||||
driveCapacityPerRemoteAccount: "Drive-Kapazität pro Benutzer fremder Instanzen"
|
driveCapacityPerRemoteAccount: "Drive-Kapazität pro Benutzer fremder Instanzen"
|
||||||
|
@ -399,6 +415,7 @@ name: "Name"
|
||||||
antennaSource: "Antennenquelle"
|
antennaSource: "Antennenquelle"
|
||||||
antennaKeywords: "Zu beobachtende Schlüsselwörter"
|
antennaKeywords: "Zu beobachtende Schlüsselwörter"
|
||||||
antennaExcludeKeywords: "Zu ignorierende Schlüsselwörter"
|
antennaExcludeKeywords: "Zu ignorierende Schlüsselwörter"
|
||||||
|
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"
|
||||||
|
@ -466,6 +483,7 @@ retype: "Erneut eingeben"
|
||||||
noteOf: "Notiz von {user}"
|
noteOf: "Notiz von {user}"
|
||||||
quoteAttached: "Zitat"
|
quoteAttached: "Zitat"
|
||||||
quoteQuestion: "Als Zitat anhängen?"
|
quoteQuestion: "Als Zitat anhängen?"
|
||||||
|
attachAsFileQuestion: "Der Text in der Zwischenablage ist lang. Möchtest du ihn als Textdatei anhängen?"
|
||||||
noMessagesYet: "Noch keine Nachrichten vorhanden"
|
noMessagesYet: "Noch keine Nachrichten vorhanden"
|
||||||
newMessageExists: "Du hast eine neue Nachricht"
|
newMessageExists: "Du hast eine neue Nachricht"
|
||||||
onlyOneFileCanBeAttached: "Es kann pro Nachricht nur eine Datei angehängt werden"
|
onlyOneFileCanBeAttached: "Es kann pro Nachricht nur eine Datei angehängt werden"
|
||||||
|
@ -491,7 +509,11 @@ uiLanguage: "Sprache der Benutzeroberfläche"
|
||||||
aboutX: "Über {x}"
|
aboutX: "Über {x}"
|
||||||
emojiStyle: "Emoji-Stil"
|
emojiStyle: "Emoji-Stil"
|
||||||
native: "Nativ"
|
native: "Nativ"
|
||||||
|
menuStyle: "Menü Stil"
|
||||||
|
style: "Stil"
|
||||||
|
popup: "Pop-up"
|
||||||
showNoteActionsOnlyHover: "Notizmenü nur bei Mouseover anzeigen"
|
showNoteActionsOnlyHover: "Notizmenü nur bei Mouseover anzeigen"
|
||||||
|
showReactionsCount: "Zeige die Anzahl der Reaktionen auf Notizen an"
|
||||||
noHistory: "Kein Verlauf gefunden"
|
noHistory: "Kein Verlauf gefunden"
|
||||||
signinHistory: "Anmeldungsverlauf"
|
signinHistory: "Anmeldungsverlauf"
|
||||||
enableAdvancedMfm: "Erweitertes MFM aktivieren"
|
enableAdvancedMfm: "Erweitertes MFM aktivieren"
|
||||||
|
@ -572,6 +594,7 @@ ascendingOrder: "Aufsteigende Reihenfolge"
|
||||||
descendingOrder: "Absteigende Reihenfolge"
|
descendingOrder: "Absteigende Reihenfolge"
|
||||||
scratchpad: "Testumgebung"
|
scratchpad: "Testumgebung"
|
||||||
scratchpadDescription: "Die Testumgebung bietet einen Bereich für AiScript-Experimente. Dort kannst du AiScript schreiben, ausführen sowie dessen Auswirkungen auf Misskey überprüfen."
|
scratchpadDescription: "Die Testumgebung bietet einen Bereich für AiScript-Experimente. Dort kannst du AiScript schreiben, ausführen sowie dessen Auswirkungen auf Misskey überprüfen."
|
||||||
|
uiInspector: "UI-Inspektor"
|
||||||
output: "Ausgabe"
|
output: "Ausgabe"
|
||||||
script: "Skript"
|
script: "Skript"
|
||||||
disablePagesScript: "AiScript auf Seiten deaktivieren"
|
disablePagesScript: "AiScript auf Seiten deaktivieren"
|
||||||
|
@ -652,6 +675,7 @@ smtpSecure: "Für SMTP-Verbindungen implizit SSL/TLS verwenden"
|
||||||
smtpSecureInfo: "Schalte dies aus, falls du STARTTLS verwendest."
|
smtpSecureInfo: "Schalte dies aus, falls du STARTTLS verwendest."
|
||||||
testEmail: "Emailversand testen"
|
testEmail: "Emailversand testen"
|
||||||
wordMute: "Wortstummschaltung"
|
wordMute: "Wortstummschaltung"
|
||||||
|
hardWordMute: "Harte Wort-Stummschaltung"
|
||||||
regexpError: "Fehler in einem regulären Ausdruck"
|
regexpError: "Fehler in einem regulären Ausdruck"
|
||||||
regexpErrorDescription: "Im regulären Ausdruck deiner in Zeile {line} von {tab}en Wortstummschaltungen ist ein Fehler aufgetreten:"
|
regexpErrorDescription: "Im regulären Ausdruck deiner in Zeile {line} von {tab}en Wortstummschaltungen ist ein Fehler aufgetreten:"
|
||||||
instanceMute: "Instanzstummschaltungen"
|
instanceMute: "Instanzstummschaltungen"
|
||||||
|
@ -673,6 +697,7 @@ useGlobalSettingDesc: "Ist diese Option aktiviert, werden die Benachrichtigungse
|
||||||
other: "Anderes"
|
other: "Anderes"
|
||||||
regenerateLoginToken: "Anmeldetoken regenerieren"
|
regenerateLoginToken: "Anmeldetoken regenerieren"
|
||||||
regenerateLoginTokenDescription: "Den zur Anmeldung intern verwendeten Token regenerieren. Normalerweise wird dies nicht benötigt. Bei Regeneration werden alle Geräte ausgeloggt."
|
regenerateLoginTokenDescription: "Den zur Anmeldung intern verwendeten Token regenerieren. Normalerweise wird dies nicht benötigt. Bei Regeneration werden alle Geräte ausgeloggt."
|
||||||
|
theKeywordWhenSearchingForCustomEmoji: "Das ist das Schlagwort beim Suchen von benutzerdefinierten Emojis."
|
||||||
setMultipleBySeparatingWithSpace: "Trenne Elemente durch ein Leerzeichen um mehrere Einstellungen zu kofigurieren."
|
setMultipleBySeparatingWithSpace: "Trenne Elemente durch ein Leerzeichen um mehrere Einstellungen zu kofigurieren."
|
||||||
fileIdOrUrl: "Datei-ID oder URL"
|
fileIdOrUrl: "Datei-ID oder URL"
|
||||||
behavior: "Verhalten"
|
behavior: "Verhalten"
|
||||||
|
@ -882,9 +907,12 @@ makeReactionsPublicDescription: "Jeder wird die Liste deiner gesendeten Reaktion
|
||||||
classic: "Classic"
|
classic: "Classic"
|
||||||
muteThread: "Thread stummschalten"
|
muteThread: "Thread stummschalten"
|
||||||
unmuteThread: "Threadstummschaltung aufheben"
|
unmuteThread: "Threadstummschaltung aufheben"
|
||||||
|
followingVisibility: "Sichtbarkeit der Gefolgten"
|
||||||
|
followersVisibility: "Sichtbarkeit der Folgenden"
|
||||||
continueThread: "Weiteren Threadverlauf anzeigen"
|
continueThread: "Weiteren Threadverlauf anzeigen"
|
||||||
deleteAccountConfirm: "Dein Benutzerkonto wird unwiderruflich gelöscht. Trotzdem fortfahren?"
|
deleteAccountConfirm: "Dein Benutzerkonto wird unwiderruflich gelöscht. Trotzdem fortfahren?"
|
||||||
incorrectPassword: "Falsches Passwort."
|
incorrectPassword: "Falsches Passwort."
|
||||||
|
incorrectTotp: "Das Einmalpasswort ist falsch oder abgelaufen."
|
||||||
voteConfirm: "Wirklich für „{choice}“ abstimmen?"
|
voteConfirm: "Wirklich für „{choice}“ abstimmen?"
|
||||||
hide: "Inhalt verbergen"
|
hide: "Inhalt verbergen"
|
||||||
useDrawerReactionPickerForMobile: "Auf mobilen Geräten ausfahrbare Reaktionsauswahl anzeigen"
|
useDrawerReactionPickerForMobile: "Auf mobilen Geräten ausfahrbare Reaktionsauswahl anzeigen"
|
||||||
|
@ -909,6 +937,9 @@ oneHour: "Eine Stunde"
|
||||||
oneDay: "Einen Tag"
|
oneDay: "Einen Tag"
|
||||||
oneWeek: "Eine Woche"
|
oneWeek: "Eine Woche"
|
||||||
oneMonth: "1 Monat"
|
oneMonth: "1 Monat"
|
||||||
|
threeMonths: "3 Monate"
|
||||||
|
oneYear: "1 Jahr"
|
||||||
|
threeDays: "3 Tage"
|
||||||
reflectMayTakeTime: "Es kann etwas dauern, bis sich dies widerspiegelt."
|
reflectMayTakeTime: "Es kann etwas dauern, bis sich dies widerspiegelt."
|
||||||
failedToFetchAccountInformation: "Benutzerkontoinformationen konnten nicht abgefragt werden"
|
failedToFetchAccountInformation: "Benutzerkontoinformationen konnten nicht abgefragt werden"
|
||||||
rateLimitExceeded: "Versuchsanzahl überschritten"
|
rateLimitExceeded: "Versuchsanzahl überschritten"
|
||||||
|
@ -982,6 +1013,7 @@ neverShow: "Nicht wieder anzeigen"
|
||||||
remindMeLater: "Vielleicht später"
|
remindMeLater: "Vielleicht später"
|
||||||
didYouLikeMisskey: "Gefällt dir Misskey?"
|
didYouLikeMisskey: "Gefällt dir Misskey?"
|
||||||
pleaseDonate: "Misskey ist die kostenlose Software, die von {host} verwendet wird. Wir würden uns über Spenden freuen, damit dessen Entwicklung weitergeführt werden kann!"
|
pleaseDonate: "Misskey ist die kostenlose Software, die von {host} verwendet wird. Wir würden uns über Spenden freuen, damit dessen Entwicklung weitergeführt werden kann!"
|
||||||
|
correspondingSourceIsAvailable: "Der entsprechende Quellcode ist verfügbar unter {anchor}"
|
||||||
roles: "Rollen"
|
roles: "Rollen"
|
||||||
role: "Rolle"
|
role: "Rolle"
|
||||||
noRole: "Rolle nicht gefunden"
|
noRole: "Rolle nicht gefunden"
|
||||||
|
@ -1009,6 +1041,7 @@ thisPostMayBeAnnoyingHome: "Zur Startseite schicken"
|
||||||
thisPostMayBeAnnoyingCancel: "Abbrechen"
|
thisPostMayBeAnnoyingCancel: "Abbrechen"
|
||||||
thisPostMayBeAnnoyingIgnore: "Trotzdem schicken"
|
thisPostMayBeAnnoyingIgnore: "Trotzdem schicken"
|
||||||
collapseRenotes: "Bereits gesehene Renotes verkürzt anzeigen"
|
collapseRenotes: "Bereits gesehene Renotes verkürzt anzeigen"
|
||||||
|
collapseRenotesDescription: "Klappe Notizen ein, auf die du bereits reagiert oder die du renoted hast."
|
||||||
internalServerError: "Serverinterner Fehler"
|
internalServerError: "Serverinterner Fehler"
|
||||||
internalServerErrorDescription: "Im Server ist ein unerwarteter Fehler aufgetreten."
|
internalServerErrorDescription: "Im Server ist ein unerwarteter Fehler aufgetreten."
|
||||||
copyErrorInfo: "Fehlerdetails kopieren"
|
copyErrorInfo: "Fehlerdetails kopieren"
|
||||||
|
@ -1032,6 +1065,8 @@ resetPasswordConfirm: "Wirklich Passwort zurücksetzen?"
|
||||||
sensitiveWords: "Sensible Wörter"
|
sensitiveWords: "Sensible Wörter"
|
||||||
sensitiveWordsDescription: "Die Notizsichtbarkeit aller Notizen, die diese Wörter enthalten, wird automatisch auf \"Startseite\" gesetzt. Durch Zeilenumbrüche können mehrere konfiguriert werden."
|
sensitiveWordsDescription: "Die Notizsichtbarkeit aller Notizen, die diese Wörter enthalten, wird automatisch auf \"Startseite\" gesetzt. Durch Zeilenumbrüche können mehrere konfiguriert werden."
|
||||||
sensitiveWordsDescription2: "Durch die Verwendung von Leerzeichen können AND-Verknüpfungen angegeben werden und durch das Umgeben von Schrägstrichen können reguläre Ausdrücke verwendet werden."
|
sensitiveWordsDescription2: "Durch die Verwendung von Leerzeichen können AND-Verknüpfungen angegeben werden und durch das Umgeben von Schrägstrichen können reguläre Ausdrücke verwendet werden."
|
||||||
|
prohibitedWords: "Verbotene Wörter"
|
||||||
|
prohibitedWordsDescription: "Aktiviert eine Fehlermeldung, wenn versucht wird, eine Notiz zu veröffentlichen, die das/die eingestellte(n) Wort(e) enthält. Mehrere Begriffe können durch Zeilenumbrüche getrennt festgelegt werden."
|
||||||
prohibitedWordsDescription2: "Durch die Verwendung von Leerzeichen können AND-Verknüpfungen angegeben werden und durch das Umgeben von Schrägstrichen können reguläre Ausdrücke verwendet werden."
|
prohibitedWordsDescription2: "Durch die Verwendung von Leerzeichen können AND-Verknüpfungen angegeben werden und durch das Umgeben von Schrägstrichen können reguläre Ausdrücke verwendet werden."
|
||||||
hiddenTags: "Ausgeblendete Hashtags"
|
hiddenTags: "Ausgeblendete Hashtags"
|
||||||
hiddenTagsDescription: "Die hier eingestellten Tags werden nicht mehr in den Trends angezeigt. Mit der Umschalttaste können mehrere ausgewählt werden."
|
hiddenTagsDescription: "Die hier eingestellten Tags werden nicht mehr in den Trends angezeigt. Mit der Umschalttaste können mehrere ausgewählt werden."
|
||||||
|
@ -1078,6 +1113,8 @@ preservedUsernames: "Reservierte Benutzernamen"
|
||||||
preservedUsernamesDescription: "Gib zu reservierende Benutzernamen durch Zeilenumbrüche getrennt an. Diese werden für die Registrierung gesperrt, können aber von Administratoren zur manuellen Erstellung von Konten verwendet werden. Existierende Konten, die diese Namen bereits verwenden, werden nicht beeinträchtigt."
|
preservedUsernamesDescription: "Gib zu reservierende Benutzernamen durch Zeilenumbrüche getrennt an. Diese werden für die Registrierung gesperrt, können aber von Administratoren zur manuellen Erstellung von Konten verwendet werden. Existierende Konten, die diese Namen bereits verwenden, werden nicht beeinträchtigt."
|
||||||
createNoteFromTheFile: "Notiz für diese Datei schreiben"
|
createNoteFromTheFile: "Notiz für diese Datei schreiben"
|
||||||
archive: "Archivieren"
|
archive: "Archivieren"
|
||||||
|
archived: "Archiviert"
|
||||||
|
unarchive: "Dearchivieren"
|
||||||
channelArchiveConfirmTitle: "{name} wirklich archivieren?"
|
channelArchiveConfirmTitle: "{name} wirklich archivieren?"
|
||||||
channelArchiveConfirmDescription: "Ein archivierter Kanal taucht nicht mehr in der Kanalliste oder in Suchergebnissen auf. Zudem können ihm keine Beiträge mehr hinzugefügt werden."
|
channelArchiveConfirmDescription: "Ein archivierter Kanal taucht nicht mehr in der Kanalliste oder in Suchergebnissen auf. Zudem können ihm keine Beiträge mehr hinzugefügt werden."
|
||||||
thisChannelArchived: "Dieser Kanal wurde archiviert."
|
thisChannelArchived: "Dieser Kanal wurde archiviert."
|
||||||
|
@ -1155,6 +1192,9 @@ confirmShowRepliesAll: "Dies ist eine unwiderrufliche Aktion. Wirklich Antworten
|
||||||
confirmHideRepliesAll: "Dies ist eine unwiderrufliche Aktion. Wirklich Antworten von allen momentan gefolgten Benutzern nicht in der Chronik anzeigen?"
|
confirmHideRepliesAll: "Dies ist eine unwiderrufliche Aktion. Wirklich Antworten von allen momentan gefolgten Benutzern nicht in der Chronik anzeigen?"
|
||||||
externalServices: "Externe Dienste"
|
externalServices: "Externe Dienste"
|
||||||
sourceCode: "Quellcode"
|
sourceCode: "Quellcode"
|
||||||
|
sourceCodeIsNotYetProvided: "Der Quellcode ist noch nicht verfügbar. Kontaktiere den Administrator, um das Problem zu lösen."
|
||||||
|
repositoryUrl: "Repository URL"
|
||||||
|
repositoryUrlOrTarballRequired: "Wenn du kein Repository veröffentlicht hast, musst du stattdessen einen Tarball bereitstellen. Siehe .config/example.yml für weitere Informationen."
|
||||||
impressum: "Impressum"
|
impressum: "Impressum"
|
||||||
impressumUrl: "Impressums-URL"
|
impressumUrl: "Impressums-URL"
|
||||||
impressumDescription: "In manchen Ländern, wie Deutschland und dessen Umgebung, ist die Angabe von Betreiberinformationen (ein Impressum) bei kommerziellem Betrieb zwingend."
|
impressumDescription: "In manchen Ländern, wie Deutschland und dessen Umgebung, ist die Angabe von Betreiberinformationen (ein Impressum) bei kommerziellem Betrieb zwingend."
|
||||||
|
@ -1176,15 +1216,82 @@ signupPendingError: "Beim Überprüfen der Mailadresse ist etwas schiefgelaufen.
|
||||||
cwNotationRequired: "Ist \"Inhaltswarnung verwenden\" aktiviert, muss eine Beschreibung gegeben werden."
|
cwNotationRequired: "Ist \"Inhaltswarnung verwenden\" aktiviert, muss eine Beschreibung gegeben werden."
|
||||||
doReaction: "Reagieren"
|
doReaction: "Reagieren"
|
||||||
code: "Code"
|
code: "Code"
|
||||||
|
remainingN: "Verbleibend: {n}"
|
||||||
|
overwriteContentConfirm: "Bist du sicher, dass du den aktuellen Inhalt überschreiben willst?"
|
||||||
|
seasonalScreenEffect: "Saisonaler Bildschirmeffekt"
|
||||||
decorate: "Dekorieren"
|
decorate: "Dekorieren"
|
||||||
addMfmFunction: "MFM hinzufügen"
|
addMfmFunction: "MFM hinzufügen"
|
||||||
|
enableQuickAddMfmFunction: "Erweiterte MFM-Auswahl anzeigen"
|
||||||
sfx: "Soundeffekte"
|
sfx: "Soundeffekte"
|
||||||
|
soundWillBePlayed: "Es wird Ton wiedergegeben"
|
||||||
|
showReplay: "Wiederholung anzeigen"
|
||||||
|
ranking: "Rangliste"
|
||||||
lastNDays: "Letzten {n} Tage"
|
lastNDays: "Letzten {n} Tage"
|
||||||
|
backToTitle: "Zurück zum Startbildschirm"
|
||||||
|
enableHorizontalSwipe: "Wischen, um zwischen Tabs zu wechseln"
|
||||||
|
loading: "Laden"
|
||||||
surrender: "Abbrechen"
|
surrender: "Abbrechen"
|
||||||
|
gameRetry: "Erneut versuchen"
|
||||||
|
notUsePleaseLeaveBlank: "Leer lassen, wenn nicht verwendet"
|
||||||
|
useTotp: "Gib das Einmalpasswort ein"
|
||||||
|
useBackupCode: "Verwende die Backup-Codes"
|
||||||
|
launchApp: "Starte die App"
|
||||||
|
useNativeUIForVideoAudioPlayer: "Browser-Benutzeroberfläche für die Video- und Audiowiedergabe verwenden"
|
||||||
|
keepOriginalFilename: "Ursprünglichen Dateinamen beibehalten"
|
||||||
|
keepOriginalFilenameDescription: "Wenn diese Einstellung deaktiviert ist, wird der Dateiname beim Hochladen automatisch durch eine zufällige Zeichenfolge ersetzt."
|
||||||
|
noDescription: "Keine Beschreibung vorhanden"
|
||||||
|
tryAgain: "Bitte später erneut versuchen"
|
||||||
|
confirmWhenRevealingSensitiveMedia: "Das Anzeigen von sensiblen Medien bestätigen"
|
||||||
|
sensitiveMediaRevealConfirm: "Es könnte sich um sensible Medien handeln. Möchtest du sie anzeigen?"
|
||||||
|
createdLists: "Erstellte Listen"
|
||||||
|
createdAntennas: "Erstellte Antennen"
|
||||||
|
fromX: "Von {x}"
|
||||||
|
genEmbedCode: "Einbettungscode generieren"
|
||||||
|
noteOfThisUser: "Notizen dieses Benutzers"
|
||||||
|
clipNoteLimitExceeded: "Zu diesem Clip können keine weiteren Notizen hinzugefügt werden."
|
||||||
|
discard: "Verwerfen"
|
||||||
|
thereAreNChanges: "Es gibt {n} Änderung(en)"
|
||||||
|
signinWithPasskey: "Mit Passkey anmelden"
|
||||||
|
passkeyVerificationFailed: "Die Passkey-Verifizierung ist fehlgeschlagen."
|
||||||
|
passkeyVerificationSucceededButPasswordlessLoginDisabled: "Die Verifizierung des Passkeys war erfolgreich, aber die passwortlose Anmeldung ist deaktiviert."
|
||||||
|
messageToFollower: "Nachricht an die Follower"
|
||||||
|
testCaptchaWarning: "Diese Funktion ist für CAPTCHA-Testzwecke gedacht.\n<strong>Nicht in einer Produktivumgebung verwenden.</strong>"
|
||||||
|
prohibitedWordsForNameOfUser: "Verbotene Begriffe für Benutzernamen"
|
||||||
|
prohibitedWordsForNameOfUserDescription: "Wenn eine Zeichenfolge aus dieser Liste im Namen eines Benutzers enthalten ist, wird der Benutzername abgelehnt. Benutzer mit Moderatorenrechten sind von dieser Einschränkung nicht betroffen."
|
||||||
|
yourNameContainsProhibitedWords: "Dein Name enthält einen verbotenen Begriff"
|
||||||
|
yourNameContainsProhibitedWordsDescription: "Der Name enthält eine verbotene Zeichenfolge. Wende dich an deinen Serveradministrator, wenn du diesen Namen verwenden möchtest."
|
||||||
|
pleaseSelectAccount: "Bitte Konto auswählen"
|
||||||
|
availableRoles: "Verfügbare Rollen"
|
||||||
|
_accountSettings:
|
||||||
|
requireSigninToViewContents: "Anmeldung erfordern, um Inhalte anzuzeigen"
|
||||||
|
requireSigninToViewContentsDescription1: "Erfordere eine Anmeldung, um alle Notizen und andere Inhalte anzuzeigen, die du erstellt hast. Dadurch wird verhindert, dass Crawler deine Informationen sammeln."
|
||||||
|
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"
|
||||||
|
makeNotesHiddenBefore: "Frühere Notizen privat machen"
|
||||||
|
mayNotEffectForFederatedNotes: "Dies hat möglicherweise keine Auswirkungen auf Notizen, die an andere Server föderiert werden."
|
||||||
|
_abuseUserReport:
|
||||||
|
forward: "Weiterleiten"
|
||||||
|
forwardDescription: "Leite die Meldung an einen entfernten Server als anonymes Systemkonto weiter."
|
||||||
|
accept: "Akzeptieren"
|
||||||
|
reject: "Ablehnen"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "Gesperrt"
|
stop: "Gesperrt"
|
||||||
_type:
|
_type:
|
||||||
none: "Wird veröffentlicht"
|
none: "Wird veröffentlicht"
|
||||||
|
manuallySuspended: "Manuell gesperrt"
|
||||||
|
_bubbleGame:
|
||||||
|
howToPlay: "Wie man spielt"
|
||||||
|
hold: "Halten"
|
||||||
|
_score:
|
||||||
|
score: "Spielstand"
|
||||||
|
scoreYen: "Verdienter Geldbetrag"
|
||||||
|
highScore: "Höchstpunktzahl"
|
||||||
|
maxChain: "Maximale Anzahl an Verkettungen"
|
||||||
|
yen: "{yen} Yen"
|
||||||
|
_howToPlay:
|
||||||
|
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."
|
||||||
|
section3: "Das Spiel ist vorbei, wenn die Objekte aus dem Spielfeld herausragen. Versuche eine hohe Punktzahl zu erreichen, indem du die Objekte miteinander verschmelzt, ohne dass das Spielfeld überläuft!"
|
||||||
_announcement:
|
_announcement:
|
||||||
forExistingUsers: "Nur für existierende Nutzer"
|
forExistingUsers: "Nur für existierende Nutzer"
|
||||||
forExistingUsersDescription: "Ist diese Option aktiviert, wird diese Ankündigung nur Nutzern angezeigt, die zum Zeitpunkt der Ankündigung bereits registriert sind. Ist sie deaktiviert, wird sie auch Nutzern, die sich nach dessen Veröffentlichung registrieren, angezeigt."
|
forExistingUsersDescription: "Ist diese Option aktiviert, wird diese Ankündigung nur Nutzern angezeigt, die zum Zeitpunkt der Ankündigung bereits registriert sind. Ist sie deaktiviert, wird sie auch Nutzern, die sich nach dessen Veröffentlichung registrieren, angezeigt."
|
||||||
|
@ -1228,8 +1335,18 @@ _initialTutorial:
|
||||||
reply: "Klicke auf diesen Button, um auf eine Nachricht zu antworten. Es ist auch möglich, auf Antworten zu antworten und die Unterhaltung wie einen Thread fortzusetzen."
|
reply: "Klicke auf diesen Button, um auf eine Nachricht zu antworten. Es ist auch möglich, auf Antworten zu antworten und die Unterhaltung wie einen Thread fortzusetzen."
|
||||||
_reaction:
|
_reaction:
|
||||||
title: "Was sind Reaktionen?"
|
title: "Was sind Reaktionen?"
|
||||||
|
description: "Auf Notizen kann mit verschiedenen Emojis reagiert werden. Reaktionen ermöglichen es dir, Nuancen auszudrücken, die mit einem einfachen „Gefällt mir“ vielleicht nicht ausgedrückt werden können."
|
||||||
|
letsTryReacting: "Reaktionen können durch Klicken auf die Schaltfläche „+“ in der Notiz hinzugefügt werden. Versuche, auf diese Beispielnotiz zu reagieren!"
|
||||||
reactToContinue: "Füge eine Reaktion hinzu, um fortzufahren."
|
reactToContinue: "Füge eine Reaktion hinzu, um fortzufahren."
|
||||||
reactNotification: "Du erhältst Echtzeit-Benachrichtigungen, wenn jemand auf deine Notiz reagiert."
|
reactNotification: "Du erhältst Echtzeit-Benachrichtigungen, wenn jemand auf deine Notiz reagiert."
|
||||||
|
reactDone: "Du kannst eine Reaktion zurücknehmen, indem du auf den '-' Button drückst."
|
||||||
|
_timeline:
|
||||||
|
title: "So funktionieren die Chroniken"
|
||||||
|
home: "Du kannst Beiträge von den Konten sehen, denen du folgst."
|
||||||
|
local: "Du kannst Beiträge aller Benutzer auf diesem Server sehen."
|
||||||
|
social: "Notizen von der Startseite und der lokalen Chronik werden angezeigt."
|
||||||
|
global: "Du kannst Notizen von allen föderierten Servern sehen."
|
||||||
|
description2: "Du kannst jederzeit am oberen Rand des Bildschirms zwischen den jeweiligen Chroniken wechseln."
|
||||||
_postNote:
|
_postNote:
|
||||||
_visibility:
|
_visibility:
|
||||||
description: "Du kannst einschränken, wer deine Notiz sehen kann."
|
description: "Du kannst einschränken, wer deine Notiz sehen kann."
|
||||||
|
@ -1237,8 +1354,16 @@ _initialTutorial:
|
||||||
doNotSendConfidencialOnDirect1: "Sei vorsichtig, wenn du sensible Informationen verschickst!"
|
doNotSendConfidencialOnDirect1: "Sei vorsichtig, wenn du sensible Informationen verschickst!"
|
||||||
_cw:
|
_cw:
|
||||||
title: "Inhaltswarnung"
|
title: "Inhaltswarnung"
|
||||||
|
_exampleNote:
|
||||||
|
note: "Ich hatte gerade einen Donut mit Schokoladenüberzug 🍩😋"
|
||||||
|
_howToMakeAttachmentsSensitive:
|
||||||
|
tryThisFile: "Versuche, das angehängte Bild als sensibel zu markieren!"
|
||||||
|
method: "Um einen Anhang als sensibel zu kennzeichnen, klicke auf das Vorschaubild der Datei, um das Menü zu öffnen, und klicke auf „Als sensibel markieren“."
|
||||||
|
sensitiveSucceeded: "Wenn du Dateien anhängst, stelle bitte die Sensibilität entsprechend der Serverrichtlinien ein."
|
||||||
|
doItToContinue: "Markiere die angehängte Datei als sensibel, um fortzufahren."
|
||||||
_done:
|
_done:
|
||||||
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}."
|
||||||
_timelineDescription:
|
_timelineDescription:
|
||||||
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."
|
||||||
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."
|
||||||
|
@ -1256,6 +1381,7 @@ _serverSettings:
|
||||||
fanoutTimelineDescription: "Ist diese Option aktiviert, kann eine erhebliche Verbesserung im Abrufen von Chroniken und eine Reduzierung der Datenbankbelastung erzielt werden, im Gegenzug zu einer Steigerung in der Speichernutzung von Redis. Bei geringem Serverspeicher oder Serverinstabilität kann diese Option deaktiviert werden."
|
fanoutTimelineDescription: "Ist diese Option aktiviert, kann eine erhebliche Verbesserung im Abrufen von Chroniken und eine Reduzierung der Datenbankbelastung erzielt werden, im Gegenzug zu einer Steigerung in der Speichernutzung von Redis. Bei geringem Serverspeicher oder Serverinstabilität kann diese Option deaktiviert werden."
|
||||||
fanoutTimelineDbFallback: "Auf die Datenbank zurückfallen"
|
fanoutTimelineDbFallback: "Auf die Datenbank zurückfallen"
|
||||||
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. "
|
||||||
|
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "Wenn über einen bestimmten Zeitraum keine Moderatorenaktivität festgestellt wird, wird diese Einstellung automatisch deaktiviert, um Spam zu verhindern."
|
||||||
_accountMigration:
|
_accountMigration:
|
||||||
moveFrom: "Von einem anderen Konto zu diesem migrieren"
|
moveFrom: "Von einem anderen Konto zu diesem migrieren"
|
||||||
moveFromSub: "Alias für ein anderes Konto erstellen"
|
moveFromSub: "Alias für ein anderes Konto erstellen"
|
||||||
|
@ -1514,7 +1640,12 @@ _achievements:
|
||||||
title: "Testüberfluss"
|
title: "Testüberfluss"
|
||||||
description: "Betätige den Benachrichtigungstest mehrfach innerhalb einer extrem kurzen Zeitspanne"
|
description: "Betätige den Benachrichtigungstest mehrfach innerhalb einer extrem kurzen Zeitspanne"
|
||||||
_tutorialCompleted:
|
_tutorialCompleted:
|
||||||
|
title: "Misskey Grundkurs-Diplom"
|
||||||
description: "Tutorial abgeschlossen"
|
description: "Tutorial abgeschlossen"
|
||||||
|
_bubbleGameExplodingHead:
|
||||||
|
title: "🤯"
|
||||||
|
_bubbleGameDoubleExplodingHead:
|
||||||
|
title: "Doppel🤯"
|
||||||
_role:
|
_role:
|
||||||
new: "Rolle erstellen"
|
new: "Rolle erstellen"
|
||||||
edit: "Rolle bearbeiten"
|
edit: "Rolle bearbeiten"
|
||||||
|
@ -1555,6 +1686,7 @@ _role:
|
||||||
gtlAvailable: "Kann auf die globale Chronik zugreifen"
|
gtlAvailable: "Kann auf die globale Chronik zugreifen"
|
||||||
ltlAvailable: "Kann auf die lokale Chronik zugreifen"
|
ltlAvailable: "Kann auf die lokale Chronik zugreifen"
|
||||||
canPublicNote: "Kann öffentliche Notizen erstellen"
|
canPublicNote: "Kann öffentliche Notizen erstellen"
|
||||||
|
mentionMax: "Maximale Anzahl von Erwähnungen in einer Notiz"
|
||||||
canInvite: "Erstellung von Einladungscodes für diese Instanz"
|
canInvite: "Erstellung von Einladungscodes für diese Instanz"
|
||||||
inviteLimit: "Maximalanzahl an Einladungen"
|
inviteLimit: "Maximalanzahl an Einladungen"
|
||||||
inviteLimitCycle: "Zyklus des Einladungslimits"
|
inviteLimitCycle: "Zyklus des Einladungslimits"
|
||||||
|
@ -1577,9 +1709,12 @@ _role:
|
||||||
canSearchNotes: "Nutzung der Notizsuchfunktion"
|
canSearchNotes: "Nutzung der Notizsuchfunktion"
|
||||||
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"
|
||||||
_condition:
|
_condition:
|
||||||
isLocal: "Lokaler Benutzer"
|
isLocal: "Lokaler Benutzer"
|
||||||
isRemote: "Benutzer fremder Instanz"
|
isRemote: "Benutzer fremder Instanz"
|
||||||
|
isCat: "Katzen-Benutzer"
|
||||||
|
isBot: "Bot-Benutzer"
|
||||||
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"
|
||||||
|
@ -1795,6 +1930,12 @@ _sfx:
|
||||||
note: "Notizen"
|
note: "Notizen"
|
||||||
noteMy: "Meine Notizen"
|
noteMy: "Meine Notizen"
|
||||||
notification: "Benachrichtigungen"
|
notification: "Benachrichtigungen"
|
||||||
|
_soundSettings:
|
||||||
|
driveFile: "Audiodatei aus dem Drive verwenden"
|
||||||
|
driveFileWarn: "Wähle eine Audiodatei aus dem Drive"
|
||||||
|
driveFileTypeWarn: "Diese Datei wird nicht unterstützt"
|
||||||
|
driveFileTypeWarnDescription: "Bitte wähle eine Audiodatei"
|
||||||
|
driveFileDurationWarn: "Audio zu lang."
|
||||||
_ago:
|
_ago:
|
||||||
future: "Zukunft"
|
future: "Zukunft"
|
||||||
justNow: "Gerade eben"
|
justNow: "Gerade eben"
|
||||||
|
@ -1876,6 +2017,23 @@ _permissions:
|
||||||
"write:flash": "Deine Plays bearbeiten oder löschen"
|
"write:flash": "Deine Plays bearbeiten oder löschen"
|
||||||
"read:flash-likes": "Liste der Plays, die mir gefallen, lesen"
|
"read:flash-likes": "Liste der Plays, die mir gefallen, lesen"
|
||||||
"write:flash-likes": "Liste der Plays, die mir gefallen, bearbeiten"
|
"write:flash-likes": "Liste der Plays, die mir gefallen, bearbeiten"
|
||||||
|
"write:admin:delete-account": "Benutzerkonto löschen"
|
||||||
|
"write:admin:delete-all-files-of-a-user": "Alle Dateien eines Benutzers löschen"
|
||||||
|
"read:admin:index-stats": "Statistiken zu Datenbankindizes einsehen"
|
||||||
|
"read:admin:table-stats": "Statistiken zu Datenbanktabellen einsehen"
|
||||||
|
"read:admin:user-ips": "IP-Adressen von Benutzern anzeigen"
|
||||||
|
"read:admin:meta": "Metadaten der Instanz einsehen"
|
||||||
|
"write:admin:reset-password": "Benutzerpasswort zurücksetzen"
|
||||||
|
"write:admin:send-email": "E-Mail versenden"
|
||||||
|
"read:admin:server-info": "Serverinformationen anzeigen"
|
||||||
|
"read:admin:show-moderation-log": "Moderationsprotokoll einsehen"
|
||||||
|
"read:admin:show-user": "Private Benutzerinformationen einsehen"
|
||||||
|
"write:admin:invite-codes": "Einladungscodes verwalten"
|
||||||
|
"read:admin:invite-codes": "Einladungscodes anzeigen"
|
||||||
|
"write:admin:announcements": "Ankündigungen verwalten"
|
||||||
|
"read:admin:announcements": "Ankündigungen einsehen"
|
||||||
|
"write:admin:avatar-decorations": "Kann Avatar-Dekorationen verwalten"
|
||||||
|
"read:admin:avatar-decorations": "Avatar-Dekorationen ansehen"
|
||||||
_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?"
|
||||||
|
@ -2115,6 +2273,7 @@ _notification:
|
||||||
pollEnded: "Umfrageergebnisse sind verfügbar"
|
pollEnded: "Umfrageergebnisse sind verfügbar"
|
||||||
newNote: "Neue Notiz"
|
newNote: "Neue Notiz"
|
||||||
unreadAntennaNote: "Antenne {name}"
|
unreadAntennaNote: "Antenne {name}"
|
||||||
|
roleAssigned: "Rolle zugewiesen"
|
||||||
emptyPushNotificationMessage: "Push-Benachrichtigungen wurden aktualisiert"
|
emptyPushNotificationMessage: "Push-Benachrichtigungen wurden aktualisiert"
|
||||||
achievementEarned: "Errungenschaft freigeschaltet"
|
achievementEarned: "Errungenschaft freigeschaltet"
|
||||||
testNotification: "Testbenachrichtigung"
|
testNotification: "Testbenachrichtigung"
|
||||||
|
@ -2289,3 +2448,31 @@ _reversi:
|
||||||
black: "Schwarz"
|
black: "Schwarz"
|
||||||
white: "Weiß"
|
white: "Weiß"
|
||||||
total: "Gesamt"
|
total: "Gesamt"
|
||||||
|
_offlineScreen:
|
||||||
|
header: "Verbindung zum Server nicht möglich"
|
||||||
|
_urlPreviewSetting:
|
||||||
|
title: "Einstellungen der URL-Vorschau"
|
||||||
|
enable: "URL-Vorschau aktivieren"
|
||||||
|
timeout: "Zeitüberschreitung beim Abrufen der Vorschau (ms)"
|
||||||
|
maximumContentLength: "Maximale Content-Length (Bytes)"
|
||||||
|
_mediaControls:
|
||||||
|
playbackRate: "Wiedergabegeschwindigkeit"
|
||||||
|
_contextMenu:
|
||||||
|
title: "Kontextmenü"
|
||||||
|
app: "Anwendung"
|
||||||
|
_embedCodeGen:
|
||||||
|
title: "Einbettungscode anpassen"
|
||||||
|
header: "Kopfzeile anzeigen"
|
||||||
|
autoload: "Automatisch mehr laden (veraltet)"
|
||||||
|
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."
|
||||||
|
maxHeightWarn: "Die Begrenzung der maximalen Höhe ist deaktiviert (0). Wenn dies nicht beabsichtigt war, setze die maximale Höhe auf einen Wert fest."
|
||||||
|
applyToPreview: "Auf die Vorschau anwenden"
|
||||||
|
generateCode: "Einbettungscode generieren"
|
||||||
|
codeGenerated: "Der Code wurde generiert"
|
||||||
|
codeGeneratedDescription: "Füge den generierten Code in deine Website ein, um den Inhalt einzubetten."
|
||||||
|
_selfXssPrevention:
|
||||||
|
warning: "WARNUNG"
|
||||||
|
title: "„Füge in diesen Bereich etwas ein“ ist eine Betrugsmasche."
|
||||||
|
description1: "Wenn du hier etwas einfügst, könnte ein böswilliger Benutzer dein Konto übernehmen oder deine persönlichen Daten stehlen."
|
||||||
|
description3: "Weitere Informationen findest du hier. {link}"
|
||||||
|
|
|
@ -331,7 +331,7 @@ selectFile: "Select a file"
|
||||||
selectFiles: "Select files"
|
selectFiles: "Select files"
|
||||||
selectFolder: "Select a folder"
|
selectFolder: "Select a folder"
|
||||||
selectFolders: "Select folders"
|
selectFolders: "Select folders"
|
||||||
fileNotSelected: ""
|
fileNotSelected: "No file selected"
|
||||||
renameFile: "Rename file"
|
renameFile: "Rename file"
|
||||||
folderName: "Folder name"
|
folderName: "Folder name"
|
||||||
createFolder: "Create a folder"
|
createFolder: "Create a folder"
|
||||||
|
@ -382,7 +382,6 @@ enableLocalTimeline: "Enable local timeline"
|
||||||
enableGlobalTimeline: "Enable global timeline"
|
enableGlobalTimeline: "Enable global timeline"
|
||||||
disablingTimelinesInfo: "Adminstrators and Moderators will always have access to all timelines, even if they are not enabled."
|
disablingTimelinesInfo: "Adminstrators and Moderators will always have access to all timelines, even if they are not enabled."
|
||||||
registration: "Register"
|
registration: "Register"
|
||||||
enableRegistration: "Enable new user registration"
|
|
||||||
invite: "Invite"
|
invite: "Invite"
|
||||||
driveCapacityPerLocalAccount: "Drive capacity per local user"
|
driveCapacityPerLocalAccount: "Drive capacity per local user"
|
||||||
driveCapacityPerRemoteAccount: "Drive capacity per remote user"
|
driveCapacityPerRemoteAccount: "Drive capacity per remote user"
|
||||||
|
@ -587,6 +586,7 @@ masterVolume: "Master volume"
|
||||||
notUseSound: "Disable sound"
|
notUseSound: "Disable sound"
|
||||||
useSoundOnlyWhenActive: "Output sounds only if Misskey is active."
|
useSoundOnlyWhenActive: "Output sounds only if Misskey is active."
|
||||||
details: "Details"
|
details: "Details"
|
||||||
|
renoteDetails: "Renote details"
|
||||||
chooseEmoji: "Select an emoji"
|
chooseEmoji: "Select an emoji"
|
||||||
unableToProcess: "The operation could not be completed"
|
unableToProcess: "The operation could not be completed"
|
||||||
recentUsed: "Recently used"
|
recentUsed: "Recently used"
|
||||||
|
@ -947,6 +947,9 @@ oneHour: "One hour"
|
||||||
oneDay: "One day"
|
oneDay: "One day"
|
||||||
oneWeek: "One week"
|
oneWeek: "One week"
|
||||||
oneMonth: "One month"
|
oneMonth: "One month"
|
||||||
|
threeMonths: "3 months"
|
||||||
|
oneYear: "1 year"
|
||||||
|
threeDays: "3 days"
|
||||||
reflectMayTakeTime: "It may take some time for this to be reflected."
|
reflectMayTakeTime: "It may take some time for this to be reflected."
|
||||||
failedToFetchAccountInformation: "Could not fetch account information"
|
failedToFetchAccountInformation: "Could not fetch account information"
|
||||||
rateLimitExceeded: "Rate limit exceeded"
|
rateLimitExceeded: "Rate limit exceeded"
|
||||||
|
@ -1087,6 +1090,7 @@ retryAllQueuesConfirmTitle: "Really retry all?"
|
||||||
retryAllQueuesConfirmText: "This will temporarily increase the server load."
|
retryAllQueuesConfirmText: "This will temporarily increase the server load."
|
||||||
enableChartsForRemoteUser: "Generate remote user data charts"
|
enableChartsForRemoteUser: "Generate remote user data charts"
|
||||||
enableChartsForFederatedInstances: "Generate remote instance data charts"
|
enableChartsForFederatedInstances: "Generate remote instance data charts"
|
||||||
|
enableStatsForFederatedInstances: "Receive remote server stats"
|
||||||
showClipButtonInNoteFooter: "Add \"Clip\" to note action menu"
|
showClipButtonInNoteFooter: "Add \"Clip\" to note action menu"
|
||||||
reactionsDisplaySize: "Reaction display size"
|
reactionsDisplaySize: "Reaction display size"
|
||||||
limitWidthOfReaction: "Limit the maximum width of reactions and display them in reduced size."
|
limitWidthOfReaction: "Limit the maximum width of reactions and display them in reduced size."
|
||||||
|
@ -1287,6 +1291,27 @@ passkeyVerificationFailed: "Passkey verification has failed."
|
||||||
passkeyVerificationSucceededButPasswordlessLoginDisabled: "Passkey verification has succeeded but password-less login is disabled."
|
passkeyVerificationSucceededButPasswordlessLoginDisabled: "Passkey verification has succeeded but password-less login is disabled."
|
||||||
messageToFollower: "Message to followers"
|
messageToFollower: "Message to followers"
|
||||||
target: "Target"
|
target: "Target"
|
||||||
|
testCaptchaWarning: "This function is intended for CAPTCHA testing purposes.\n<strong>Do not use in a production environment.</strong>"
|
||||||
|
prohibitedWordsForNameOfUser: "Prohibited words for user names"
|
||||||
|
prohibitedWordsForNameOfUserDescription: "If any of the strings in this list are included in the user's name, the name will be denied. Users with moderator privileges are not affected by this restriction."
|
||||||
|
yourNameContainsProhibitedWords: "Your name contains prohibited words"
|
||||||
|
yourNameContainsProhibitedWordsDescription: "If you wish to use this name, please contact your server administrator."
|
||||||
|
thisContentsAreMarkedAsSigninRequiredByAuthor: "Set by the author to require login to view"
|
||||||
|
lockdown: "Lockdown"
|
||||||
|
pleaseSelectAccount: "Select an account"
|
||||||
|
availableRoles: "Available roles"
|
||||||
|
_accountSettings:
|
||||||
|
requireSigninToViewContents: "Require sign-in to view contents"
|
||||||
|
requireSigninToViewContentsDescription1: "Require login to view all notes and other content you have created. This will have the effect of preventing crawlers from collecting your information."
|
||||||
|
requireSigninToViewContentsDescription2: "Content will not be displayed in URL previews (OGP), embedded in web pages, or on servers that don't support note quotes."
|
||||||
|
requireSigninToViewContentsDescription3: "These restrictions may not apply to federated content from other remote servers."
|
||||||
|
makeNotesFollowersOnlyBefore: "Make past notes to be displayed only to followers"
|
||||||
|
makeNotesFollowersOnlyBeforeDescription: "While this feature is enabled, only followers can see notes past the set date and time or have been visible for a set time. When it is deactivated, the note publication status will also be restored."
|
||||||
|
makeNotesHiddenBefore: "Make past notes private"
|
||||||
|
makeNotesHiddenBeforeDescription: "While this feature is enabled, notes that are past the set date and time or have been visible only to you. When it is deactivated, the note publication status will also be restored."
|
||||||
|
mayNotEffectForFederatedNotes: "Notes federated to a remote server may not be affected."
|
||||||
|
notesHavePassedSpecifiedPeriod: "Note that the specified time has passed"
|
||||||
|
notesOlderThanSpecifiedDateAndTime: "Notes before the specified date and time"
|
||||||
_abuseUserReport:
|
_abuseUserReport:
|
||||||
forward: "Forward"
|
forward: "Forward"
|
||||||
forwardDescription: "Forward the report to a remote server as an anonymous system account."
|
forwardDescription: "Forward the report to a remote server as an anonymous system account."
|
||||||
|
@ -1431,6 +1456,7 @@ _serverSettings:
|
||||||
reactionsBufferingDescription: "When enabled, performance during reaction creation will be greatly improved, reducing the load on the database. However, Redis memory usage will increase."
|
reactionsBufferingDescription: "When enabled, performance during reaction creation will be greatly improved, reducing the load on the database. However, Redis memory usage will increase."
|
||||||
inquiryUrl: "Inquiry URL"
|
inquiryUrl: "Inquiry URL"
|
||||||
inquiryUrlDescription: "Specify a URL for the inquiry form to the server maintainer or a web page for the contact information."
|
inquiryUrlDescription: "Specify a URL for the inquiry form to the server maintainer or a web page for the contact information."
|
||||||
|
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "If no moderator activity is detected for a while, this setting will be automatically turned off to prevent spam."
|
||||||
_accountMigration:
|
_accountMigration:
|
||||||
moveFrom: "Migrate another account to this one"
|
moveFrom: "Migrate another account to this one"
|
||||||
moveFromSub: "Create alias to another account"
|
moveFromSub: "Create alias to another account"
|
||||||
|
@ -2150,8 +2176,11 @@ _auth:
|
||||||
permissionAsk: "This application requests the following permissions"
|
permissionAsk: "This application requests the following permissions"
|
||||||
pleaseGoBack: "Please go back to the application"
|
pleaseGoBack: "Please go back to the application"
|
||||||
callback: "Returning to the application"
|
callback: "Returning to the application"
|
||||||
|
accepted: "Access granted"
|
||||||
denied: "Access denied"
|
denied: "Access denied"
|
||||||
|
scopeUser: "Operate as the following user"
|
||||||
pleaseLogin: "Please log in to authorize applications."
|
pleaseLogin: "Please log in to authorize applications."
|
||||||
|
byClickingYouWillBeRedirectedToThisUrl: "When access is granted, you will automatically be redirected to the following URL"
|
||||||
_antennaSources:
|
_antennaSources:
|
||||||
all: "All notes"
|
all: "All notes"
|
||||||
homeTimeline: "Notes from followed users"
|
homeTimeline: "Notes from followed users"
|
||||||
|
@ -2196,7 +2225,7 @@ _widgets:
|
||||||
_userList:
|
_userList:
|
||||||
chooseList: "Select a list"
|
chooseList: "Select a list"
|
||||||
clicker: "Clicker"
|
clicker: "Clicker"
|
||||||
birthdayFollowings: "Users who celebrate their birthday today"
|
birthdayFollowings: "Today's Birthdays"
|
||||||
_cw:
|
_cw:
|
||||||
hide: "Hide"
|
hide: "Hide"
|
||||||
show: "Show content"
|
show: "Show content"
|
||||||
|
@ -2485,6 +2514,8 @@ _webhookSettings:
|
||||||
abuseReport: "When received a new report"
|
abuseReport: "When received a new report"
|
||||||
abuseReportResolved: "When resolved report"
|
abuseReportResolved: "When resolved report"
|
||||||
userCreated: "When user is created"
|
userCreated: "When user is created"
|
||||||
|
inactiveModeratorsWarning: "When moderators have been inactive for a while"
|
||||||
|
inactiveModeratorsInvitationOnlyChanged: "When a moderator has been inactive for a while, and the server is changed to invitation-only"
|
||||||
deleteConfirm: "Are you sure you want to delete the Webhook?"
|
deleteConfirm: "Are you sure you want to delete the Webhook?"
|
||||||
testRemarks: "Click the button to the right of the switch to send a test Webhook with dummy data."
|
testRemarks: "Click the button to the right of the switch to send a test Webhook with dummy data."
|
||||||
_abuseReport:
|
_abuseReport:
|
||||||
|
@ -2701,3 +2732,9 @@ _embedCodeGen:
|
||||||
generateCode: "Generate embed code"
|
generateCode: "Generate embed code"
|
||||||
codeGenerated: "The code has been generated"
|
codeGenerated: "The code has been generated"
|
||||||
codeGeneratedDescription: "Paste the generated code into your website to embed the content."
|
codeGeneratedDescription: "Paste the generated code into your website to embed the content."
|
||||||
|
_selfXssPrevention:
|
||||||
|
warning: "WARNING"
|
||||||
|
title: "\"Paste something on this screen\" is all a scam."
|
||||||
|
description1: "If you paste something here, a malicious user could hijack your account or steal your personal information."
|
||||||
|
description2: "If you do not understand exactly what you are trying to paste, %cstop working right now and close this window."
|
||||||
|
description3: "For more information, please refer to this. {link}"
|
||||||
|
|
|
@ -8,6 +8,8 @@ search: "Buscar"
|
||||||
notifications: "Notificaciones"
|
notifications: "Notificaciones"
|
||||||
username: "Nombre de usuario"
|
username: "Nombre de usuario"
|
||||||
password: "Contraseña"
|
password: "Contraseña"
|
||||||
|
initialPasswordForSetup: "Contraseña para iniciar la inicialización"
|
||||||
|
initialPasswordIsIncorrect: "La contraseña para iniciar la configuración inicial es incorrecta."
|
||||||
forgotPassword: "Olvidé mi contraseña"
|
forgotPassword: "Olvidé mi contraseña"
|
||||||
fetchingAsApObject: "Buscando en el fediverso"
|
fetchingAsApObject: "Buscando en el fediverso"
|
||||||
ok: "OK"
|
ok: "OK"
|
||||||
|
@ -371,7 +373,6 @@ enableLocalTimeline: "Habilitar linea de tiempo local"
|
||||||
enableGlobalTimeline: "Habilitar linea de tiempo global"
|
enableGlobalTimeline: "Habilitar linea de tiempo global"
|
||||||
disablingTimelinesInfo: "Aunque se desactiven estas lineas de tiempo, por conveniencia el administrador y los moderadores pueden seguir usándolos"
|
disablingTimelinesInfo: "Aunque se desactiven estas lineas de tiempo, por conveniencia el administrador y los moderadores pueden seguir usándolos"
|
||||||
registration: "Registro"
|
registration: "Registro"
|
||||||
enableRegistration: "Permitir nuevos registros"
|
|
||||||
invite: "Invitar"
|
invite: "Invitar"
|
||||||
driveCapacityPerLocalAccount: "Capacidad del drive por usuario local"
|
driveCapacityPerLocalAccount: "Capacidad del drive por usuario local"
|
||||||
driveCapacityPerRemoteAccount: "Capacidad del drive por usuario remoto"
|
driveCapacityPerRemoteAccount: "Capacidad del drive por usuario remoto"
|
||||||
|
@ -502,6 +503,8 @@ uiLanguage: "Idioma de visualización de la interfaz"
|
||||||
aboutX: "Acerca de {x}"
|
aboutX: "Acerca de {x}"
|
||||||
emojiStyle: "Estilo de emoji"
|
emojiStyle: "Estilo de emoji"
|
||||||
native: "Nativo"
|
native: "Nativo"
|
||||||
|
menuStyle: "Diseño del menú"
|
||||||
|
style: "Diseño"
|
||||||
showNoteActionsOnlyHover: "Mostrar acciones de la nota sólo al pasar el cursor"
|
showNoteActionsOnlyHover: "Mostrar acciones de la nota sólo al pasar el cursor"
|
||||||
showReactionsCount: "Mostrar el número de reacciones en las notas"
|
showReactionsCount: "Mostrar el número de reacciones en las notas"
|
||||||
noHistory: "No hay datos en el historial"
|
noHistory: "No hay datos en el historial"
|
||||||
|
@ -925,6 +928,9 @@ oneHour: "1 hora"
|
||||||
oneDay: "1 día"
|
oneDay: "1 día"
|
||||||
oneWeek: "1 semana"
|
oneWeek: "1 semana"
|
||||||
oneMonth: "1 mes"
|
oneMonth: "1 mes"
|
||||||
|
threeMonths: "Tres meses"
|
||||||
|
oneYear: "Un año"
|
||||||
|
threeDays: "Tres días"
|
||||||
reflectMayTakeTime: "Puede pasar un tiempo hasta que se reflejen los cambios"
|
reflectMayTakeTime: "Puede pasar un tiempo hasta que se reflejen los cambios"
|
||||||
failedToFetchAccountInformation: "No se pudo obtener información de la cuenta"
|
failedToFetchAccountInformation: "No se pudo obtener información de la cuenta"
|
||||||
rateLimitExceeded: "Se excedió el límite de peticiones"
|
rateLimitExceeded: "Se excedió el límite de peticiones"
|
||||||
|
@ -1240,6 +1246,14 @@ useNativeUIForVideoAudioPlayer: "Usar la interfaz del navegador cuando se reprod
|
||||||
keepOriginalFilename: "Mantener el nombre original del archivo"
|
keepOriginalFilename: "Mantener el nombre original del archivo"
|
||||||
noDescription: "No hay descripción"
|
noDescription: "No hay descripción"
|
||||||
alwaysConfirmFollow: "Confirmar siempre cuando se sigue a alguien"
|
alwaysConfirmFollow: "Confirmar siempre cuando se sigue a alguien"
|
||||||
|
inquiry: "Contacto"
|
||||||
|
tryAgain: "Por favor , inténtalo de nuevo"
|
||||||
|
performance: "Rendimiento"
|
||||||
|
unknownWebAuthnKey: "Esto no se ha registrado llave maestra."
|
||||||
|
messageToFollower: "Mensaje a seguidores"
|
||||||
|
_abuseUserReport:
|
||||||
|
accept: "Acepte"
|
||||||
|
reject: "repudio"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "Suspendido"
|
stop: "Suspendido"
|
||||||
_type:
|
_type:
|
||||||
|
@ -2340,6 +2354,7 @@ _notification:
|
||||||
roleAssigned: "Rol asignado"
|
roleAssigned: "Rol asignado"
|
||||||
achievementEarned: "Logro desbloqueado"
|
achievementEarned: "Logro desbloqueado"
|
||||||
login: "Iniciar sesión"
|
login: "Iniciar sesión"
|
||||||
|
test: "Pruebas de nofiticaciones"
|
||||||
app: "Notificaciones desde aplicaciones"
|
app: "Notificaciones desde aplicaciones"
|
||||||
_actions:
|
_actions:
|
||||||
followBack: "Te sigue de vuelta"
|
followBack: "Te sigue de vuelta"
|
||||||
|
@ -2398,6 +2413,8 @@ _webhookSettings:
|
||||||
renote: "Cuando reciba un \"re-note\""
|
renote: "Cuando reciba un \"re-note\""
|
||||||
reaction: "Cuando se recibe una reacción"
|
reaction: "Cuando se recibe una reacción"
|
||||||
mention: "Cuando hay una mención"
|
mention: "Cuando hay una mención"
|
||||||
|
_systemEvents:
|
||||||
|
userCreated: "Cuando se crea el usuario."
|
||||||
_abuseReport:
|
_abuseReport:
|
||||||
_notificationRecipient:
|
_notificationRecipient:
|
||||||
_recipientType:
|
_recipientType:
|
||||||
|
|
|
@ -8,6 +8,9 @@ search: "Rechercher"
|
||||||
notifications: "Notifications"
|
notifications: "Notifications"
|
||||||
username: "Nom d’utilisateur·rice"
|
username: "Nom d’utilisateur·rice"
|
||||||
password: "Mot de passe"
|
password: "Mot de passe"
|
||||||
|
initialPasswordForSetup: "Mot de passe initial pour la configuration"
|
||||||
|
initialPasswordIsIncorrect: "Mot de passe initial pour la configuration est incorrecte"
|
||||||
|
initialPasswordForSetupDescription: "Utilisez le mot de passe que vous avez entré pour le fichier de configuration si vous avez installé Misskey vous-même.\nSi vous utilisez un service d'hébergement Misskey, utilisez le mot de passe fourni.\nSi vous n'avez pas défini de mot de passe, laissez le champ vide pour continuer."
|
||||||
forgotPassword: "Mot de passe oublié"
|
forgotPassword: "Mot de passe oublié"
|
||||||
fetchingAsApObject: "Récupération depuis le fédiverse …"
|
fetchingAsApObject: "Récupération depuis le fédiverse …"
|
||||||
ok: "OK"
|
ok: "OK"
|
||||||
|
@ -60,6 +63,7 @@ copyFileId: "Copier l'identifiant du fichier"
|
||||||
copyFolderId: "Copier l'identifiant du dossier"
|
copyFolderId: "Copier l'identifiant du dossier"
|
||||||
copyProfileUrl: "Copier l'URL du profil"
|
copyProfileUrl: "Copier l'URL du profil"
|
||||||
searchUser: "Chercher un·e utilisateur·rice"
|
searchUser: "Chercher un·e utilisateur·rice"
|
||||||
|
searchThisUsersNotes: "Cherchez les notes de cet·te utilisateur·rice"
|
||||||
reply: "Répondre"
|
reply: "Répondre"
|
||||||
loadMore: "Afficher plus …"
|
loadMore: "Afficher plus …"
|
||||||
showMore: "Voir plus"
|
showMore: "Voir plus"
|
||||||
|
@ -108,6 +112,7 @@ enterEmoji: "Insérer un émoji"
|
||||||
renote: "Renoter"
|
renote: "Renoter"
|
||||||
unrenote: "Annuler la Renote"
|
unrenote: "Annuler la Renote"
|
||||||
renoted: "Renoté !"
|
renoted: "Renoté !"
|
||||||
|
renotedToX: "Renoté en {name}"
|
||||||
cantRenote: "Ce message ne peut pas être renoté."
|
cantRenote: "Ce message ne peut pas être renoté."
|
||||||
cantReRenote: "Impossible de renoter une Renote."
|
cantReRenote: "Impossible de renoter une Renote."
|
||||||
quote: "Citer"
|
quote: "Citer"
|
||||||
|
@ -151,6 +156,7 @@ editList: "Modifier la liste"
|
||||||
selectChannel: "Sélectionner un canal"
|
selectChannel: "Sélectionner un canal"
|
||||||
selectAntenna: "Sélectionner une antenne"
|
selectAntenna: "Sélectionner une antenne"
|
||||||
editAntenna: "Modifier l'antenne"
|
editAntenna: "Modifier l'antenne"
|
||||||
|
createAntenna: "Créer une antenne"
|
||||||
selectWidget: "Sélectionner un widget"
|
selectWidget: "Sélectionner un widget"
|
||||||
editWidgets: "Modifier les widgets"
|
editWidgets: "Modifier les widgets"
|
||||||
editWidgetsExit: "Valider les modifications"
|
editWidgetsExit: "Valider les modifications"
|
||||||
|
@ -177,6 +183,7 @@ addAccount: "Ajouter un compte"
|
||||||
reloadAccountsList: "Rafraichir la liste des comptes"
|
reloadAccountsList: "Rafraichir la liste des comptes"
|
||||||
loginFailed: "Échec de la connexion"
|
loginFailed: "Échec de la connexion"
|
||||||
showOnRemote: "Voir sur l’instance distante"
|
showOnRemote: "Voir sur l’instance distante"
|
||||||
|
continueOnRemote: "Continuer sur l'instance distante"
|
||||||
general: "Général"
|
general: "Général"
|
||||||
wallpaper: "Fond d’écran"
|
wallpaper: "Fond d’écran"
|
||||||
setWallpaper: "Définir le fond d’écran"
|
setWallpaper: "Définir le fond d’écran"
|
||||||
|
@ -187,6 +194,7 @@ followConfirm: "Êtes-vous sûr·e de vouloir suivre {name} ?"
|
||||||
proxyAccount: "Compte proxy"
|
proxyAccount: "Compte proxy"
|
||||||
proxyAccountDescription: "Un compte proxy se comporte, dans certaines conditions, comme un·e abonné·e distant·e pour les utilisateurs d'autres instances. Par exemple, quand un·e utilisateur·rice ajoute un·e utilisateur·rice distant·e à une liste, ses notes ne seront pas visibles sur l'instance si personne ne suit cet·te utilisateur·rice. Le compte proxy va donc suivre cet·te utilisateur·rice pour que ses notes soient acheminées."
|
proxyAccountDescription: "Un compte proxy se comporte, dans certaines conditions, comme un·e abonné·e distant·e pour les utilisateurs d'autres instances. Par exemple, quand un·e utilisateur·rice ajoute un·e utilisateur·rice distant·e à une liste, ses notes ne seront pas visibles sur l'instance si personne ne suit cet·te utilisateur·rice. Le compte proxy va donc suivre cet·te utilisateur·rice pour que ses notes soient acheminées."
|
||||||
host: "Serveur distant"
|
host: "Serveur distant"
|
||||||
|
selectSelf: "Sélectionner manuellement"
|
||||||
selectUser: "Sélectionner un·e utilisateur·rice"
|
selectUser: "Sélectionner un·e utilisateur·rice"
|
||||||
recipient: "Destinataire"
|
recipient: "Destinataire"
|
||||||
annotation: "Commentaires"
|
annotation: "Commentaires"
|
||||||
|
@ -320,6 +328,7 @@ renameFolder: "Renommer le dossier"
|
||||||
deleteFolder: "Supprimer le dossier"
|
deleteFolder: "Supprimer le dossier"
|
||||||
folder: "Dossier"
|
folder: "Dossier"
|
||||||
addFile: "Ajouter un fichier"
|
addFile: "Ajouter un fichier"
|
||||||
|
showFile: "Voir les fichiers"
|
||||||
emptyDrive: "Le Disque est vide"
|
emptyDrive: "Le Disque est vide"
|
||||||
emptyFolder: "Le dossier est vide"
|
emptyFolder: "Le dossier est vide"
|
||||||
unableToDelete: "Suppression impossible"
|
unableToDelete: "Suppression impossible"
|
||||||
|
@ -362,7 +371,6 @@ enableLocalTimeline: "Activer le fil local"
|
||||||
enableGlobalTimeline: "Activer le fil global"
|
enableGlobalTimeline: "Activer le fil global"
|
||||||
disablingTimelinesInfo: "Même si vous désactivez ces fils, les administrateur·rice·s et les modérateur·rice·s pourront toujours y accéder."
|
disablingTimelinesInfo: "Même si vous désactivez ces fils, les administrateur·rice·s et les modérateur·rice·s pourront toujours y accéder."
|
||||||
registration: "S’inscrire"
|
registration: "S’inscrire"
|
||||||
enableRegistration: "Autoriser les nouvelles inscriptions"
|
|
||||||
invite: "Inviter"
|
invite: "Inviter"
|
||||||
driveCapacityPerLocalAccount: "Capacité de stockage du Disque par utilisateur local"
|
driveCapacityPerLocalAccount: "Capacité de stockage du Disque par utilisateur local"
|
||||||
driveCapacityPerRemoteAccount: "Capacité de stockage du Disque par utilisateur distant"
|
driveCapacityPerRemoteAccount: "Capacité de stockage du Disque par utilisateur distant"
|
||||||
|
@ -430,10 +438,11 @@ token: "Jeton"
|
||||||
2fa: "Authentification à deux facteurs"
|
2fa: "Authentification à deux facteurs"
|
||||||
setupOf2fa: "Configuration de l’authentification à deux facteurs"
|
setupOf2fa: "Configuration de l’authentification à deux facteurs"
|
||||||
totp: "Application d'authentification"
|
totp: "Application d'authentification"
|
||||||
totpDescription: "Entrez un mot de passe à usage unique à l'aide d'une application d'authentification"
|
totpDescription: "Entrer un mot de passe à usage unique à l'aide d'une application d'authentification"
|
||||||
moderator: "Modérateur·rice·s"
|
moderator: "Modérateur·rice·s"
|
||||||
moderation: "Modérations"
|
moderation: "Modérations"
|
||||||
moderationNote: "Note de modération"
|
moderationNote: "Note de modération"
|
||||||
|
moderationNoteDescription: "Vous pouvez remplir des notes qui seront partagés seulement entre modérateurs."
|
||||||
addModerationNote: "Ajouter une note de modération"
|
addModerationNote: "Ajouter une note de modération"
|
||||||
moderationLogs: "Journal de modération"
|
moderationLogs: "Journal de modération"
|
||||||
nUsersMentioned: "{n} utilisateur·rice·s mentionné·e·s"
|
nUsersMentioned: "{n} utilisateur·rice·s mentionné·e·s"
|
||||||
|
@ -493,6 +502,10 @@ uiLanguage: "Langue d’affichage de l’interface"
|
||||||
aboutX: "À propos de {x}"
|
aboutX: "À propos de {x}"
|
||||||
emojiStyle: "Style des émojis"
|
emojiStyle: "Style des émojis"
|
||||||
native: "Natif"
|
native: "Natif"
|
||||||
|
menuStyle: "Style du menu"
|
||||||
|
style: "Style"
|
||||||
|
drawer: "Sélecteur"
|
||||||
|
popup: "Pop-up"
|
||||||
showNoteActionsOnlyHover: "Afficher les actions de note uniquement au survol"
|
showNoteActionsOnlyHover: "Afficher les actions de note uniquement au survol"
|
||||||
showReactionsCount: "Afficher le nombre de réactions des notes"
|
showReactionsCount: "Afficher le nombre de réactions des notes"
|
||||||
noHistory: "Pas d'historique"
|
noHistory: "Pas d'historique"
|
||||||
|
@ -575,6 +588,7 @@ ascendingOrder: "Ascendant"
|
||||||
descendingOrder: "Descendant"
|
descendingOrder: "Descendant"
|
||||||
scratchpad: "ScratchPad"
|
scratchpad: "ScratchPad"
|
||||||
scratchpadDescription: "ScratchPad fournit un environnement expérimental pour AiScript. Vous pouvez vérifier la rédaction de votre code, sa bonne exécution et le résultat de son interaction avec Misskey."
|
scratchpadDescription: "ScratchPad fournit un environnement expérimental pour AiScript. Vous pouvez vérifier la rédaction de votre code, sa bonne exécution et le résultat de son interaction avec Misskey."
|
||||||
|
uiInspector: "Inspecteur UI"
|
||||||
output: "Sortie"
|
output: "Sortie"
|
||||||
script: "Script"
|
script: "Script"
|
||||||
disablePagesScript: "Désactiver AiScript sur les Pages"
|
disablePagesScript: "Désactiver AiScript sur les Pages"
|
||||||
|
@ -618,7 +632,7 @@ description: "Description"
|
||||||
describeFile: "Ajouter une description d'image"
|
describeFile: "Ajouter une description d'image"
|
||||||
enterFileDescription: "Saisissez une description"
|
enterFileDescription: "Saisissez une description"
|
||||||
author: "Auteur·rice"
|
author: "Auteur·rice"
|
||||||
leaveConfirm: "Vous avez des modifications non-sauvegardées. Voulez-vous les ignorer ?"
|
leaveConfirm: "Vous avez des modifications non sauvegardées. Voulez-vous les ignorer ?"
|
||||||
manage: "Gestion"
|
manage: "Gestion"
|
||||||
plugins: "Extensions"
|
plugins: "Extensions"
|
||||||
preferencesBackups: "Sauvegarder les paramètres"
|
preferencesBackups: "Sauvegarder les paramètres"
|
||||||
|
@ -828,6 +842,7 @@ administration: "Gestion"
|
||||||
accounts: "Comptes"
|
accounts: "Comptes"
|
||||||
switch: "Remplacer"
|
switch: "Remplacer"
|
||||||
noMaintainerInformationWarning: "Informations administrateur non configurées."
|
noMaintainerInformationWarning: "Informations administrateur non configurées."
|
||||||
|
noInquiryUrlWarning: "L'URL demandé n'est pas définie"
|
||||||
noBotProtectionWarning: "La protection contre les bots n'est pas configurée."
|
noBotProtectionWarning: "La protection contre les bots n'est pas configurée."
|
||||||
configure: "Configurer"
|
configure: "Configurer"
|
||||||
postToGallery: "Publier dans la galerie"
|
postToGallery: "Publier dans la galerie"
|
||||||
|
@ -892,6 +907,7 @@ followersVisibility: "Visibilité des abonnés"
|
||||||
continueThread: "Afficher la suite du fil"
|
continueThread: "Afficher la suite du fil"
|
||||||
deleteAccountConfirm: "Votre compte sera supprimé. Êtes vous certain ?"
|
deleteAccountConfirm: "Votre compte sera supprimé. Êtes vous certain ?"
|
||||||
incorrectPassword: "Le mot de passe est incorrect."
|
incorrectPassword: "Le mot de passe est incorrect."
|
||||||
|
incorrectTotp: "Le mot de passe à usage unique est incorrect ou a expiré."
|
||||||
voteConfirm: "Confirmez-vous votre vote pour « {choice} » ?"
|
voteConfirm: "Confirmez-vous votre vote pour « {choice} » ?"
|
||||||
hide: "Masquer"
|
hide: "Masquer"
|
||||||
useDrawerReactionPickerForMobile: "Afficher le sélecteur de réactions en tant que panneau sur mobile"
|
useDrawerReactionPickerForMobile: "Afficher le sélecteur de réactions en tant que panneau sur mobile"
|
||||||
|
@ -916,6 +932,9 @@ oneHour: "1 heure"
|
||||||
oneDay: "1 jour"
|
oneDay: "1 jour"
|
||||||
oneWeek: "1 semaine"
|
oneWeek: "1 semaine"
|
||||||
oneMonth: "Un mois"
|
oneMonth: "Un mois"
|
||||||
|
threeMonths: "3 mois"
|
||||||
|
oneYear: "1 an"
|
||||||
|
threeDays: "3 jours"
|
||||||
reflectMayTakeTime: "Cela peut prendre un certain temps avant que cela ne se termine."
|
reflectMayTakeTime: "Cela peut prendre un certain temps avant que cela ne se termine."
|
||||||
failedToFetchAccountInformation: "Impossible de récupérer les informations du compte."
|
failedToFetchAccountInformation: "Impossible de récupérer les informations du compte."
|
||||||
rateLimitExceeded: "Limite de taux dépassée"
|
rateLimitExceeded: "Limite de taux dépassée"
|
||||||
|
@ -923,7 +942,7 @@ cropImage: "Recadrer l'image"
|
||||||
cropImageAsk: "Voulez-vous recadrer cette image ?"
|
cropImageAsk: "Voulez-vous recadrer cette image ?"
|
||||||
cropYes: "Rogner"
|
cropYes: "Rogner"
|
||||||
cropNo: "Utiliser en l'état"
|
cropNo: "Utiliser en l'état"
|
||||||
file: "Fichiers"
|
file: "Fichier"
|
||||||
recentNHours: "Dernières {n} heures"
|
recentNHours: "Dernières {n} heures"
|
||||||
recentNDays: "Derniers {n} jours"
|
recentNDays: "Derniers {n} jours"
|
||||||
noEmailServerWarning: "Serveur de courrier non configuré."
|
noEmailServerWarning: "Serveur de courrier non configuré."
|
||||||
|
@ -1055,6 +1074,7 @@ retryAllQueuesConfirmTitle: "Vraiment réessayer ?"
|
||||||
retryAllQueuesConfirmText: "Cela peut augmenter temporairement la charge du serveur."
|
retryAllQueuesConfirmText: "Cela peut augmenter temporairement la charge du serveur."
|
||||||
enableChartsForRemoteUser: "Générer les graphiques pour les utilisateurs distants"
|
enableChartsForRemoteUser: "Générer les graphiques pour les utilisateurs distants"
|
||||||
enableChartsForFederatedInstances: "Générer les graphiques pour les instances distantes"
|
enableChartsForFederatedInstances: "Générer les graphiques pour les instances distantes"
|
||||||
|
enableStatsForFederatedInstances: "Recevoir les statistiques des instances distantes"
|
||||||
showClipButtonInNoteFooter: "Ajouter « Clip » au menu d'action de la note"
|
showClipButtonInNoteFooter: "Ajouter « Clip » au menu d'action de la note"
|
||||||
reactionsDisplaySize: "Taille de l'affichage des réactions"
|
reactionsDisplaySize: "Taille de l'affichage des réactions"
|
||||||
limitWidthOfReaction: "Limiter la largeur maximale des réactions et les afficher en taille réduite"
|
limitWidthOfReaction: "Limiter la largeur maximale des réactions et les afficher en taille réduite"
|
||||||
|
@ -1102,6 +1122,8 @@ preventAiLearning: "Refuser l'usage dans l'apprentissage automatique d'IA géné
|
||||||
preventAiLearningDescription: "Demander aux robots d'indexation de ne pas utiliser le contenu publié, tel que les notes et les images, dans l'apprentissage automatique d'IA générative. Cela est réalisé en incluant le drapeau « noai » dans la réponse HTML. Une prévention complète n'est toutefois pas possible, car il est au robot d'indexation de respecter cette demande."
|
preventAiLearningDescription: "Demander aux robots d'indexation de ne pas utiliser le contenu publié, tel que les notes et les images, dans l'apprentissage automatique d'IA générative. Cela est réalisé en incluant le drapeau « noai » dans la réponse HTML. Une prévention complète n'est toutefois pas possible, car il est au robot d'indexation de respecter cette demande."
|
||||||
options: "Options"
|
options: "Options"
|
||||||
specifyUser: "Spécifier l'utilisateur·rice"
|
specifyUser: "Spécifier l'utilisateur·rice"
|
||||||
|
openTagPageConfirm: "Ouvrir une page d'hashtags ?"
|
||||||
|
specifyHost: "Spécifier un serveur distant"
|
||||||
failedToPreviewUrl: "Aperçu d'URL échoué"
|
failedToPreviewUrl: "Aperçu d'URL échoué"
|
||||||
update: "Mettre à jour"
|
update: "Mettre à jour"
|
||||||
rolesThatCanBeUsedThisEmojiAsReaction: "Rôles qui peuvent utiliser cet émoji comme réaction"
|
rolesThatCanBeUsedThisEmojiAsReaction: "Rôles qui peuvent utiliser cet émoji comme réaction"
|
||||||
|
@ -1222,13 +1244,55 @@ enableHorizontalSwipe: "Glisser pour changer d'onglet"
|
||||||
loading: "Chargement en cours"
|
loading: "Chargement en cours"
|
||||||
surrender: "Annuler"
|
surrender: "Annuler"
|
||||||
gameRetry: "Réessayer"
|
gameRetry: "Réessayer"
|
||||||
|
notUsePleaseLeaveBlank: "Laisser vide si non utilisé"
|
||||||
|
useTotp: "Entrer un mot de passe à usage unique"
|
||||||
|
useBackupCode: "Utiliser le codes de secours"
|
||||||
launchApp: "Lancer l'app"
|
launchApp: "Lancer l'app"
|
||||||
|
useNativeUIForVideoAudioPlayer: "Lire les vidéos et audios en utilisant l'UI du navigateur"
|
||||||
|
keepOriginalFilename: "Garder le nom original du fichier"
|
||||||
|
keepOriginalFilenameDescription: "Si vous désactivez ce paramètre, les noms de fichiers seront automatiquement remplacés par des noms aléatoires lorsque vous téléchargerez des fichiers."
|
||||||
|
noDescription: "Il n'y a pas de description"
|
||||||
|
alwaysConfirmFollow: "Confirmer lors d'un abonnement"
|
||||||
inquiry: "Contact"
|
inquiry: "Contact"
|
||||||
|
tryAgain: "Veuillez réessayer plus tard"
|
||||||
|
confirmWhenRevealingSensitiveMedia: "Confirmer pour révéler du contenu sensible"
|
||||||
|
sensitiveMediaRevealConfirm: "Ceci pourrait être du contenu sensible. Voulez-vous l'afficher ?"
|
||||||
|
createdLists: "Listes créées"
|
||||||
|
createdAntennas: "Antennes créées"
|
||||||
|
fromX: "De {x}"
|
||||||
|
genEmbedCode: "Générer le code d'intégration"
|
||||||
|
noteOfThisUser: "Notes de cet·te utilisateur·rice"
|
||||||
|
clipNoteLimitExceeded: "Aucune note supplémentaire ne peut être ajoutée à ce clip."
|
||||||
|
performance: "Performance"
|
||||||
|
modified: "Modifié"
|
||||||
|
discard: "Annuler"
|
||||||
|
thereAreNChanges: "Il y a {n} modification(s)"
|
||||||
|
signinWithPasskey: "Se connecter avec une clé d'accès"
|
||||||
|
unknownWebAuthnKey: "Clé d'accès inconnue."
|
||||||
|
passkeyVerificationFailed: "La vérification de la clé d'accès a échoué."
|
||||||
|
passkeyVerificationSucceededButPasswordlessLoginDisabled: "La vérification de la clé d'accès a réussi, mais la connexion sans mot de passe est désactivée."
|
||||||
|
messageToFollower: "Message aux abonné·es"
|
||||||
|
target: "Destinataire"
|
||||||
|
prohibitedWordsForNameOfUser: "Mots interdits pour les noms d'utilisateur·rices"
|
||||||
|
lockdown: "Verrouiller"
|
||||||
|
pleaseSelectAccount: "Sélectionner un compte"
|
||||||
|
availableRoles: "Rôles disponibles"
|
||||||
|
_abuseUserReport:
|
||||||
|
forward: "Transférer"
|
||||||
|
forwardDescription: "Transférer le signalement vers une instance distante en tant qu'anonyme."
|
||||||
|
resolve: "Résoudre"
|
||||||
|
accept: "Accepter"
|
||||||
|
reject: "Rejeter"
|
||||||
|
resolveTutorial: "Si le signalement est légitime dans son contenu, sélectionnez « Accepter » pour marquer le cas comme résolu par l'affirmative.\nSi le contenu du rapport n'est pas légitime, sélectionnez « Rejeter » pour marquer le cas comme résolu par la négative."
|
||||||
_delivery:
|
_delivery:
|
||||||
status: "Statut de la diffusion"
|
status: "Statut de la diffusion"
|
||||||
stop: "Suspendu·e"
|
stop: "Suspendu·e"
|
||||||
|
resume: "Reprendre"
|
||||||
_type:
|
_type:
|
||||||
none: "Publié"
|
none: "Publié"
|
||||||
|
manuallySuspended: "Suspendre manuellement"
|
||||||
|
goneSuspended: "L'instance est suspendue en raison de la suppression de ce dernier"
|
||||||
|
autoSuspendedForNotResponding: "L'instance est suspendue car elle ne répond pas"
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
howToPlay: "Comment jouer"
|
howToPlay: "Comment jouer"
|
||||||
hold: "Réserver"
|
hold: "Réserver"
|
||||||
|
@ -1239,6 +1303,7 @@ _bubbleGame:
|
||||||
maxChain: "Nombre maximum de chaînes"
|
maxChain: "Nombre maximum de chaînes"
|
||||||
yen: "{yen} yens"
|
yen: "{yen} yens"
|
||||||
estimatedQty: "{qty} pièces"
|
estimatedQty: "{qty} pièces"
|
||||||
|
scoreSweets: "{onigiriQtyWithUnit} Onigiri(s)"
|
||||||
_announcement:
|
_announcement:
|
||||||
forExistingUsers: "Pour les utilisateurs existants seulement"
|
forExistingUsers: "Pour les utilisateurs existants seulement"
|
||||||
needConfirmationToRead: "Exiger la confirmation de la lecture"
|
needConfirmationToRead: "Exiger la confirmation de la lecture"
|
||||||
|
@ -1258,6 +1323,7 @@ _initialAccountSetting:
|
||||||
profileSetting: "Paramètres du profil"
|
profileSetting: "Paramètres du profil"
|
||||||
privacySetting: "Paramètres de confidentialité"
|
privacySetting: "Paramètres de confidentialité"
|
||||||
initialAccountSettingCompleted: "Configuration du profil terminée avec succès !"
|
initialAccountSettingCompleted: "Configuration du profil terminée avec succès !"
|
||||||
|
haveFun: "Profitez de {name} !"
|
||||||
youCanContinueTutorial: "Vous pouvez procéder au tutoriel sur l'utilisation de {name}(Misskey) ou vous arrêter ici et commencer à l'utiliser immédiatement."
|
youCanContinueTutorial: "Vous pouvez procéder au tutoriel sur l'utilisation de {name}(Misskey) ou vous arrêter ici et commencer à l'utiliser immédiatement."
|
||||||
startTutorial: "Démarrer le tutoriel"
|
startTutorial: "Démarrer le tutoriel"
|
||||||
skipAreYouSure: "Désirez-vous ignorer la configuration du profil ?"
|
skipAreYouSure: "Désirez-vous ignorer la configuration du profil ?"
|
||||||
|
@ -1351,18 +1417,60 @@ _achievements:
|
||||||
flavor: "Passez un bon moment avec Misskey !"
|
flavor: "Passez un bon moment avec Misskey !"
|
||||||
_notes10:
|
_notes10:
|
||||||
title: "Quelques notes"
|
title: "Quelques notes"
|
||||||
|
description: "Poster 10 notes"
|
||||||
_notes100:
|
_notes100:
|
||||||
title: "Beaucoup de notes"
|
title: "Beaucoup de notes"
|
||||||
|
description: "Poster 100 notes"
|
||||||
|
_notes500:
|
||||||
|
title: "Couvert de notes"
|
||||||
|
description: "Poster 500 notes"
|
||||||
|
_notes1000:
|
||||||
|
title: "Une montagne de notes"
|
||||||
|
description: "Poster 1000 notes"
|
||||||
|
_notes5000:
|
||||||
|
title: "Débordement de notes"
|
||||||
|
description: "Poster 5 000 notes"
|
||||||
|
_notes10000:
|
||||||
|
title: "Super note"
|
||||||
|
description: "Poster 10 000 notes"
|
||||||
|
_notes20000:
|
||||||
|
title: "Encore... plus... de... notes..."
|
||||||
|
description: "Poster 20 000 notes"
|
||||||
|
_notes30000:
|
||||||
|
title: "Notes notes notes !"
|
||||||
|
description: "Poster 30 000 notes"
|
||||||
|
_notes40000:
|
||||||
|
title: "Usine de notes"
|
||||||
|
description: "Poster 40 000 notes"
|
||||||
|
_notes50000:
|
||||||
|
title: "Planète des notes"
|
||||||
|
description: "Poster 50 000 notes"
|
||||||
|
_notes60000:
|
||||||
|
title: "Quasar de note"
|
||||||
|
description: "Poster 50 000 notes"
|
||||||
|
_notes70000:
|
||||||
|
title: "Trou noir de notes"
|
||||||
|
description: "Poster 70 000 notes"
|
||||||
|
_notes80000:
|
||||||
|
title: "Galaxie de notes"
|
||||||
|
description: "Poster 80 000 notes"
|
||||||
|
_notes90000:
|
||||||
|
title: "Univers de notes"
|
||||||
|
description: "Poster 90 000 notes"
|
||||||
_notes100000:
|
_notes100000:
|
||||||
title: "ALL YOUR NOTE ARE BELONG TO US"
|
title: "ALL YOUR NOTE ARE BELONG TO US"
|
||||||
|
description: "Poster 100 000 notes"
|
||||||
|
flavor: "Avez-vous tant de choses à dire ?"
|
||||||
_login3:
|
_login3:
|
||||||
title: "Débutant Ⅰ"
|
title: "Débutant I"
|
||||||
description: "Se connecter pour un total de 3 jours"
|
description: "Se connecter pour un total de 3 jours"
|
||||||
|
flavor: "Dès maintenant, appelez-moi Misskeynaute"
|
||||||
_login7:
|
_login7:
|
||||||
title: "Débutant Ⅱ"
|
title: "Débutant II"
|
||||||
description: "Se connecter pour un total de 7 jours"
|
description: "Se connecter pour un total de 7 jours"
|
||||||
|
flavor: "On s'habitue ?"
|
||||||
_login15:
|
_login15:
|
||||||
title: "Débutant Ⅲ"
|
title: "Débutant III"
|
||||||
description: "Se connecter pour un total de 15 jours"
|
description: "Se connecter pour un total de 15 jours"
|
||||||
_login30:
|
_login30:
|
||||||
title: "Misskeynaute I"
|
title: "Misskeynaute I"
|
||||||
|
@ -1386,6 +1494,7 @@ _achievements:
|
||||||
_login500:
|
_login500:
|
||||||
title: "Expert I"
|
title: "Expert I"
|
||||||
description: "Se connecter pour un total de 500 jours"
|
description: "Se connecter pour un total de 500 jours"
|
||||||
|
flavor: "Non, mes amis, j'aime les notes"
|
||||||
_login600:
|
_login600:
|
||||||
title: "Expert II"
|
title: "Expert II"
|
||||||
description: "Se connecter pour un total de 600 jours"
|
description: "Se connecter pour un total de 600 jours"
|
||||||
|
@ -1393,11 +1502,18 @@ _achievements:
|
||||||
title: "Expert III"
|
title: "Expert III"
|
||||||
description: "Se connecter pour un total de 700 jours"
|
description: "Se connecter pour un total de 700 jours"
|
||||||
_login800:
|
_login800:
|
||||||
|
title: "Maître des notes I"
|
||||||
description: "Se connecter pour un total de 800 jours"
|
description: "Se connecter pour un total de 800 jours"
|
||||||
_login900:
|
_login900:
|
||||||
|
title: "Maître des notes II"
|
||||||
description: "Se connecter pour un total de 900 jours"
|
description: "Se connecter pour un total de 900 jours"
|
||||||
_login1000:
|
_login1000:
|
||||||
|
title: "Maître des notes III"
|
||||||
|
description: "Se connecter pour un total de 1 000 jours"
|
||||||
flavor: "Merci d'utiliser Misskey !"
|
flavor: "Merci d'utiliser Misskey !"
|
||||||
|
_noteClipped1:
|
||||||
|
title: "Je... dois... clip..."
|
||||||
|
description: "Ajouter sa première note aux clips"
|
||||||
_profileFilled:
|
_profileFilled:
|
||||||
title: "Bien préparé"
|
title: "Bien préparé"
|
||||||
description: "Configuration de votre profil"
|
description: "Configuration de votre profil"
|
||||||
|
@ -1456,21 +1572,31 @@ _achievements:
|
||||||
_driveFolderCircularReference:
|
_driveFolderCircularReference:
|
||||||
title: "Référence circulaire"
|
title: "Référence circulaire"
|
||||||
_setNameToSyuilo:
|
_setNameToSyuilo:
|
||||||
|
title: "Complexe de dieu"
|
||||||
description: "Vous avez spécifié « syuilo » comme nom"
|
description: "Vous avez spécifié « syuilo » comme nom"
|
||||||
_passedSinceAccountCreated1:
|
_passedSinceAccountCreated1:
|
||||||
title: "Premier anniversaire"
|
title: "Premier anniversaire"
|
||||||
|
description: "Un an est passé depuis la création du compte"
|
||||||
_passedSinceAccountCreated2:
|
_passedSinceAccountCreated2:
|
||||||
title: "Second anniversaire"
|
title: "Second anniversaire"
|
||||||
|
description: "Deux ans sont passés depuis la création du compte"
|
||||||
_passedSinceAccountCreated3:
|
_passedSinceAccountCreated3:
|
||||||
title: "3ème anniversaire"
|
title: "3ème anniversaire"
|
||||||
|
description: "Trois ans sont passés depuis la création du compte"
|
||||||
_loggedInOnBirthday:
|
_loggedInOnBirthday:
|
||||||
title: "Joyeux Anniversaire !"
|
title: "Joyeux Anniversaire !"
|
||||||
description: "Vous vous êtes connecté à la date de votre anniversaire"
|
description: "Vous vous êtes connecté à la date de votre anniversaire"
|
||||||
_loggedInOnNewYearsDay:
|
_loggedInOnNewYearsDay:
|
||||||
title: "Bonne année !"
|
title: "Bonne année !"
|
||||||
|
description: "Vous vous êtes connecté le premier jour de l'année"
|
||||||
|
flavor: "Merci pour le soutient continue sur cette instance."
|
||||||
_cookieClicked:
|
_cookieClicked:
|
||||||
|
title: "Jeu de clic sur des cookies"
|
||||||
|
description: "Cliqué sur un cookie"
|
||||||
flavor: "Attendez une minute, vous êtes sur le mauvais site web ?"
|
flavor: "Attendez une minute, vous êtes sur le mauvais site web ?"
|
||||||
_brainDiver:
|
_brainDiver:
|
||||||
|
title: "Brain Diver"
|
||||||
|
description: "Poster le lien sur Brain Diver"
|
||||||
flavor: "Misskey-Misskey La-Tu-Ma"
|
flavor: "Misskey-Misskey La-Tu-Ma"
|
||||||
_smashTestNotificationButton:
|
_smashTestNotificationButton:
|
||||||
title: "Débordement de tests"
|
title: "Débordement de tests"
|
||||||
|
@ -1478,6 +1604,11 @@ _achievements:
|
||||||
_tutorialCompleted:
|
_tutorialCompleted:
|
||||||
title: "Diplôme de la course élémentaire de Misskey"
|
title: "Diplôme de la course élémentaire de Misskey"
|
||||||
description: "Terminer le tutoriel"
|
description: "Terminer le tutoriel"
|
||||||
|
_bubbleGameExplodingHead:
|
||||||
|
title: "🤯"
|
||||||
|
description: "Le plus gros objet du jeu de bulles"
|
||||||
|
_bubbleGameDoubleExplodingHead:
|
||||||
|
title: "Double🤯"
|
||||||
_role:
|
_role:
|
||||||
new: "Nouveau rôle"
|
new: "Nouveau rôle"
|
||||||
edit: "Modifier le rôle"
|
edit: "Modifier le rôle"
|
||||||
|
@ -1508,9 +1639,11 @@ _role:
|
||||||
canManageCustomEmojis: "Gestion des émojis personnalisés"
|
canManageCustomEmojis: "Gestion des émojis personnalisés"
|
||||||
canManageAvatarDecorations: "Gestion des décorations d'avatar"
|
canManageAvatarDecorations: "Gestion des décorations d'avatar"
|
||||||
driveCapacity: "Capacité de stockage du Disque"
|
driveCapacity: "Capacité de stockage du Disque"
|
||||||
|
antennaMax: "Nombre maximum d'antennes"
|
||||||
wordMuteMax: "Nombre maximal de caractères dans le filtre de mots"
|
wordMuteMax: "Nombre maximal de caractères dans le filtre de mots"
|
||||||
canUseTranslator: "Usage de la fonctionnalité de traduction"
|
canUseTranslator: "Usage de la fonctionnalité de traduction"
|
||||||
avatarDecorationLimit: "Nombre maximal de décorations d'avatar"
|
avatarDecorationLimit: "Nombre maximal de décorations d'avatar"
|
||||||
|
canImportAntennas: "Autoriser l'importation d'antennes"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "L'apprentissage automatique peut être utilisé pour détecter automatiquement les médias sensibles à modérer. La sollicitation des serveurs augmente légèrement."
|
description: "L'apprentissage automatique peut être utilisé pour détecter automatiquement les médias sensibles à modérer. La sollicitation des serveurs augmente légèrement."
|
||||||
sensitivity: "Sensibilité de la détection"
|
sensitivity: "Sensibilité de la détection"
|
||||||
|
@ -1793,6 +1926,29 @@ _permissions:
|
||||||
"write:gallery": "Éditer la galerie"
|
"write:gallery": "Éditer la galerie"
|
||||||
"read:gallery-likes": "Voir les mentions « J'aime » dans la galerie"
|
"read:gallery-likes": "Voir les mentions « J'aime » dans la galerie"
|
||||||
"write:gallery-likes": "Gérer les mentions « J'aime » dans la galerie"
|
"write:gallery-likes": "Gérer les mentions « J'aime » dans la galerie"
|
||||||
|
"read:flash": "Voir le Play"
|
||||||
|
"write:flash": "Modifier le Play"
|
||||||
|
"read:flash-likes": "Lire vos mentions j'aime des Play"
|
||||||
|
"write:flash-likes": "Modifier vos mentions j'aime des Play"
|
||||||
|
"read:admin:abuse-user-reports": "Voir les utilisateurs signalés"
|
||||||
|
"write:admin:delete-account": "Supprimer le compte d'utilisateur"
|
||||||
|
"write:admin:delete-all-files-of-a-user": "Supprimer tous les fichiers d'un utilisateur"
|
||||||
|
"read:admin:index-stats": "Voir les statistiques sur les index de base de données"
|
||||||
|
"read:admin:table-stats": "Voir les statistiques sur les index de base de données"
|
||||||
|
"read:admin:user-ips": "Voir l'adresse IP de l'utilisateur"
|
||||||
|
"read:admin:meta": "Voir les métadonnées de l'instance"
|
||||||
|
"write:admin:reset-password": "Réinitialiser le mot de passe de l'utilisateur"
|
||||||
|
"write:admin:resolve-abuse-user-report": "Résoudre le signalement d'un utilisateur"
|
||||||
|
"write:admin:send-email": "Envoyer un mail"
|
||||||
|
"read:admin:server-info": "Voir les informations de l'instance"
|
||||||
|
"read:admin:show-moderation-log": "Voir les logs de modération"
|
||||||
|
"read:admin:show-user": "Voir les informations privées de l'utilisateur"
|
||||||
|
"write:admin:suspend-user": "Suspendre l'utilisateur"
|
||||||
|
"write:admin:unset-user-avatar": "Retirer l'avatar de l'utilisateur"
|
||||||
|
"write:admin:unset-user-banner": "Retirer la bannière de l'utilisateur"
|
||||||
|
"write:admin:unsuspend-user": "Lever la suspension d'un utilisateur"
|
||||||
|
"write:admin:meta": "Gérer les métadonnées de l'instance"
|
||||||
|
"write:admin:roles": "Gérer les rôles"
|
||||||
_auth:
|
_auth:
|
||||||
shareAccess: "Autoriser \"{name}\" à accéder à votre compte ?"
|
shareAccess: "Autoriser \"{name}\" à accéder à votre compte ?"
|
||||||
shareAccessAsk: "Voulez-vous vraiment autoriser cette application à accéder à votre compte?"
|
shareAccessAsk: "Voulez-vous vraiment autoriser cette application à accéder à votre compte?"
|
||||||
|
@ -1944,7 +2100,16 @@ _timelines:
|
||||||
social: "Social"
|
social: "Social"
|
||||||
global: "Global"
|
global: "Global"
|
||||||
_play:
|
_play:
|
||||||
|
new: "Créer un Play"
|
||||||
|
edit: "Modifier un Play"
|
||||||
|
created: "Play créé"
|
||||||
|
updated: "Play édité"
|
||||||
|
deleted: "Play supprimé"
|
||||||
|
pageSetting: "Configuration du Play"
|
||||||
|
editThisPage: "Modifier ce Play"
|
||||||
viewSource: "Afficher la source"
|
viewSource: "Afficher la source"
|
||||||
|
my: "Mes Play"
|
||||||
|
liked: "Play aimés"
|
||||||
featured: "Populaire"
|
featured: "Populaire"
|
||||||
title: "Titre"
|
title: "Titre"
|
||||||
script: "Script"
|
script: "Script"
|
||||||
|
@ -2018,10 +2183,13 @@ _notification:
|
||||||
achievementEarned: "Accomplissement déverrouillé"
|
achievementEarned: "Accomplissement déverrouillé"
|
||||||
testNotification: "Tester la notification"
|
testNotification: "Tester la notification"
|
||||||
reactedBySomeUsers: "{n} utilisateur·rice·s ont réagi"
|
reactedBySomeUsers: "{n} utilisateur·rice·s ont réagi"
|
||||||
|
likedBySomeUsers: "{n} utilisateurs ont aimé votre note"
|
||||||
renotedBySomeUsers: "{n} utilisateur·rice·s ont renoté"
|
renotedBySomeUsers: "{n} utilisateur·rice·s ont renoté"
|
||||||
followedBySomeUsers: "{n} utilisateur·rice·s se sont abonné·e·s à vous"
|
followedBySomeUsers: "{n} utilisateur·rice·s se sont abonné·e·s à vous"
|
||||||
|
login: "Quelqu'un s'est connecté"
|
||||||
_types:
|
_types:
|
||||||
all: "Toutes"
|
all: "Toutes"
|
||||||
|
note: "Nouvelles notes"
|
||||||
follow: "Nouvel·le abonné·e"
|
follow: "Nouvel·le abonné·e"
|
||||||
mention: "Mentions"
|
mention: "Mentions"
|
||||||
reply: "Réponses"
|
reply: "Réponses"
|
||||||
|
@ -2071,11 +2239,14 @@ _drivecleaner:
|
||||||
orderByCreatedAtAsc: "Date d'ajout ascendante"
|
orderByCreatedAtAsc: "Date d'ajout ascendante"
|
||||||
_webhookSettings:
|
_webhookSettings:
|
||||||
name: "Nom"
|
name: "Nom"
|
||||||
|
secret: "Secret"
|
||||||
|
trigger: "Activateur"
|
||||||
active: "Activé"
|
active: "Activé"
|
||||||
_abuseReport:
|
_abuseReport:
|
||||||
_notificationRecipient:
|
_notificationRecipient:
|
||||||
_recipientType:
|
_recipientType:
|
||||||
mail: "E-mail "
|
mail: "E-mail "
|
||||||
|
keywords: "Mots clés "
|
||||||
_moderationLogTypes:
|
_moderationLogTypes:
|
||||||
createRole: "Rôle créé"
|
createRole: "Rôle créé"
|
||||||
deleteRole: "Rôle supprimé"
|
deleteRole: "Rôle supprimé"
|
||||||
|
@ -2112,6 +2283,7 @@ _moderationLogTypes:
|
||||||
deleteAvatarDecoration: "Décoration d'avatar supprimée"
|
deleteAvatarDecoration: "Décoration d'avatar supprimée"
|
||||||
unsetUserAvatar: "Supprimer l'avatar de l'utilisateur·rice"
|
unsetUserAvatar: "Supprimer l'avatar de l'utilisateur·rice"
|
||||||
unsetUserBanner: "Supprimer la bannière de l'utilisateur·rice"
|
unsetUserBanner: "Supprimer la bannière de l'utilisateur·rice"
|
||||||
|
deleteFlash: "Supprimer le Play"
|
||||||
_fileViewer:
|
_fileViewer:
|
||||||
title: "Détails du fichier"
|
title: "Détails du fichier"
|
||||||
type: "Type du fichier"
|
type: "Type du fichier"
|
||||||
|
@ -2175,5 +2347,20 @@ _dataSaver:
|
||||||
title: "Mise en évidence du code"
|
title: "Mise en évidence du code"
|
||||||
description: "Si la notation de mise en évidence du code est utilisée, par exemple dans la MFM, elle ne sera pas chargée tant qu'elle n'aura pas été tapée. La mise en évidence du code nécessite le chargement du fichier de définition de chaque langue à mettre en évidence, mais comme ces fichiers ne sont plus chargés automatiquement, on peut s'attendre à une réduction du trafic de données."
|
description: "Si la notation de mise en évidence du code est utilisée, par exemple dans la MFM, elle ne sera pas chargée tant qu'elle n'aura pas été tapée. La mise en évidence du code nécessite le chargement du fichier de définition de chaque langue à mettre en évidence, mais comme ces fichiers ne sont plus chargés automatiquement, on peut s'attendre à une réduction du trafic de données."
|
||||||
_reversi:
|
_reversi:
|
||||||
|
reversi: "Reversi"
|
||||||
|
blackIs: "{name} joue les noirs"
|
||||||
|
rules: "Règles"
|
||||||
waitingBoth: "Préparez-vous"
|
waitingBoth: "Préparez-vous"
|
||||||
|
myTurn: "C’est votre tour"
|
||||||
|
turnOf: "C'est le tour de {name}"
|
||||||
|
pastTurnOf: "Tour de {name}"
|
||||||
|
surrender: "Se rendre"
|
||||||
|
surrendered: "Par abandon"
|
||||||
total: "Total"
|
total: "Total"
|
||||||
|
playing: "En cours"
|
||||||
|
lookingForPlayer: "Recherche d'adversaire"
|
||||||
|
_mediaControls:
|
||||||
|
playbackRate: "Vitesse de lecture"
|
||||||
|
_embedCodeGen:
|
||||||
|
title: "Personnaliser le code d'intégration"
|
||||||
|
generateCode: "Générer le code d'intégration"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
_lang_: "Japán"
|
_lang_: "Magyar"
|
||||||
monthAndDay: "{month}.{day}."
|
monthAndDay: "{month}.{day}."
|
||||||
search: "Keresés"
|
search: "Keresés"
|
||||||
notifications: "Értesítések"
|
notifications: "Értesítések"
|
||||||
|
|
|
@ -196,6 +196,7 @@ followConfirm: "Apakah kamu yakin ingin mengikuti {name}?"
|
||||||
proxyAccount: "Akun proksi"
|
proxyAccount: "Akun proksi"
|
||||||
proxyAccountDescription: "Akun proksi merupakan sebuah akun yang bertindak sebagai pengikut instansi luar untuk pengguna dalam kondisi tertentu. Sebagai contoh, ketika pengguna menambahkan seorang pengguna instansi luar ke dalam daftar, aktivitas dari pengguna instansi luar tidak akan disampaikan ke instansi apabila tidak ada pengguna lokal yang mengikuti pengguna tersebut, dengan begitu akun proksilah yang akan mengikutinya."
|
proxyAccountDescription: "Akun proksi merupakan sebuah akun yang bertindak sebagai pengikut instansi luar untuk pengguna dalam kondisi tertentu. Sebagai contoh, ketika pengguna menambahkan seorang pengguna instansi luar ke dalam daftar, aktivitas dari pengguna instansi luar tidak akan disampaikan ke instansi apabila tidak ada pengguna lokal yang mengikuti pengguna tersebut, dengan begitu akun proksilah yang akan mengikutinya."
|
||||||
host: "Host"
|
host: "Host"
|
||||||
|
selectSelf: "Pilih diri sendiri"
|
||||||
selectUser: "Pilih pengguna"
|
selectUser: "Pilih pengguna"
|
||||||
recipient: "Penerima"
|
recipient: "Penerima"
|
||||||
annotation: "Keterangan konten"
|
annotation: "Keterangan konten"
|
||||||
|
@ -232,6 +233,7 @@ blockedInstances: "Instansi terblokir"
|
||||||
blockedInstancesDescription: "Daftar nama host dari instansi yang diperlukan untuk diblokir. Instansi yang didaftarkan tidak akan dapat berkomunikasi dengan instansi ini."
|
blockedInstancesDescription: "Daftar nama host dari instansi yang diperlukan untuk diblokir. Instansi yang didaftarkan tidak akan dapat berkomunikasi dengan instansi ini."
|
||||||
silencedInstances: "Instansi yang disenyapkan"
|
silencedInstances: "Instansi yang disenyapkan"
|
||||||
silencedInstancesDescription: "Daftar nama host dari instansi yang ingin kamu senyapkan. Semua akun dari instansi yang terdaftar akan diperlakukan sebagai disenyapkan. Hal ini membuat akun hanya dapat membuat permintaan mengikuti, dan tidak dapat menyebutkan akun lokal apabila tidak mengikuti. Hal ini tidak akan mempengaruhi instansi yang diblokir."
|
silencedInstancesDescription: "Daftar nama host dari instansi yang ingin kamu senyapkan. Semua akun dari instansi yang terdaftar akan diperlakukan sebagai disenyapkan. Hal ini membuat akun hanya dapat membuat permintaan mengikuti, dan tidak dapat menyebutkan akun lokal apabila tidak mengikuti. Hal ini tidak akan mempengaruhi instansi yang diblokir."
|
||||||
|
federationAllowedHosts: "Server yang membolehkan federasi"
|
||||||
muteAndBlock: "Bisukan / Blokir"
|
muteAndBlock: "Bisukan / Blokir"
|
||||||
mutedUsers: "Pengguna yang dibisukan"
|
mutedUsers: "Pengguna yang dibisukan"
|
||||||
blockedUsers: "Pengguna yang diblokir"
|
blockedUsers: "Pengguna yang diblokir"
|
||||||
|
@ -330,6 +332,7 @@ renameFolder: "Ubah nama folder"
|
||||||
deleteFolder: "Hapus folder"
|
deleteFolder: "Hapus folder"
|
||||||
folder: "Folder"
|
folder: "Folder"
|
||||||
addFile: "Tambahkan berkas"
|
addFile: "Tambahkan berkas"
|
||||||
|
showFile: "Tampilkan berkas"
|
||||||
emptyDrive: "Drive kosong"
|
emptyDrive: "Drive kosong"
|
||||||
emptyFolder: "Folder kosong"
|
emptyFolder: "Folder kosong"
|
||||||
unableToDelete: "Tidak dapat menghapus"
|
unableToDelete: "Tidak dapat menghapus"
|
||||||
|
@ -372,7 +375,6 @@ enableLocalTimeline: "Nyalakan lini masa lokal"
|
||||||
enableGlobalTimeline: "Nyalakan lini masa global"
|
enableGlobalTimeline: "Nyalakan lini masa global"
|
||||||
disablingTimelinesInfo: "Admin dan Moderator akan selalu memiliki akses ke semua lini masa meskipun lini masa tersebut tidak diaktifkan."
|
disablingTimelinesInfo: "Admin dan Moderator akan selalu memiliki akses ke semua lini masa meskipun lini masa tersebut tidak diaktifkan."
|
||||||
registration: "Pendaftaran"
|
registration: "Pendaftaran"
|
||||||
enableRegistration: "Nyalakan pendaftaran pengguna baru"
|
|
||||||
invite: "Undang"
|
invite: "Undang"
|
||||||
driveCapacityPerLocalAccount: "Kapasitas drive per pengguna lokal"
|
driveCapacityPerLocalAccount: "Kapasitas drive per pengguna lokal"
|
||||||
driveCapacityPerRemoteAccount: "Kapasitas drive per pengguna remote"
|
driveCapacityPerRemoteAccount: "Kapasitas drive per pengguna remote"
|
||||||
|
@ -504,6 +506,8 @@ uiLanguage: "Bahasa antarmuka pengguna"
|
||||||
aboutX: "Tentang {x}"
|
aboutX: "Tentang {x}"
|
||||||
emojiStyle: "Gaya emoji"
|
emojiStyle: "Gaya emoji"
|
||||||
native: "Native"
|
native: "Native"
|
||||||
|
menuStyle: "Gaya menu"
|
||||||
|
style: "Gaya"
|
||||||
showNoteActionsOnlyHover: "Hanya tampilkan aksi catatan saat ditunjuk"
|
showNoteActionsOnlyHover: "Hanya tampilkan aksi catatan saat ditunjuk"
|
||||||
showReactionsCount: "Lihat jumlah reaksi dalam catatan"
|
showReactionsCount: "Lihat jumlah reaksi dalam catatan"
|
||||||
noHistory: "Tidak ada riwayat"
|
noHistory: "Tidak ada riwayat"
|
||||||
|
@ -927,6 +931,9 @@ oneHour: "1 Jam"
|
||||||
oneDay: "1 Hari"
|
oneDay: "1 Hari"
|
||||||
oneWeek: "1 Bulan"
|
oneWeek: "1 Bulan"
|
||||||
oneMonth: "satu bulan"
|
oneMonth: "satu bulan"
|
||||||
|
threeMonths: "3 bulan"
|
||||||
|
oneYear: "1 tahun"
|
||||||
|
threeDays: "3 hari"
|
||||||
reflectMayTakeTime: "Mungkin perlu beberapa saat untuk dicerminkan."
|
reflectMayTakeTime: "Mungkin perlu beberapa saat untuk dicerminkan."
|
||||||
failedToFetchAccountInformation: "Gagal untuk mendapatkan informasi akun"
|
failedToFetchAccountInformation: "Gagal untuk mendapatkan informasi akun"
|
||||||
rateLimitExceeded: "Batas sudah terlampaui"
|
rateLimitExceeded: "Batas sudah terlampaui"
|
||||||
|
@ -1101,6 +1108,7 @@ preservedUsernames: "Nama pengguna tercadangkan"
|
||||||
preservedUsernamesDescription: "Daftar nama pengguna yang dicadangkan dipisah dengan baris baru. Nama pengguna berikut akan tidak dapat dipakai pada pembuatan akun normal, namun dapat digunakan oleh admin untuk membuat akun baru. Akun yang sudah ada dengan menggunakan nama pengguna ini tidak akan terpengaruh."
|
preservedUsernamesDescription: "Daftar nama pengguna yang dicadangkan dipisah dengan baris baru. Nama pengguna berikut akan tidak dapat dipakai pada pembuatan akun normal, namun dapat digunakan oleh admin untuk membuat akun baru. Akun yang sudah ada dengan menggunakan nama pengguna ini tidak akan terpengaruh."
|
||||||
createNoteFromTheFile: "Buat catatan dari berkas ini"
|
createNoteFromTheFile: "Buat catatan dari berkas ini"
|
||||||
archive: "Arsipkan"
|
archive: "Arsipkan"
|
||||||
|
archived: "Diarsipkan"
|
||||||
channelArchiveConfirmTitle: "Yakin untuk mengarsipkan {name}?"
|
channelArchiveConfirmTitle: "Yakin untuk mengarsipkan {name}?"
|
||||||
channelArchiveConfirmDescription: "Kanal yang diarsipkan tidak akan muncul pada daftar kanal atau hasil pencarian. Postingan baru juga tidak dapat ditambahkan lagi."
|
channelArchiveConfirmDescription: "Kanal yang diarsipkan tidak akan muncul pada daftar kanal atau hasil pencarian. Postingan baru juga tidak dapat ditambahkan lagi."
|
||||||
thisChannelArchived: "Kanal ini telah diarsipkan."
|
thisChannelArchived: "Kanal ini telah diarsipkan."
|
||||||
|
@ -1111,6 +1119,7 @@ preventAiLearning: "Tolak penggunaan Pembelajaran Mesin (AI Generatif)"
|
||||||
preventAiLearningDescription: "Minta perayap web untuk tidak menggunakan materi teks atau gambar yang telah diposting ke dalam set data Pembelajaran Mesin (Prediktif / Generatif). Hal ini dicapai dengan menambahkan flag HTML-Response \"noai\" ke masing-masing konten. Pencegahan penuh mungkin tidak dapat dicapai dengan flag ini, karena juga dapat diabaikan begitu saja."
|
preventAiLearningDescription: "Minta perayap web untuk tidak menggunakan materi teks atau gambar yang telah diposting ke dalam set data Pembelajaran Mesin (Prediktif / Generatif). Hal ini dicapai dengan menambahkan flag HTML-Response \"noai\" ke masing-masing konten. Pencegahan penuh mungkin tidak dapat dicapai dengan flag ini, karena juga dapat diabaikan begitu saja."
|
||||||
options: "Opsi peran"
|
options: "Opsi peran"
|
||||||
specifyUser: "Pengguna spesifik"
|
specifyUser: "Pengguna spesifik"
|
||||||
|
openTagPageConfirm: "Apakah ingin membuka laman tagar?"
|
||||||
failedToPreviewUrl: "Tidak dapat dipratinjau"
|
failedToPreviewUrl: "Tidak dapat dipratinjau"
|
||||||
update: "Perbarui"
|
update: "Perbarui"
|
||||||
rolesThatCanBeUsedThisEmojiAsReaction: "Peran yang dapat menggunakan emoji ini sebagai reaksi"
|
rolesThatCanBeUsedThisEmojiAsReaction: "Peran yang dapat menggunakan emoji ini sebagai reaksi"
|
||||||
|
@ -1243,6 +1252,18 @@ noDescription: "Tidak ada deskripsi"
|
||||||
alwaysConfirmFollow: "Selalu konfirmasi ketika mengikuti"
|
alwaysConfirmFollow: "Selalu konfirmasi ketika mengikuti"
|
||||||
inquiry: "Hubungi kami"
|
inquiry: "Hubungi kami"
|
||||||
tryAgain: "Silahkan coba lagi."
|
tryAgain: "Silahkan coba lagi."
|
||||||
|
createdLists: "Senarai yang dibuat"
|
||||||
|
createdAntennas: "Antena yang dibuat"
|
||||||
|
fromX: "Dari {x}"
|
||||||
|
noteOfThisUser: "Catatan oleh pengguna ini"
|
||||||
|
clipNoteLimitExceeded: "Klip ini tak bisa ditambahi lagi catatan."
|
||||||
|
performance: "Kinerja"
|
||||||
|
modified: "Diubah"
|
||||||
|
thereAreNChanges: "Ada {n} perubahan"
|
||||||
|
prohibitedWordsForNameOfUser: "Kata yang dilarang untuk nama pengguna"
|
||||||
|
_abuseUserReport:
|
||||||
|
accept: "Setuju"
|
||||||
|
reject: "Tolak"
|
||||||
_delivery:
|
_delivery:
|
||||||
status: "Status pengiriman"
|
status: "Status pengiriman"
|
||||||
stop: "Ditangguhkan"
|
stop: "Ditangguhkan"
|
||||||
|
@ -1707,6 +1728,8 @@ _role:
|
||||||
canSearchNotes: "Penggunaan pencarian catatan"
|
canSearchNotes: "Penggunaan pencarian catatan"
|
||||||
canUseTranslator: "Penggunaan penerjemah"
|
canUseTranslator: "Penggunaan penerjemah"
|
||||||
avatarDecorationLimit: "Jumlah maksimum dekorasi avatar yang dapat diterapkan"
|
avatarDecorationLimit: "Jumlah maksimum dekorasi avatar yang dapat diterapkan"
|
||||||
|
canImportAntennas: "Izinkan mengimpor antena"
|
||||||
|
canImportUserLists: "Izinkan mengimpor senarai"
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "Ditugaskan ke peran manual"
|
roleAssignedTo: "Ditugaskan ke peran manual"
|
||||||
isLocal: "Pengguna lokal"
|
isLocal: "Pengguna lokal"
|
||||||
|
@ -1943,6 +1966,7 @@ _soundSettings:
|
||||||
driveFileTypeWarnDescription: "Pilih berkas audio"
|
driveFileTypeWarnDescription: "Pilih berkas audio"
|
||||||
driveFileDurationWarn: "Audio ini terlalu panjang"
|
driveFileDurationWarn: "Audio ini terlalu panjang"
|
||||||
driveFileDurationWarnDescription: "Audio panjang dapat mengganggu penggunaan Misskey. Masih ingin melanjutkan?"
|
driveFileDurationWarnDescription: "Audio panjang dapat mengganggu penggunaan Misskey. Masih ingin melanjutkan?"
|
||||||
|
driveFileError: "Tak bisa memuat audio. Mohon ubah pengaturan"
|
||||||
_ago:
|
_ago:
|
||||||
future: "Masa depan"
|
future: "Masa depan"
|
||||||
justNow: "Baru saja"
|
justNow: "Baru saja"
|
||||||
|
@ -2415,6 +2439,8 @@ _abuseReport:
|
||||||
_notificationRecipient:
|
_notificationRecipient:
|
||||||
_recipientType:
|
_recipientType:
|
||||||
mail: "Surel"
|
mail: "Surel"
|
||||||
|
webhook: "Webhook"
|
||||||
|
keywords: "Kata kunci"
|
||||||
_moderationLogTypes:
|
_moderationLogTypes:
|
||||||
createRole: "Peran telah dibuat"
|
createRole: "Peran telah dibuat"
|
||||||
deleteRole: "Peran telah dihapus"
|
deleteRole: "Peran telah dihapus"
|
||||||
|
@ -2452,6 +2478,7 @@ _moderationLogTypes:
|
||||||
deleteAvatarDecoration: "Hapus dekorasi avatar"
|
deleteAvatarDecoration: "Hapus dekorasi avatar"
|
||||||
unsetUserAvatar: "Hapus avatar pengguna"
|
unsetUserAvatar: "Hapus avatar pengguna"
|
||||||
unsetUserBanner: "Hapus banner pengguna"
|
unsetUserBanner: "Hapus banner pengguna"
|
||||||
|
deleteAccount: "Akun dihapus"
|
||||||
_fileViewer:
|
_fileViewer:
|
||||||
title: "Rincian berkas"
|
title: "Rincian berkas"
|
||||||
type: "Jenis berkas"
|
type: "Jenis berkas"
|
||||||
|
|
72
locales/index.d.ts
vendored
72
locales/index.d.ts
vendored
|
@ -1546,10 +1546,6 @@ export interface Locale extends ILocale {
|
||||||
* 登録
|
* 登録
|
||||||
*/
|
*/
|
||||||
"registration": string;
|
"registration": string;
|
||||||
/**
|
|
||||||
* 誰でも新規登録できるようにする
|
|
||||||
*/
|
|
||||||
"enableRegistration": string;
|
|
||||||
/**
|
/**
|
||||||
* 招待
|
* 招待
|
||||||
*/
|
*/
|
||||||
|
@ -2366,6 +2362,10 @@ export interface Locale extends ILocale {
|
||||||
* 詳細
|
* 詳細
|
||||||
*/
|
*/
|
||||||
"details": string;
|
"details": string;
|
||||||
|
/**
|
||||||
|
* リノートの詳細
|
||||||
|
*/
|
||||||
|
"renoteDetails": string;
|
||||||
/**
|
/**
|
||||||
* 絵文字を選択
|
* 絵文字を選択
|
||||||
*/
|
*/
|
||||||
|
@ -5210,6 +5210,18 @@ export interface Locale extends ILocale {
|
||||||
* ロックダウン
|
* ロックダウン
|
||||||
*/
|
*/
|
||||||
"lockdown": string;
|
"lockdown": string;
|
||||||
|
/**
|
||||||
|
* アカウントを選択してください
|
||||||
|
*/
|
||||||
|
"pleaseSelectAccount": string;
|
||||||
|
/**
|
||||||
|
* 利用可能なロール
|
||||||
|
*/
|
||||||
|
"availableRoles": string;
|
||||||
|
/**
|
||||||
|
* 注意事項を理解した上でオンにします。
|
||||||
|
*/
|
||||||
|
"acknowledgeNotesAndEnable": string;
|
||||||
"_accountSettings": {
|
"_accountSettings": {
|
||||||
/**
|
/**
|
||||||
* コンテンツの表示にログインを必須にする
|
* コンテンツの表示にログインを必須にする
|
||||||
|
@ -5786,6 +5798,14 @@ export interface Locale extends ILocale {
|
||||||
* サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定します。
|
* サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定します。
|
||||||
*/
|
*/
|
||||||
"inquiryUrlDescription": string;
|
"inquiryUrlDescription": string;
|
||||||
|
/**
|
||||||
|
* アカウントの作成をオープンにする
|
||||||
|
*/
|
||||||
|
"openRegistration": string;
|
||||||
|
/**
|
||||||
|
* 登録を開放することはリスクが伴います。サーバーを常に監視し、トラブルが発生した際にすぐに対応できる体制がある場合のみオンにすることを推奨します。
|
||||||
|
*/
|
||||||
|
"openRegistrationWarning": string;
|
||||||
/**
|
/**
|
||||||
* 一定期間モデレーターのアクティビティが検出されなかった場合、スパム防止のためこの設定は自動でオフになります。
|
* 一定期間モデレーターのアクティビティが検出されなかった場合、スパム防止のためこの設定は自動でオフになります。
|
||||||
*/
|
*/
|
||||||
|
@ -8448,14 +8468,26 @@ export interface Locale extends ILocale {
|
||||||
* アプリケーションに戻っています
|
* アプリケーションに戻っています
|
||||||
*/
|
*/
|
||||||
"callback": string;
|
"callback": string;
|
||||||
|
/**
|
||||||
|
* アクセスを許可しました
|
||||||
|
*/
|
||||||
|
"accepted": string;
|
||||||
/**
|
/**
|
||||||
* アクセスを拒否しました
|
* アクセスを拒否しました
|
||||||
*/
|
*/
|
||||||
"denied": string;
|
"denied": string;
|
||||||
|
/**
|
||||||
|
* 以下のユーザーとして操作しています
|
||||||
|
*/
|
||||||
|
"scopeUser": string;
|
||||||
/**
|
/**
|
||||||
* アプリケーションにアクセス許可を与えるには、ログインが必要です。
|
* アプリケーションにアクセス許可を与えるには、ログインが必要です。
|
||||||
*/
|
*/
|
||||||
"pleaseLogin": string;
|
"pleaseLogin": string;
|
||||||
|
/**
|
||||||
|
* アクセスを許可すると、自動で以下のURLに遷移します
|
||||||
|
*/
|
||||||
|
"byClickingYouWillBeRedirectedToThisUrl": string;
|
||||||
};
|
};
|
||||||
"_antennaSources": {
|
"_antennaSources": {
|
||||||
/**
|
/**
|
||||||
|
@ -10537,6 +10569,38 @@ export interface Locale extends ILocale {
|
||||||
*/
|
*/
|
||||||
"codeGeneratedDescription": string;
|
"codeGeneratedDescription": string;
|
||||||
};
|
};
|
||||||
|
"_selfXssPrevention": {
|
||||||
|
/**
|
||||||
|
* 警告
|
||||||
|
*/
|
||||||
|
"warning": string;
|
||||||
|
/**
|
||||||
|
* 「この画面に何か貼り付けろ」はすべて詐欺です。
|
||||||
|
*/
|
||||||
|
"title": string;
|
||||||
|
/**
|
||||||
|
* ここに何かを貼り付けると、悪意のあるユーザーにアカウントを乗っ取られたり、個人情報を盗まれたりする可能性があります。
|
||||||
|
*/
|
||||||
|
"description1": string;
|
||||||
|
/**
|
||||||
|
* 貼り付けようとしているものが何なのかを正確に理解していない場合は、%c今すぐ作業を中止してこのウィンドウを閉じてください。
|
||||||
|
*/
|
||||||
|
"description2": string;
|
||||||
|
/**
|
||||||
|
* 詳しくはこちらをご確認ください。 {link}
|
||||||
|
*/
|
||||||
|
"description3": ParameterizedString<"link">;
|
||||||
|
};
|
||||||
|
"_followRequest": {
|
||||||
|
/**
|
||||||
|
* 受け取った申請
|
||||||
|
*/
|
||||||
|
"recieved": string;
|
||||||
|
/**
|
||||||
|
* 送った申請
|
||||||
|
*/
|
||||||
|
"sent": string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
declare const locales: {
|
declare const locales: {
|
||||||
[lang: string]: Locale;
|
[lang: string]: Locale;
|
||||||
|
|
|
@ -15,6 +15,7 @@ const merge = (...args) => args.reduce((a, c) => ({
|
||||||
|
|
||||||
const languages = [
|
const languages = [
|
||||||
'ar-SA',
|
'ar-SA',
|
||||||
|
'ca-ES',
|
||||||
'cs-CZ',
|
'cs-CZ',
|
||||||
'da-DK',
|
'da-DK',
|
||||||
'de-DE',
|
'de-DE',
|
||||||
|
|
|
@ -68,7 +68,7 @@ reply: "Rispondi"
|
||||||
loadMore: "Mostra di più"
|
loadMore: "Mostra di più"
|
||||||
showMore: "Espandi"
|
showMore: "Espandi"
|
||||||
showLess: "Comprimi"
|
showLess: "Comprimi"
|
||||||
youGotNewFollower: "Adesso ti segue"
|
youGotNewFollower: "Hai un nuovo Follower"
|
||||||
receiveFollowRequest: "Hai ricevuto una richiesta di follow"
|
receiveFollowRequest: "Hai ricevuto una richiesta di follow"
|
||||||
followRequestAccepted: "Ha accettato la tua richiesta di follow"
|
followRequestAccepted: "Ha accettato la tua richiesta di follow"
|
||||||
mention: "Menzioni"
|
mention: "Menzioni"
|
||||||
|
@ -80,14 +80,14 @@ export: "Esporta"
|
||||||
files: "Allegati"
|
files: "Allegati"
|
||||||
download: "Scarica"
|
download: "Scarica"
|
||||||
driveFileDeleteConfirm: "Vuoi davvero eliminare il file \"{name}\", e le Note a cui è stato allegato?"
|
driveFileDeleteConfirm: "Vuoi davvero eliminare il file \"{name}\", e le Note a cui è stato allegato?"
|
||||||
unfollowConfirm: "Vuoi davvero smettere di seguire {name}?"
|
unfollowConfirm: "Vuoi davvero togliere il Following a {name}?"
|
||||||
exportRequested: "Hai richiesto un'esportazione, e potrebbe volerci tempo. Quando sarà compiuta, il file verrà aggiunto direttamente al Drive."
|
exportRequested: "Hai richiesto un'esportazione, e potrebbe volerci tempo. Quando sarà compiuta, il file verrà aggiunto direttamente al Drive."
|
||||||
importRequested: "Hai richiesto un'importazione. Potrebbe richiedere un po' di tempo."
|
importRequested: "Hai richiesto un'importazione. Potrebbe richiedere un po' di tempo."
|
||||||
lists: "Liste"
|
lists: "Liste"
|
||||||
noLists: "Nessuna lista"
|
noLists: "Nessuna lista"
|
||||||
note: "Nota"
|
note: "Nota"
|
||||||
notes: "Note"
|
notes: "Note"
|
||||||
following: "Follow"
|
following: "Following"
|
||||||
followers: "Follower"
|
followers: "Follower"
|
||||||
followsYou: "Follower"
|
followsYou: "Follower"
|
||||||
createList: "Aggiungi una nuova lista"
|
createList: "Aggiungi una nuova lista"
|
||||||
|
@ -106,7 +106,7 @@ defaultNoteVisibility: "Privacy predefinita delle note"
|
||||||
follow: "Segui"
|
follow: "Segui"
|
||||||
followRequest: "Richiesta di follow"
|
followRequest: "Richiesta di follow"
|
||||||
followRequests: "Richieste di follow"
|
followRequests: "Richieste di follow"
|
||||||
unfollow: "Smetti di seguire"
|
unfollow: "Togli Following"
|
||||||
followRequestPending: "Richiesta in approvazione"
|
followRequestPending: "Richiesta in approvazione"
|
||||||
enterEmoji: "Inserisci emoji"
|
enterEmoji: "Inserisci emoji"
|
||||||
renote: "Rinota"
|
renote: "Rinota"
|
||||||
|
@ -195,7 +195,7 @@ setWallpaper: "Imposta sfondo"
|
||||||
removeWallpaper: "Elimina lo sfondo"
|
removeWallpaper: "Elimina lo sfondo"
|
||||||
searchWith: "Cerca: {q}"
|
searchWith: "Cerca: {q}"
|
||||||
youHaveNoLists: "Non hai ancora creato nessuna lista"
|
youHaveNoLists: "Non hai ancora creato nessuna lista"
|
||||||
followConfirm: "Vuoi seguire {name}?"
|
followConfirm: "Confermi il Following a {name}?"
|
||||||
proxyAccount: "Profilo proxy"
|
proxyAccount: "Profilo proxy"
|
||||||
proxyAccountDescription: "Un profilo proxy funziona come follower per i profili remoti, sotto certe condizioni. Ad esempio, quando un profilo locale ne inserisce uno remoto in una lista (senza seguirlo), se nessun altro segue quel profilo remoto, le attività non possono essere distribuite. Dunque, il profilo proxy le seguirà per tutti."
|
proxyAccountDescription: "Un profilo proxy funziona come follower per i profili remoti, sotto certe condizioni. Ad esempio, quando un profilo locale ne inserisce uno remoto in una lista (senza seguirlo), se nessun altro segue quel profilo remoto, le attività non possono essere distribuite. Dunque, il profilo proxy le seguirà per tutti."
|
||||||
host: "Host"
|
host: "Host"
|
||||||
|
@ -263,7 +263,7 @@ all: "Tutte"
|
||||||
subscribing: "Iscrizione"
|
subscribing: "Iscrizione"
|
||||||
publishing: "Pubblicazione"
|
publishing: "Pubblicazione"
|
||||||
notResponding: "Nessuna risposta"
|
notResponding: "Nessuna risposta"
|
||||||
instanceFollowing: "Seguiti dall'istanza"
|
instanceFollowing: "Istanza Following"
|
||||||
instanceFollowers: "Follower dell'istanza"
|
instanceFollowers: "Follower dell'istanza"
|
||||||
instanceUsers: "Profili nell'istanza"
|
instanceUsers: "Profili nell'istanza"
|
||||||
changePassword: "Aggiorna Password"
|
changePassword: "Aggiorna Password"
|
||||||
|
@ -382,7 +382,6 @@ enableLocalTimeline: "Abilita la timeline locale"
|
||||||
enableGlobalTimeline: "Abilita la timeline federata"
|
enableGlobalTimeline: "Abilita la timeline federata"
|
||||||
disablingTimelinesInfo: "Anche disabilitandole, gli Amministratori e i Moderatori potranno comunque accedervi."
|
disablingTimelinesInfo: "Anche disabilitandole, gli Amministratori e i Moderatori potranno comunque accedervi."
|
||||||
registration: "Iscriviti"
|
registration: "Iscriviti"
|
||||||
enableRegistration: "Consenti a chiunque di registrarsi"
|
|
||||||
invite: "Invita"
|
invite: "Invita"
|
||||||
driveCapacityPerLocalAccount: "Capienza del Drive per profilo locale"
|
driveCapacityPerLocalAccount: "Capienza del Drive per profilo locale"
|
||||||
driveCapacityPerRemoteAccount: "Capienza del Drive per profilo remoto"
|
driveCapacityPerRemoteAccount: "Capienza del Drive per profilo remoto"
|
||||||
|
@ -615,7 +614,7 @@ unsetUserBannerConfirm: "Vuoi davvero rimuovere l'intestazione dal profilo?"
|
||||||
deleteAllFiles: "Elimina tutti i file"
|
deleteAllFiles: "Elimina tutti i file"
|
||||||
deleteAllFilesConfirm: "Vuoi davvero eliminare tutti i file?"
|
deleteAllFilesConfirm: "Vuoi davvero eliminare tutti i file?"
|
||||||
removeAllFollowing: "Annulla tutti i follow"
|
removeAllFollowing: "Annulla tutti i follow"
|
||||||
removeAllFollowingDescription: "Cancella tutti i follows del server {host}. Per favore, esegui se, ad esempio, l'istanza non esiste più."
|
removeAllFollowingDescription: "Togli il Following a tutti i profili su {host}. Utile, ad esempio, quando l'istanza non esiste più."
|
||||||
userSuspended: "L'utente è in sospensione"
|
userSuspended: "L'utente è in sospensione"
|
||||||
userSilenced: "Profilo silenziato"
|
userSilenced: "Profilo silenziato"
|
||||||
yourAccountSuspendedTitle: "Questo profilo è sospeso"
|
yourAccountSuspendedTitle: "Questo profilo è sospeso"
|
||||||
|
@ -688,7 +687,7 @@ hardWordMute: "Filtro parole forte"
|
||||||
regexpError: "errore regex"
|
regexpError: "errore regex"
|
||||||
regexpErrorDescription: "Si è verificato un errore nell'espressione regolare alla riga {line} della parola muta {tab}:"
|
regexpErrorDescription: "Si è verificato un errore nell'espressione regolare alla riga {line} della parola muta {tab}:"
|
||||||
instanceMute: "Silenziare l'istanza"
|
instanceMute: "Silenziare l'istanza"
|
||||||
userSaysSomething: "{name} ha parlato"
|
userSaysSomething: "{name} ha detto qualcosa"
|
||||||
makeActive: "Attiva"
|
makeActive: "Attiva"
|
||||||
display: "Visualizza"
|
display: "Visualizza"
|
||||||
copy: "Copia"
|
copy: "Copia"
|
||||||
|
@ -703,7 +702,7 @@ notificationSetting: "Impostazioni notifiche"
|
||||||
notificationSettingDesc: "Seleziona il tipo di notifiche da visualizzare."
|
notificationSettingDesc: "Seleziona il tipo di notifiche da visualizzare."
|
||||||
useGlobalSetting: "Usa impostazioni generali"
|
useGlobalSetting: "Usa impostazioni generali"
|
||||||
useGlobalSettingDesc: "Quando attiva, verranno utilizzate le impostazioni notifiche del profilo. Altrimenti si possono segliere impostazioni personalizzate."
|
useGlobalSettingDesc: "Quando attiva, verranno utilizzate le impostazioni notifiche del profilo. Altrimenti si possono segliere impostazioni personalizzate."
|
||||||
other: "Ulteriori"
|
other: "Eccetera"
|
||||||
regenerateLoginToken: "Genera di nuovo un token di connessione"
|
regenerateLoginToken: "Genera di nuovo un token di connessione"
|
||||||
regenerateLoginTokenDescription: "Genera un nuovo token di autenticazione. Solitamente questa operazione non è necessaria: quando si genera un nuovo token, tutti i dispositivi vanno disconnessi."
|
regenerateLoginTokenDescription: "Genera un nuovo token di autenticazione. Solitamente questa operazione non è necessaria: quando si genera un nuovo token, tutti i dispositivi vanno disconnessi."
|
||||||
theKeywordWhenSearchingForCustomEmoji: "Questa sarà la parola chiave durante la ricerca di emoji personalizzate"
|
theKeywordWhenSearchingForCustomEmoji: "Questa sarà la parola chiave durante la ricerca di emoji personalizzate"
|
||||||
|
@ -747,7 +746,7 @@ repliesCount: "Numero di risposte inviate"
|
||||||
renotesCount: "Numero di note che hai ricondiviso"
|
renotesCount: "Numero di note che hai ricondiviso"
|
||||||
repliedCount: "Numero di risposte ricevute"
|
repliedCount: "Numero di risposte ricevute"
|
||||||
renotedCount: "Numero delle tue note ricondivise"
|
renotedCount: "Numero delle tue note ricondivise"
|
||||||
followingCount: "Numero di profili seguiti"
|
followingCount: "Numero di Following"
|
||||||
followersCount: "Numero di profili che ti seguono"
|
followersCount: "Numero di profili che ti seguono"
|
||||||
sentReactionsCount: "Numero di reazioni inviate"
|
sentReactionsCount: "Numero di reazioni inviate"
|
||||||
receivedReactionsCount: "Numero di reazioni ricevute"
|
receivedReactionsCount: "Numero di reazioni ricevute"
|
||||||
|
@ -901,8 +900,8 @@ pubSub: "Publish/Subscribe del profilo"
|
||||||
lastCommunication: "La comunicazione più recente"
|
lastCommunication: "La comunicazione più recente"
|
||||||
resolved: "Risolto"
|
resolved: "Risolto"
|
||||||
unresolved: "Non risolto"
|
unresolved: "Non risolto"
|
||||||
breakFollow: "Impedire di seguirmi"
|
breakFollow: "Rimuovi Follower"
|
||||||
breakFollowConfirm: "Vuoi davvero che questo profilo smetta di seguirti?"
|
breakFollowConfirm: "Vuoi davvero togliere questo Follower?"
|
||||||
itsOn: "Abilitato"
|
itsOn: "Abilitato"
|
||||||
itsOff: "Disabilitato"
|
itsOff: "Disabilitato"
|
||||||
on: "Acceso"
|
on: "Acceso"
|
||||||
|
@ -917,7 +916,7 @@ makeReactionsPublicDescription: "La lista delle reazioni che avete fatto è a di
|
||||||
classic: "Classico"
|
classic: "Classico"
|
||||||
muteThread: "Silenziare conversazione"
|
muteThread: "Silenziare conversazione"
|
||||||
unmuteThread: "Riattiva la conversazione"
|
unmuteThread: "Riattiva la conversazione"
|
||||||
followingVisibility: "Visibilità dei profili seguiti"
|
followingVisibility: "Visibilità dei Following"
|
||||||
followersVisibility: "Visibilità dei profili che ti seguono"
|
followersVisibility: "Visibilità dei profili che ti seguono"
|
||||||
continueThread: "Altre conversazioni"
|
continueThread: "Altre conversazioni"
|
||||||
deleteAccountConfirm: "Così verrà eliminato il profilo. Vuoi procedere?"
|
deleteAccountConfirm: "Così verrà eliminato il profilo. Vuoi procedere?"
|
||||||
|
@ -947,6 +946,9 @@ oneHour: "1 ora"
|
||||||
oneDay: "1 giorno"
|
oneDay: "1 giorno"
|
||||||
oneWeek: "1 settimana"
|
oneWeek: "1 settimana"
|
||||||
oneMonth: "Un mese"
|
oneMonth: "Un mese"
|
||||||
|
threeMonths: "3 mesi"
|
||||||
|
oneYear: "1 anno"
|
||||||
|
threeDays: "3 giorni"
|
||||||
reflectMayTakeTime: "Potrebbe essere necessario un po' di tempo perché ciò abbia effetto."
|
reflectMayTakeTime: "Potrebbe essere necessario un po' di tempo perché ciò abbia effetto."
|
||||||
failedToFetchAccountInformation: "Impossibile recuperare le informazioni sul profilo"
|
failedToFetchAccountInformation: "Impossibile recuperare le informazioni sul profilo"
|
||||||
rateLimitExceeded: "Superato il limite di richieste."
|
rateLimitExceeded: "Superato il limite di richieste."
|
||||||
|
@ -965,7 +967,7 @@ driveCapOverrideLabel: "Modificare la capienza del Drive per questo profilo"
|
||||||
driveCapOverrideCaption: "Se viene specificato meno di 0, viene annullato."
|
driveCapOverrideCaption: "Se viene specificato meno di 0, viene annullato."
|
||||||
requireAdminForView: "Per visualizzarli, è necessario aver effettuato l'accesso con un profilo amministratore."
|
requireAdminForView: "Per visualizzarli, è necessario aver effettuato l'accesso con un profilo amministratore."
|
||||||
isSystemAccount: "Questi profili vengono creati e gestiti automaticamente dal sistema"
|
isSystemAccount: "Questi profili vengono creati e gestiti automaticamente dal sistema"
|
||||||
typeToConfirm: "Per eseguire questa operazione, digitare {x}"
|
typeToConfirm: "Digita {x} per continuare"
|
||||||
deleteAccount: "Eliminazione profilo"
|
deleteAccount: "Eliminazione profilo"
|
||||||
document: "Documento"
|
document: "Documento"
|
||||||
numberOfPageCache: "Numero di pagine cache"
|
numberOfPageCache: "Numero di pagine cache"
|
||||||
|
@ -1020,7 +1022,7 @@ neverShow: "Non mostrare più"
|
||||||
remindMeLater: "Rimanda"
|
remindMeLater: "Rimanda"
|
||||||
didYouLikeMisskey: "Ti piace Misskey?"
|
didYouLikeMisskey: "Ti piace Misskey?"
|
||||||
pleaseDonate: "Misskey è il software libero utilizzato su {host}. Offrendo una donazione è più facile continuare a svilupparlo!"
|
pleaseDonate: "Misskey è il software libero utilizzato su {host}. Offrendo una donazione è più facile continuare a svilupparlo!"
|
||||||
correspondingSourceIsAvailable: ""
|
correspondingSourceIsAvailable: "Il codice sorgente corrispondente è disponibile su {anchor}."
|
||||||
roles: "Ruoli"
|
roles: "Ruoli"
|
||||||
role: "Ruolo"
|
role: "Ruolo"
|
||||||
noRole: "Ruolo non trovato"
|
noRole: "Ruolo non trovato"
|
||||||
|
@ -1130,7 +1132,7 @@ channelArchiveConfirmDescription: "Un canale archiviato non compare nell'elenco
|
||||||
thisChannelArchived: "Questo canale è stato archiviato."
|
thisChannelArchived: "Questo canale è stato archiviato."
|
||||||
displayOfNote: "Visualizzazione delle Note"
|
displayOfNote: "Visualizzazione delle Note"
|
||||||
initialAccountSetting: "Impostazioni iniziali del profilo"
|
initialAccountSetting: "Impostazioni iniziali del profilo"
|
||||||
youFollowing: "Seguiti"
|
youFollowing: "Following"
|
||||||
preventAiLearning: "Impedisci l'apprendimento della IA"
|
preventAiLearning: "Impedisci l'apprendimento della IA"
|
||||||
preventAiLearningDescription: "Aggiungendo il campo \"noai\" alla risposta HTML, si indica ai Robot esterni di non usare testi e allegati per addestrare sistemi di Machine Learning (IA predittiva/generativa). Anche se è impossibile sapere se la richiesta venga onorata o semplicemente ignorata."
|
preventAiLearningDescription: "Aggiungendo il campo \"noai\" alla risposta HTML, si indica ai Robot esterni di non usare testi e allegati per addestrare sistemi di Machine Learning (IA predittiva/generativa). Anche se è impossibile sapere se la richiesta venga onorata o semplicemente ignorata."
|
||||||
options: "Opzioni del ruolo"
|
options: "Opzioni del ruolo"
|
||||||
|
@ -1293,6 +1295,21 @@ prohibitedWordsForNameOfUser: "Parole proibite (nome utente)"
|
||||||
prohibitedWordsForNameOfUserDescription: "Il sistema rifiuta di rinominare un utente, se il nome contiene qualsiasi parola nell'elenco. Sono esenti i profili con privilegi di moderazione."
|
prohibitedWordsForNameOfUserDescription: "Il sistema rifiuta di rinominare un utente, se il nome contiene qualsiasi parola nell'elenco. Sono esenti i profili con privilegi di moderazione."
|
||||||
yourNameContainsProhibitedWords: "Il nome che hai scelto contiene una o più parole vietate"
|
yourNameContainsProhibitedWords: "Il nome che hai scelto contiene una o più parole vietate"
|
||||||
yourNameContainsProhibitedWordsDescription: "Se desideri comunque utilizzare questo nome, contatta l''amministrazione."
|
yourNameContainsProhibitedWordsDescription: "Se desideri comunque utilizzare questo nome, contatta l''amministrazione."
|
||||||
|
thisContentsAreMarkedAsSigninRequiredByAuthor: "L'autore richiede di iscriversi per vedere il contenuto"
|
||||||
|
lockdown: "Isolamento"
|
||||||
|
pleaseSelectAccount: "Per favore, seleziona un profilo"
|
||||||
|
_accountSettings:
|
||||||
|
requireSigninToViewContents: "Per vedere il contenuto, è necessaria l'iscrizione"
|
||||||
|
requireSigninToViewContentsDescription1: "Richiedere l'iscrizione per visualizzare tutte le Note e gli altri contenuti che hai creato. Probabilmente l'effetto è impedire la raccolta di informazioni da parte dei bot crawler."
|
||||||
|
requireSigninToViewContentsDescription2: "La visualizzazione verrà disabilitata a server che non supportano l'anteprima URL (OGP), all'incorporamento nelle pagine Web e alla citazione delle Note."
|
||||||
|
requireSigninToViewContentsDescription3: "Queste restrizioni potrebbero non applicarsi al contenuto federato su server remoti."
|
||||||
|
makeNotesFollowersOnlyBefore: "Rendi visibili solo ai Follower le Note pubblicate in precedenza"
|
||||||
|
makeNotesFollowersOnlyBeforeDescription: "Mentre questa funzione è abilitata, le Note antecedenti al momento impostato, saranno visibili solo ai profili Follower. Disabilitandola nuovamente, verrà ripristinata anche la visibilità pubblica della Nota."
|
||||||
|
makeNotesHiddenBefore: "Nascondi le Note pubblicate in precedenza"
|
||||||
|
makeNotesHiddenBeforeDescription: "Mentre questa funzione è abilitata, le Note antecedenti al momento impostato, saranno visibili soltanto a te (private). Disabilitandola nuovamente, verrà ripristinata anche la visibilità pubblica della Nota."
|
||||||
|
mayNotEffectForFederatedNotes: "Le Note già federate su server remoti potrebbero non essere modificate."
|
||||||
|
notesHavePassedSpecifiedPeriod: "Note antecedenti al periodo specificato"
|
||||||
|
notesOlderThanSpecifiedDateAndTime: "Note antecedenti al momento specificato"
|
||||||
_abuseUserReport:
|
_abuseUserReport:
|
||||||
forward: "Inoltra"
|
forward: "Inoltra"
|
||||||
forwardDescription: "Inoltra il report al server remoto, per mezzo di account di sistema, anonimo."
|
forwardDescription: "Inoltra il report al server remoto, per mezzo di account di sistema, anonimo."
|
||||||
|
@ -1378,7 +1395,7 @@ _initialTutorial:
|
||||||
_timeline:
|
_timeline:
|
||||||
title: "Come funziona la Timeline"
|
title: "Come funziona la Timeline"
|
||||||
description1: "Misskey fornisce alcune Timeline (sequenze cronologiche di Note). Una di queste potrebbe essere stata disattivata dagli amministratori."
|
description1: "Misskey fornisce alcune Timeline (sequenze cronologiche di Note). Una di queste potrebbe essere stata disattivata dagli amministratori."
|
||||||
home: "le Note provenienti dai profili che segui (follow)."
|
home: "le Note provenienti dai profili che segui (Following)."
|
||||||
local: "tutte le Note pubblicate dai profili di questa istanza."
|
local: "tutte le Note pubblicate dai profili di questa istanza."
|
||||||
social: "sia le Note della Timeline Home che quelle della Timeline Locale, insieme!"
|
social: "sia le Note della Timeline Home che quelle della Timeline Locale, insieme!"
|
||||||
global: "le Note da pubblicate da tutte le altre istanze federate con la nostra."
|
global: "le Note da pubblicate da tutte le altre istanze federate con la nostra."
|
||||||
|
@ -1416,7 +1433,7 @@ _initialTutorial:
|
||||||
title: "Il tutorial è finito! 🎉"
|
title: "Il tutorial è finito! 🎉"
|
||||||
description: "Queste sono solamente alcune delle funzionalità principali di Misskey. Per ulteriori informazioni, {link}."
|
description: "Queste sono solamente alcune delle funzionalità principali di Misskey. Per ulteriori informazioni, {link}."
|
||||||
_timelineDescription:
|
_timelineDescription:
|
||||||
home: "Nella Timeline Home, la tua cronologia principale, puoi vedere le Note provenienti dai profili che segui (follow)."
|
home: "Nella Timeline Home, la tua cronologia principale, puoi vedere le Note provenienti dai profili che segui (Following)."
|
||||||
local: "La Timeline Locale, è una cronologia di Note pubblicate da tutti i profili iscritti su questo server."
|
local: "La Timeline Locale, è una cronologia di Note pubblicate da tutti i profili iscritti su questo server."
|
||||||
social: "La Timeline Sociale, unisce in ordine cronologico l'elenco di Note presenti nella Timeline Home e quella Locale."
|
social: "La Timeline Sociale, unisce in ordine cronologico l'elenco di Note presenti nella Timeline Home e quella Locale."
|
||||||
global: "La Timeline Federata ti consente di vedere le Note pubblicate dai profili di tutti gli altri server federati a questo."
|
global: "La Timeline Federata ti consente di vedere le Note pubblicate dai profili di tutti gli altri server federati a questo."
|
||||||
|
@ -1442,7 +1459,7 @@ _accountMigration:
|
||||||
moveFrom: "Migra un altro profilo dentro a questo"
|
moveFrom: "Migra un altro profilo dentro a questo"
|
||||||
moveFromSub: "Crea un alias verso un altro profilo remoto"
|
moveFromSub: "Crea un alias verso un altro profilo remoto"
|
||||||
moveFromLabel: "Profilo da cui migrare #{n}"
|
moveFromLabel: "Profilo da cui migrare #{n}"
|
||||||
moveFromDescription: "Se desideri spostare i profili follower da un altro profilo a questo, devi prima creare un alias qui. Assicurati averlo creato PRIMA di eseguire l'attività! Inserisci l'indirizzo del profilo mittente in questo modo: @persona@istanza.it"
|
moveFromDescription: "Se desideri spostare i Follower da un altro profilo a questo, devi prima creare un alias qui. Assicurati averlo creato PRIMA di eseguire l'attività! Inserisci l'indirizzo del profilo mittente in questo modo: @persona@istanza.it"
|
||||||
moveTo: "Migrare questo profilo verso un un altro"
|
moveTo: "Migrare questo profilo verso un un altro"
|
||||||
moveToLabel: "Profilo verso cui migrare"
|
moveToLabel: "Profilo verso cui migrare"
|
||||||
moveCannotBeUndone: "La migrazione è irreversibile, non può essere interrotta o annullata."
|
moveCannotBeUndone: "La migrazione è irreversibile, non può essere interrotta o annullata."
|
||||||
|
@ -1451,7 +1468,7 @@ _accountMigration:
|
||||||
startMigration: "Avvia la migrazione"
|
startMigration: "Avvia la migrazione"
|
||||||
migrationConfirm: "Vuoi davvero migrare questo profilo su {account}? L'azione è irreversibile e non potrai più utilizzare questo profilo nel suo stato originale.\nInoltre, assicurati di aver già creato un alias sull'account a cui ti stai trasferendo."
|
migrationConfirm: "Vuoi davvero migrare questo profilo su {account}? L'azione è irreversibile e non potrai più utilizzare questo profilo nel suo stato originale.\nInoltre, assicurati di aver già creato un alias sull'account a cui ti stai trasferendo."
|
||||||
movedAndCannotBeUndone: "Il tuo profilo è stato migrato.\nLa migrazione non può essere annullata."
|
movedAndCannotBeUndone: "Il tuo profilo è stato migrato.\nLa migrazione non può essere annullata."
|
||||||
postMigrationNote: "Questo profilo smetterà di seguire gli altri profili remoti a 24 ore dal termine della migrazione.\nSia i Follow che i Follower scenderanno a zero. I tuoi follower saranno comunque in grado di vedere le Note per soli follower, poiché non smetteranno di seguirti."
|
postMigrationNote: "Questo profilo smetterà di seguire gli altri profili remoti a 24 ore dal termine della migrazione.\nSia i Following che i Follower scenderanno a zero. I tuoi Follower saranno comunque in grado di vedere le Note per soli Follower, poiché non smetteranno di seguirti."
|
||||||
movedTo: "Profilo verso cui migrare"
|
movedTo: "Profilo verso cui migrare"
|
||||||
_achievements:
|
_achievements:
|
||||||
earnedAt: "Data di conseguimento"
|
earnedAt: "Data di conseguimento"
|
||||||
|
@ -1844,7 +1861,7 @@ _gallery:
|
||||||
unlike: "Non mi piace più"
|
unlike: "Non mi piace più"
|
||||||
_email:
|
_email:
|
||||||
_follow:
|
_follow:
|
||||||
title: "Adesso ti segue"
|
title: "Follower aggiuntivo"
|
||||||
_receiveFollowRequest:
|
_receiveFollowRequest:
|
||||||
title: "Hai ricevuto una richiesta di follow"
|
title: "Hai ricevuto una richiesta di follow"
|
||||||
_plugin:
|
_plugin:
|
||||||
|
@ -1908,7 +1925,7 @@ _channel:
|
||||||
removeBanner: "Rimuovi intestazione"
|
removeBanner: "Rimuovi intestazione"
|
||||||
featured: "Di tendenza"
|
featured: "Di tendenza"
|
||||||
owned: "I miei canali"
|
owned: "I miei canali"
|
||||||
following: "Seguiti"
|
following: "Following"
|
||||||
usersCount: "{n} partecipanti"
|
usersCount: "{n} partecipanti"
|
||||||
notesCount: "{n} note"
|
notesCount: "{n} note"
|
||||||
nameAndDescription: "Nome e descrizione"
|
nameAndDescription: "Nome e descrizione"
|
||||||
|
@ -2074,7 +2091,7 @@ _permissions:
|
||||||
"read:favorites": "Visualizza i tuoi preferiti"
|
"read:favorites": "Visualizza i tuoi preferiti"
|
||||||
"write:favorites": "Gestisci i tuoi preferiti"
|
"write:favorites": "Gestisci i tuoi preferiti"
|
||||||
"read:following": "Vedi le informazioni di follow"
|
"read:following": "Vedi le informazioni di follow"
|
||||||
"write:following": "Following di altri profili"
|
"write:following": "Aggiungere e togliere Following"
|
||||||
"read:messaging": "Visualizzare la chat"
|
"read:messaging": "Visualizzare la chat"
|
||||||
"write:messaging": "Gestire la chat"
|
"write:messaging": "Gestire la chat"
|
||||||
"read:mutes": "Vedi i profili silenziati"
|
"read:mutes": "Vedi i profili silenziati"
|
||||||
|
@ -2157,11 +2174,14 @@ _auth:
|
||||||
permissionAsk: "Questa app richiede le seguenti autorizzazioni:"
|
permissionAsk: "Questa app richiede le seguenti autorizzazioni:"
|
||||||
pleaseGoBack: "Si prega di ritornare sulla app"
|
pleaseGoBack: "Si prega di ritornare sulla app"
|
||||||
callback: "Ritornando sulla app"
|
callback: "Ritornando sulla app"
|
||||||
|
accepted: "Accesso concesso"
|
||||||
denied: "Accesso negato"
|
denied: "Accesso negato"
|
||||||
|
scopeUser: "Sto funzionando per il seguente profilo"
|
||||||
pleaseLogin: "Per favore accedi al tuo account per cambiare i permessi dell'applicazione"
|
pleaseLogin: "Per favore accedi al tuo account per cambiare i permessi dell'applicazione"
|
||||||
|
byClickingYouWillBeRedirectedToThisUrl: "Consentendo l'accesso, si verrà reindirizzati presso questo indirizzo URL"
|
||||||
_antennaSources:
|
_antennaSources:
|
||||||
all: "Tutte le note"
|
all: "Tutte le note"
|
||||||
homeTimeline: "Note dagli utenti che segui"
|
homeTimeline: "Note dai tuoi Following"
|
||||||
users: "Note dagli utenti selezionati"
|
users: "Note dagli utenti selezionati"
|
||||||
userList: "Note dagli utenti della lista selezionata"
|
userList: "Note dagli utenti della lista selezionata"
|
||||||
userBlacklist: "Tutte le Note tranne quelle di uno o più profili specificati"
|
userBlacklist: "Tutte le Note tranne quelle di uno o più profili specificati"
|
||||||
|
@ -2274,7 +2294,7 @@ _exportOrImport:
|
||||||
allNotes: "Tutte le note"
|
allNotes: "Tutte le note"
|
||||||
favoritedNotes: "Note preferite"
|
favoritedNotes: "Note preferite"
|
||||||
clips: "Clip"
|
clips: "Clip"
|
||||||
followingList: "Follow"
|
followingList: "Following"
|
||||||
muteList: "Elenco profili silenziati"
|
muteList: "Elenco profili silenziati"
|
||||||
blockingList: "Elenco profili bloccati"
|
blockingList: "Elenco profili bloccati"
|
||||||
userLists: "Liste"
|
userLists: "Liste"
|
||||||
|
@ -2390,7 +2410,7 @@ _notification:
|
||||||
youGotReply: "{name} ti ha risposto"
|
youGotReply: "{name} ti ha risposto"
|
||||||
youGotQuote: "{name} ha citato la tua Nota e ha detto"
|
youGotQuote: "{name} ha citato la tua Nota e ha detto"
|
||||||
youRenoted: "{name} ha rinotato"
|
youRenoted: "{name} ha rinotato"
|
||||||
youWereFollowed: "Adesso ti segue"
|
youWereFollowed: "Follower aggiuntivo"
|
||||||
youReceivedFollowRequest: "Hai ricevuto una richiesta di follow"
|
youReceivedFollowRequest: "Hai ricevuto una richiesta di follow"
|
||||||
yourFollowRequestAccepted: "La tua richiesta di follow è stata accettata"
|
yourFollowRequestAccepted: "La tua richiesta di follow è stata accettata"
|
||||||
pollEnded: "Risultati del sondaggio."
|
pollEnded: "Risultati del sondaggio."
|
||||||
|
@ -2413,7 +2433,7 @@ _notification:
|
||||||
_types:
|
_types:
|
||||||
all: "Tutto"
|
all: "Tutto"
|
||||||
note: "Nuove Note"
|
note: "Nuove Note"
|
||||||
follow: "Nuovi profili follower"
|
follow: "Follower"
|
||||||
mention: "Menzioni"
|
mention: "Menzioni"
|
||||||
reply: "Risposte"
|
reply: "Risposte"
|
||||||
renote: "Rinota"
|
renote: "Rinota"
|
||||||
|
@ -2429,7 +2449,7 @@ _notification:
|
||||||
test: "Prova la notifica"
|
test: "Prova la notifica"
|
||||||
app: "Notifiche da applicazioni"
|
app: "Notifiche da applicazioni"
|
||||||
_actions:
|
_actions:
|
||||||
followBack: "Segui"
|
followBack: "Following ricambiato"
|
||||||
reply: "Rispondi"
|
reply: "Rispondi"
|
||||||
renote: "Rinota"
|
renote: "Rinota"
|
||||||
_deck:
|
_deck:
|
||||||
|
@ -2481,7 +2501,7 @@ _webhookSettings:
|
||||||
trigger: "Trigger"
|
trigger: "Trigger"
|
||||||
active: "Attivo"
|
active: "Attivo"
|
||||||
_events:
|
_events:
|
||||||
follow: "Quando segui un profilo"
|
follow: "Quando aggiungi Following"
|
||||||
followed: "Quando ti segue un profilo"
|
followed: "Quando ti segue un profilo"
|
||||||
note: "Quando pubblichi una Nota"
|
note: "Quando pubblichi una Nota"
|
||||||
reply: "Quando rispondono ad una Nota"
|
reply: "Quando rispondono ad una Nota"
|
||||||
|
@ -2710,3 +2730,9 @@ _embedCodeGen:
|
||||||
generateCode: "Crea il codice di incorporamento"
|
generateCode: "Crea il codice di incorporamento"
|
||||||
codeGenerated: "Codice generato"
|
codeGenerated: "Codice generato"
|
||||||
codeGeneratedDescription: "Incolla il codice appena generato sul tuo sito web."
|
codeGeneratedDescription: "Incolla il codice appena generato sul tuo sito web."
|
||||||
|
_selfXssPrevention:
|
||||||
|
warning: "Avviso"
|
||||||
|
title: "\"Incolla qualcosa su questa schermata\" è tutta una truffa."
|
||||||
|
description1: "Incollando qualcosa qui, malintenzionati potrebbero prendere il controllo del tuo profilo o rubare i tuoi dati personali."
|
||||||
|
description2: "Se non sai esattamente cosa stai facendo, %c smetti subito e chiudi questa finestra."
|
||||||
|
description3: "Per favore, controlla questo collegamento per avere maggiori dettagli. {link}"
|
||||||
|
|
|
@ -382,7 +382,6 @@ enableLocalTimeline: "ローカルタイムラインを有効にする"
|
||||||
enableGlobalTimeline: "グローバルタイムラインを有効にする"
|
enableGlobalTimeline: "グローバルタイムラインを有効にする"
|
||||||
disablingTimelinesInfo: "これらのタイムラインを無効化しても、利便性のため管理者およびモデレーターは引き続き利用することができます。"
|
disablingTimelinesInfo: "これらのタイムラインを無効化しても、利便性のため管理者およびモデレーターは引き続き利用することができます。"
|
||||||
registration: "登録"
|
registration: "登録"
|
||||||
enableRegistration: "誰でも新規登録できるようにする"
|
|
||||||
invite: "招待"
|
invite: "招待"
|
||||||
driveCapacityPerLocalAccount: "ローカルユーザーひとりあたりのドライブ容量"
|
driveCapacityPerLocalAccount: "ローカルユーザーひとりあたりのドライブ容量"
|
||||||
driveCapacityPerRemoteAccount: "リモートユーザーひとりあたりのドライブ容量"
|
driveCapacityPerRemoteAccount: "リモートユーザーひとりあたりのドライブ容量"
|
||||||
|
@ -587,6 +586,7 @@ masterVolume: "マスター音量"
|
||||||
notUseSound: "サウンドを出力しない"
|
notUseSound: "サウンドを出力しない"
|
||||||
useSoundOnlyWhenActive: "Misskeyがアクティブな時のみサウンドを出力する"
|
useSoundOnlyWhenActive: "Misskeyがアクティブな時のみサウンドを出力する"
|
||||||
details: "詳細"
|
details: "詳細"
|
||||||
|
renoteDetails: "リノートの詳細"
|
||||||
chooseEmoji: "絵文字を選択"
|
chooseEmoji: "絵文字を選択"
|
||||||
unableToProcess: "操作を完了できません"
|
unableToProcess: "操作を完了できません"
|
||||||
recentUsed: "最近使用"
|
recentUsed: "最近使用"
|
||||||
|
@ -1298,6 +1298,9 @@ yourNameContainsProhibitedWords: "変更しようとした名前に禁止され
|
||||||
yourNameContainsProhibitedWordsDescription: "名前に禁止されている文字列が含まれています。この名前を使用したい場合は、サーバー管理者にお問い合わせください。"
|
yourNameContainsProhibitedWordsDescription: "名前に禁止されている文字列が含まれています。この名前を使用したい場合は、サーバー管理者にお問い合わせください。"
|
||||||
thisContentsAreMarkedAsSigninRequiredByAuthor: "投稿者により、表示にはログインが必要と設定されています"
|
thisContentsAreMarkedAsSigninRequiredByAuthor: "投稿者により、表示にはログインが必要と設定されています"
|
||||||
lockdown: "ロックダウン"
|
lockdown: "ロックダウン"
|
||||||
|
pleaseSelectAccount: "アカウントを選択してください"
|
||||||
|
availableRoles: "利用可能なロール"
|
||||||
|
acknowledgeNotesAndEnable: "注意事項を理解した上でオンにします。"
|
||||||
|
|
||||||
_accountSettings:
|
_accountSettings:
|
||||||
requireSigninToViewContents: "コンテンツの表示にログインを必須にする"
|
requireSigninToViewContents: "コンテンツの表示にログインを必須にする"
|
||||||
|
@ -1464,6 +1467,8 @@ _serverSettings:
|
||||||
reactionsBufferingDescription: "有効にすると、リアクション作成時のパフォーマンスが大幅に向上し、データベースへの負荷を軽減することが可能です。ただし、Redisのメモリ使用量は増加します。"
|
reactionsBufferingDescription: "有効にすると、リアクション作成時のパフォーマンスが大幅に向上し、データベースへの負荷を軽減することが可能です。ただし、Redisのメモリ使用量は増加します。"
|
||||||
inquiryUrl: "問い合わせ先URL"
|
inquiryUrl: "問い合わせ先URL"
|
||||||
inquiryUrlDescription: "サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定します。"
|
inquiryUrlDescription: "サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定します。"
|
||||||
|
openRegistration: "アカウントの作成をオープンにする"
|
||||||
|
openRegistrationWarning: "登録を開放することはリスクが伴います。サーバーを常に監視し、トラブルが発生した際にすぐに対応できる体制がある場合のみオンにすることを推奨します。"
|
||||||
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "一定期間モデレーターのアクティビティが検出されなかった場合、スパム防止のためこの設定は自動でオフになります。"
|
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "一定期間モデレーターのアクティビティが検出されなかった場合、スパム防止のためこの設定は自動でオフになります。"
|
||||||
|
|
||||||
_accountMigration:
|
_accountMigration:
|
||||||
|
@ -2217,8 +2222,11 @@ _auth:
|
||||||
permissionAsk: "このアプリは次の権限を要求しています"
|
permissionAsk: "このアプリは次の権限を要求しています"
|
||||||
pleaseGoBack: "アプリケーションに戻ってやっていってください"
|
pleaseGoBack: "アプリケーションに戻ってやっていってください"
|
||||||
callback: "アプリケーションに戻っています"
|
callback: "アプリケーションに戻っています"
|
||||||
|
accepted: "アクセスを許可しました"
|
||||||
denied: "アクセスを拒否しました"
|
denied: "アクセスを拒否しました"
|
||||||
|
scopeUser: "以下のユーザーとして操作しています"
|
||||||
pleaseLogin: "アプリケーションにアクセス許可を与えるには、ログインが必要です。"
|
pleaseLogin: "アプリケーションにアクセス許可を与えるには、ログインが必要です。"
|
||||||
|
byClickingYouWillBeRedirectedToThisUrl: "アクセスを許可すると、自動で以下のURLに遷移します"
|
||||||
|
|
||||||
_antennaSources:
|
_antennaSources:
|
||||||
all: "全てのノート"
|
all: "全てのノート"
|
||||||
|
@ -2807,3 +2815,14 @@ _embedCodeGen:
|
||||||
generateCode: "埋め込みコードを作成"
|
generateCode: "埋め込みコードを作成"
|
||||||
codeGenerated: "コードが生成されました"
|
codeGenerated: "コードが生成されました"
|
||||||
codeGeneratedDescription: "生成されたコードをウェブサイトに貼り付けてご利用ください。"
|
codeGeneratedDescription: "生成されたコードをウェブサイトに貼り付けてご利用ください。"
|
||||||
|
|
||||||
|
_selfXssPrevention:
|
||||||
|
warning: "警告"
|
||||||
|
title: "「この画面に何か貼り付けろ」はすべて詐欺です。"
|
||||||
|
description1: "ここに何かを貼り付けると、悪意のあるユーザーにアカウントを乗っ取られたり、個人情報を盗まれたりする可能性があります。"
|
||||||
|
description2: "貼り付けようとしているものが何なのかを正確に理解していない場合は、%c今すぐ作業を中止してこのウィンドウを閉じてください。"
|
||||||
|
description3: "詳しくはこちらをご確認ください。 {link}"
|
||||||
|
|
||||||
|
_followRequest:
|
||||||
|
recieved: "受け取った申請"
|
||||||
|
sent: "送った申請"
|
||||||
|
|
|
@ -8,6 +8,9 @@ search: "探す"
|
||||||
notifications: "通知"
|
notifications: "通知"
|
||||||
username: "ユーザー名"
|
username: "ユーザー名"
|
||||||
password: "パスワード"
|
password: "パスワード"
|
||||||
|
initialPasswordForSetup: "初期設定開始用パスワード"
|
||||||
|
initialPasswordIsIncorrect: "初期設定開始用のパスワードがちゃうで。"
|
||||||
|
initialPasswordForSetupDescription: "Miskkeyを自分でインストールしたんやったら、設定ファイルに入れたパスワードを使ってや。\nホスティングサービスを使っとるんやったら、サービスから言われたやつを使うんやで。\n別に何も設定しとらんのやったら、何も入れずに空けといてな。"
|
||||||
forgotPassword: "パスワード忘れたん?"
|
forgotPassword: "パスワード忘れたん?"
|
||||||
fetchingAsApObject: "今ちと連合に照会しとるで"
|
fetchingAsApObject: "今ちと連合に照会しとるで"
|
||||||
ok: "ええで"
|
ok: "ええで"
|
||||||
|
@ -236,6 +239,8 @@ silencedInstances: "サーバーサイレンスされてんねん"
|
||||||
silencedInstancesDescription: "サイレンスしたいサーバーのホストを改行で区切って設定すんで。サイレンスされたサーバーに所属するアカウントはすべて「サイレンス」として扱われ、フォローがすべてリクエストになり、フォロワーでないローカルアカウントにはメンションできなくなんねん。ブロックしたインスタンスには影響せーへんで。"
|
silencedInstancesDescription: "サイレンスしたいサーバーのホストを改行で区切って設定すんで。サイレンスされたサーバーに所属するアカウントはすべて「サイレンス」として扱われ、フォローがすべてリクエストになり、フォロワーでないローカルアカウントにはメンションできなくなんねん。ブロックしたインスタンスには影響せーへんで。"
|
||||||
mediaSilencedInstances: "メディアサイレンスしたサーバー"
|
mediaSilencedInstances: "メディアサイレンスしたサーバー"
|
||||||
mediaSilencedInstancesDescription: "メディアサイレンスしたいサーバーのホストを改行で区切って設定するで。メディアサイレンスされたサーバーに所属するアカウントによるファイルはすべてセンシティブとして扱われてな、カスタム絵文字が使えへんようになるで。ブロックしたインスタンスには影響せえへんで。"
|
mediaSilencedInstancesDescription: "メディアサイレンスしたいサーバーのホストを改行で区切って設定するで。メディアサイレンスされたサーバーに所属するアカウントによるファイルはすべてセンシティブとして扱われてな、カスタム絵文字が使えへんようになるで。ブロックしたインスタンスには影響せえへんで。"
|
||||||
|
federationAllowedHosts: "連合を許すサーバー"
|
||||||
|
federationAllowedHostsDescription: "連合してもいいサーバーのホストを行ごとに区切って設定してや。"
|
||||||
muteAndBlock: "ミュートとブロック"
|
muteAndBlock: "ミュートとブロック"
|
||||||
mutedUsers: "ミュートしとるユーザー"
|
mutedUsers: "ミュートしとるユーザー"
|
||||||
blockedUsers: "ブロックしとるユーザー"
|
blockedUsers: "ブロックしとるユーザー"
|
||||||
|
@ -334,6 +339,7 @@ renameFolder: "フォルダー名を変える"
|
||||||
deleteFolder: "フォルダーをほかす"
|
deleteFolder: "フォルダーをほかす"
|
||||||
folder: "フォルダー"
|
folder: "フォルダー"
|
||||||
addFile: "ファイルを追加"
|
addFile: "ファイルを追加"
|
||||||
|
showFile: "ファイル出す"
|
||||||
emptyDrive: "ドライブは空っぽや"
|
emptyDrive: "ドライブは空っぽや"
|
||||||
emptyFolder: "このフォルダーは空や"
|
emptyFolder: "このフォルダーは空や"
|
||||||
unableToDelete: "消せんかったわ"
|
unableToDelete: "消せんかったわ"
|
||||||
|
@ -376,7 +382,6 @@ enableLocalTimeline: "ローカルタイムラインを使えるようにする
|
||||||
enableGlobalTimeline: "グローバルタイムラインを使えるようにするわ"
|
enableGlobalTimeline: "グローバルタイムラインを使えるようにするわ"
|
||||||
disablingTimelinesInfo: "ここらへんのタイムラインを使えんようにしてしもても、管理者とモデレーターは使えるままになってるで、そうやなかったら不便やからな。"
|
disablingTimelinesInfo: "ここらへんのタイムラインを使えんようにしてしもても、管理者とモデレーターは使えるままになってるで、そうやなかったら不便やからな。"
|
||||||
registration: "登録"
|
registration: "登録"
|
||||||
enableRegistration: "一見さんでも誰でもいらっしゃ~い"
|
|
||||||
invite: "来てや"
|
invite: "来てや"
|
||||||
driveCapacityPerLocalAccount: "ローカルユーザーはんひとりあたりのドライブ容量"
|
driveCapacityPerLocalAccount: "ローカルユーザーはんひとりあたりのドライブ容量"
|
||||||
driveCapacityPerRemoteAccount: "リモートユーザーはんひとりあたりのドライブ容量"
|
driveCapacityPerRemoteAccount: "リモートユーザーはんひとりあたりのドライブ容量"
|
||||||
|
@ -448,6 +453,7 @@ totpDescription: "認証アプリ使うてワンタイムパスワードを入
|
||||||
moderator: "モデレーター"
|
moderator: "モデレーター"
|
||||||
moderation: "モデレーション"
|
moderation: "モデレーション"
|
||||||
moderationNote: "モデレーションノート"
|
moderationNote: "モデレーションノート"
|
||||||
|
moderationNoteDescription: "モデレーターの中だけで共有するメモを入れれるで。"
|
||||||
addModerationNote: "モデレーションノートを追加するで"
|
addModerationNote: "モデレーションノートを追加するで"
|
||||||
moderationLogs: "モデログ"
|
moderationLogs: "モデログ"
|
||||||
nUsersMentioned: "{n}人が投稿"
|
nUsersMentioned: "{n}人が投稿"
|
||||||
|
@ -509,6 +515,10 @@ uiLanguage: "UIの表示言語"
|
||||||
aboutX: "{x}について"
|
aboutX: "{x}について"
|
||||||
emojiStyle: "絵文字のスタイル"
|
emojiStyle: "絵文字のスタイル"
|
||||||
native: "ネイティブ"
|
native: "ネイティブ"
|
||||||
|
menuStyle: "メニューのスタイル"
|
||||||
|
style: "スタイル"
|
||||||
|
drawer: "ドロワー"
|
||||||
|
popup: "ポップアップ"
|
||||||
showNoteActionsOnlyHover: "ノートの操作部をホバー時のみ表示するで"
|
showNoteActionsOnlyHover: "ノートの操作部をホバー時のみ表示するで"
|
||||||
showReactionsCount: "ノートのリアクション数を表示する"
|
showReactionsCount: "ノートのリアクション数を表示する"
|
||||||
noHistory: "履歴はないわ。"
|
noHistory: "履歴はないわ。"
|
||||||
|
@ -591,6 +601,8 @@ ascendingOrder: "小さい順"
|
||||||
descendingOrder: "大きい順"
|
descendingOrder: "大きい順"
|
||||||
scratchpad: "スクラッチパッド"
|
scratchpad: "スクラッチパッド"
|
||||||
scratchpadDescription: "スクラッチパッドではAiScriptを色々試すことができるんや。Misskeyに対して色々できるコードを書いて動かしてみたり、結果を見たりできるで。"
|
scratchpadDescription: "スクラッチパッドではAiScriptを色々試すことができるんや。Misskeyに対して色々できるコードを書いて動かしてみたり、結果を見たりできるで。"
|
||||||
|
uiInspector: "UIインスペクター"
|
||||||
|
uiInspectorDescription: "メモリ上にあるUIコンポーネントのインスタンス一覧を見れるで。UIコンポーネントはUi:C:系関数で生成されるで。"
|
||||||
output: "出力"
|
output: "出力"
|
||||||
script: "スクリプト"
|
script: "スクリプト"
|
||||||
disablePagesScript: "Pagesのスクリプトを無効にしてや"
|
disablePagesScript: "Pagesのスクリプトを無効にしてや"
|
||||||
|
@ -909,6 +921,7 @@ followersVisibility: "フォロワーの公開範囲"
|
||||||
continueThread: "さらにスレッドを見るで"
|
continueThread: "さらにスレッドを見るで"
|
||||||
deleteAccountConfirm: "アカウントを消すで?ええんか?"
|
deleteAccountConfirm: "アカウントを消すで?ええんか?"
|
||||||
incorrectPassword: "パスワードがちゃうわ。"
|
incorrectPassword: "パスワードがちゃうわ。"
|
||||||
|
incorrectTotp: "ワンタイムパスワードが間違っとるか、期限が切れとるみたいやな。"
|
||||||
voteConfirm: "「{choice}」に投票するんか?"
|
voteConfirm: "「{choice}」に投票するんか?"
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
useDrawerReactionPickerForMobile: "ケータイとかのときドロワーで表示するで"
|
useDrawerReactionPickerForMobile: "ケータイとかのときドロワーで表示するで"
|
||||||
|
@ -1073,6 +1086,7 @@ retryAllQueuesConfirmTitle: "もっかいやってみるか?"
|
||||||
retryAllQueuesConfirmText: "一時的にサーバー重なるかもしれへんで。"
|
retryAllQueuesConfirmText: "一時的にサーバー重なるかもしれへんで。"
|
||||||
enableChartsForRemoteUser: "リモートユーザーのチャートを作る"
|
enableChartsForRemoteUser: "リモートユーザーのチャートを作る"
|
||||||
enableChartsForFederatedInstances: "リモートサーバーのチャートを作る"
|
enableChartsForFederatedInstances: "リモートサーバーのチャートを作る"
|
||||||
|
enableStatsForFederatedInstances: "リモートサーバの情報を取得"
|
||||||
showClipButtonInNoteFooter: "ノートのアクションにクリップを追加"
|
showClipButtonInNoteFooter: "ノートのアクションにクリップを追加"
|
||||||
reactionsDisplaySize: "ツッコミの表示のでかさ"
|
reactionsDisplaySize: "ツッコミの表示のでかさ"
|
||||||
limitWidthOfReaction: "ツッコミの最大横幅を制限して、ちっさく表示するで"
|
limitWidthOfReaction: "ツッコミの最大横幅を制限して、ちっさく表示するで"
|
||||||
|
@ -1259,6 +1273,32 @@ confirmWhenRevealingSensitiveMedia: "センシティブなメディアを表示
|
||||||
sensitiveMediaRevealConfirm: "センシティブなメディアやで。表示するんか?"
|
sensitiveMediaRevealConfirm: "センシティブなメディアやで。表示するんか?"
|
||||||
createdLists: "作成したリスト"
|
createdLists: "作成したリスト"
|
||||||
createdAntennas: "作成したアンテナ"
|
createdAntennas: "作成したアンテナ"
|
||||||
|
fromX: "{x}から"
|
||||||
|
genEmbedCode: "埋め込みコードを作る"
|
||||||
|
noteOfThisUser: "このユーザーのノート全部"
|
||||||
|
clipNoteLimitExceeded: "これ以上このクリップにノート追加でけへんわ。"
|
||||||
|
performance: "パフォーマンス"
|
||||||
|
modified: "変更あり"
|
||||||
|
discard: "やめる"
|
||||||
|
thereAreNChanges: "{n}個の変更があるみたいや"
|
||||||
|
signinWithPasskey: "パスキーでログイン"
|
||||||
|
unknownWebAuthnKey: "登録されてへんパスキーやな。"
|
||||||
|
passkeyVerificationFailed: "パスキーの検証に失敗したで。"
|
||||||
|
passkeyVerificationSucceededButPasswordlessLoginDisabled: "パスキーの検証は成功したんやけど、パスワードレスログインが無効になっとるわ。"
|
||||||
|
messageToFollower: "フォロワーへのメッセージ"
|
||||||
|
target: "対象"
|
||||||
|
testCaptchaWarning: "CAPTCHAのテストを目的としてるで。<strong>絶対に本番環境で使わんといてな。絶対やで。</strong>"
|
||||||
|
prohibitedWordsForNameOfUser: "禁止ワード(ユーザー名)"
|
||||||
|
prohibitedWordsForNameOfUserDescription: "このリストの中にある文字列がユーザー名に入っとったら、その名前に変更できひんようになるで。モデレーター権限があるユーザーは除外や。"
|
||||||
|
yourNameContainsProhibitedWords: "その名前は禁止した文字列が含まれとるで"
|
||||||
|
yourNameContainsProhibitedWordsDescription: "その名前は禁止した文字列が含まれとるわ。どうしてもって言うなら、サーバー管理者に言うしかないで。"
|
||||||
|
_abuseUserReport:
|
||||||
|
forward: "転送"
|
||||||
|
forwardDescription: "匿名のシステムアカウントってことにして、リモートサーバーに通報を転送するで。"
|
||||||
|
resolve: "解決"
|
||||||
|
accept: "ええよ"
|
||||||
|
reject: "あかんよ"
|
||||||
|
resolveTutorial: "内容がええなら「ええよ」を選ぶんや。肯定的に解決されたことにして記録するで。\n逆に、内容がだめなら「あかんよ」を選びいや。否定的に解決されたって記録しとくで。"
|
||||||
_delivery:
|
_delivery:
|
||||||
status: "配信状態"
|
status: "配信状態"
|
||||||
stop: "配信せぇへん"
|
stop: "配信せぇへん"
|
||||||
|
@ -1393,8 +1433,10 @@ _serverSettings:
|
||||||
fanoutTimelineDescription: "入れると、おのおのタイムラインを取得するときにめちゃめちゃ動きが良うなって、データベースが軽くなるわ。でも、Redisのメモリ使う量が増えるから注意な。サーバーのメモリが足りんときとか、動きが変なときは切れるで。"
|
fanoutTimelineDescription: "入れると、おのおのタイムラインを取得するときにめちゃめちゃ動きが良うなって、データベースが軽くなるわ。でも、Redisのメモリ使う量が増えるから注意な。サーバーのメモリが足りんときとか、動きが変なときは切れるで。"
|
||||||
fanoutTimelineDbFallback: "データベースにフォールバックする"
|
fanoutTimelineDbFallback: "データベースにフォールバックする"
|
||||||
fanoutTimelineDbFallbackDescription: "有効にしたら、タイムラインがキャッシュん中に入ってないときにDBにもっかい問い合わせるフォールバック処理ってのをやっとくで。切ったらフォールバック処理をやらんからサーバーはもっと軽くなんねんけど、タイムラインの取得範囲がちょっと減るで。"
|
fanoutTimelineDbFallbackDescription: "有効にしたら、タイムラインがキャッシュん中に入ってないときにDBにもっかい問い合わせるフォールバック処理ってのをやっとくで。切ったらフォールバック処理をやらんからサーバーはもっと軽くなんねんけど、タイムラインの取得範囲がちょっと減るで。"
|
||||||
|
reactionsBufferingDescription: "有効にしたら、リアクション作るときのパフォーマンスがすっごい上がって、データベースへの負荷が減るで。代わりに、Redisのメモリ使用は増えるで。"
|
||||||
inquiryUrl: "問い合わせ先URL"
|
inquiryUrl: "問い合わせ先URL"
|
||||||
inquiryUrlDescription: "サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定するで。"
|
inquiryUrlDescription: "サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定するで。"
|
||||||
|
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "一定期間モデレーターがおらんかったら、スパムを防ぐためにこの設定は勝手に切られるで。"
|
||||||
_accountMigration:
|
_accountMigration:
|
||||||
moveFrom: "別のアカウントからこのアカウントに引っ越す"
|
moveFrom: "別のアカウントからこのアカウントに引っ越す"
|
||||||
moveFromSub: "別のアカウントへエイリアスを作る"
|
moveFromSub: "別のアカウントへエイリアスを作る"
|
||||||
|
@ -1726,6 +1768,11 @@ _role:
|
||||||
canSearchNotes: "ノート探せるかどうか"
|
canSearchNotes: "ノート探せるかどうか"
|
||||||
canUseTranslator: "翻訳使えるかどうか"
|
canUseTranslator: "翻訳使えるかどうか"
|
||||||
avatarDecorationLimit: "アイコンデコのいっちばんつけれる数"
|
avatarDecorationLimit: "アイコンデコのいっちばんつけれる数"
|
||||||
|
canImportAntennas: "アンテナのインポートを許す"
|
||||||
|
canImportBlocking: "ブロックのインポートを許す"
|
||||||
|
canImportFollowing: "フォローのインポートを許す"
|
||||||
|
canImportMuting: "ミュートのインポートを許す"
|
||||||
|
canImportUserLists: "リストのインポートを許す"
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "マニュアルロールにアサイン済み"
|
roleAssignedTo: "マニュアルロールにアサイン済み"
|
||||||
isLocal: "ローカルユーザー"
|
isLocal: "ローカルユーザー"
|
||||||
|
@ -2219,6 +2266,9 @@ _profile:
|
||||||
changeBanner: "バナー画像を変更するで"
|
changeBanner: "バナー画像を変更するで"
|
||||||
verifiedLinkDescription: "内容をURLに設定すると、リンク先のwebサイトに自分のプロフのリンクが含まれてる場合に所有者確認済みアイコンを表示させることができるで。"
|
verifiedLinkDescription: "内容をURLに設定すると、リンク先のwebサイトに自分のプロフのリンクが含まれてる場合に所有者確認済みアイコンを表示させることができるで。"
|
||||||
avatarDecorationMax: "最大{max}つまでデコつけれんで"
|
avatarDecorationMax: "最大{max}つまでデコつけれんで"
|
||||||
|
followedMessage: "フォローされたら返すメッセージ"
|
||||||
|
followedMessageDescription: "フォローされたときに相手に返す短めのメッセージを決めれるで。"
|
||||||
|
followedMessageDescriptionForLockedAccount: "フォローが承認制なら、フォローリクエストをOKしたときに見せるで。"
|
||||||
_exportOrImport:
|
_exportOrImport:
|
||||||
allNotes: "全てのノート"
|
allNotes: "全てのノート"
|
||||||
favoritedNotes: "お気に入りにしたノート"
|
favoritedNotes: "お気に入りにしたノート"
|
||||||
|
@ -2311,6 +2361,7 @@ _pages:
|
||||||
eyeCatchingImageSet: "アイキャッチ画像を設定"
|
eyeCatchingImageSet: "アイキャッチ画像を設定"
|
||||||
eyeCatchingImageRemove: "アイキャッチ画像を削除"
|
eyeCatchingImageRemove: "アイキャッチ画像を削除"
|
||||||
chooseBlock: "ブロックを追加"
|
chooseBlock: "ブロックを追加"
|
||||||
|
enterSectionTitle: "セクションタイトルを入れる"
|
||||||
selectType: "種類を選択"
|
selectType: "種類を選択"
|
||||||
contentBlocks: "コンテンツ"
|
contentBlocks: "コンテンツ"
|
||||||
inputBlocks: "入力"
|
inputBlocks: "入力"
|
||||||
|
@ -2356,13 +2407,15 @@ _notification:
|
||||||
renotedBySomeUsers: "{n}人がリノートしたで"
|
renotedBySomeUsers: "{n}人がリノートしたで"
|
||||||
followedBySomeUsers: "{n}人にフォローされたで"
|
followedBySomeUsers: "{n}人にフォローされたで"
|
||||||
flushNotification: "通知の履歴をリセットする"
|
flushNotification: "通知の履歴をリセットする"
|
||||||
|
exportOfXCompleted: "{x}のエクスポートが終わったわ"
|
||||||
|
login: "ログインしとったで"
|
||||||
_types:
|
_types:
|
||||||
all: "すべて"
|
all: "すべて"
|
||||||
note: "あんたらの新規投稿"
|
note: "あんたらの新規投稿"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
mention: "メンション"
|
mention: "メンション"
|
||||||
reply: "リプライ"
|
reply: "リプライ"
|
||||||
renote: "Renote"
|
renote: "リノート"
|
||||||
quote: "引用"
|
quote: "引用"
|
||||||
reaction: "ツッコミ"
|
reaction: "ツッコミ"
|
||||||
pollEnded: "アンケートが終了したで"
|
pollEnded: "アンケートが終了したで"
|
||||||
|
@ -2370,12 +2423,14 @@ _notification:
|
||||||
followRequestAccepted: "フォローが受理されたで"
|
followRequestAccepted: "フォローが受理されたで"
|
||||||
roleAssigned: "ロールが付与された"
|
roleAssigned: "ロールが付与された"
|
||||||
achievementEarned: "実績の獲得"
|
achievementEarned: "実績の獲得"
|
||||||
|
exportCompleted: "エクスポート終わった"
|
||||||
login: "ログイン"
|
login: "ログイン"
|
||||||
|
test: "通知テスト"
|
||||||
app: "連携アプリからの通知や"
|
app: "連携アプリからの通知や"
|
||||||
_actions:
|
_actions:
|
||||||
followBack: "フォローバック"
|
followBack: "フォローバック"
|
||||||
reply: "返事"
|
reply: "返事"
|
||||||
renote: "Renote"
|
renote: "リノート"
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "いつもメインカラムを表示"
|
alwaysShowMainColumn: "いつもメインカラムを表示"
|
||||||
columnAlign: "カラムの寄せ"
|
columnAlign: "カラムの寄せ"
|
||||||
|
@ -2436,7 +2491,10 @@ _webhookSettings:
|
||||||
abuseReport: "ユーザーから通報があったとき"
|
abuseReport: "ユーザーから通報があったとき"
|
||||||
abuseReportResolved: "ユーザーからの通報を処理したとき"
|
abuseReportResolved: "ユーザーからの通報を処理したとき"
|
||||||
userCreated: "ユーザーが作成されたとき"
|
userCreated: "ユーザーが作成されたとき"
|
||||||
|
inactiveModeratorsWarning: "モデレーターがしばらくおらんかったとき"
|
||||||
|
inactiveModeratorsInvitationOnlyChanged: "モデレーターがしばらくおらんかったから、システムが招待制に変えたとき"
|
||||||
deleteConfirm: "ほんまにWebhookをほかしてもええんか?"
|
deleteConfirm: "ほんまにWebhookをほかしてもええんか?"
|
||||||
|
testRemarks: "スイッチ右のボタンを押すとダミーデータを使ったテスト用Webhookを送れるで。"
|
||||||
_abuseReport:
|
_abuseReport:
|
||||||
_notificationRecipient:
|
_notificationRecipient:
|
||||||
createRecipient: "通報の通知先を追加"
|
createRecipient: "通報の通知先を追加"
|
||||||
|
@ -2480,6 +2538,8 @@ _moderationLogTypes:
|
||||||
markSensitiveDriveFile: "ファイルをセンシティブ付与"
|
markSensitiveDriveFile: "ファイルをセンシティブ付与"
|
||||||
unmarkSensitiveDriveFile: "ファイルをセンシティブ解除"
|
unmarkSensitiveDriveFile: "ファイルをセンシティブ解除"
|
||||||
resolveAbuseReport: "苦情を解決"
|
resolveAbuseReport: "苦情を解決"
|
||||||
|
forwardAbuseReport: "通報を転送"
|
||||||
|
updateAbuseReportNote: "通報のモデレーションノート更新"
|
||||||
createInvitation: "招待コード作る"
|
createInvitation: "招待コード作る"
|
||||||
createAd: "広告を作んで"
|
createAd: "広告を作んで"
|
||||||
deleteAd: "広告ほかす"
|
deleteAd: "広告ほかす"
|
||||||
|
@ -2491,6 +2551,14 @@ _moderationLogTypes:
|
||||||
unsetUserBanner: "この子のバナー元に戻す"
|
unsetUserBanner: "この子のバナー元に戻す"
|
||||||
createSystemWebhook: "SystemWebhookを作成"
|
createSystemWebhook: "SystemWebhookを作成"
|
||||||
updateSystemWebhook: "SystemWebhookを更新"
|
updateSystemWebhook: "SystemWebhookを更新"
|
||||||
|
deleteSystemWebhook: "SystemWebhookを削除"
|
||||||
|
createAbuseReportNotificationRecipient: "通報の通知先作る"
|
||||||
|
updateAbuseReportNotificationRecipient: "通報の通知先更新"
|
||||||
|
deleteAbuseReportNotificationRecipient: "通報の通知先消す"
|
||||||
|
deleteAccount: "アカウント消す"
|
||||||
|
deletePage: "ページ消す"
|
||||||
|
deleteFlash: "Playをほかす"
|
||||||
|
deleteGalleryPost: "ギャラリーの投稿をほかす"
|
||||||
_fileViewer:
|
_fileViewer:
|
||||||
title: "ファイルの詳しい情報"
|
title: "ファイルの詳しい情報"
|
||||||
type: "ファイルの種類"
|
type: "ファイルの種類"
|
||||||
|
@ -2622,3 +2690,22 @@ _mediaControls:
|
||||||
pip: "ピクチャインピクチャ"
|
pip: "ピクチャインピクチャ"
|
||||||
playbackRate: "再生速度"
|
playbackRate: "再生速度"
|
||||||
loop: "ループ再生"
|
loop: "ループ再生"
|
||||||
|
_contextMenu:
|
||||||
|
title: "コンテキストメニュー"
|
||||||
|
app: "アプリ"
|
||||||
|
appWithShift: "Shiftキーでアプリ"
|
||||||
|
native: "ブラウザのUI"
|
||||||
|
_embedCodeGen:
|
||||||
|
title: "埋め込みコードをカスタム"
|
||||||
|
header: "ヘッダー出す"
|
||||||
|
autoload: "勝手に続きを読み込む(非推奨)"
|
||||||
|
maxHeight: "高さの最大値"
|
||||||
|
maxHeightDescription: "0は最大値を指定せえへんけど、ウィジェットが伸び続けるから絶対1以上にしといてや。"
|
||||||
|
maxHeightWarn: "高さの最大値が無効になっとるで。意図してへん変更なら、普通の値に戻してや。"
|
||||||
|
previewIsNotActual: "プレビュー画面で出せる範囲をはみ出したから、ホンマの表示とはちゃうとおもうで。"
|
||||||
|
rounded: "角丸める"
|
||||||
|
border: "外枠に枠線つける"
|
||||||
|
applyToPreview: "プレビューに反映"
|
||||||
|
generateCode: "埋め込みコード作る"
|
||||||
|
codeGenerated: "コード作ったで"
|
||||||
|
codeGeneratedDescription: "作ったコードはウェブサイトに貼っつけて使ってや。"
|
||||||
|
|
|
@ -356,7 +356,6 @@ enableLocalTimeline: "로컬 타임라인 키기"
|
||||||
enableGlobalTimeline: "글로벌 타임라인 키기"
|
enableGlobalTimeline: "글로벌 타임라인 키기"
|
||||||
disablingTimelinesInfo: "요 타임라인얼 꺼도 간리자하고 중재자넌 고대로 설 수 잇십니다."
|
disablingTimelinesInfo: "요 타임라인얼 꺼도 간리자하고 중재자넌 고대로 설 수 잇십니다."
|
||||||
registration: "맨걸기"
|
registration: "맨걸기"
|
||||||
enableRegistration: "누라도 새로 맨걸 수 잇거로 하기"
|
|
||||||
invite: "초대하기"
|
invite: "초대하기"
|
||||||
driveCapacityPerLocalAccount: "로컬 사용자 하나마중 드라이브 커기"
|
driveCapacityPerLocalAccount: "로컬 사용자 하나마중 드라이브 커기"
|
||||||
driveCapacityPerRemoteAccount: "웬겍 사용자 하나마중 드라이브 커기"
|
driveCapacityPerRemoteAccount: "웬겍 사용자 하나마중 드라이브 커기"
|
||||||
|
@ -468,7 +467,7 @@ tooShort: "억수로 짜립니다"
|
||||||
tooLong: "억수로 집니다"
|
tooLong: "억수로 집니다"
|
||||||
passwordMatched: "맞십니다"
|
passwordMatched: "맞십니다"
|
||||||
passwordNotMatched: "안 맞십니다"
|
passwordNotMatched: "안 맞십니다"
|
||||||
signinWith: "{n}서 로그인"
|
signinWith: "{x} 서 로그인"
|
||||||
signinFailed: "로그인 몬 했십니다. 고 이름이랑 비밀번호 제대로 썼는가 확인해 주이소."
|
signinFailed: "로그인 몬 했십니다. 고 이름이랑 비밀번호 제대로 썼는가 확인해 주이소."
|
||||||
or: "아니면"
|
or: "아니면"
|
||||||
language: "언어"
|
language: "언어"
|
||||||
|
@ -809,11 +808,13 @@ _notification:
|
||||||
_types:
|
_types:
|
||||||
follow: "팔로잉"
|
follow: "팔로잉"
|
||||||
mention: "멘션"
|
mention: "멘션"
|
||||||
|
renote: "리노트"
|
||||||
quote: "따오기"
|
quote: "따오기"
|
||||||
reaction: "반엉"
|
reaction: "반엉"
|
||||||
login: "로그인"
|
login: "로그인"
|
||||||
_actions:
|
_actions:
|
||||||
reply: "답하기"
|
reply: "답하기"
|
||||||
|
renote: "리노트"
|
||||||
_deck:
|
_deck:
|
||||||
_columns:
|
_columns:
|
||||||
notifications: "알림"
|
notifications: "알림"
|
||||||
|
|
|
@ -42,7 +42,7 @@ favorite: "즐겨찾기"
|
||||||
favorites: "즐겨찾기"
|
favorites: "즐겨찾기"
|
||||||
unfavorite: "즐겨찾기에서 제거"
|
unfavorite: "즐겨찾기에서 제거"
|
||||||
favorited: "즐겨찾기에 등록했습니다."
|
favorited: "즐겨찾기에 등록했습니다."
|
||||||
alreadyFavorited: "이미 즐겨찾기에 등록했습니다."
|
alreadyFavorited: "이미 즐겨찾기에 등록되어 있습니다."
|
||||||
cantFavorite: "즐겨찾기에 등록하지 못했습니다."
|
cantFavorite: "즐겨찾기에 등록하지 못했습니다."
|
||||||
pin: "프로필에 고정"
|
pin: "프로필에 고정"
|
||||||
unpin: "프로필에서 고정 해제"
|
unpin: "프로필에서 고정 해제"
|
||||||
|
@ -382,7 +382,6 @@ enableLocalTimeline: "로컬 타임라인 활성화"
|
||||||
enableGlobalTimeline: "글로벌 타임라인 활성화"
|
enableGlobalTimeline: "글로벌 타임라인 활성화"
|
||||||
disablingTimelinesInfo: "특정 타임라인을 비활성화하더라도 관리자 및 모더레이터는 계속 사용할 수 있습니다."
|
disablingTimelinesInfo: "특정 타임라인을 비활성화하더라도 관리자 및 모더레이터는 계속 사용할 수 있습니다."
|
||||||
registration: "등록"
|
registration: "등록"
|
||||||
enableRegistration: "신규 회원가입을 활성화"
|
|
||||||
invite: "초대"
|
invite: "초대"
|
||||||
driveCapacityPerLocalAccount: "로컬 유저 한 명당 드라이브 용량"
|
driveCapacityPerLocalAccount: "로컬 유저 한 명당 드라이브 용량"
|
||||||
driveCapacityPerRemoteAccount: "원격 사용자별 드라이브 용량"
|
driveCapacityPerRemoteAccount: "원격 사용자별 드라이브 용량"
|
||||||
|
@ -587,6 +586,7 @@ masterVolume: "마스터 볼륨"
|
||||||
notUseSound: "음소거 하기"
|
notUseSound: "음소거 하기"
|
||||||
useSoundOnlyWhenActive: "Misskey를 활성화한 때에만 소리를 출력하기"
|
useSoundOnlyWhenActive: "Misskey를 활성화한 때에만 소리를 출력하기"
|
||||||
details: "자세히"
|
details: "자세히"
|
||||||
|
renoteDetails: "리노트 상세 내용"
|
||||||
chooseEmoji: "이모지 선택"
|
chooseEmoji: "이모지 선택"
|
||||||
unableToProcess: "작업을 완료할 수 없습니다"
|
unableToProcess: "작업을 완료할 수 없습니다"
|
||||||
recentUsed: "최근 사용"
|
recentUsed: "최근 사용"
|
||||||
|
@ -947,6 +947,9 @@ oneHour: "1시간"
|
||||||
oneDay: "1일"
|
oneDay: "1일"
|
||||||
oneWeek: "일주일"
|
oneWeek: "일주일"
|
||||||
oneMonth: "1개월"
|
oneMonth: "1개월"
|
||||||
|
threeMonths: "3개월"
|
||||||
|
oneYear: "1년"
|
||||||
|
threeDays: "3일"
|
||||||
reflectMayTakeTime: "반영되기까지 시간이 걸릴 수 있습니다."
|
reflectMayTakeTime: "반영되기까지 시간이 걸릴 수 있습니다."
|
||||||
failedToFetchAccountInformation: "계정 정보를 가져오지 못했습니다"
|
failedToFetchAccountInformation: "계정 정보를 가져오지 못했습니다"
|
||||||
rateLimitExceeded: "요청 제한 횟수를 초과하였습니다"
|
rateLimitExceeded: "요청 제한 횟수를 초과하였습니다"
|
||||||
|
@ -1254,7 +1257,7 @@ lastNDays: "최근 {n}일"
|
||||||
backToTitle: "타이틀로 가기"
|
backToTitle: "타이틀로 가기"
|
||||||
hemisphere: "거주 지역"
|
hemisphere: "거주 지역"
|
||||||
withSensitive: "민감한 파일이 포함된 노트 보기"
|
withSensitive: "민감한 파일이 포함된 노트 보기"
|
||||||
userSaysSomethingSensitive: "{name} 같은 민감한 파일이 포함된 글"
|
userSaysSomethingSensitive: "{name}의 민감한 파일이 포함된 게시물"
|
||||||
enableHorizontalSwipe: "스와이프하여 탭 전환"
|
enableHorizontalSwipe: "스와이프하여 탭 전환"
|
||||||
loading: "불러오는 중"
|
loading: "불러오는 중"
|
||||||
surrender: "그만두기"
|
surrender: "그만두기"
|
||||||
|
@ -1286,13 +1289,30 @@ signinWithPasskey: "패스키로 로그인"
|
||||||
unknownWebAuthnKey: "등록되지 않은 패스키입니다."
|
unknownWebAuthnKey: "등록되지 않은 패스키입니다."
|
||||||
passkeyVerificationFailed: "패스키 검증을 실패했습니다."
|
passkeyVerificationFailed: "패스키 검증을 실패했습니다."
|
||||||
passkeyVerificationSucceededButPasswordlessLoginDisabled: "패스키를 검증했으나, 비밀번호 없이 로그인하기가 꺼져 있습니다."
|
passkeyVerificationSucceededButPasswordlessLoginDisabled: "패스키를 검증했으나, 비밀번호 없이 로그인하기가 꺼져 있습니다."
|
||||||
messageToFollower: "팔로워에 보낼 메시지"
|
messageToFollower: "팔로워에게 보낼 메시지"
|
||||||
target: "대상"
|
target: "대상"
|
||||||
testCaptchaWarning: "CAPTCHA를 테스트하기 위한 기능입니다. <strong>실제 환경에서는 사용하지 마세요.</strong>"
|
testCaptchaWarning: "CAPTCHA를 테스트하기 위한 기능입니다. <strong>실제 환경에서는 사용하지 마세요.</strong>"
|
||||||
prohibitedWordsForNameOfUser: "금지 단어 (사용자 이름)"
|
prohibitedWordsForNameOfUser: "금지 단어 (사용자 이름)"
|
||||||
prohibitedWordsForNameOfUserDescription: "이 목록에 포함되는 키워드가 사용자 이름에 있는 경우, 일반 사용자는 이름을 바꿀 수 없습니다. 모더레이터 권한을 가진 사용자는 제한 대상에서 제외됩니다."
|
prohibitedWordsForNameOfUserDescription: "이 목록에 포함되는 키워드가 사용자 이름에 있는 경우, 일반 사용자는 이름을 바꿀 수 없습니다. 모더레이터 권한을 가진 사용자는 제한 대상에서 제외됩니다."
|
||||||
yourNameContainsProhibitedWords: "바꾸려는 이름에 금지된 키워드가 포함되어 있습니다."
|
yourNameContainsProhibitedWords: "바꾸려는 이름에 금지된 키워드가 포함되어 있습니다."
|
||||||
yourNameContainsProhibitedWordsDescription: "이름에 금지된 키워드가 있습니다. 이름을 사용해야 하는 경우, 서버 관리자에 문의하세요."
|
yourNameContainsProhibitedWordsDescription: "이름에 금지된 키워드가 있습니다. 이름을 사용해야 하는 경우, 서버 관리자에 문의하세요."
|
||||||
|
thisContentsAreMarkedAsSigninRequiredByAuthor: "게시자에 의해 로그인해야 볼 수 있도록 설정되어 있습니다."
|
||||||
|
lockdown: "잠금"
|
||||||
|
pleaseSelectAccount: "계정을 선택해주세요."
|
||||||
|
availableRoles: "사용 가능한 역할"
|
||||||
|
acknowledgeNotesAndEnable: "활성화 하기 전에 주의 사항을 확인했습니다."
|
||||||
|
_accountSettings:
|
||||||
|
requireSigninToViewContents: "콘텐츠 열람을 위해 로그인으 필수로 설정하기"
|
||||||
|
requireSigninToViewContentsDescription1: "자신이 작성한 모든 노트 등의 콘텐츠를 보기 위해 로그인을 필수로 설정합니다. 크롤러가 정보 수집하는 것을 방지하는 효과를 기대할 수 있습니다."
|
||||||
|
requireSigninToViewContentsDescription2: "URL 미리보기(OGP), 웹페이지에 삽입, 노트 인용을 지원하지 않는 서버에서 볼 수 없게 됩니다."
|
||||||
|
requireSigninToViewContentsDescription3: "원격 서버에 연합된 콘텐츠에는 이러한 제한이 적용되지 않을 수 있습니다."
|
||||||
|
makeNotesFollowersOnlyBefore: "과거 노트는 팔로워만 볼 수 있도록 설정하기"
|
||||||
|
makeNotesFollowersOnlyBeforeDescription: "이 기능이 활성화되어 있는 동안, 설정된 날짜 및 시간보다 과거 또는 설정된 시간이 지난 노트는 팔로워만 볼 수 있게 됩니다.비활성화하면 노트의 공개 상태도 원래대로 돌아갑니다."
|
||||||
|
makeNotesHiddenBefore: "과거 노트 비공개로 전환하기"
|
||||||
|
makeNotesHiddenBeforeDescription: "이 기능이 활성화되어 있는 동안 설정한 날짜 및 시간보다 과거 또는 설정한 시간이 지난 노트는 본인만 볼 수 있게(비공개로 전환) 됩니다. 비활성화하면 노트의 공개 상태도 원래대로 돌아갑니다."
|
||||||
|
mayNotEffectForFederatedNotes: "원격 서버에 연합된 노트에는 효과가 없을 수도 있습니다."
|
||||||
|
notesHavePassedSpecifiedPeriod: "지정한 시간이 경과된 노트"
|
||||||
|
notesOlderThanSpecifiedDateAndTime: "지정된 날짜 및 시간 이전의 노트"
|
||||||
_abuseUserReport:
|
_abuseUserReport:
|
||||||
forward: "전달"
|
forward: "전달"
|
||||||
forwardDescription: "익명 시스템 계정을 사용하여 리모트 서버에 신고 내용을 전달할 수 있습니다."
|
forwardDescription: "익명 시스템 계정을 사용하여 리모트 서버에 신고 내용을 전달할 수 있습니다."
|
||||||
|
@ -1437,6 +1457,8 @@ _serverSettings:
|
||||||
reactionsBufferingDescription: "활성화 한 경우, 리액션 작성 퍼포먼스가 대폭 향상되어 DB의 부하를 줄일 수 있으나, Redis의 메모리 사용량이 많아집니다."
|
reactionsBufferingDescription: "활성화 한 경우, 리액션 작성 퍼포먼스가 대폭 향상되어 DB의 부하를 줄일 수 있으나, Redis의 메모리 사용량이 많아집니다."
|
||||||
inquiryUrl: "문의처 URL"
|
inquiryUrl: "문의처 URL"
|
||||||
inquiryUrlDescription: "서버 운영자에게 보내는 문의 양식의 URL이나 운영자의 연락처 등이 적힌 웹 페이지의 URL을 설정합니다."
|
inquiryUrlDescription: "서버 운영자에게 보내는 문의 양식의 URL이나 운영자의 연락처 등이 적힌 웹 페이지의 URL을 설정합니다."
|
||||||
|
openRegistration: "회원 가입을 활성화 하기"
|
||||||
|
openRegistrationWarning: "회원 가입을 개방하는 것은 리스크가 따릅니다. 서버를 항상 감시할 수 있고, 문제가 발생했을 때 바로 대응할 수 있는 상태에서만 활성화 하는 것을 권장합니다."
|
||||||
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "일정 기간동안 모더레이터의 활동이 감지되지 않는 경우, 스팸 방지를 위해 이 설정은 자동으로 꺼집니다."
|
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "일정 기간동안 모더레이터의 활동이 감지되지 않는 경우, 스팸 방지를 위해 이 설정은 자동으로 꺼집니다."
|
||||||
_accountMigration:
|
_accountMigration:
|
||||||
moveFrom: "다른 계정에서 이 계정으로 이사"
|
moveFrom: "다른 계정에서 이 계정으로 이사"
|
||||||
|
@ -2157,8 +2179,11 @@ _auth:
|
||||||
permissionAsk: "이 앱은 다음의 권한을 요청합니다"
|
permissionAsk: "이 앱은 다음의 권한을 요청합니다"
|
||||||
pleaseGoBack: "앱으로 돌아가서 시도해 주세요"
|
pleaseGoBack: "앱으로 돌아가서 시도해 주세요"
|
||||||
callback: "앱으로 돌아갑니다"
|
callback: "앱으로 돌아갑니다"
|
||||||
|
accepted: "접근 권한이 부여되었습니다."
|
||||||
denied: "접근이 거부되었습니다"
|
denied: "접근이 거부되었습니다"
|
||||||
|
scopeUser: "다음 사용자로 활동하고 있습니다."
|
||||||
pleaseLogin: "어플리케이션의 접근을 허가하려면 로그인하십시오."
|
pleaseLogin: "어플리케이션의 접근을 허가하려면 로그인하십시오."
|
||||||
|
byClickingYouWillBeRedirectedToThisUrl: "접근을 허용하면 자동으로 다음 URL로 이동합니다."
|
||||||
_antennaSources:
|
_antennaSources:
|
||||||
all: "모든 노트"
|
all: "모든 노트"
|
||||||
homeTimeline: "팔로우중인 유저의 노트"
|
homeTimeline: "팔로우중인 유저의 노트"
|
||||||
|
@ -2710,3 +2735,12 @@ _embedCodeGen:
|
||||||
generateCode: "임베디드 코드를 만들기"
|
generateCode: "임베디드 코드를 만들기"
|
||||||
codeGenerated: "코드를 만들었습니다."
|
codeGenerated: "코드를 만들었습니다."
|
||||||
codeGeneratedDescription: "만들어진 코드를 웹 사이트에 붙여서 사용하세요."
|
codeGeneratedDescription: "만들어진 코드를 웹 사이트에 붙여서 사용하세요."
|
||||||
|
_selfXssPrevention:
|
||||||
|
warning: "경고"
|
||||||
|
title: "“이 화면에 뭔가를 붙여넣어라\"는 것은 모두 사기입니다."
|
||||||
|
description1: "여기에 무언가를 붙여넣으면 악의적인 사용자에게 계정을 탈취당하거나 개인정보를 도용당할 수 있습니다."
|
||||||
|
description2: "붙여 넣으려는 항목이 무엇인지 정확히 이해하지 못하는 경우, %c지금 바로 작업을 중단하고 이 창을 닫으십시오."
|
||||||
|
description3: "자세한 내용은 여기를 확인해 주세요. {link}"
|
||||||
|
_followRequest:
|
||||||
|
recieved: "받은 신청"
|
||||||
|
sent: "보낸 신청"
|
||||||
|
|
|
@ -299,7 +299,6 @@ enableLocalTimeline: "ເປີດໃຊ້ທາມລາຍທ້ອງຖິ
|
||||||
enableGlobalTimeline: "ເປີດໃຊ້ທາມລາຍທົ່ວໂລກ"
|
enableGlobalTimeline: "ເປີດໃຊ້ທາມລາຍທົ່ວໂລກ"
|
||||||
disablingTimelinesInfo: "ຜູ້ດູແລລະບບແລະຜູ້ຄວບຄຸມຈະສາມາດເຂົ້າເຖີງໄທມ໌ໄລນ໌ທັ້ງເບີດ ເຖີງວ່າຈະບໍ່ໄດ້ເປີດໃຊ້ງານກໍ່ຕາມ"
|
disablingTimelinesInfo: "ຜູ້ດູແລລະບບແລະຜູ້ຄວບຄຸມຈະສາມາດເຂົ້າເຖີງໄທມ໌ໄລນ໌ທັ້ງເບີດ ເຖີງວ່າຈະບໍ່ໄດ້ເປີດໃຊ້ງານກໍ່ຕາມ"
|
||||||
registration: "ລົງທະບຽນ"
|
registration: "ລົງທະບຽນ"
|
||||||
enableRegistration: "ເປີດໃຊ້ການລົງທະບຽນຜູ້ໃຊ້ໃໝ່"
|
|
||||||
invite: "ເຊີນ"
|
invite: "ເຊີນ"
|
||||||
driveCapacityPerLocalAccount: "ຄວາມຈຸຂອງ drive ຕໍ່ຜູ້ໃຊ້ທ້ອງຖິ່ນ"
|
driveCapacityPerLocalAccount: "ຄວາມຈຸຂອງ drive ຕໍ່ຜູ້ໃຊ້ທ້ອງຖິ່ນ"
|
||||||
driveCapacityPerRemoteAccount: "ຄວາມຈຸຂອງ drive ຕໍ່ຜູ້ໃຊ້ໄລຍະໄກ"
|
driveCapacityPerRemoteAccount: "ຄວາມຈຸຂອງ drive ຕໍ່ຜູ້ໃຊ້ໄລຍະໄກ"
|
||||||
|
|
|
@ -333,7 +333,6 @@ enableLocalTimeline: "Inschakelen lokale tijdlijn"
|
||||||
enableGlobalTimeline: "Inschakelen globale tijdlijn "
|
enableGlobalTimeline: "Inschakelen globale tijdlijn "
|
||||||
disablingTimelinesInfo: "Beheerders en moderators hebben altijd toegang tot alle tijdlijnen, ook als ze niet actief zijn."
|
disablingTimelinesInfo: "Beheerders en moderators hebben altijd toegang tot alle tijdlijnen, ook als ze niet actief zijn."
|
||||||
registration: "Registreren"
|
registration: "Registreren"
|
||||||
enableRegistration: "Inschakelen registratie nieuwe gebruikers "
|
|
||||||
invite: "Uitnodigen"
|
invite: "Uitnodigen"
|
||||||
driveCapacityPerLocalAccount: "Opslagruimte per lokale gebruiker"
|
driveCapacityPerLocalAccount: "Opslagruimte per lokale gebruiker"
|
||||||
driveCapacityPerRemoteAccount: "Opslagruimte per externe gebruiker"
|
driveCapacityPerRemoteAccount: "Opslagruimte per externe gebruiker"
|
||||||
|
|
|
@ -260,7 +260,6 @@ enableLocalTimeline: "Aktiver lokal tidslinje"
|
||||||
enableGlobalTimeline: "Aktiver global tidslinje"
|
enableGlobalTimeline: "Aktiver global tidslinje"
|
||||||
disablingTimelinesInfo: "Administratorer og Moderatorer vil alltid ha tilgang til alle tidslinjer, selv om de ikke er aktivert."
|
disablingTimelinesInfo: "Administratorer og Moderatorer vil alltid ha tilgang til alle tidslinjer, selv om de ikke er aktivert."
|
||||||
registration: "Registrer"
|
registration: "Registrer"
|
||||||
enableRegistration: "Aktiver registrering av nye brukere"
|
|
||||||
invite: "Inviter"
|
invite: "Inviter"
|
||||||
basicInfo: "Grunnleggende informasjon"
|
basicInfo: "Grunnleggende informasjon"
|
||||||
pinnedUsers: "Festede brukrere"
|
pinnedUsers: "Festede brukrere"
|
||||||
|
|
|
@ -362,7 +362,6 @@ enableLocalTimeline: "Włącz lokalną oś czasu"
|
||||||
enableGlobalTimeline: "Włącz globalną oś czasu"
|
enableGlobalTimeline: "Włącz globalną oś czasu"
|
||||||
disablingTimelinesInfo: "Administratorzy i moderatorzy będą zawsze mieć dostęp do wszystkich osi czasu, nawet gdy są one wyłączone."
|
disablingTimelinesInfo: "Administratorzy i moderatorzy będą zawsze mieć dostęp do wszystkich osi czasu, nawet gdy są one wyłączone."
|
||||||
registration: "Zarejestruj się"
|
registration: "Zarejestruj się"
|
||||||
enableRegistration: "Włącz rejestrację nowych użytkowników"
|
|
||||||
invite: "Zaproś"
|
invite: "Zaproś"
|
||||||
driveCapacityPerLocalAccount: "Powierzchnia dyskowa na lokalnego użytkownika"
|
driveCapacityPerLocalAccount: "Powierzchnia dyskowa na lokalnego użytkownika"
|
||||||
driveCapacityPerRemoteAccount: "Powierzchnia dyskowa na zdalnego użytkownika"
|
driveCapacityPerRemoteAccount: "Powierzchnia dyskowa na zdalnego użytkownika"
|
||||||
|
@ -492,6 +491,10 @@ uiLanguage: "Język wyświetlania UI"
|
||||||
aboutX: "O {x}"
|
aboutX: "O {x}"
|
||||||
emojiStyle: "Styl emoji"
|
emojiStyle: "Styl emoji"
|
||||||
native: "Natywny"
|
native: "Natywny"
|
||||||
|
menuStyle: "Styl Menu"
|
||||||
|
style: "Styl"
|
||||||
|
drawer: "Schowek"
|
||||||
|
popup: "Wyskakujące okienka"
|
||||||
showNoteActionsOnlyHover: "Pokazuj akcje notatek tylko po najechaniu myszką"
|
showNoteActionsOnlyHover: "Pokazuj akcje notatek tylko po najechaniu myszką"
|
||||||
showReactionsCount: "Wyświetl liczbę reakcji na notatkę"
|
showReactionsCount: "Wyświetl liczbę reakcji na notatkę"
|
||||||
noHistory: "Brak historii"
|
noHistory: "Brak historii"
|
||||||
|
@ -574,6 +577,7 @@ ascendingOrder: "Rosnąco"
|
||||||
descendingOrder: "Malejąco"
|
descendingOrder: "Malejąco"
|
||||||
scratchpad: "Brudnopis"
|
scratchpad: "Brudnopis"
|
||||||
scratchpadDescription: "Brudnopis zawiera eksperymentalne środowisko dla AiScript. Możesz pisać, wykonywać i sprawdzać wyniki w interakcji z Misskey."
|
scratchpadDescription: "Brudnopis zawiera eksperymentalne środowisko dla AiScript. Możesz pisać, wykonywać i sprawdzać wyniki w interakcji z Misskey."
|
||||||
|
uiInspector: "Inspektor UI"
|
||||||
output: "Wyjście"
|
output: "Wyjście"
|
||||||
script: "Skrypt"
|
script: "Skrypt"
|
||||||
disablePagesScript: "Wyłącz AiScript na Stronach"
|
disablePagesScript: "Wyłącz AiScript na Stronach"
|
||||||
|
@ -654,6 +658,7 @@ smtpSecure: "Użyj niejawnego SSL/TLS dla połączeń SMTP"
|
||||||
smtpSecureInfo: "Wyłącz, jeżeli używasz STARTTLS"
|
smtpSecureInfo: "Wyłącz, jeżeli używasz STARTTLS"
|
||||||
testEmail: "Przetestuj dostarczanie wiadomości e-mail"
|
testEmail: "Przetestuj dostarczanie wiadomości e-mail"
|
||||||
wordMute: "Wyciszenie słowa"
|
wordMute: "Wyciszenie słowa"
|
||||||
|
hardWordMute: "Wyciszaj przekleństwa"
|
||||||
regexpError: "Błąd wyrażenia regularnego"
|
regexpError: "Błąd wyrażenia regularnego"
|
||||||
regexpErrorDescription: "Wystąpił błąd w wyrażeniu regularnym w linii {line} twoich {tab} wyciszeń:"
|
regexpErrorDescription: "Wystąpił błąd w wyrażeniu regularnym w linii {line} twoich {tab} wyciszeń:"
|
||||||
instanceMute: "Wyciszone instancje"
|
instanceMute: "Wyciszone instancje"
|
||||||
|
@ -826,6 +831,7 @@ administration: "Zarządzanie"
|
||||||
accounts: "Konta"
|
accounts: "Konta"
|
||||||
switch: "Przełącz"
|
switch: "Przełącz"
|
||||||
noMaintainerInformationWarning: "Informacje o administratorze nie są skonfigurowane."
|
noMaintainerInformationWarning: "Informacje o administratorze nie są skonfigurowane."
|
||||||
|
noInquiryUrlWarning: "Adres URL zapytania nie został ustawiony"
|
||||||
noBotProtectionWarning: "Zabezpieczenie przed botami nie jest skonfigurowane."
|
noBotProtectionWarning: "Zabezpieczenie przed botami nie jest skonfigurowane."
|
||||||
configure: "Skonfiguruj"
|
configure: "Skonfiguruj"
|
||||||
postToGallery: "Opublikuj w galerii"
|
postToGallery: "Opublikuj w galerii"
|
||||||
|
@ -890,6 +896,7 @@ followersVisibility: "Widoczność obserwujących"
|
||||||
continueThread: "Pokaż kontynuację wątku"
|
continueThread: "Pokaż kontynuację wątku"
|
||||||
deleteAccountConfirm: "Spowoduje to nieodwracalne usunięcie Twojego konta. Kontynuować?"
|
deleteAccountConfirm: "Spowoduje to nieodwracalne usunięcie Twojego konta. Kontynuować?"
|
||||||
incorrectPassword: "Nieprawidłowe hasło."
|
incorrectPassword: "Nieprawidłowe hasło."
|
||||||
|
incorrectTotp: "Hasło pojedynczego użytku jest nie poprawne, lub straciło ważność"
|
||||||
voteConfirm: "Potwierdzić swój głos na \"{choice}\"?"
|
voteConfirm: "Potwierdzić swój głos na \"{choice}\"?"
|
||||||
hide: "Ukryj"
|
hide: "Ukryj"
|
||||||
useDrawerReactionPickerForMobile: "Wyświetlaj wybornik reakcji jako szufladę na urządzeniach mobilnych"
|
useDrawerReactionPickerForMobile: "Wyświetlaj wybornik reakcji jako szufladę na urządzeniach mobilnych"
|
||||||
|
@ -914,6 +921,10 @@ oneHour: "1 godzina"
|
||||||
oneDay: "1 dzień"
|
oneDay: "1 dzień"
|
||||||
oneWeek: "1 tydzień"
|
oneWeek: "1 tydzień"
|
||||||
oneMonth: "jeden miesiąc"
|
oneMonth: "jeden miesiąc"
|
||||||
|
threeMonths: "3 miesiące"
|
||||||
|
oneYear: "Rok"
|
||||||
|
threeDays: "3 dni"
|
||||||
|
reflectMayTakeTime: "Może minąć trochę czasu, zanim będzie to uwzględnione"
|
||||||
failedToFetchAccountInformation: "Nie udało się uzyskać informacji o koncie"
|
failedToFetchAccountInformation: "Nie udało się uzyskać informacji o koncie"
|
||||||
rateLimitExceeded: "Limit szybkości przekroczony"
|
rateLimitExceeded: "Limit szybkości przekroczony"
|
||||||
cropImage: "Przytnij obraz"
|
cropImage: "Przytnij obraz"
|
||||||
|
@ -924,9 +935,11 @@ file: "Pliki"
|
||||||
recentNHours: "W ciągu ostatnich {n} godzin"
|
recentNHours: "W ciągu ostatnich {n} godzin"
|
||||||
recentNDays: "W ciągu ostatnich {n} dni"
|
recentNDays: "W ciągu ostatnich {n} dni"
|
||||||
noEmailServerWarning: "Serwer Email nie jest skonfigurowany"
|
noEmailServerWarning: "Serwer Email nie jest skonfigurowany"
|
||||||
|
thereIsUnresolvedAbuseReportWarning: "Istnieją niewyjaśnione raporty"
|
||||||
recommended: "Zalecane"
|
recommended: "Zalecane"
|
||||||
check: "Zweryfikuj"
|
check: "Zweryfikuj"
|
||||||
driveCapOverrideLabel: "Zmień limit pojemności dysku użytkownika"
|
driveCapOverrideLabel: "Zmień limit pojemności dysku użytkownika"
|
||||||
|
driveCapOverrideCaption: "Resetuje pojemność do wartości domyślnej, przez wpisanie wartości 0 lub niższej"
|
||||||
requireAdminForView: "Aby to zobaczyć, musisz być administratorem"
|
requireAdminForView: "Aby to zobaczyć, musisz być administratorem"
|
||||||
isSystemAccount: "To jest konto stworzone i zarządzane przez system"
|
isSystemAccount: "To jest konto stworzone i zarządzane przez system"
|
||||||
typeToConfirm: "Wprowadź {x}, aby potwierdzić"
|
typeToConfirm: "Wprowadź {x}, aby potwierdzić"
|
||||||
|
@ -995,17 +1008,29 @@ unassign: "Cofnij przydzielenie"
|
||||||
color: "Kolor"
|
color: "Kolor"
|
||||||
manageCustomEmojis: "Zarządzaj niestandardowymi Emoji"
|
manageCustomEmojis: "Zarządzaj niestandardowymi Emoji"
|
||||||
manageAvatarDecorations: "Zarządzaj dekoracjami awatara"
|
manageAvatarDecorations: "Zarządzaj dekoracjami awatara"
|
||||||
|
youCannotCreateAnymore: "Limit kreacji został przekroczony"
|
||||||
|
cannotPerformTemporary: "Opcja tymczasowo niedostępna"
|
||||||
|
cannotPerformTemporaryDescription: "Ta akcja nie może zostać wykonana, z powodu przekroczenia limitu wykonań. Prosimy poczekać chwilę i spróbować ponownie"
|
||||||
invalidParamError: "Błąd parametrów"
|
invalidParamError: "Błąd parametrów"
|
||||||
|
invalidParamErrorDescription: "Wartości, które zostały podane są niepoprawne. Zwykle jest to spowodowane bugiem, lecz również może być to spowodowane przekroczeniem limitu wartości, lub podobnym problemem"
|
||||||
permissionDeniedError: "Odrzucono operacje"
|
permissionDeniedError: "Odrzucono operacje"
|
||||||
permissionDeniedErrorDescription: "Konto nie posiada uprawnień"
|
permissionDeniedErrorDescription: "Konto nie posiada uprawnień"
|
||||||
preset: "Konfiguracja"
|
preset: "Konfiguracja"
|
||||||
selectFromPresets: "Wybierz konfiguracje"
|
selectFromPresets: "Wybierz konfiguracje"
|
||||||
achievements: "Osiągnięcia"
|
achievements: "Osiągnięcia"
|
||||||
|
gotInvalidResponseError: "Niepoprawna odpowiedź serwera"
|
||||||
|
gotInvalidResponseErrorDescription: "Wystąpił problem z Twoim połączeniem z Internetem, lub z serwerem. {Spróbuj ponownie} wkrótce."
|
||||||
|
thisPostMayBeAnnoying: "Ten wpis może obrażać pozostałych użytkowników"
|
||||||
|
thisPostMayBeAnnoyingHome: "Opublikuj na domowej osi czasu"
|
||||||
thisPostMayBeAnnoyingCancel: "Odrzuć"
|
thisPostMayBeAnnoyingCancel: "Odrzuć"
|
||||||
|
thisPostMayBeAnnoyingIgnore: "Zignoruj i wyślij"
|
||||||
|
collapseRenotes: "Zwiń wpisy, które już zobaczyłeś"
|
||||||
|
collapseRenotesDescription: "Zwiń wpisy, na które już zareagowałeś lub udostępniłeś"
|
||||||
internalServerError: "Wewnętrzny błąd serwera"
|
internalServerError: "Wewnętrzny błąd serwera"
|
||||||
internalServerErrorDescription: "Niespodziewany błąd po stronie serwera"
|
internalServerErrorDescription: "Niespodziewany błąd po stronie serwera"
|
||||||
copyErrorInfo: "Kopiuj informacje o błędzie"
|
copyErrorInfo: "Kopiuj informacje o błędzie"
|
||||||
joinThisServer: "Dołącz do chaty"
|
joinThisServer: "Dołącz do chaty"
|
||||||
|
exploreOtherServers: "Szukaj innej instancji"
|
||||||
disableFederationOk: "Wyłącz federacje"
|
disableFederationOk: "Wyłącz federacje"
|
||||||
invitationRequiredToRegister: "Ten serwer wymaga zaproszenia. Tylko osoby z zaproszeniem mogą się zarejestrować"
|
invitationRequiredToRegister: "Ten serwer wymaga zaproszenia. Tylko osoby z zaproszeniem mogą się zarejestrować"
|
||||||
emailNotSupported: "Wysyłanie wiadomości E-mail nie jest obsługiwane na tym serwerze"
|
emailNotSupported: "Wysyłanie wiadomości E-mail nie jest obsługiwane na tym serwerze"
|
||||||
|
|
|
@ -376,7 +376,6 @@ enableLocalTimeline: "Ativar linha do tempo local"
|
||||||
enableGlobalTimeline: "Ativar linha do tempo global"
|
enableGlobalTimeline: "Ativar linha do tempo global"
|
||||||
disablingTimelinesInfo: "Se você desabilitar essas linhas do tempo, administradores e moderadores ainda poderão usá-las por conveniência."
|
disablingTimelinesInfo: "Se você desabilitar essas linhas do tempo, administradores e moderadores ainda poderão usá-las por conveniência."
|
||||||
registration: "Registar"
|
registration: "Registar"
|
||||||
enableRegistration: "Permitir que qualquer pessoa se registre"
|
|
||||||
invite: "Convidar"
|
invite: "Convidar"
|
||||||
driveCapacityPerLocalAccount: "Capacidade do drive por usuário local"
|
driveCapacityPerLocalAccount: "Capacidade do drive por usuário local"
|
||||||
driveCapacityPerRemoteAccount: "Capacidade do drive por usuário remoto"
|
driveCapacityPerRemoteAccount: "Capacidade do drive por usuário remoto"
|
||||||
|
|
|
@ -341,7 +341,6 @@ enableLocalTimeline: "Activează cronologia locală"
|
||||||
enableGlobalTimeline: "Activeaza cronologia globală"
|
enableGlobalTimeline: "Activeaza cronologia globală"
|
||||||
disablingTimelinesInfo: "Administratorii și Moderatorii vor avea mereu access la toate cronologiile, chiar dacă nu sunt activate."
|
disablingTimelinesInfo: "Administratorii și Moderatorii vor avea mereu access la toate cronologiile, chiar dacă nu sunt activate."
|
||||||
registration: "Inregistrare"
|
registration: "Inregistrare"
|
||||||
enableRegistration: "Activează înregistrările pentru utilizatori noi"
|
|
||||||
invite: "Invită"
|
invite: "Invită"
|
||||||
driveCapacityPerLocalAccount: "Capacitatea Drive-ului per utilizator local"
|
driveCapacityPerLocalAccount: "Capacitatea Drive-ului per utilizator local"
|
||||||
driveCapacityPerRemoteAccount: "Capacitatea Drive-ului per utilizator extern"
|
driveCapacityPerRemoteAccount: "Capacitatea Drive-ului per utilizator extern"
|
||||||
|
|
|
@ -8,6 +8,9 @@ search: "Поиск"
|
||||||
notifications: "Уведомления"
|
notifications: "Уведомления"
|
||||||
username: "Имя пользователя"
|
username: "Имя пользователя"
|
||||||
password: "Пароль"
|
password: "Пароль"
|
||||||
|
initialPasswordForSetup: "Пароль для начала настройки"
|
||||||
|
initialPasswordIsIncorrect: "Пароль для запуска настройки неверен"
|
||||||
|
initialPasswordForSetupDescription: "Если вы установили Misskey самостоятельно, используйте пароль, который вы указали в файле конфигурации.\nЕсли вы используете что-то вроде хостинга Misskey, используйте предоставленный пароль.\nЕсли вы не установили пароль, оставьте его пустым и продолжайте."
|
||||||
forgotPassword: "Забыли пароль?"
|
forgotPassword: "Забыли пароль?"
|
||||||
fetchingAsApObject: "Приём с других сайтов"
|
fetchingAsApObject: "Приём с других сайтов"
|
||||||
ok: "Подтвердить"
|
ok: "Подтвердить"
|
||||||
|
@ -232,6 +235,7 @@ clearCachedFilesConfirm: "Удалить все закэшированные ф
|
||||||
blockedInstances: "Заблокированные инстансы"
|
blockedInstances: "Заблокированные инстансы"
|
||||||
blockedInstancesDescription: "Введите список инстансов, которые хотите заблокировать. Они больше не смогут обмениваться с вашим инстансом."
|
blockedInstancesDescription: "Введите список инстансов, которые хотите заблокировать. Они больше не смогут обмениваться с вашим инстансом."
|
||||||
silencedInstances: "Заглушённые инстансы"
|
silencedInstances: "Заглушённые инстансы"
|
||||||
|
federationAllowedHosts: "Серверы, поддерживающие федерацию"
|
||||||
muteAndBlock: "Скрытие и блокировка"
|
muteAndBlock: "Скрытие и блокировка"
|
||||||
mutedUsers: "Скрытые пользователи"
|
mutedUsers: "Скрытые пользователи"
|
||||||
blockedUsers: "Заблокированные пользователи"
|
blockedUsers: "Заблокированные пользователи"
|
||||||
|
@ -330,6 +334,7 @@ renameFolder: "Переименовать папку"
|
||||||
deleteFolder: "Удалить папку"
|
deleteFolder: "Удалить папку"
|
||||||
folder: "Папка"
|
folder: "Папка"
|
||||||
addFile: "Добавить файл"
|
addFile: "Добавить файл"
|
||||||
|
showFile: "Посмотреть файл"
|
||||||
emptyDrive: "Диск пуст"
|
emptyDrive: "Диск пуст"
|
||||||
emptyFolder: "Папка пуста"
|
emptyFolder: "Папка пуста"
|
||||||
unableToDelete: "Удаление невозможно"
|
unableToDelete: "Удаление невозможно"
|
||||||
|
@ -372,7 +377,6 @@ enableLocalTimeline: "Включить локальную ленту"
|
||||||
enableGlobalTimeline: "Включить глобальную ленту"
|
enableGlobalTimeline: "Включить глобальную ленту"
|
||||||
disablingTimelinesInfo: "У администраторов и модераторов есть доступ ко всем лентам, даже если они отключены."
|
disablingTimelinesInfo: "У администраторов и модераторов есть доступ ко всем лентам, даже если они отключены."
|
||||||
registration: "Регистрация"
|
registration: "Регистрация"
|
||||||
enableRegistration: "Разрешить регистрацию"
|
|
||||||
invite: "Пригласить"
|
invite: "Пригласить"
|
||||||
driveCapacityPerLocalAccount: "Объём Диска на одного локального пользователя"
|
driveCapacityPerLocalAccount: "Объём Диска на одного локального пользователя"
|
||||||
driveCapacityPerRemoteAccount: "Объём Диска на одного пользователя с другого экземпляра"
|
driveCapacityPerRemoteAccount: "Объём Диска на одного пользователя с другого экземпляра"
|
||||||
|
@ -443,6 +447,7 @@ totp: "Приложение-аутентификатор"
|
||||||
totpDescription: "Описание приложения-аутентификатора"
|
totpDescription: "Описание приложения-аутентификатора"
|
||||||
moderator: "Модератор"
|
moderator: "Модератор"
|
||||||
moderation: "Модерация"
|
moderation: "Модерация"
|
||||||
|
moderationNote: "Примечания модератора"
|
||||||
moderationLogs: "Журнал модерации"
|
moderationLogs: "Журнал модерации"
|
||||||
nUsersMentioned: "Упомянуло пользователей: {n}"
|
nUsersMentioned: "Упомянуло пользователей: {n}"
|
||||||
securityKeyAndPasskey: "Ключ безопасности и парольная фраза"
|
securityKeyAndPasskey: "Ключ безопасности и парольная фраза"
|
||||||
|
@ -503,6 +508,8 @@ uiLanguage: "Язык интерфейса"
|
||||||
aboutX: "Описание {x}"
|
aboutX: "Описание {x}"
|
||||||
emojiStyle: "Стиль эмодзи"
|
emojiStyle: "Стиль эмодзи"
|
||||||
native: "Системные"
|
native: "Системные"
|
||||||
|
menuStyle: "Стиль меню"
|
||||||
|
style: "Стиль"
|
||||||
showNoteActionsOnlyHover: "Показывать кнопки у заметок только при наведении"
|
showNoteActionsOnlyHover: "Показывать кнопки у заметок только при наведении"
|
||||||
showReactionsCount: "Видеть количество реакций на заметках"
|
showReactionsCount: "Видеть количество реакций на заметках"
|
||||||
noHistory: "История пока пуста"
|
noHistory: "История пока пуста"
|
||||||
|
|
|
@ -331,7 +331,6 @@ enableLocalTimeline: "Povoliť lokálnu časovú os"
|
||||||
enableGlobalTimeline: "Povoliť globálnu časovú os"
|
enableGlobalTimeline: "Povoliť globálnu časovú os"
|
||||||
disablingTimelinesInfo: "Administrátori a moderátori majú vždy prístup ku všetkým časovým osiam, aj keď sú vypnuté."
|
disablingTimelinesInfo: "Administrátori a moderátori majú vždy prístup ku všetkým časovým osiam, aj keď sú vypnuté."
|
||||||
registration: "Registrácia"
|
registration: "Registrácia"
|
||||||
enableRegistration: "Povoliť registráciu nových používateľov"
|
|
||||||
invite: "Pozvať"
|
invite: "Pozvať"
|
||||||
driveCapacityPerLocalAccount: "Kapacita disku pre používateľa"
|
driveCapacityPerLocalAccount: "Kapacita disku pre používateľa"
|
||||||
driveCapacityPerRemoteAccount: "Kapacita disku pre vzdialeného používateľa"
|
driveCapacityPerRemoteAccount: "Kapacita disku pre vzdialeného používateľa"
|
||||||
|
|
|
@ -333,7 +333,6 @@ disconnectService: "Koppla från"
|
||||||
enableLocalTimeline: "Aktivera lokal tidslinje"
|
enableLocalTimeline: "Aktivera lokal tidslinje"
|
||||||
enableGlobalTimeline: "Aktivera global tidslinje"
|
enableGlobalTimeline: "Aktivera global tidslinje"
|
||||||
registration: "Registrera"
|
registration: "Registrera"
|
||||||
enableRegistration: "Aktivera registrering av nya användare"
|
|
||||||
invite: "Inbjudan"
|
invite: "Inbjudan"
|
||||||
inMb: "I megabyte"
|
inMb: "I megabyte"
|
||||||
bannerUrl: "URL till banner-bilden"
|
bannerUrl: "URL till banner-bilden"
|
||||||
|
@ -385,6 +384,7 @@ passwordLessLoginDescription: "Tillåter lösenordsfri inloggning med endast en
|
||||||
resetPassword: "Återställ Lösenord"
|
resetPassword: "Återställ Lösenord"
|
||||||
newPasswordIs: "Det nya lösenordet är \"{password}\""
|
newPasswordIs: "Det nya lösenordet är \"{password}\""
|
||||||
share: "Dela"
|
share: "Dela"
|
||||||
|
markAsReadAllTalkMessages: "Markera alla meddelanden som lästa"
|
||||||
help: "Hjälp"
|
help: "Hjälp"
|
||||||
close: "Stäng"
|
close: "Stäng"
|
||||||
invites: "Inbjudan"
|
invites: "Inbjudan"
|
||||||
|
@ -393,12 +393,15 @@ transfer: "Överför"
|
||||||
text: "Text"
|
text: "Text"
|
||||||
enable: "Aktivera"
|
enable: "Aktivera"
|
||||||
next: "Nästa"
|
next: "Nästa"
|
||||||
|
retype: "Ange igen"
|
||||||
|
noMessagesYet: "Inga meddelanden än"
|
||||||
invitations: "Inbjudan"
|
invitations: "Inbjudan"
|
||||||
invitationCode: "Inbjudningskod"
|
invitationCode: "Inbjudningskod"
|
||||||
available: "Tillgängligt"
|
available: "Tillgängligt"
|
||||||
weakPassword: "Svagt Lösenord"
|
weakPassword: "Svagt Lösenord"
|
||||||
normalPassword: "Medel Lösenord"
|
normalPassword: "Medel Lösenord"
|
||||||
strongPassword: "Starkt Lösenord"
|
strongPassword: "Starkt Lösenord"
|
||||||
|
signinWith: "Logga in med {x}"
|
||||||
signinFailed: "Kan inte logga in. Det angivna användarnamnet eller lösenordet är felaktigt."
|
signinFailed: "Kan inte logga in. Det angivna användarnamnet eller lösenordet är felaktigt."
|
||||||
or: "eller"
|
or: "eller"
|
||||||
language: "Språk"
|
language: "Språk"
|
||||||
|
@ -410,70 +413,124 @@ existingAccount: "Existerande konto"
|
||||||
regenerate: "Regenerera"
|
regenerate: "Regenerera"
|
||||||
fontSize: "Textstorlek"
|
fontSize: "Textstorlek"
|
||||||
openImageInNewTab: "Öppna bild i ny flik"
|
openImageInNewTab: "Öppna bild i ny flik"
|
||||||
|
appearance: "Utseende"
|
||||||
clientSettings: "Klientinställningar"
|
clientSettings: "Klientinställningar"
|
||||||
accountSettings: "Kontoinställningar"
|
accountSettings: "Kontoinställningar"
|
||||||
numberOfDays: "Antal dagar"
|
numberOfDays: "Antal dagar"
|
||||||
|
objectStorageUseSSL: "Använd SSL"
|
||||||
|
serverLogs: "Serverloggar"
|
||||||
deleteAll: "Radera alla"
|
deleteAll: "Radera alla"
|
||||||
sounds: "Ljud"
|
sounds: "Ljud"
|
||||||
sound: "Ljud"
|
sound: "Ljud"
|
||||||
listen: "Lyssna"
|
listen: "Lyssna"
|
||||||
none: "Ingen"
|
none: "Ingen"
|
||||||
volume: "Volym"
|
volume: "Volym"
|
||||||
|
notUseSound: "Inaktivera ljud"
|
||||||
chooseEmoji: "Välj en emoji"
|
chooseEmoji: "Välj en emoji"
|
||||||
recentUsed: "Senast använd"
|
recentUsed: "Senast använd"
|
||||||
install: "Installera"
|
install: "Installera"
|
||||||
uninstall: "Avinstallera"
|
uninstall: "Avinstallera"
|
||||||
|
deleteAllFiles: "Radera alla filer"
|
||||||
|
deleteAllFilesConfirm: "Är du säker på att du vill radera alla filer?"
|
||||||
menu: "Meny"
|
menu: "Meny"
|
||||||
|
addItem: "Lägg till objekt"
|
||||||
serviceworkerInfo: "Måste vara aktiverad för pushnotiser."
|
serviceworkerInfo: "Måste vara aktiverad för pushnotiser."
|
||||||
enableInfiniteScroll: "Ladda mer automatiskt"
|
enableInfiniteScroll: "Ladda mer automatiskt"
|
||||||
enablePlayer: "Öppna videospelare"
|
enablePlayer: "Öppna videospelare"
|
||||||
|
description: "Beskrivning"
|
||||||
permission: "Behörigheter"
|
permission: "Behörigheter"
|
||||||
enableAll: "Aktivera alla"
|
enableAll: "Aktivera alla"
|
||||||
|
disableAll: "Inaktivera alla"
|
||||||
edit: "Ändra"
|
edit: "Ändra"
|
||||||
enableEmail: "Aktivera epost-utskick"
|
enableEmail: "Aktivera epost-utskick"
|
||||||
email: "E-post"
|
email: "E-post"
|
||||||
|
emailAddress: "E-postadress"
|
||||||
smtpHost: "Värd"
|
smtpHost: "Värd"
|
||||||
smtpUser: "Användarnamn"
|
smtpUser: "Användarnamn"
|
||||||
smtpPass: "Lösenord"
|
smtpPass: "Lösenord"
|
||||||
emptyToDisableSmtpAuth: "Lämna användarnamn och lösenord tomt för att avaktivera SMTP verifiering"
|
emptyToDisableSmtpAuth: "Lämna användarnamn och lösenord tomt för att avaktivera SMTP verifiering"
|
||||||
|
makeActive: "Aktivera"
|
||||||
|
copy: "Kopiera"
|
||||||
|
overview: "Översikt"
|
||||||
logs: "Logg"
|
logs: "Logg"
|
||||||
|
database: "Databas"
|
||||||
channel: "kanal"
|
channel: "kanal"
|
||||||
create: "Skapa"
|
create: "Skapa"
|
||||||
other: "Mer"
|
other: "Mer"
|
||||||
|
abuseReports: "Rapporter"
|
||||||
|
reportAbuse: "Rapporter"
|
||||||
|
reportAbuseOf: "Rapportera {name}"
|
||||||
|
abuseReported: "Din rapport har skickats. Tack så mycket."
|
||||||
send: "Skicka"
|
send: "Skicka"
|
||||||
openInNewTab: "Öppna i ny flik"
|
openInNewTab: "Öppna i ny flik"
|
||||||
createNew: "Skapa ny"
|
createNew: "Skapa ny"
|
||||||
|
private: "Privat"
|
||||||
i18nInfo: "Misskey översätts till många olika språk av volontärer. Du kan hjälpa till med översättningen på {link}."
|
i18nInfo: "Misskey översätts till många olika språk av volontärer. Du kan hjälpa till med översättningen på {link}."
|
||||||
accountInfo: "Kontoinformation"
|
accountInfo: "Kontoinformation"
|
||||||
|
followersCount: "Antal följare"
|
||||||
|
yes: "Ja"
|
||||||
|
no: "Nej"
|
||||||
clips: "Klipp"
|
clips: "Klipp"
|
||||||
duplicate: "Duplicera"
|
duplicate: "Duplicera"
|
||||||
reloadToApplySetting: "Inställningen tillämpas efter sidan laddas om. Vill du göra det nu?"
|
reloadToApplySetting: "Inställningen tillämpas efter sidan laddas om. Vill du göra det nu?"
|
||||||
clearCache: "Rensa cache"
|
clearCache: "Rensa cache"
|
||||||
onlineUsersCount: "{n} användare är online"
|
onlineUsersCount: "{n} användare är online"
|
||||||
|
nUsers: "{n} användare"
|
||||||
nNotes: "{n} Noter"
|
nNotes: "{n} Noter"
|
||||||
backgroundColor: "Bakgrundsbild"
|
backgroundColor: "Bakgrundsbild"
|
||||||
textColor: "Text"
|
textColor: "Text"
|
||||||
|
saveAs: "Spara som..."
|
||||||
|
saveConfirm: "Spara ändringar?"
|
||||||
youAreRunningUpToDateClient: "Klienten du använder är uppdaterat."
|
youAreRunningUpToDateClient: "Klienten du använder är uppdaterat."
|
||||||
newVersionOfClientAvailable: "Ny version av klienten är tillgänglig."
|
newVersionOfClientAvailable: "Ny version av klienten är tillgänglig."
|
||||||
|
editCode: "Redigera kod"
|
||||||
publish: "Publicera"
|
publish: "Publicera"
|
||||||
typingUsers: "{users} skriver"
|
typingUsers: "{users} skriver"
|
||||||
|
goBack: "Tillbaka"
|
||||||
|
addDescription: "Lägg till beskrivning"
|
||||||
info: "Om"
|
info: "Om"
|
||||||
|
online: "Online"
|
||||||
|
active: "Aktiv"
|
||||||
|
offline: "Offline"
|
||||||
enabled: "Aktiverad"
|
enabled: "Aktiverad"
|
||||||
|
quickAction: "Snabbåtgärder"
|
||||||
user: "Användare"
|
user: "Användare"
|
||||||
|
gallery: "Galleri"
|
||||||
|
popularPosts: "Populära inlägg"
|
||||||
customCssWarn: "Den här inställningen borde bara ändrats av en som har rätta kunskaper. Om du ställer in det här fel så kan klienten sluta fungera rätt."
|
customCssWarn: "Den här inställningen borde bara ändrats av en som har rätta kunskaper. Om du ställer in det här fel så kan klienten sluta fungera rätt."
|
||||||
global: "Global"
|
global: "Global"
|
||||||
squareAvatars: "Visa fyrkantiga profilbilder"
|
squareAvatars: "Visa fyrkantiga profilbilder"
|
||||||
sent: "Skicka"
|
sent: "Skicka"
|
||||||
|
searchResult: "Sökresultat"
|
||||||
|
learnMore: "Läs mer"
|
||||||
misskeyUpdated: "Misskey har uppdaterats!"
|
misskeyUpdated: "Misskey har uppdaterats!"
|
||||||
|
translate: "Översätt"
|
||||||
|
controlPanel: "Kontrollpanel"
|
||||||
|
manageAccounts: "Hantera konton"
|
||||||
incorrectPassword: "Fel lösenord."
|
incorrectPassword: "Fel lösenord."
|
||||||
|
hide: "Dölj"
|
||||||
welcomeBackWithName: "Välkommen tillbaka, {name}"
|
welcomeBackWithName: "Välkommen tillbaka, {name}"
|
||||||
clickToFinishEmailVerification: "Tryck på [{ok}] för att slutföra bekräftelsen på e-postadressen."
|
clickToFinishEmailVerification: "Tryck på [{ok}] för att slutföra bekräftelsen på e-postadressen."
|
||||||
|
size: "Storlek"
|
||||||
searchByGoogle: "Sök"
|
searchByGoogle: "Sök"
|
||||||
|
indefinitely: "Aldrig"
|
||||||
|
tenMinutes: "10 minuter"
|
||||||
|
oneHour: "En timme"
|
||||||
|
oneDay: "En dag"
|
||||||
|
oneWeek: "En vecka"
|
||||||
|
oneMonth: "En månad"
|
||||||
|
threeMonths: "3 månader"
|
||||||
|
oneYear: "1 år"
|
||||||
|
threeDays: "3 dagar"
|
||||||
file: "Filer"
|
file: "Filer"
|
||||||
|
deleteAccount: "Radera konto"
|
||||||
|
label: "Etikett"
|
||||||
cannotUploadBecauseNoFreeSpace: "Kan inte ladda upp filen för att det finns inget lagringsutrymme kvar."
|
cannotUploadBecauseNoFreeSpace: "Kan inte ladda upp filen för att det finns inget lagringsutrymme kvar."
|
||||||
cannotUploadBecauseExceedsFileSizeLimit: "Kan inte ladda upp filen för att den är större än filstorleksgränsen."
|
cannotUploadBecauseExceedsFileSizeLimit: "Kan inte ladda upp filen för att den är större än filstorleksgränsen."
|
||||||
|
beta: "Beta"
|
||||||
enableAutoSensitive: "Automatisk NSFW markering"
|
enableAutoSensitive: "Automatisk NSFW markering"
|
||||||
enableAutoSensitiveDescription: "Tillåter automatiskt detektering och marketing av NSFW media genom Maskininlärning när möjligt. Även om denna inställningen är avaktiverad, kan det vara aktiverat på hela instansen."
|
enableAutoSensitiveDescription: "Tillåter automatiskt detektering och marketing av NSFW media genom Maskininlärning när möjligt. Även om denna inställningen är avaktiverad, kan det vara aktiverat på hela instansen."
|
||||||
|
move: "Flytta"
|
||||||
pushNotification: "Pushnotiser"
|
pushNotification: "Pushnotiser"
|
||||||
subscribePushNotification: "Aktivera pushnotiser"
|
subscribePushNotification: "Aktivera pushnotiser"
|
||||||
unsubscribePushNotification: "Avaktivera pushnotiser"
|
unsubscribePushNotification: "Avaktivera pushnotiser"
|
||||||
|
@ -482,38 +539,86 @@ pushNotificationNotSupported: "Din webbläsare eller instans har inte stöd för
|
||||||
windowMaximize: "Maximera"
|
windowMaximize: "Maximera"
|
||||||
windowMinimize: "Minimera"
|
windowMinimize: "Minimera"
|
||||||
windowRestore: "Återställ"
|
windowRestore: "Återställ"
|
||||||
|
tools: "Verktyg"
|
||||||
|
like: "Gilla"
|
||||||
pleaseDonate: "Misskey är en gratis programvara som används på {host}. Donera gärna för att göra utvecklingen ständigt, tack!"
|
pleaseDonate: "Misskey är en gratis programvara som används på {host}. Donera gärna för att göra utvecklingen ständigt, tack!"
|
||||||
|
roles: "Roll"
|
||||||
|
role: "Roll"
|
||||||
|
color: "Färg"
|
||||||
resetPasswordConfirm: "Återställ verkligen ditt lösenord?"
|
resetPasswordConfirm: "Återställ verkligen ditt lösenord?"
|
||||||
dataSaver: "Databesparing"
|
dataSaver: "Databesparing"
|
||||||
icon: "Profilbild"
|
icon: "Profilbild"
|
||||||
|
forYou: "För dig"
|
||||||
replies: "Svara"
|
replies: "Svara"
|
||||||
renotes: "Omnotera"
|
renotes: "Omnotera"
|
||||||
|
loadReplies: "Visa svar"
|
||||||
|
loadConversation: "Visa konversation"
|
||||||
|
authentication: "Autentisering"
|
||||||
|
sourceCode: "Källkod"
|
||||||
|
doReaction: "Lägg till reaktion"
|
||||||
|
code: "Kod"
|
||||||
|
gameRetry: "Försök igen"
|
||||||
|
inquiry: "Kontakt"
|
||||||
|
tryAgain: "Försök igen senare"
|
||||||
|
signinWithPasskey: "Logga in med nyckel"
|
||||||
|
unknownWebAuthnKey: "Okänd nyckel"
|
||||||
_delivery:
|
_delivery:
|
||||||
stop: "Suspenderad"
|
stop: "Suspenderad"
|
||||||
_type:
|
_type:
|
||||||
none: "Publiceras"
|
none: "Publiceras"
|
||||||
|
_initialAccountSetting:
|
||||||
|
profileSetting: "Profilinställningar"
|
||||||
|
_initialTutorial:
|
||||||
|
_reaction:
|
||||||
|
title: "Vad är reaktioner?"
|
||||||
_achievements:
|
_achievements:
|
||||||
_types:
|
_types:
|
||||||
_open3windows:
|
_open3windows:
|
||||||
title: "Flera Fönster"
|
title: "Flera Fönster"
|
||||||
description: "Ha minst 3 fönster öppna samtidigt"
|
description: "Ha minst 3 fönster öppna samtidigt"
|
||||||
|
_role:
|
||||||
|
edit: "Redigera roll"
|
||||||
_ffVisibility:
|
_ffVisibility:
|
||||||
public: "Publicera"
|
public: "Publicera"
|
||||||
|
private: "Privat"
|
||||||
|
_accountDelete:
|
||||||
|
accountDelete: "Radera konto"
|
||||||
|
_ad:
|
||||||
|
back: "Tillbaka"
|
||||||
|
_gallery:
|
||||||
|
like: "Gilla"
|
||||||
_email:
|
_email:
|
||||||
_follow:
|
_follow:
|
||||||
title: "följde dig"
|
title: "följde dig"
|
||||||
|
_aboutMisskey:
|
||||||
|
source: "Källkod"
|
||||||
|
projectMembers: "Projektmedlemmar"
|
||||||
_channel:
|
_channel:
|
||||||
setBanner: "Välj banner"
|
setBanner: "Välj banner"
|
||||||
removeBanner: "Ta bort banner"
|
removeBanner: "Ta bort banner"
|
||||||
|
nameAndDescription: "Namn och beskrivning"
|
||||||
|
_menuDisplay:
|
||||||
|
hide: "Dölj"
|
||||||
_theme:
|
_theme:
|
||||||
|
description: "Beskrivning"
|
||||||
|
color: "Färg"
|
||||||
keys:
|
keys:
|
||||||
mention: "Nämn"
|
mention: "Nämn"
|
||||||
renote: "Omnotera"
|
renote: "Omnotera"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "Noter"
|
note: "Noter"
|
||||||
notification: "Notifikationer"
|
notification: "Notifikationer"
|
||||||
|
_ago:
|
||||||
|
justNow: "Just nu"
|
||||||
_2fa:
|
_2fa:
|
||||||
|
step3Title: "Ange en autentiseringskod"
|
||||||
renewTOTPCancel: "Nej tack"
|
renewTOTPCancel: "Nej tack"
|
||||||
|
_permissions:
|
||||||
|
"read:reactions": "Visa dina reaktioner"
|
||||||
|
"write:reactions": "Redigera dina reaktioner"
|
||||||
|
"write:admin:delete-account": "Radera användarkonto"
|
||||||
|
"write:admin:roles": "Hantera roller"
|
||||||
|
"read:admin:roles": "Visa roller"
|
||||||
_antennaSources:
|
_antennaSources:
|
||||||
all: "Alla noter"
|
all: "Alla noter"
|
||||||
homeTimeline: "Noter från följda användare"
|
homeTimeline: "Noter från följda användare"
|
||||||
|
@ -530,13 +635,19 @@ _widgets:
|
||||||
_userList:
|
_userList:
|
||||||
chooseList: "Välj lista"
|
chooseList: "Välj lista"
|
||||||
_cw:
|
_cw:
|
||||||
|
hide: "Dölj"
|
||||||
show: "Ladda mer"
|
show: "Ladda mer"
|
||||||
|
chars: "{count} tecken"
|
||||||
|
files: "{count} fil(er)"
|
||||||
|
_poll:
|
||||||
|
infinite: "Aldrig"
|
||||||
_visibility:
|
_visibility:
|
||||||
home: "Hem"
|
home: "Hem"
|
||||||
followers: "Följare"
|
followers: "Följare"
|
||||||
_profile:
|
_profile:
|
||||||
name: "Namn"
|
name: "Namn"
|
||||||
username: "Användarnamn"
|
username: "Användarnamn"
|
||||||
|
metadataLabel: "Etikett"
|
||||||
changeAvatar: "Ändra profilbild"
|
changeAvatar: "Ändra profilbild"
|
||||||
changeBanner: "Ändra banner"
|
changeBanner: "Ändra banner"
|
||||||
_exportOrImport:
|
_exportOrImport:
|
||||||
|
@ -547,9 +658,12 @@ _exportOrImport:
|
||||||
userLists: "Listor"
|
userLists: "Listor"
|
||||||
_charts:
|
_charts:
|
||||||
federation: "Federation"
|
federation: "Federation"
|
||||||
|
activeUsers: "Aktiva användare"
|
||||||
_timelines:
|
_timelines:
|
||||||
home: "Hem"
|
home: "Hem"
|
||||||
global: "Global"
|
global: "Global"
|
||||||
|
_play:
|
||||||
|
summary: "Beskrivning"
|
||||||
_pages:
|
_pages:
|
||||||
blocks:
|
blocks:
|
||||||
image: "Bilder"
|
image: "Bilder"
|
||||||
|
@ -567,6 +681,8 @@ _notification:
|
||||||
reply: "Svara"
|
reply: "Svara"
|
||||||
renote: "Omnotera"
|
renote: "Omnotera"
|
||||||
_deck:
|
_deck:
|
||||||
|
addColumn: "Lägg till kolumn"
|
||||||
|
deleteProfile: "Radera profil"
|
||||||
_columns:
|
_columns:
|
||||||
notifications: "Notifikationer"
|
notifications: "Notifikationer"
|
||||||
tl: "Tidslinje"
|
tl: "Tidslinje"
|
||||||
|
@ -584,3 +700,10 @@ _abuseReport:
|
||||||
_moderationLogTypes:
|
_moderationLogTypes:
|
||||||
suspend: "Suspendera"
|
suspend: "Suspendera"
|
||||||
resetPassword: "Återställ Lösenord"
|
resetPassword: "Återställ Lösenord"
|
||||||
|
_reversi:
|
||||||
|
blackOrWhite: "Svart/Vit"
|
||||||
|
rules: "Regler"
|
||||||
|
black: "Svart"
|
||||||
|
white: "Vit"
|
||||||
|
_selfXssPrevention:
|
||||||
|
warning: "VARNING"
|
||||||
|
|
|
@ -8,6 +8,9 @@ search: "ค้นหา"
|
||||||
notifications: "เเจ้งเตือน"
|
notifications: "เเจ้งเตือน"
|
||||||
username: "ชื่อผู้ใช้"
|
username: "ชื่อผู้ใช้"
|
||||||
password: "รหัสผ่าน"
|
password: "รหัสผ่าน"
|
||||||
|
initialPasswordForSetup: "รหัสผ่านเริ่มต้นสำหรับการตั้งค่า"
|
||||||
|
initialPasswordIsIncorrect: "รหัสผ่านเริ่มต้นสำหรับตั้งค่านั้นไม่ถูกต้องค่ะ"
|
||||||
|
initialPasswordForSetupDescription: "ถ้าหากคุณติดตั้ง Misskey เอง ให้ใช้รหัสผ่านที่คุณป้อนในไฟล์กำหนดค่า \nถ้าหากคุณกำลังใช้บริการโฮสต์ Misskey ให้ใช้รหัสผ่านที่ได้รับมา\nถ้ายังไม่มีรหัสผ่าน ให้ข้ามช่องรหัสผ่านไป แล้วกดต่อไป"
|
||||||
forgotPassword: "ลืมรหัสผ่าน"
|
forgotPassword: "ลืมรหัสผ่าน"
|
||||||
fetchingAsApObject: "กำลังดึงข้อมูลจากสหพันธ์..."
|
fetchingAsApObject: "กำลังดึงข้อมูลจากสหพันธ์..."
|
||||||
ok: "ตกลง"
|
ok: "ตกลง"
|
||||||
|
@ -236,6 +239,8 @@ silencedInstances: "ปิดปากเซิร์ฟเวอร์นี้
|
||||||
silencedInstancesDescription: "ระบุโฮสต์ของเซิร์ฟเวอร์ที่ต้องการปิดปาก คั่นด้วยการขึ้นบรรทัดใหม่, บัญชีทั้งหมดของเซิร์ฟเวอร์ดังกล่าวจะถือว่าถูกปิดปากเช่นกัน ทำได้เฉพาะคำขอติดตามเท่านั้น และไม่สามารถกล่าวถึงบัญชีในเซิร์ฟเวอร์นี้ได้หากไม่ได้ถูกติดตามกลับ | สิ่งนี้ไม่มีผลต่ออินสแตนซ์ที่ถูกบล็อก"
|
silencedInstancesDescription: "ระบุโฮสต์ของเซิร์ฟเวอร์ที่ต้องการปิดปาก คั่นด้วยการขึ้นบรรทัดใหม่, บัญชีทั้งหมดของเซิร์ฟเวอร์ดังกล่าวจะถือว่าถูกปิดปากเช่นกัน ทำได้เฉพาะคำขอติดตามเท่านั้น และไม่สามารถกล่าวถึงบัญชีในเซิร์ฟเวอร์นี้ได้หากไม่ได้ถูกติดตามกลับ | สิ่งนี้ไม่มีผลต่ออินสแตนซ์ที่ถูกบล็อก"
|
||||||
mediaSilencedInstances: "เซิร์ฟเวอร์ที่ถูกปิดปากสื่อ"
|
mediaSilencedInstances: "เซิร์ฟเวอร์ที่ถูกปิดปากสื่อ"
|
||||||
mediaSilencedInstancesDescription: "ระบุโฮสต์ของเซิร์ฟเวอร์ที่ต้องการปิดปากสื่อ คั่นด้วยการขึ้นบรรทัดใหม่, ไฟล์ที่ถูกส่งจากบัญชีของเซิร์ฟเวอร์ดังกล่าวจะถือว่าถูกปิดปาก แล้วจะถูกติดเครื่องหมายว่ามีเนื้อหาละเอียดอ่อน และเอโมจิแบบกำหนดเองก็จะใช้ไม่ได้ด้วย | สิ่งนี้ไม่มีผลต่ออินสแตนซ์ที่ถูกบล็อก"
|
mediaSilencedInstancesDescription: "ระบุโฮสต์ของเซิร์ฟเวอร์ที่ต้องการปิดปากสื่อ คั่นด้วยการขึ้นบรรทัดใหม่, ไฟล์ที่ถูกส่งจากบัญชีของเซิร์ฟเวอร์ดังกล่าวจะถือว่าถูกปิดปาก แล้วจะถูกติดเครื่องหมายว่ามีเนื้อหาละเอียดอ่อน และเอโมจิแบบกำหนดเองก็จะใช้ไม่ได้ด้วย | สิ่งนี้ไม่มีผลต่ออินสแตนซ์ที่ถูกบล็อก"
|
||||||
|
federationAllowedHosts: "เซิร์ฟเวอร์ที่เปิดให้บริการแบบเฟเดอเรชั่น"
|
||||||
|
federationAllowedHostsDescription: "ระบุชื่อโฮสต์ของเซิร์ฟเวอร์ที่คุณต้องการอนุญาตให้เชื่อมต่อแบบเฟเดอเรชั่น โดยต้องเว้นวรรคแต่ละบรรทัด"
|
||||||
muteAndBlock: "ปิดเสียงและบล็อก"
|
muteAndBlock: "ปิดเสียงและบล็อก"
|
||||||
mutedUsers: "ผู้ใช้ที่ถูกปิดเสียง"
|
mutedUsers: "ผู้ใช้ที่ถูกปิดเสียง"
|
||||||
blockedUsers: "ผู้ใช้ที่ถูกบล็อก"
|
blockedUsers: "ผู้ใช้ที่ถูกบล็อก"
|
||||||
|
@ -334,6 +339,7 @@ renameFolder: "เปลี่ยนชื่อโฟลเดอร์"
|
||||||
deleteFolder: "ลบโฟลเดอร์"
|
deleteFolder: "ลบโฟลเดอร์"
|
||||||
folder: "โฟลเดอร์"
|
folder: "โฟลเดอร์"
|
||||||
addFile: "เพิ่มไฟล์"
|
addFile: "เพิ่มไฟล์"
|
||||||
|
showFile: "แสดงไฟล์"
|
||||||
emptyDrive: "ไดรฟ์ของคุณว่างเปล่านะ"
|
emptyDrive: "ไดรฟ์ของคุณว่างเปล่านะ"
|
||||||
emptyFolder: "โฟลเดอร์นี้ว่างเปล่า"
|
emptyFolder: "โฟลเดอร์นี้ว่างเปล่า"
|
||||||
unableToDelete: "ไม่สามารถลบออกได้"
|
unableToDelete: "ไม่สามารถลบออกได้"
|
||||||
|
@ -376,7 +382,6 @@ enableLocalTimeline: "เปิดใช้งานไทม์ไลน์ท
|
||||||
enableGlobalTimeline: "เปิดใช้งานไทม์ไลน์ทั่วโลก"
|
enableGlobalTimeline: "เปิดใช้งานไทม์ไลน์ทั่วโลก"
|
||||||
disablingTimelinesInfo: "ผู้ดูแลระบบและผู้ควบคุมจะสามารถเข้าถึงไทม์ไลน์ทั้งหมด ถึงแม้ว่าจะไม่ได้เปิดใช้งานก็ตาม"
|
disablingTimelinesInfo: "ผู้ดูแลระบบและผู้ควบคุมจะสามารถเข้าถึงไทม์ไลน์ทั้งหมด ถึงแม้ว่าจะไม่ได้เปิดใช้งานก็ตาม"
|
||||||
registration: "ลงทะเบียน"
|
registration: "ลงทะเบียน"
|
||||||
enableRegistration: "เปิดใช้งานการลงทะเบียนผู้ใช้ใหม่"
|
|
||||||
invite: "คำเชิญ"
|
invite: "คำเชิญ"
|
||||||
driveCapacityPerLocalAccount: "ความจุของไดรฟ์ต่อผู้ใช้ท้องถิ่น"
|
driveCapacityPerLocalAccount: "ความจุของไดรฟ์ต่อผู้ใช้ท้องถิ่น"
|
||||||
driveCapacityPerRemoteAccount: "ความจุของไดรฟ์ต่อผู้ใช้ระยะไกล"
|
driveCapacityPerRemoteAccount: "ความจุของไดรฟ์ต่อผู้ใช้ระยะไกล"
|
||||||
|
@ -448,6 +453,7 @@ totpDescription: "ใช้แอปยืนยันตัวตนเพื
|
||||||
moderator: "ผู้ควบคุม"
|
moderator: "ผู้ควบคุม"
|
||||||
moderation: "การกลั่นกรอง"
|
moderation: "การกลั่นกรอง"
|
||||||
moderationNote: "โน้ตการกลั่นกรอง"
|
moderationNote: "โน้ตการกลั่นกรอง"
|
||||||
|
moderationNoteDescription: "คุณสามารถใส่โน้ตส่วนตัวที่เฉพาะผู้ดูแลระบบเท่านั้นที่สามารถเข้าถึงได้"
|
||||||
addModerationNote: "เพิ่มโน้ตการกลั่นกรอง"
|
addModerationNote: "เพิ่มโน้ตการกลั่นกรอง"
|
||||||
moderationLogs: "ปูมการควบคุมดูแล"
|
moderationLogs: "ปูมการควบคุมดูแล"
|
||||||
nUsersMentioned: "กล่าวถึงโดยผู้ใช้ {n} ราย"
|
nUsersMentioned: "กล่าวถึงโดยผู้ใช้ {n} ราย"
|
||||||
|
@ -509,6 +515,10 @@ uiLanguage: "ภาษาอินเทอร์เฟซผู้ใช้ง
|
||||||
aboutX: "เกี่ยวกับ {x}"
|
aboutX: "เกี่ยวกับ {x}"
|
||||||
emojiStyle: "สไตล์ของเอโมจิ"
|
emojiStyle: "สไตล์ของเอโมจิ"
|
||||||
native: "ภาษาแม่"
|
native: "ภาษาแม่"
|
||||||
|
menuStyle: "สไตล์เมนู"
|
||||||
|
style: "สไตล์"
|
||||||
|
drawer: "ตัววาด"
|
||||||
|
popup: "ป๊อปอัพ"
|
||||||
showNoteActionsOnlyHover: "แสดงการดำเนินการโน้ตเมื่อโฮเวอร์(วางเมาส์เหนือ)เท่านั้น"
|
showNoteActionsOnlyHover: "แสดงการดำเนินการโน้ตเมื่อโฮเวอร์(วางเมาส์เหนือ)เท่านั้น"
|
||||||
showReactionsCount: "แสดงจำนวนรีแอกชั่นในโน้ต"
|
showReactionsCount: "แสดงจำนวนรีแอกชั่นในโน้ต"
|
||||||
noHistory: "ไม่มีประวัติ"
|
noHistory: "ไม่มีประวัติ"
|
||||||
|
@ -591,6 +601,8 @@ ascendingOrder: "เรียงลำดับขึ้น"
|
||||||
descendingOrder: "เรียงลำดับลง"
|
descendingOrder: "เรียงลำดับลง"
|
||||||
scratchpad: "Scratchpad"
|
scratchpad: "Scratchpad"
|
||||||
scratchpadDescription: "Scratchpad ให้สภาพแวดล้อมสำหรับการทดลอง AiScript คุณสามารถเขียนโค้ด/สั่งดำเนินการ/ตรวจสอบผลลัพธ์ ของการโต้ตอบกับ Misskey ได้"
|
scratchpadDescription: "Scratchpad ให้สภาพแวดล้อมสำหรับการทดลอง AiScript คุณสามารถเขียนโค้ด/สั่งดำเนินการ/ตรวจสอบผลลัพธ์ ของการโต้ตอบกับ Misskey ได้"
|
||||||
|
uiInspector: "ตัวตรวจสอบ UI"
|
||||||
|
uiInspectorDescription: "คุณสามารถตรวจสอบรายชื่อเซิร์ฟเวอร์ที่เกี่ยวข้องกับส่วนประกอบอินเตอร์เฟซผู้ใช้ (UI) บนหน่วยความจำของระบบ ส่วนประกอบ UI เหล่านี้จะถูกสร้างขึ้นโดยฟังก์ชัน Ui:C:"
|
||||||
output: "เอาท์พุต"
|
output: "เอาท์พุต"
|
||||||
script: "สคริปต์"
|
script: "สคริปต์"
|
||||||
disablePagesScript: "ปิดการใช้งาน AiScript บนเพจ"
|
disablePagesScript: "ปิดการใช้งาน AiScript บนเพจ"
|
||||||
|
@ -909,6 +921,7 @@ followersVisibility: "การมองเห็นผู้ที่กำล
|
||||||
continueThread: "ดูความต่อเนื่องเธรด"
|
continueThread: "ดูความต่อเนื่องเธรด"
|
||||||
deleteAccountConfirm: "การดำเนินการนี้จะลบบัญชีของคุณอย่างถาวรเลยนะ แน่ใจหรอดำเนินการ?"
|
deleteAccountConfirm: "การดำเนินการนี้จะลบบัญชีของคุณอย่างถาวรเลยนะ แน่ใจหรอดำเนินการ?"
|
||||||
incorrectPassword: "รหัสผ่านไม่ถูกต้อง"
|
incorrectPassword: "รหัสผ่านไม่ถูกต้อง"
|
||||||
|
incorrectTotp: "รหัสยืนยันตัวตนแบบใช้ครั้งเดียวที่ท่านได้ระบุมานั้น ไม่ถูกต้องหรือหมดอายุลงแล้วค่ะ"
|
||||||
voteConfirm: "ต้องการโหวต “{choice}” ใช่ไหม?"
|
voteConfirm: "ต้องการโหวต “{choice}” ใช่ไหม?"
|
||||||
hide: "ซ่อน"
|
hide: "ซ่อน"
|
||||||
useDrawerReactionPickerForMobile: "แสดง ตัวจิ้มรีแอคชั่น เป็นแบบลิ้นชัก เมื่อใช้บนมือถือ"
|
useDrawerReactionPickerForMobile: "แสดง ตัวจิ้มรีแอคชั่น เป็นแบบลิ้นชัก เมื่อใช้บนมือถือ"
|
||||||
|
@ -1073,6 +1086,7 @@ retryAllQueuesConfirmTitle: "ลองใหม่ทั้งหมดจริ
|
||||||
retryAllQueuesConfirmText: "สิ่งนี้จะเพิ่มการโหลดเซิร์ฟเวอร์ชั่วคราวนะ"
|
retryAllQueuesConfirmText: "สิ่งนี้จะเพิ่มการโหลดเซิร์ฟเวอร์ชั่วคราวนะ"
|
||||||
enableChartsForRemoteUser: "สร้างแผนภูมิข้อมูลผู้ใช้ระยะไกล"
|
enableChartsForRemoteUser: "สร้างแผนภูมิข้อมูลผู้ใช้ระยะไกล"
|
||||||
enableChartsForFederatedInstances: "สร้างแผนภูมิของเซิร์ฟเวอร์ระยะไกล"
|
enableChartsForFederatedInstances: "สร้างแผนภูมิของเซิร์ฟเวอร์ระยะไกล"
|
||||||
|
enableStatsForFederatedInstances: "ดึงข้อมูลสถิติจากเซิร์ฟเวอร์ที่อยู่ห่างไกล"
|
||||||
showClipButtonInNoteFooter: "เพิ่ม “คลิป” ไปยังเมนูสั่งการของโน้ต"
|
showClipButtonInNoteFooter: "เพิ่ม “คลิป” ไปยังเมนูสั่งการของโน้ต"
|
||||||
reactionsDisplaySize: "ขนาดของรีแอคชั่น"
|
reactionsDisplaySize: "ขนาดของรีแอคชั่น"
|
||||||
limitWidthOfReaction: "จำกัดความกว้างสูงสุดของรีแอคชั่นและแสดงให้เล็กลง"
|
limitWidthOfReaction: "จำกัดความกว้างสูงสุดของรีแอคชั่นและแสดงให้เล็กลง"
|
||||||
|
@ -1259,6 +1273,32 @@ confirmWhenRevealingSensitiveMedia: "ตรวจสอบก่อนแสด
|
||||||
sensitiveMediaRevealConfirm: "สื่อนี้มีเนื้อหาละเอียดอ่อน, ต้องการแสดงใช่ไหม?"
|
sensitiveMediaRevealConfirm: "สื่อนี้มีเนื้อหาละเอียดอ่อน, ต้องการแสดงใช่ไหม?"
|
||||||
createdLists: "รายชื่อที่ถูกสร้าง"
|
createdLists: "รายชื่อที่ถูกสร้าง"
|
||||||
createdAntennas: "เสาอากาศที่ถูกสร้าง"
|
createdAntennas: "เสาอากาศที่ถูกสร้าง"
|
||||||
|
fromX: "จาก {x}"
|
||||||
|
genEmbedCode: "สร้างรหัสฝัง"
|
||||||
|
noteOfThisUser: "โน้ตโดยผู้ใช้นี้"
|
||||||
|
clipNoteLimitExceeded: "ไม่สามารถเพิ่มโน้ตเพิ่มเติมในคลิปนี้ได้อีกแล้ว"
|
||||||
|
performance: "ประสิทธิภาพ"
|
||||||
|
modified: "แก้ไข"
|
||||||
|
discard: "ละทิ้ง"
|
||||||
|
thereAreNChanges: "มีอยู่ {n} เปลี่ยนแปลง(s)"
|
||||||
|
signinWithPasskey: "ลงชื่อเข้าใช้ด้วย Passkey"
|
||||||
|
unknownWebAuthnKey: "พาสคีย์ไม่ถูกต้องค่ะ"
|
||||||
|
passkeyVerificationFailed: "การยืนยันกุญแจดิจิทัลไม่สำเร็จค่ะ"
|
||||||
|
passkeyVerificationSucceededButPasswordlessLoginDisabled: "การยืนยันพาสคีย์สำเร็จแล้ว แต่การลงชื่อเข้าใช้แบบไม่ต้องใส่รหัสผ่านถูกปิดใช้งานแล้ว"
|
||||||
|
messageToFollower: "ข้อความถึงผู้ติดตาม"
|
||||||
|
target: "เป้า"
|
||||||
|
testCaptchaWarning: "ฟังก์ชันนี้มีไว้สำหรับทดสอบ CAPTCHA เท่านั้น\n<strong>ห้ามนำไปใช้ในระบบจริงโดยเด็ดขาด</strong>"
|
||||||
|
prohibitedWordsForNameOfUser: "คำนี้ไม่สามารถใช้เป็นชื่อผู้ใช้ได้"
|
||||||
|
prohibitedWordsForNameOfUserDescription: "หากมีสตริงใดๆ ในรายการนี้ปรากฏอยู่ในชื่อของผู้ใช้ ชื่อนั้นจะถูกปฏิเสธ ผู้ใช้ที่มีสิทธิ์แต่ผู้ดูแลระบบนั้นจะไม่ได้รับผลกระทบใดๆจากข้อจำกัดนี้ค่ะ"
|
||||||
|
yourNameContainsProhibitedWords: "ชื่อของคุณนั้นมีคำที่ต้องห้าม"
|
||||||
|
yourNameContainsProhibitedWordsDescription: "ถ้าหากคุณต้องการใช้ชื่อนี้ กรุณาติดต่อผู้ดูแลระบบของเซิร์ฟเวอร์นะค่ะ"
|
||||||
|
_abuseUserReport:
|
||||||
|
forward: "ส่งต่อ"
|
||||||
|
forwardDescription: "ส่งรายงานไปยังเซิร์ฟเวอร์ระยะไกลโดยใช้บัญชีระบบที่ไม่ระบุตัวตน"
|
||||||
|
resolve: "แก้ไข"
|
||||||
|
accept: "ยอมรับ"
|
||||||
|
reject: "ปฏิเสธ"
|
||||||
|
resolveTutorial: "ถ้าหากรายงานนี้มีเนื้อหาถูกต้อง ให้เลือก \"ยอมรับ\" เพื่อปิดเคสกรณีนี้โดยถือว่าได้รับการแก้ไขแล้ว\nถ้าหากเนื้อหาในรายงานนี้นั้นไม่ถูกต้อง ให้เลือก \"ปฏิเสธ\" เพื่อปิดเคสกรณีนี้โดยถือว่าไม่ได้รับการแก้ไข"
|
||||||
_delivery:
|
_delivery:
|
||||||
status: "สถานะการจัดส่ง"
|
status: "สถานะการจัดส่ง"
|
||||||
stop: "ระงับการส่ง"
|
stop: "ระงับการส่ง"
|
||||||
|
@ -1393,8 +1433,10 @@ _serverSettings:
|
||||||
fanoutTimelineDescription: "เพิ่มประสิทธิภาพการดึงข้อมูลไทม์ไลน์อย่างมาก และลดภาระในฐานข้อมูลเมื่อเปิดใช้งาน ในทางกลับกัน การใช้หน่วยความจำของ Redis จะเพิ่มขึ้น ลองปิดการใช้งานนี้ในกรณีที่หน่วยความจำเซิร์ฟเวอร์เหลือน้อยหรือเซิร์ฟเวอร์ไม่เสถียร"
|
fanoutTimelineDescription: "เพิ่มประสิทธิภาพการดึงข้อมูลไทม์ไลน์อย่างมาก และลดภาระในฐานข้อมูลเมื่อเปิดใช้งาน ในทางกลับกัน การใช้หน่วยความจำของ Redis จะเพิ่มขึ้น ลองปิดการใช้งานนี้ในกรณีที่หน่วยความจำเซิร์ฟเวอร์เหลือน้อยหรือเซิร์ฟเวอร์ไม่เสถียร"
|
||||||
fanoutTimelineDbFallback: "ฟอลแบ๊กกลับฐานข้อมูล"
|
fanoutTimelineDbFallback: "ฟอลแบ๊กกลับฐานข้อมูล"
|
||||||
fanoutTimelineDbFallbackDescription: "เมื่อเปิดใช้งาน หากไม่ได้แคชไทม์ไลน์ ไทม์ไลน์จะฟอลแบ๊กไปยังฐานข้อมูลสำหรับการ query เพิ่มเติม การปิดใช้งานจะช่วยลดภาระของเซิร์ฟเวอร์ด้วยการกำจัดกระบวนฟอลแบ๊ก แต่มันก็จะจำกัดช่วงเวลาไทม์ไลน์ที่สามารถดึงข้อมูลได้"
|
fanoutTimelineDbFallbackDescription: "เมื่อเปิดใช้งาน หากไม่ได้แคชไทม์ไลน์ ไทม์ไลน์จะฟอลแบ๊กไปยังฐานข้อมูลสำหรับการ query เพิ่มเติม การปิดใช้งานจะช่วยลดภาระของเซิร์ฟเวอร์ด้วยการกำจัดกระบวนฟอลแบ๊ก แต่มันก็จะจำกัดช่วงเวลาไทม์ไลน์ที่สามารถดึงข้อมูลได้"
|
||||||
|
reactionsBufferingDescription: "เมื่อเปิดใช้งานฟังก์ชันนี้ก็จะช่วยลด latency ในการสร้างปฏิกิริยา แต่อาจจะส่งผลให้ memory footprint ของ Redis เพิ่มขึ้นนะ"
|
||||||
inquiryUrl: "URL สำหรับการติดต่อสอบถาม"
|
inquiryUrl: "URL สำหรับการติดต่อสอบถาม"
|
||||||
inquiryUrlDescription: "ระบุ URL ของหน้าเว็บที่มีแบบฟอร์มสำหรับติดต่อผู้ดูแลเซิร์ฟเวอร์ หรือข้อมูลการติดต่อของผู้ดูแลเซิร์ฟเวอร์"
|
inquiryUrlDescription: "ระบุ URL ของหน้าเว็บที่มีแบบฟอร์มสำหรับติดต่อผู้ดูแลเซิร์ฟเวอร์ หรือข้อมูลการติดต่อของผู้ดูแลเซิร์ฟเวอร์"
|
||||||
|
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "ถ้าหากไม่มีการตรวจสอบจากผู้ดูแลระบบหรือไม่มีความเคลื่อนไหวมาเป็นระยะเวลาหนึ่ง ระบบจะทำการปิดใช้งานฟังก์ชันนี้โดยอัตโนมัติ เพื่อลดความเสี่ยงในการถูกโจมตีด้วยสแปมและอื่นๆ"
|
||||||
_accountMigration:
|
_accountMigration:
|
||||||
moveFrom: "ย้ายจากบัญชีอื่นมาที่บัญชีนี้"
|
moveFrom: "ย้ายจากบัญชีอื่นมาที่บัญชีนี้"
|
||||||
moveFromSub: "สร้างนามแฝงไปยังบัญชีอื่น"
|
moveFromSub: "สร้างนามแฝงไปยังบัญชีอื่น"
|
||||||
|
@ -1726,6 +1768,11 @@ _role:
|
||||||
canSearchNotes: "การใช้การค้นหาโน้ต"
|
canSearchNotes: "การใช้การค้นหาโน้ต"
|
||||||
canUseTranslator: "การใช้งานแปล"
|
canUseTranslator: "การใช้งานแปล"
|
||||||
avatarDecorationLimit: "จำนวนการตกแต่งไอคอนสูงสุดที่สามารถติดตั้งได้"
|
avatarDecorationLimit: "จำนวนการตกแต่งไอคอนสูงสุดที่สามารถติดตั้งได้"
|
||||||
|
canImportAntennas: "อนุญาตให้นำเข้าเสาอากาศ"
|
||||||
|
canImportBlocking: "อนุญาตให้นำเข้าการบล็อก"
|
||||||
|
canImportFollowing: "อนุญาตให้นำเข้ารายการต่อไปนี้"
|
||||||
|
canImportMuting: "อนุญาตให้นำเข้าการปิดกั้น"
|
||||||
|
canImportUserLists: "อนุญาตให้นำเข้ารายการ"
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "มอบหมายให้มีบทบาทแบบทำมือ"
|
roleAssignedTo: "มอบหมายให้มีบทบาทแบบทำมือ"
|
||||||
isLocal: "ผู้ใช้ท้องถิ่น"
|
isLocal: "ผู้ใช้ท้องถิ่น"
|
||||||
|
@ -2219,6 +2266,9 @@ _profile:
|
||||||
changeBanner: "เปลี่ยนแบนเนอร์"
|
changeBanner: "เปลี่ยนแบนเนอร์"
|
||||||
verifiedLinkDescription: "หากป้อน URL ที่มีลิงก์ไปยังโปรไฟล์ของคุณ ไอคอนการยืนยันความเป็นเจ้าของจะแสดงถัดจากฟิลด์นั้น ๆ"
|
verifiedLinkDescription: "หากป้อน URL ที่มีลิงก์ไปยังโปรไฟล์ของคุณ ไอคอนการยืนยันความเป็นเจ้าของจะแสดงถัดจากฟิลด์นั้น ๆ"
|
||||||
avatarDecorationMax: "คุณสามารถเพิ่มการตกแต่งได้สูงสุด {max}"
|
avatarDecorationMax: "คุณสามารถเพิ่มการตกแต่งได้สูงสุด {max}"
|
||||||
|
followedMessage: "ส่งข้อความเมื่อมีคนกดติดตาม"
|
||||||
|
followedMessageDescription: "ส่งข้อความเมื่อมีคนกดติดตามแล้ว"
|
||||||
|
followedMessageDescriptionForLockedAccount: "ถ้าหากคุณตั้งค่าให้คนอื่นต้องขออนุญาตก่อนที่จะติดตามคุณ ระบบจะขึ้นข้อความนี้ในตอนที่คุณอนุมัติให้เขาติดตาม"
|
||||||
_exportOrImport:
|
_exportOrImport:
|
||||||
allNotes: "โน้ตทั้งหมด"
|
allNotes: "โน้ตทั้งหมด"
|
||||||
favoritedNotes: "โน้ตที่ถูกใจไว้"
|
favoritedNotes: "โน้ตที่ถูกใจไว้"
|
||||||
|
@ -2311,6 +2361,7 @@ _pages:
|
||||||
eyeCatchingImageSet: "ตั้งค่าภาพขนาดย่อ"
|
eyeCatchingImageSet: "ตั้งค่าภาพขนาดย่อ"
|
||||||
eyeCatchingImageRemove: "ลบภาพขนาดย่อ"
|
eyeCatchingImageRemove: "ลบภาพขนาดย่อ"
|
||||||
chooseBlock: "เพิ่มบล็อค"
|
chooseBlock: "เพิ่มบล็อค"
|
||||||
|
enterSectionTitle: "ป้อนชื่อหัวข้อ"
|
||||||
selectType: "เลือกชนิด"
|
selectType: "เลือกชนิด"
|
||||||
contentBlocks: "เนื้อหา"
|
contentBlocks: "เนื้อหา"
|
||||||
inputBlocks: "ป้อนข้อมูล"
|
inputBlocks: "ป้อนข้อมูล"
|
||||||
|
@ -2356,6 +2407,8 @@ _notification:
|
||||||
renotedBySomeUsers: "รีโน้ตจากผู้ใช้ {n} ราย"
|
renotedBySomeUsers: "รีโน้ตจากผู้ใช้ {n} ราย"
|
||||||
followedBySomeUsers: "มีผู้ติดตาม {n} ราย"
|
followedBySomeUsers: "มีผู้ติดตาม {n} ราย"
|
||||||
flushNotification: "ล้างประวัติการแจ้งเตือน"
|
flushNotification: "ล้างประวัติการแจ้งเตือน"
|
||||||
|
exportOfXCompleted: "การดำเนินการส่งออก {x} ได้เสร็จสิ้นลงแล้ว"
|
||||||
|
login: "มีคนล็อกอิน"
|
||||||
_types:
|
_types:
|
||||||
all: "ทั้งหมด"
|
all: "ทั้งหมด"
|
||||||
note: "โน้ตใหม่"
|
note: "โน้ตใหม่"
|
||||||
|
@ -2370,7 +2423,9 @@ _notification:
|
||||||
followRequestAccepted: "อนุมัติให้ติดตามแล้ว"
|
followRequestAccepted: "อนุมัติให้ติดตามแล้ว"
|
||||||
roleAssigned: "ให้บทบาท"
|
roleAssigned: "ให้บทบาท"
|
||||||
achievementEarned: "ปลดล็อกความสำเร็จแล้ว"
|
achievementEarned: "ปลดล็อกความสำเร็จแล้ว"
|
||||||
|
exportCompleted: "กระบวนการส่งออกข้อมูลได้เสร็จสิ้นสมบูรณ์แล้ว"
|
||||||
login: "เข้าสู่ระบบ"
|
login: "เข้าสู่ระบบ"
|
||||||
|
test: "ทดสอบระบบแจ้งเตือน"
|
||||||
app: "การแจ้งเตือนจากแอปที่มีลิงก์"
|
app: "การแจ้งเตือนจากแอปที่มีลิงก์"
|
||||||
_actions:
|
_actions:
|
||||||
followBack: "ติดตามกลับด้วย"
|
followBack: "ติดตามกลับด้วย"
|
||||||
|
@ -2436,7 +2491,10 @@ _webhookSettings:
|
||||||
abuseReport: "เมื่อมีการรายงานจากผู้ใช้"
|
abuseReport: "เมื่อมีการรายงานจากผู้ใช้"
|
||||||
abuseReportResolved: "เมื่อมีการจัดการกับการรายงานจากผู้ใช้"
|
abuseReportResolved: "เมื่อมีการจัดการกับการรายงานจากผู้ใช้"
|
||||||
userCreated: "เมื่อผู้ใช้ถูกสร้างขึ้น"
|
userCreated: "เมื่อผู้ใช้ถูกสร้างขึ้น"
|
||||||
|
inactiveModeratorsWarning: "เมื่อผู้ดูแลระบบไม่ได้ใช้งานมานานระยะหนึ่ง"
|
||||||
|
inactiveModeratorsInvitationOnlyChanged: "เมื่อผู้ดูแลระบบที่ไม่ได้ใช้งานมานาน และเซิร์ฟเวอร์เปลี่ยนเป็นแบบเชิญเข้าร่วมเท่านั้น"
|
||||||
deleteConfirm: "ต้องการลบ Webhook ใช่ไหม?"
|
deleteConfirm: "ต้องการลบ Webhook ใช่ไหม?"
|
||||||
|
testRemarks: "คลิกปุ่มทางด้านขวาของสวิตช์เพื่อส่ง Webhook ทดสอบที่มีข้อมูลจำลอง"
|
||||||
_abuseReport:
|
_abuseReport:
|
||||||
_notificationRecipient:
|
_notificationRecipient:
|
||||||
createRecipient: "เพิ่มปลายทางการแจ้งเตือนการรายงาน"
|
createRecipient: "เพิ่มปลายทางการแจ้งเตือนการรายงาน"
|
||||||
|
@ -2480,6 +2538,8 @@ _moderationLogTypes:
|
||||||
markSensitiveDriveFile: "ทำเครื่องหมายไฟล์ว่ามีเนื้อหาละเอียดอ่อน"
|
markSensitiveDriveFile: "ทำเครื่องหมายไฟล์ว่ามีเนื้อหาละเอียดอ่อน"
|
||||||
unmarkSensitiveDriveFile: "ยกเลิกทำเครื่องหมายไฟล์ว่ามีเนื้อหาละเอียดอ่อน"
|
unmarkSensitiveDriveFile: "ยกเลิกทำเครื่องหมายไฟล์ว่ามีเนื้อหาละเอียดอ่อน"
|
||||||
resolveAbuseReport: "รายงานได้รับการแก้ไขแล้ว"
|
resolveAbuseReport: "รายงานได้รับการแก้ไขแล้ว"
|
||||||
|
forwardAbuseReport: "ได้ส่งรายงานไปแล้ว"
|
||||||
|
updateAbuseReportNote: "โน้ตการกลั่นกรองที่รายงานไปนั้น ได้รับการอัปเดตแล้ว"
|
||||||
createInvitation: "สร้างรหัสเชิญ"
|
createInvitation: "สร้างรหัสเชิญ"
|
||||||
createAd: "สร้างโฆษณาแล้ว"
|
createAd: "สร้างโฆษณาแล้ว"
|
||||||
deleteAd: "ลบโฆษณาออกแล้ว"
|
deleteAd: "ลบโฆษณาออกแล้ว"
|
||||||
|
@ -2495,6 +2555,10 @@ _moderationLogTypes:
|
||||||
createAbuseReportNotificationRecipient: "สร้างปลายทางการแจ้งเตือนการรายงาน"
|
createAbuseReportNotificationRecipient: "สร้างปลายทางการแจ้งเตือนการรายงาน"
|
||||||
updateAbuseReportNotificationRecipient: "อัปเดตปลายทางการแจ้งเตือนการรายงาน"
|
updateAbuseReportNotificationRecipient: "อัปเดตปลายทางการแจ้งเตือนการรายงาน"
|
||||||
deleteAbuseReportNotificationRecipient: "ลบปลายทางการแจ้งเตือนการรายงาน"
|
deleteAbuseReportNotificationRecipient: "ลบปลายทางการแจ้งเตือนการรายงาน"
|
||||||
|
deleteAccount: "บัญชีถูกลบไปแล้ว"
|
||||||
|
deletePage: "เพจถูกลบออกไปแล้ว"
|
||||||
|
deleteFlash: "Play ถูกลบออกไปแล้ว"
|
||||||
|
deleteGalleryPost: "โพสต์แกลเลอรี่ถูกลบออกแล้ว"
|
||||||
_fileViewer:
|
_fileViewer:
|
||||||
title: "รายละเอียดไฟล์"
|
title: "รายละเอียดไฟล์"
|
||||||
type: "ประเภทไฟล์"
|
type: "ประเภทไฟล์"
|
||||||
|
@ -2631,3 +2695,17 @@ _contextMenu:
|
||||||
app: "แอปพลิเคชัน"
|
app: "แอปพลิเคชัน"
|
||||||
appWithShift: "แอปฟลิเคชันด้วยปุ่มยกแคร่ (Shift)"
|
appWithShift: "แอปฟลิเคชันด้วยปุ่มยกแคร่ (Shift)"
|
||||||
native: "UI ของเบราว์เซอร์"
|
native: "UI ของเบราว์เซอร์"
|
||||||
|
_embedCodeGen:
|
||||||
|
title: "ปรับแต่งโค้ดฝัง"
|
||||||
|
header: "แสดงส่วนหัว"
|
||||||
|
autoload: "โหลดเพิ่มโดยอัตโนมัติ (เลิกใช้แล้ว)"
|
||||||
|
maxHeight: "ความสูงสุด"
|
||||||
|
maxHeightDescription: "หากถ้าตั้งค่าเป็น 0 จะทำให้ไม่มีการจำกัดความสูงของวิดเจ็ต แต่ควรตั้งค่าเป็นตัวเลขอื่นๆ เพื่อไม่ให้วิดเจ็ตยืดตัวลงไปเรื่อยๆ"
|
||||||
|
maxHeightWarn: "การจำกัดความสูงสูงสุดถูกปิดใช้งาน (0) หากไม่ได้ตั้งใจให้เป็นเช่นนี้ โปรดตั้งค่าความสูงสูงสุดให้เป็นค่าอื่นๆแทน"
|
||||||
|
previewIsNotActual: "การแสดงผลนั้นต่างจากการฝังจริงเพราะเกินขอบเขตที่แสดงบนหน้าจอตัวอย่างนะ"
|
||||||
|
rounded: "ทำให้มันกลม"
|
||||||
|
border: "เพิ่มขอบให้กับกรอบด้านนอก"
|
||||||
|
applyToPreview: "นำไปใช้กับการแสดงตัวอย่าง"
|
||||||
|
generateCode: "สร้างโค้ดสำหรับการฝัง"
|
||||||
|
codeGenerated: "รหัสถูกสร้างขึ้นแล้ว"
|
||||||
|
codeGeneratedDescription: "นำโค้ดที่สร้างแล้วไปวางในเว็บไซต์ของคุณเพื่อฝังเนื้อหา"
|
||||||
|
|
|
@ -344,7 +344,6 @@ today: "Bugün"
|
||||||
monthX: "{month} ay"
|
monthX: "{month} ay"
|
||||||
pages: "Sayfalar"
|
pages: "Sayfalar"
|
||||||
integration: "Entegrasyon"
|
integration: "Entegrasyon"
|
||||||
enableRegistration: "Kayıtlara izin ver"
|
|
||||||
basicInfo: "Temel bilgiler"
|
basicInfo: "Temel bilgiler"
|
||||||
pinnedUsers: "Sabitlenmiş kullanıcılar"
|
pinnedUsers: "Sabitlenmiş kullanıcılar"
|
||||||
pinnedNotes: "Sabitlenen"
|
pinnedNotes: "Sabitlenen"
|
||||||
|
|
|
@ -334,7 +334,6 @@ enableLocalTimeline: "Увімкнути локальну стрічку"
|
||||||
enableGlobalTimeline: "Увімкнути глобальну стрічку"
|
enableGlobalTimeline: "Увімкнути глобальну стрічку"
|
||||||
disablingTimelinesInfo: "Адміністратори та модератори завжди мають доступ до всіх стрічок, навіть якщо вони вимкнуті."
|
disablingTimelinesInfo: "Адміністратори та модератори завжди мають доступ до всіх стрічок, навіть якщо вони вимкнуті."
|
||||||
registration: "Реєстрація"
|
registration: "Реєстрація"
|
||||||
enableRegistration: "Дозволити реєстрацію"
|
|
||||||
invite: "Запросити"
|
invite: "Запросити"
|
||||||
driveCapacityPerLocalAccount: "Об'єм диска на одного локального користувача"
|
driveCapacityPerLocalAccount: "Об'єм диска на одного локального користувача"
|
||||||
driveCapacityPerRemoteAccount: "Об'єм диска на одного віддаленого користувача"
|
driveCapacityPerRemoteAccount: "Об'єм диска на одного віддаленого користувача"
|
||||||
|
|
|
@ -349,7 +349,6 @@ enableLocalTimeline: "Mahalliy vaqt mintaqasini yoqing"
|
||||||
enableGlobalTimeline: "Global vaqt mintaqasini yoqing"
|
enableGlobalTimeline: "Global vaqt mintaqasini yoqing"
|
||||||
disablingTimelinesInfo: "Administratorlar va Moderatorlar har doim barcha vaqt jadvallariga kirish huquqiga ega bo'ladilar, hatto ular yoqilmagan bo'lsa ham."
|
disablingTimelinesInfo: "Administratorlar va Moderatorlar har doim barcha vaqt jadvallariga kirish huquqiga ega bo'ladilar, hatto ular yoqilmagan bo'lsa ham."
|
||||||
registration: "Ro'yxatdan o'tish"
|
registration: "Ro'yxatdan o'tish"
|
||||||
enableRegistration: "Ro'yxatdan o'tishni yoqing"
|
|
||||||
invite: "Taklif qilish"
|
invite: "Taklif qilish"
|
||||||
driveCapacityPerLocalAccount: "Har bir mahalliy foydalanuvchi uchun disk maydoni"
|
driveCapacityPerLocalAccount: "Har bir mahalliy foydalanuvchi uchun disk maydoni"
|
||||||
driveCapacityPerRemoteAccount: "Har bir masofaviy foydalanuvchi uchun disk maydoni"
|
driveCapacityPerRemoteAccount: "Har bir masofaviy foydalanuvchi uchun disk maydoni"
|
||||||
|
|
|
@ -8,6 +8,9 @@ search: "Tìm kiếm"
|
||||||
notifications: "Thông báo"
|
notifications: "Thông báo"
|
||||||
username: "Tên người dùng"
|
username: "Tên người dùng"
|
||||||
password: "Mật khẩu"
|
password: "Mật khẩu"
|
||||||
|
initialPasswordForSetup: "Mật khẩu ban đầu để thiết lập"
|
||||||
|
initialPasswordIsIncorrect: "Mật khẩu ban đầu đã nhập sai"
|
||||||
|
initialPasswordForSetupDescription: "Nếu bạn tự cài đặt Misskey, hãy sử dụng mật khẩu ban đầu của bạn đã nhập trong tệp cấu hình.\nNếu bạn đang sử dụng dịch vụ nào đó giống như dịch vụ lưu trữ của Misskey, hãy sử dụng mật khẩu ban đầu được cung cấp.\nNếu bạn chưa đặt mật khẩu ban đầu, vui lòng để trống và tiếp tục."
|
||||||
forgotPassword: "Quên mật khẩu"
|
forgotPassword: "Quên mật khẩu"
|
||||||
fetchingAsApObject: "Đang nạp dữ liệu từ Fediverse..."
|
fetchingAsApObject: "Đang nạp dữ liệu từ Fediverse..."
|
||||||
ok: "Đồng ý"
|
ok: "Đồng ý"
|
||||||
|
@ -354,7 +357,6 @@ enableLocalTimeline: "Bật bảng tin máy chủ"
|
||||||
enableGlobalTimeline: "Bật bảng tin liên hợp"
|
enableGlobalTimeline: "Bật bảng tin liên hợp"
|
||||||
disablingTimelinesInfo: "Quản trị viên và Kiểm duyệt viên luôn có quyền truy cập mọi bảng tin, kể cả khi chúng không được bật."
|
disablingTimelinesInfo: "Quản trị viên và Kiểm duyệt viên luôn có quyền truy cập mọi bảng tin, kể cả khi chúng không được bật."
|
||||||
registration: "Đăng ký"
|
registration: "Đăng ký"
|
||||||
enableRegistration: "Cho phép đăng ký mới"
|
|
||||||
invite: "Mời"
|
invite: "Mời"
|
||||||
driveCapacityPerLocalAccount: "Dung lượng ổ đĩa tối đa cho mỗi người dùng"
|
driveCapacityPerLocalAccount: "Dung lượng ổ đĩa tối đa cho mỗi người dùng"
|
||||||
driveCapacityPerRemoteAccount: "Dung lượng ổ đĩa tối đa cho mỗi người dùng từ xa"
|
driveCapacityPerRemoteAccount: "Dung lượng ổ đĩa tối đa cho mỗi người dùng từ xa"
|
||||||
|
|
|
@ -107,7 +107,7 @@ follow: "关注"
|
||||||
followRequest: "关注申请"
|
followRequest: "关注申请"
|
||||||
followRequests: "关注申请"
|
followRequests: "关注申请"
|
||||||
unfollow: "取消关注"
|
unfollow: "取消关注"
|
||||||
followRequestPending: "关注请求批准中"
|
followRequestPending: "关注请求待批准"
|
||||||
enterEmoji: "输入表情符号"
|
enterEmoji: "输入表情符号"
|
||||||
renote: "转发"
|
renote: "转发"
|
||||||
unrenote: "取消转发"
|
unrenote: "取消转发"
|
||||||
|
@ -136,7 +136,7 @@ overwriteFromPinnedEmojisForReaction: "从「置顶(回应)」设置覆盖"
|
||||||
overwriteFromPinnedEmojis: "从全局设置覆盖"
|
overwriteFromPinnedEmojis: "从全局设置覆盖"
|
||||||
reactionSettingDescription2: "拖动重新排序,单击删除,点击 + 添加。"
|
reactionSettingDescription2: "拖动重新排序,单击删除,点击 + 添加。"
|
||||||
rememberNoteVisibility: "保存上次设置的可见性"
|
rememberNoteVisibility: "保存上次设置的可见性"
|
||||||
attachCancel: "删除附件"
|
attachCancel: "取消添加附件"
|
||||||
deleteFile: "删除文件"
|
deleteFile: "删除文件"
|
||||||
markAsSensitive: "标记为敏感内容"
|
markAsSensitive: "标记为敏感内容"
|
||||||
unmarkAsSensitive: "取消标记为敏感内容"
|
unmarkAsSensitive: "取消标记为敏感内容"
|
||||||
|
@ -213,8 +213,8 @@ charts: "图表"
|
||||||
perHour: "每小时"
|
perHour: "每小时"
|
||||||
perDay: "每天"
|
perDay: "每天"
|
||||||
stopActivityDelivery: "停止发送活动"
|
stopActivityDelivery: "停止发送活动"
|
||||||
blockThisInstance: "阻止此服务器向本服务器推流"
|
blockThisInstance: "封锁此服务器"
|
||||||
silenceThisInstance: "使服务器静音"
|
silenceThisInstance: "静音此服务器"
|
||||||
mediaSilenceThisInstance: "隐藏此服务器的媒体文件"
|
mediaSilenceThisInstance: "隐藏此服务器的媒体文件"
|
||||||
operations: "操作"
|
operations: "操作"
|
||||||
software: "软件"
|
software: "软件"
|
||||||
|
@ -258,7 +258,7 @@ noCustomEmojis: "没有自定义表情符号"
|
||||||
noJobs: "没有任务"
|
noJobs: "没有任务"
|
||||||
federating: "联合中"
|
federating: "联合中"
|
||||||
blocked: "已拉黑"
|
blocked: "已拉黑"
|
||||||
suspended: "停止推流"
|
suspended: "停止投递"
|
||||||
all: "全部"
|
all: "全部"
|
||||||
subscribing: "已订阅"
|
subscribing: "已订阅"
|
||||||
publishing: "投递中"
|
publishing: "投递中"
|
||||||
|
@ -382,7 +382,6 @@ enableLocalTimeline: "启用本地时间线"
|
||||||
enableGlobalTimeline: "启用全局时间线"
|
enableGlobalTimeline: "启用全局时间线"
|
||||||
disablingTimelinesInfo: "即使时间线功能被禁用,出于方便,管理员和监察员也可以继续使用。"
|
disablingTimelinesInfo: "即使时间线功能被禁用,出于方便,管理员和监察员也可以继续使用。"
|
||||||
registration: "注册"
|
registration: "注册"
|
||||||
enableRegistration: "允许任何人注册"
|
|
||||||
invite: "邀请"
|
invite: "邀请"
|
||||||
driveCapacityPerLocalAccount: "每个用户的网盘容量"
|
driveCapacityPerLocalAccount: "每个用户的网盘容量"
|
||||||
driveCapacityPerRemoteAccount: "每个远程用户的网盘容量"
|
driveCapacityPerRemoteAccount: "每个远程用户的网盘容量"
|
||||||
|
@ -587,6 +586,7 @@ masterVolume: "主音量"
|
||||||
notUseSound: "静音"
|
notUseSound: "静音"
|
||||||
useSoundOnlyWhenActive: "仅在 Misskey 活跃时输出声音"
|
useSoundOnlyWhenActive: "仅在 Misskey 活跃时输出声音"
|
||||||
details: "详情"
|
details: "详情"
|
||||||
|
renoteDetails: "转帖详情"
|
||||||
chooseEmoji: "选择表情符号"
|
chooseEmoji: "选择表情符号"
|
||||||
unableToProcess: "操作无法完成"
|
unableToProcess: "操作无法完成"
|
||||||
recentUsed: "最近使用"
|
recentUsed: "最近使用"
|
||||||
|
@ -603,7 +603,7 @@ descendingOrder: "降序"
|
||||||
scratchpad: "AiScript 控制台"
|
scratchpad: "AiScript 控制台"
|
||||||
scratchpadDescription: "AiScript 控制台为 AiScript 提供了实验环境。您可以编写代码与 Misskey 交互,运行并查看结果。"
|
scratchpadDescription: "AiScript 控制台为 AiScript 提供了实验环境。您可以编写代码与 Misskey 交互,运行并查看结果。"
|
||||||
uiInspector: "UI 检查器"
|
uiInspector: "UI 检查器"
|
||||||
uiInspectorDescription: "查看所有内存中由 UI 组件生成出的实例。UI 组件由 UI:C 系列函数所生成。"
|
uiInspectorDescription: "查看内存中所有由 UI 组件生成出的实例。UI 组件由 UI:C 系列函数所生成。"
|
||||||
output: "输出"
|
output: "输出"
|
||||||
script: "脚本"
|
script: "脚本"
|
||||||
disablePagesScript: "禁用页面脚本"
|
disablePagesScript: "禁用页面脚本"
|
||||||
|
@ -706,7 +706,7 @@ useGlobalSettingDesc: "启用时,将使用账户通知设置。关闭时,则
|
||||||
other: "其他"
|
other: "其他"
|
||||||
regenerateLoginToken: "重新生成登录令牌"
|
regenerateLoginToken: "重新生成登录令牌"
|
||||||
regenerateLoginTokenDescription: "重新生成用于登录的内部令牌。通常您不需要这样做。重新生成后,您将在所有设备上登出。"
|
regenerateLoginTokenDescription: "重新生成用于登录的内部令牌。通常您不需要这样做。重新生成后,您将在所有设备上登出。"
|
||||||
theKeywordWhenSearchingForCustomEmoji: "这将是搜素自定义表情符号时的关键词。"
|
theKeywordWhenSearchingForCustomEmoji: "这将是搜索自定义表情符号时的关键词。"
|
||||||
setMultipleBySeparatingWithSpace: "您可以使用空格分隔多个项目。"
|
setMultipleBySeparatingWithSpace: "您可以使用空格分隔多个项目。"
|
||||||
fileIdOrUrl: "文件 ID 或者 URL"
|
fileIdOrUrl: "文件 ID 或者 URL"
|
||||||
behavior: "行为"
|
behavior: "行为"
|
||||||
|
@ -856,9 +856,9 @@ user: "用户"
|
||||||
administration: "管理"
|
administration: "管理"
|
||||||
accounts: "账户"
|
accounts: "账户"
|
||||||
switch: "切换"
|
switch: "切换"
|
||||||
noMaintainerInformationWarning: "管理人员信息未设置。"
|
noMaintainerInformationWarning: "尚未设置管理员信息。"
|
||||||
noInquiryUrlWarning: "尚未设置联络地址。"
|
noInquiryUrlWarning: "尚未设置联络地址。"
|
||||||
noBotProtectionWarning: "Bot 防御未设置。"
|
noBotProtectionWarning: "尚未设置 Bot 防御。"
|
||||||
configure: "设置"
|
configure: "设置"
|
||||||
postToGallery: "发送到图库"
|
postToGallery: "发送到图库"
|
||||||
postToHashtag: "投稿到这个标签"
|
postToHashtag: "投稿到这个标签"
|
||||||
|
@ -874,11 +874,11 @@ priority: "优先级"
|
||||||
high: "高"
|
high: "高"
|
||||||
middle: "中"
|
middle: "中"
|
||||||
low: "低"
|
low: "低"
|
||||||
emailNotConfiguredWarning: "电子邮件地址未设置。"
|
emailNotConfiguredWarning: "尚未设置电子邮件地址。"
|
||||||
ratio: "比率"
|
ratio: "比率"
|
||||||
previewNoteText: "预览文本"
|
previewNoteText: "预览文本"
|
||||||
customCss: "自定义 CSS"
|
customCss: "自定义 CSS"
|
||||||
customCssWarn: "这些设置必须有相关的基础知识,不当的配置可能导致客户端无法正常使用!"
|
customCssWarn: "这些设置必须有相关的基础知识,不当的配置可能导致客户端无法正常使用。"
|
||||||
global: "全局"
|
global: "全局"
|
||||||
squareAvatars: "显示方形头像图标"
|
squareAvatars: "显示方形头像图标"
|
||||||
sent: "发送"
|
sent: "发送"
|
||||||
|
@ -947,6 +947,9 @@ oneHour: "1 小时"
|
||||||
oneDay: "1 天"
|
oneDay: "1 天"
|
||||||
oneWeek: "1 周"
|
oneWeek: "1 周"
|
||||||
oneMonth: "1 个月"
|
oneMonth: "1 个月"
|
||||||
|
threeMonths: "3 个月"
|
||||||
|
oneYear: "1 年"
|
||||||
|
threeDays: "3 天"
|
||||||
reflectMayTakeTime: "可能需要一些时间才能体现出效果。"
|
reflectMayTakeTime: "可能需要一些时间才能体现出效果。"
|
||||||
failedToFetchAccountInformation: "获取账户信息失败"
|
failedToFetchAccountInformation: "获取账户信息失败"
|
||||||
rateLimitExceeded: "已超过速率限制"
|
rateLimitExceeded: "已超过速率限制"
|
||||||
|
@ -1054,7 +1057,7 @@ internalServerErrorDescription: "内部服务器发生了预期外的错误"
|
||||||
copyErrorInfo: "复制错误信息"
|
copyErrorInfo: "复制错误信息"
|
||||||
joinThisServer: "在本服务器上注册"
|
joinThisServer: "在本服务器上注册"
|
||||||
exploreOtherServers: "探索其他服务器"
|
exploreOtherServers: "探索其他服务器"
|
||||||
letsLookAtTimeline: "时间线"
|
letsLookAtTimeline: "看看时间线"
|
||||||
disableFederationConfirm: "确定要禁用联合?"
|
disableFederationConfirm: "确定要禁用联合?"
|
||||||
disableFederationConfirmWarn: "禁用联合不会将帖子设为私有。在大多数情况下,不需要禁用联合。"
|
disableFederationConfirmWarn: "禁用联合不会将帖子设为私有。在大多数情况下,不需要禁用联合。"
|
||||||
disableFederationOk: "联合禁用"
|
disableFederationOk: "联合禁用"
|
||||||
|
@ -1070,10 +1073,10 @@ nonSensitiveOnlyForLocalLikeOnlyForRemote: "仅限非敏感内容(远程仅点
|
||||||
rolesAssignedToMe: "指派给自己的角色"
|
rolesAssignedToMe: "指派给自己的角色"
|
||||||
resetPasswordConfirm: "确定重置密码?"
|
resetPasswordConfirm: "确定重置密码?"
|
||||||
sensitiveWords: "敏感词"
|
sensitiveWords: "敏感词"
|
||||||
sensitiveWordsDescription: "将包含设置词的帖子的可见范围设置为首页。可以通过用换行符分隔来设置多个。"
|
sensitiveWordsDescription: "包含这些词的帖子将只在首页可见。可用换行来设定多个词。"
|
||||||
sensitiveWordsDescription2: "AND 条件用空格分隔,正则表达式用斜线包裹。"
|
sensitiveWordsDescription2: "AND 条件用空格分隔,正则表达式用斜线包裹。"
|
||||||
prohibitedWords: "禁用词"
|
prohibitedWords: "禁用词"
|
||||||
prohibitedWordsDescription: "发布包含设定词汇的帖子时将出错。可用换行设定多个关键字"
|
prohibitedWordsDescription: "发布包含设定词汇的帖子时将出错。可用换行设定多个关键字。"
|
||||||
prohibitedWordsDescription2: "AND 条件用空格分隔,正则表达式用斜线包裹。"
|
prohibitedWordsDescription2: "AND 条件用空格分隔,正则表达式用斜线包裹。"
|
||||||
hiddenTags: "隐藏标签"
|
hiddenTags: "隐藏标签"
|
||||||
hiddenTagsDescription: "设定的标签将不会在时间线上显示。可使用换行来设置多个标签。"
|
hiddenTagsDescription: "设定的标签将不会在时间线上显示。可使用换行来设置多个标签。"
|
||||||
|
@ -1116,7 +1119,7 @@ vertical: "纵向"
|
||||||
horizontal: "横向"
|
horizontal: "横向"
|
||||||
position: "位置"
|
position: "位置"
|
||||||
serverRules: "服务器规则"
|
serverRules: "服务器规则"
|
||||||
pleaseConfirmBelowBeforeSignup: "在这个服务器上注册账号前,请确认以下信息。"
|
pleaseConfirmBelowBeforeSignup: "如果要在此服务器上注册,需要确认并同意以下内容。"
|
||||||
pleaseAgreeAllToContinue: "必须全部勾选「同意」才能够继续。"
|
pleaseAgreeAllToContinue: "必须全部勾选「同意」才能够继续。"
|
||||||
continue: "继续"
|
continue: "继续"
|
||||||
preservedUsernames: "保留的用户名"
|
preservedUsernames: "保留的用户名"
|
||||||
|
@ -1156,10 +1159,10 @@ turnOffToImprovePerformance: "关闭该选项可以提高性能。"
|
||||||
createInviteCode: "生成邀请码"
|
createInviteCode: "生成邀请码"
|
||||||
createWithOptions: "使用选项来创建"
|
createWithOptions: "使用选项来创建"
|
||||||
createCount: "发行数"
|
createCount: "发行数"
|
||||||
inviteCodeCreated: "已创建邀请码"
|
inviteCodeCreated: "已生成邀请码"
|
||||||
inviteLimitExceeded: "可供发行的邀请码已达上限。"
|
inviteLimitExceeded: "可供生成的邀请码已达上限。"
|
||||||
createLimitRemaining: "可供发行的邀请码:剩余{limit}个"
|
createLimitRemaining: "可供生成的邀请码:剩余 {limit} 个"
|
||||||
inviteLimitResetCycle: "可以在{time}内发行最多{limit}个邀请码。"
|
inviteLimitResetCycle: "可以在 {time} 内生成最多 {limit} 个邀请码。"
|
||||||
expirationDate: "有效日期"
|
expirationDate: "有效日期"
|
||||||
noExpirationDate: "不设置有效日期"
|
noExpirationDate: "不设置有效日期"
|
||||||
inviteCodeUsedAt: "邀请码被使用的日期和时间"
|
inviteCodeUsedAt: "邀请码被使用的日期和时间"
|
||||||
|
@ -1293,6 +1296,23 @@ prohibitedWordsForNameOfUser: "用户名中禁止的词"
|
||||||
prohibitedWordsForNameOfUserDescription: "更改用户名时,如果用户名中包含此列表里的词汇,用户的改名请求将被拒绝。持有管理员权限的用户不受此限制。"
|
prohibitedWordsForNameOfUserDescription: "更改用户名时,如果用户名中包含此列表里的词汇,用户的改名请求将被拒绝。持有管理员权限的用户不受此限制。"
|
||||||
yourNameContainsProhibitedWords: "目标用户名包含违禁词"
|
yourNameContainsProhibitedWords: "目标用户名包含违禁词"
|
||||||
yourNameContainsProhibitedWordsDescription: "用户名内含有违禁词。若想使用此用户名,请联系服务器管理员。"
|
yourNameContainsProhibitedWordsDescription: "用户名内含有违禁词。若想使用此用户名,请联系服务器管理员。"
|
||||||
|
thisContentsAreMarkedAsSigninRequiredByAuthor: "根据发帖者的设定,需要登录才能显示"
|
||||||
|
lockdown: "锁定"
|
||||||
|
pleaseSelectAccount: "请选择帐户"
|
||||||
|
availableRoles: "可用角色"
|
||||||
|
acknowledgeNotesAndEnable: "理解注意事项后再开启。"
|
||||||
|
_accountSettings:
|
||||||
|
requireSigninToViewContents: "需要登录才能显示内容"
|
||||||
|
requireSigninToViewContentsDescription1: "您发布的所有帖子将变成需要登入后才会显示。有望防止爬虫收集各种信息。"
|
||||||
|
requireSigninToViewContentsDescription2: "没有 URL 预览(OGP)、内嵌网页、引用帖子的功能的服务器也将无法显示。"
|
||||||
|
requireSigninToViewContentsDescription3: "这些限制可能不适用于联合到远程服务器的内容。"
|
||||||
|
makeNotesFollowersOnlyBefore: "可将过去的帖子设为仅关注者可见"
|
||||||
|
makeNotesFollowersOnlyBeforeDescription: "开启此设定时,超过设定的时间或日期后,帖子将变为仅关注者可见。关闭后帖子的公开状态将恢复成原本的设定。"
|
||||||
|
makeNotesHiddenBefore: "将过去的帖子设为私密"
|
||||||
|
makeNotesHiddenBeforeDescription: "开启此设定时,超过设定的时间或日期后,帖子将变为仅自己可见。关闭后帖子的公开状态将恢复成原本的设定。"
|
||||||
|
mayNotEffectForFederatedNotes: "与远程服务器联合的帖子在远端可能会没有效果。"
|
||||||
|
notesHavePassedSpecifiedPeriod: "超过指定时间的帖子"
|
||||||
|
notesOlderThanSpecifiedDateAndTime: "指定日期前的帖子"
|
||||||
_abuseUserReport:
|
_abuseUserReport:
|
||||||
forward: "转发"
|
forward: "转发"
|
||||||
forwardDescription: "目标是匿名系统账户,将把举报转发给远程服务器。"
|
forwardDescription: "目标是匿名系统账户,将把举报转发给远程服务器。"
|
||||||
|
@ -1408,8 +1428,8 @@ _initialTutorial:
|
||||||
description: "对于服务器方针所要求要求的,又或者不适合直接展示的附件,请添加「敏感」标记。\n"
|
description: "对于服务器方针所要求要求的,又或者不适合直接展示的附件,请添加「敏感」标记。\n"
|
||||||
tryThisFile: "试试看,将附加到此窗口的图像标注为敏感!"
|
tryThisFile: "试试看,将附加到此窗口的图像标注为敏感!"
|
||||||
_exampleNote:
|
_exampleNote:
|
||||||
note: "拆纳豆包装时出错了…"
|
note: "拆纳豆包装时失手了…"
|
||||||
method: "要标注附件为敏感内容,请单击该文件以打开菜单,然后单击“标记为敏感内容”。"
|
method: "要标注附件为敏感内容,请单击该文件以打开菜单,然后单击「标记为敏感内容」。"
|
||||||
sensitiveSucceeded: "附加文件时,请遵循服务器的条款来设置正确敏感设定。\n"
|
sensitiveSucceeded: "附加文件时,请遵循服务器的条款来设置正确敏感设定。\n"
|
||||||
doItToContinue: "将图像标记为敏感后才能够继续"
|
doItToContinue: "将图像标记为敏感后才能够继续"
|
||||||
_done:
|
_done:
|
||||||
|
@ -1437,6 +1457,8 @@ _serverSettings:
|
||||||
reactionsBufferingDescription: "开启时可显著提高发送回应时的性能,及减轻数据库负荷。但 Redis 的内存用量会相应增加。"
|
reactionsBufferingDescription: "开启时可显著提高发送回应时的性能,及减轻数据库负荷。但 Redis 的内存用量会相应增加。"
|
||||||
inquiryUrl: "联络地址"
|
inquiryUrl: "联络地址"
|
||||||
inquiryUrlDescription: "用来指定诸如向服务运营商咨询的论坛地址,或记载了运营商联系方式之类的网页地址。"
|
inquiryUrlDescription: "用来指定诸如向服务运营商咨询的论坛地址,或记载了运营商联系方式之类的网页地址。"
|
||||||
|
openRegistration: "开放注册"
|
||||||
|
openRegistrationWarning: "开放注册有风险。建议仅当能够持续监控服务器并在出现问题时能够立即响应时才打开它。"
|
||||||
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "若在一段时间内没有检测到管理活动,为防止垃圾信息,此设定将自动关闭。"
|
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "若在一段时间内没有检测到管理活动,为防止垃圾信息,此设定将自动关闭。"
|
||||||
_accountMigration:
|
_accountMigration:
|
||||||
moveFrom: "从别的账号迁移到此账户"
|
moveFrom: "从别的账号迁移到此账户"
|
||||||
|
@ -1685,9 +1707,9 @@ _achievements:
|
||||||
description: "在元旦登入"
|
description: "在元旦登入"
|
||||||
flavor: "今年也请对本服务器多多指教!"
|
flavor: "今年也请对本服务器多多指教!"
|
||||||
_cookieClicked:
|
_cookieClicked:
|
||||||
title: "点击饼干小游戏"
|
title: "饼干点点乐"
|
||||||
description: "点击了饼干"
|
description: "点击了饼干"
|
||||||
flavor: "用错软件了?"
|
flavor: "穿越了?"
|
||||||
_brainDiver:
|
_brainDiver:
|
||||||
title: "Brain Diver"
|
title: "Brain Diver"
|
||||||
description: "发布了包含 Brain Diver 链接的帖子"
|
description: "发布了包含 Brain Diver 链接的帖子"
|
||||||
|
@ -2157,8 +2179,11 @@ _auth:
|
||||||
permissionAsk: "这个应用程序需要以下权限"
|
permissionAsk: "这个应用程序需要以下权限"
|
||||||
pleaseGoBack: "请返回到应用程序"
|
pleaseGoBack: "请返回到应用程序"
|
||||||
callback: "回到应用程序"
|
callback: "回到应用程序"
|
||||||
|
accepted: "已允许访问"
|
||||||
denied: "拒绝访问"
|
denied: "拒绝访问"
|
||||||
|
scopeUser: "以下面的用户进行操作"
|
||||||
pleaseLogin: "在对应用进行授权许可之前,请先登录"
|
pleaseLogin: "在对应用进行授权许可之前,请先登录"
|
||||||
|
byClickingYouWillBeRedirectedToThisUrl: "允许访问后将会自动重定向到以下 URL"
|
||||||
_antennaSources:
|
_antennaSources:
|
||||||
all: "所有帖子"
|
all: "所有帖子"
|
||||||
homeTimeline: "已关注用户的帖子"
|
homeTimeline: "已关注用户的帖子"
|
||||||
|
@ -2710,3 +2735,12 @@ _embedCodeGen:
|
||||||
generateCode: "生成嵌入代码"
|
generateCode: "生成嵌入代码"
|
||||||
codeGenerated: "已生成代码"
|
codeGenerated: "已生成代码"
|
||||||
codeGeneratedDescription: "将生成的代码贴到网站上来使用。"
|
codeGeneratedDescription: "将生成的代码贴到网站上来使用。"
|
||||||
|
_selfXssPrevention:
|
||||||
|
warning: "警告"
|
||||||
|
title: "「在此处粘贴什么东西」是欺诈行为。"
|
||||||
|
description1: "如果在此处粘贴了什么,恶意用户可能会接管账户或者盗取个人资料。"
|
||||||
|
description2: "如果不能完全理解将要粘贴的内容,%c 请立即停止操作并关闭这个窗口。"
|
||||||
|
description3: "详情请看这里。{link}"
|
||||||
|
_followRequest:
|
||||||
|
recieved: "已收到申请"
|
||||||
|
sent: "已发送申请"
|
||||||
|
|
|
@ -8,8 +8,8 @@ search: "搜尋"
|
||||||
notifications: "通知"
|
notifications: "通知"
|
||||||
username: "使用者名稱"
|
username: "使用者名稱"
|
||||||
password: "密碼"
|
password: "密碼"
|
||||||
initialPasswordForSetup: "初始設定用的密碼"
|
initialPasswordForSetup: "啟動初始設定的密碼"
|
||||||
initialPasswordIsIncorrect: "初始設定用的密碼錯誤。"
|
initialPasswordIsIncorrect: "啟動初始設定的密碼錯誤。"
|
||||||
initialPasswordForSetupDescription: "如果您自己安裝了 Misskey,請使用您在設定檔中輸入的密碼。\n如果您使用 Misskey 的託管服務之類的服務,請使用提供的密碼。\n如果您尚未設定密碼,請將其留空並繼續。"
|
initialPasswordForSetupDescription: "如果您自己安裝了 Misskey,請使用您在設定檔中輸入的密碼。\n如果您使用 Misskey 的託管服務之類的服務,請使用提供的密碼。\n如果您尚未設定密碼,請將其留空並繼續。"
|
||||||
forgotPassword: "忘記密碼"
|
forgotPassword: "忘記密碼"
|
||||||
fetchingAsApObject: "從聯邦宇宙取得中..."
|
fetchingAsApObject: "從聯邦宇宙取得中..."
|
||||||
|
@ -382,7 +382,6 @@ enableLocalTimeline: "啟用本地時間軸"
|
||||||
enableGlobalTimeline: "啟用全域時間軸"
|
enableGlobalTimeline: "啟用全域時間軸"
|
||||||
disablingTimelinesInfo: "為了方便,即使您關閉了時間軸功能,管理員和審查員仍可以繼續使用。"
|
disablingTimelinesInfo: "為了方便,即使您關閉了時間軸功能,管理員和審查員仍可以繼續使用。"
|
||||||
registration: "註冊"
|
registration: "註冊"
|
||||||
enableRegistration: "開放新使用者註冊"
|
|
||||||
invite: "邀請"
|
invite: "邀請"
|
||||||
driveCapacityPerLocalAccount: "每個本地使用者的雲端硬碟容量"
|
driveCapacityPerLocalAccount: "每個本地使用者的雲端硬碟容量"
|
||||||
driveCapacityPerRemoteAccount: "每個非本地用戶的雲端空間大小"
|
driveCapacityPerRemoteAccount: "每個非本地用戶的雲端空間大小"
|
||||||
|
@ -587,6 +586,7 @@ masterVolume: "主音量"
|
||||||
notUseSound: "關閉音效"
|
notUseSound: "關閉音效"
|
||||||
useSoundOnlyWhenActive: "瀏覽器在前景運作時,Misskey 才會發出音效"
|
useSoundOnlyWhenActive: "瀏覽器在前景運作時,Misskey 才會發出音效"
|
||||||
details: "詳細資訊"
|
details: "詳細資訊"
|
||||||
|
renoteDetails: "轉發貼文的細節"
|
||||||
chooseEmoji: "選擇您的表情符號"
|
chooseEmoji: "選擇您的表情符號"
|
||||||
unableToProcess: "操作無法完成"
|
unableToProcess: "操作無法完成"
|
||||||
recentUsed: "最近使用"
|
recentUsed: "最近使用"
|
||||||
|
@ -947,6 +947,9 @@ oneHour: "一小時"
|
||||||
oneDay: "一天"
|
oneDay: "一天"
|
||||||
oneWeek: "一週"
|
oneWeek: "一週"
|
||||||
oneMonth: "一個月"
|
oneMonth: "一個月"
|
||||||
|
threeMonths: "3 個月"
|
||||||
|
oneYear: "1 年"
|
||||||
|
threeDays: "3 日"
|
||||||
reflectMayTakeTime: "可能需要一些時間才會出現效果。"
|
reflectMayTakeTime: "可能需要一些時間才會出現效果。"
|
||||||
failedToFetchAccountInformation: "取得帳戶資訊失敗"
|
failedToFetchAccountInformation: "取得帳戶資訊失敗"
|
||||||
rateLimitExceeded: "已超過速率限制"
|
rateLimitExceeded: "已超過速率限制"
|
||||||
|
@ -1116,7 +1119,7 @@ vertical: "直向"
|
||||||
horizontal: "橫向"
|
horizontal: "橫向"
|
||||||
position: "位置"
|
position: "位置"
|
||||||
serverRules: "伺服器規則"
|
serverRules: "伺服器規則"
|
||||||
pleaseConfirmBelowBeforeSignup: "在本伺服器註冊之前,請確認下列事項。"
|
pleaseConfirmBelowBeforeSignup: "在本伺服器註冊之前,必須確認並同意以下內容。"
|
||||||
pleaseAgreeAllToContinue: "必須全部勾選「同意」才能繼續。"
|
pleaseAgreeAllToContinue: "必須全部勾選「同意」才能繼續。"
|
||||||
continue: "繼續"
|
continue: "繼續"
|
||||||
preservedUsernames: "保留的使用者名稱"
|
preservedUsernames: "保留的使用者名稱"
|
||||||
|
@ -1293,6 +1296,23 @@ prohibitedWordsForNameOfUser: "禁止使用的字詞(使用者名稱)"
|
||||||
prohibitedWordsForNameOfUserDescription: "如果使用者名稱包含此清單中的任何字串,則拒絕重新命名使用者。 具有審查員權限的使用者不受此限制的影響。"
|
prohibitedWordsForNameOfUserDescription: "如果使用者名稱包含此清單中的任何字串,則拒絕重新命名使用者。 具有審查員權限的使用者不受此限制的影響。"
|
||||||
yourNameContainsProhibitedWords: "您嘗試更改的名稱包含禁止的字串"
|
yourNameContainsProhibitedWords: "您嘗試更改的名稱包含禁止的字串"
|
||||||
yourNameContainsProhibitedWordsDescription: "名稱中包含禁止使用的字串。 如果您想使用此名稱,請聯絡您的伺服器管理員。"
|
yourNameContainsProhibitedWordsDescription: "名稱中包含禁止使用的字串。 如果您想使用此名稱,請聯絡您的伺服器管理員。"
|
||||||
|
thisContentsAreMarkedAsSigninRequiredByAuthor: "作者將其設定為需要登入才能顯示。"
|
||||||
|
lockdown: "鎖定"
|
||||||
|
pleaseSelectAccount: "請選擇帳戶"
|
||||||
|
availableRoles: "可用角色"
|
||||||
|
acknowledgeNotesAndEnable: "了解注意事項後再開啟。"
|
||||||
|
_accountSettings:
|
||||||
|
requireSigninToViewContents: "須登入以顯示內容"
|
||||||
|
requireSigninToViewContentsDescription1: "必須登入才會顯示您建立的貼文等內容。可望有效防止資訊被爬蟲蒐集。"
|
||||||
|
requireSigninToViewContentsDescription2: "來自不支援 URL 預覽 (OGP)、 網頁嵌入和引用貼文的伺服器,也將停止顯示。"
|
||||||
|
requireSigninToViewContentsDescription3: "這些限制可能不適用於被聯邦發送至遠端伺服器的內容。"
|
||||||
|
makeNotesFollowersOnlyBefore: "讓過去的貼文僅對追隨者顯示"
|
||||||
|
makeNotesFollowersOnlyBeforeDescription: "啟用此功能後,超過設定的日期和時間或超過設定時間的貼文將僅對追隨者顯示。 如果您再次停用它,貼文的公開狀態也會恢復原狀。"
|
||||||
|
makeNotesHiddenBefore: "隱藏過去的貼文"
|
||||||
|
makeNotesHiddenBeforeDescription: "啟用此功能後,超過設定的日期和時間或超過設定時間的貼文將僅對自己顯示(私密化)。 如果您再次停用它,貼文的公開狀態也會恢復原狀。"
|
||||||
|
mayNotEffectForFederatedNotes: "聯邦發送至遠端伺服器的貼文可能會不受影響。"
|
||||||
|
notesHavePassedSpecifiedPeriod: "早於指定時間的貼文"
|
||||||
|
notesOlderThanSpecifiedDateAndTime: "指定時間和日期之前的貼文"
|
||||||
_abuseUserReport:
|
_abuseUserReport:
|
||||||
forward: "轉發"
|
forward: "轉發"
|
||||||
forwardDescription: "以匿名系統帳戶將檢舉轉發至遠端伺服器。"
|
forwardDescription: "以匿名系統帳戶將檢舉轉發至遠端伺服器。"
|
||||||
|
@ -1437,6 +1457,8 @@ _serverSettings:
|
||||||
reactionsBufferingDescription: "啟用時,可以顯著提高建立反應時的效能並減少資料庫的負載。 但是,Redis 記憶體使用量會增加。"
|
reactionsBufferingDescription: "啟用時,可以顯著提高建立反應時的效能並減少資料庫的負載。 但是,Redis 記憶體使用量會增加。"
|
||||||
inquiryUrl: "聯絡表單網址"
|
inquiryUrl: "聯絡表單網址"
|
||||||
inquiryUrlDescription: "指定伺服器運營者的聯絡表單網址,或包含運營者聯絡資訊網頁的網址。"
|
inquiryUrlDescription: "指定伺服器運營者的聯絡表單網址,或包含運營者聯絡資訊網頁的網址。"
|
||||||
|
openRegistration: "允許建立帳戶"
|
||||||
|
openRegistrationWarning: "開放註冊伴隨著風險。 建議只有在伺服器受到持續監控,並準備好在出現問題時能立即處理的情況下才開放註冊。"
|
||||||
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "為了防止 spam,如果一段期間內沒有偵測到審查員的活動,此設定將自動關閉。"
|
thisSettingWillAutomaticallyOffWhenModeratorsInactive: "為了防止 spam,如果一段期間內沒有偵測到審查員的活動,此設定將自動關閉。"
|
||||||
_accountMigration:
|
_accountMigration:
|
||||||
moveFrom: "從其他帳戶遷移到這個帳戶"
|
moveFrom: "從其他帳戶遷移到這個帳戶"
|
||||||
|
@ -2157,8 +2179,11 @@ _auth:
|
||||||
permissionAsk: "此應用程式需要以下權限"
|
permissionAsk: "此應用程式需要以下權限"
|
||||||
pleaseGoBack: "請返回至應用程式"
|
pleaseGoBack: "請返回至應用程式"
|
||||||
callback: "回到應用程式"
|
callback: "回到應用程式"
|
||||||
|
accepted: "已授予存取權限"
|
||||||
denied: "拒絕訪問"
|
denied: "拒絕訪問"
|
||||||
|
scopeUser: "以下列使用者身分操作"
|
||||||
pleaseLogin: "必須登入以提供應用程式的存取權限。"
|
pleaseLogin: "必須登入以提供應用程式的存取權限。"
|
||||||
|
byClickingYouWillBeRedirectedToThisUrl: "如果授予存取權限,就會自動導向到以下的網址"
|
||||||
_antennaSources:
|
_antennaSources:
|
||||||
all: "全部貼文"
|
all: "全部貼文"
|
||||||
homeTimeline: "來自已追隨使用者的貼文"
|
homeTimeline: "來自已追隨使用者的貼文"
|
||||||
|
@ -2416,7 +2441,7 @@ _notification:
|
||||||
follow: "追隨中"
|
follow: "追隨中"
|
||||||
mention: "提及"
|
mention: "提及"
|
||||||
reply: "回覆"
|
reply: "回覆"
|
||||||
renote: "轉發貼文"
|
renote: "轉發"
|
||||||
quote: "引用"
|
quote: "引用"
|
||||||
reaction: "反應"
|
reaction: "反應"
|
||||||
pollEnded: "問卷調查結束"
|
pollEnded: "問卷調查結束"
|
||||||
|
@ -2710,3 +2735,12 @@ _embedCodeGen:
|
||||||
generateCode: "建立嵌入程式碼"
|
generateCode: "建立嵌入程式碼"
|
||||||
codeGenerated: "已產生程式碼"
|
codeGenerated: "已產生程式碼"
|
||||||
codeGeneratedDescription: "請將產生的程式碼貼到您的網站上。"
|
codeGeneratedDescription: "請將產生的程式碼貼到您的網站上。"
|
||||||
|
_selfXssPrevention:
|
||||||
|
warning: "警告"
|
||||||
|
title: "「在此畫面貼上一些內容」完全是個騙局。"
|
||||||
|
description1: "如果您在此處貼上任何內容,惡意使用者可能會接管您的帳戶或竊取您的個人資訊。"
|
||||||
|
description2: "如果您不確切知道要貼上的內容,%c 請立即停止工作並關閉此視窗。"
|
||||||
|
description3: "細節請看這裡。{link}"
|
||||||
|
_followRequest:
|
||||||
|
recieved: "收到的請求"
|
||||||
|
sent: "送出的請求"
|
||||||
|
|
18
package.json
18
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "2024.10.2-alpha.0",
|
"version": "2024.11.0-beta.4",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -56,22 +56,22 @@
|
||||||
"fast-glob": "3.3.2",
|
"fast-glob": "3.3.2",
|
||||||
"ignore-walk": "6.0.5",
|
"ignore-walk": "6.0.5",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"postcss": "8.4.47",
|
"postcss": "8.4.49",
|
||||||
"tar": "6.2.1",
|
"tar": "6.2.1",
|
||||||
"terser": "5.33.0",
|
"terser": "5.36.0",
|
||||||
"typescript": "5.6.2",
|
"typescript": "5.6.3",
|
||||||
"esbuild": "0.23.1",
|
"esbuild": "0.24.0",
|
||||||
"glob": "11.0.0"
|
"glob": "11.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@misskey-dev/eslint-plugin": "2.0.3",
|
"@misskey-dev/eslint-plugin": "2.0.3",
|
||||||
"@types/node": "20.14.12",
|
"@types/node": "22.9.0",
|
||||||
"@typescript-eslint/eslint-plugin": "7.17.0",
|
"@typescript-eslint/eslint-plugin": "7.17.0",
|
||||||
"@typescript-eslint/parser": "7.17.0",
|
"@typescript-eslint/parser": "7.17.0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"cypress": "13.14.2",
|
"cypress": "13.15.2",
|
||||||
"eslint": "9.8.0",
|
"eslint": "9.14.0",
|
||||||
"globals": "15.9.0",
|
"globals": "15.12.0",
|
||||||
"ncp": "2.0.0",
|
"ncp": "2.0.0",
|
||||||
"start-server-and-test": "2.0.8"
|
"start-server-and-test": "2.0.8"
|
||||||
},
|
},
|
||||||
|
|
|
@ -69,32 +69,32 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "3.620.0",
|
"@aws-sdk/client-s3": "3.620.0",
|
||||||
"@aws-sdk/lib-storage": "3.620.0",
|
"@aws-sdk/lib-storage": "3.620.0",
|
||||||
"@bull-board/api": "6.0.0",
|
"@bull-board/api": "6.5.0",
|
||||||
"@bull-board/fastify": "6.0.0",
|
"@bull-board/fastify": "6.5.0",
|
||||||
"@bull-board/ui": "6.0.0",
|
"@bull-board/ui": "6.5.0",
|
||||||
"@discordapp/twemoji": "15.1.0",
|
"@discordapp/twemoji": "15.1.0",
|
||||||
"@fastify/accepts": "5.0.1",
|
"@fastify/accepts": "5.0.1",
|
||||||
"@fastify/cookie": "10.0.1",
|
"@fastify/cookie": "11.0.1",
|
||||||
"@fastify/cors": "10.0.1",
|
"@fastify/cors": "10.0.1",
|
||||||
"@fastify/express": "4.0.1",
|
"@fastify/express": "4.0.1",
|
||||||
"@fastify/http-proxy": "10.0.0",
|
"@fastify/http-proxy": "10.0.1",
|
||||||
"@fastify/multipart": "9.0.1",
|
"@fastify/multipart": "9.0.1",
|
||||||
"@fastify/static": "8.0.1",
|
"@fastify/static": "8.0.2",
|
||||||
"@fastify/view": "10.0.1",
|
"@fastify/view": "10.0.1",
|
||||||
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
||||||
"@misskey-dev/summaly": "5.1.0",
|
"@misskey-dev/summaly": "5.1.0",
|
||||||
"@napi-rs/canvas": "0.1.56",
|
"@napi-rs/canvas": "0.1.56",
|
||||||
"@nestjs/common": "10.4.4",
|
"@nestjs/common": "10.4.7",
|
||||||
"@nestjs/core": "10.4.4",
|
"@nestjs/core": "10.4.7",
|
||||||
"@nestjs/testing": "10.4.4",
|
"@nestjs/testing": "10.4.7",
|
||||||
"@peertube/http-signature": "1.7.0",
|
"@peertube/http-signature": "1.7.0",
|
||||||
"@sentry/node": "8.20.0",
|
"@sentry/node": "8.38.0",
|
||||||
"@sentry/profiling-node": "8.20.0",
|
"@sentry/profiling-node": "8.38.0",
|
||||||
"@simplewebauthn/server": "10.0.1",
|
"@simplewebauthn/server": "10.0.1",
|
||||||
"@sinonjs/fake-timers": "11.2.2",
|
"@sinonjs/fake-timers": "11.2.2",
|
||||||
"@smithy/node-http-handler": "2.5.0",
|
"@smithy/node-http-handler": "2.5.0",
|
||||||
"@swc/cli": "0.3.12",
|
"@swc/cli": "0.3.12",
|
||||||
"@swc/core": "1.6.6",
|
"@swc/core": "1.9.2",
|
||||||
"@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",
|
||||||
|
@ -103,7 +103,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.15.0",
|
"bullmq": "5.26.1",
|
||||||
"cacheable-lookup": "7.0.0",
|
"cacheable-lookup": "7.0.0",
|
||||||
"cbor": "9.0.2",
|
"cbor": "9.0.2",
|
||||||
"chalk": "5.3.0",
|
"chalk": "5.3.0",
|
||||||
|
@ -117,11 +117,11 @@
|
||||||
"fastify": "5.0.0",
|
"fastify": "5.0.0",
|
||||||
"fastify-raw-body": "5.0.0",
|
"fastify-raw-body": "5.0.0",
|
||||||
"feed": "4.2.2",
|
"feed": "4.2.2",
|
||||||
"file-type": "19.5.0",
|
"file-type": "19.6.0",
|
||||||
"fluent-ffmpeg": "2.1.3",
|
"fluent-ffmpeg": "2.1.3",
|
||||||
"form-data": "4.0.0",
|
"form-data": "4.0.1",
|
||||||
"got": "14.4.2",
|
"got": "14.4.4",
|
||||||
"happy-dom": "15.7.4",
|
"happy-dom": "15.11.4",
|
||||||
"hpagent": "1.2.0",
|
"hpagent": "1.2.0",
|
||||||
"htmlescape": "1.1.1",
|
"htmlescape": "1.1.1",
|
||||||
"http-link-header": "1.1.3",
|
"http-link-header": "1.1.3",
|
||||||
|
@ -134,7 +134,7 @@
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"jsonld": "8.3.2",
|
"jsonld": "8.3.2",
|
||||||
"jsrsasign": "11.1.0",
|
"jsrsasign": "11.1.0",
|
||||||
"meilisearch": "0.42.0",
|
"meilisearch": "0.45.0",
|
||||||
"juice": "11.0.0",
|
"juice": "11.0.0",
|
||||||
"mfm-js": "0.24.0",
|
"mfm-js": "0.24.0",
|
||||||
"microformats-parser": "2.0.2",
|
"microformats-parser": "2.0.2",
|
||||||
|
@ -142,18 +142,18 @@
|
||||||
"misskey-js": "workspace:*",
|
"misskey-js": "workspace:*",
|
||||||
"misskey-reversi": "workspace:*",
|
"misskey-reversi": "workspace:*",
|
||||||
"ms": "3.0.0-canary.1",
|
"ms": "3.0.0-canary.1",
|
||||||
"nanoid": "5.0.7",
|
"nanoid": "5.0.8",
|
||||||
"nested-property": "4.0.0",
|
"nested-property": "4.0.0",
|
||||||
"node-fetch": "3.3.2",
|
"node-fetch": "3.3.2",
|
||||||
"nodemailer": "6.9.15",
|
"nodemailer": "6.9.16",
|
||||||
"nsfwjs": "2.4.2",
|
"nsfwjs": "2.4.2",
|
||||||
"oauth": "0.10.0",
|
"oauth": "0.10.0",
|
||||||
"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.4",
|
"otpauth": "9.3.4",
|
||||||
"parse5": "7.1.2",
|
"parse5": "7.2.1",
|
||||||
"pg": "8.13.0",
|
"pg": "8.13.1",
|
||||||
"pkce-challenge": "4.1.0",
|
"pkce-challenge": "4.1.0",
|
||||||
"probe-image-size": "7.2.3",
|
"probe-image-size": "7.2.3",
|
||||||
"promise-limit": "2.7.0",
|
"promise-limit": "2.7.0",
|
||||||
|
@ -180,7 +180,7 @@
|
||||||
"tsc-alias": "1.8.10",
|
"tsc-alias": "1.8.10",
|
||||||
"tsconfig-paths": "4.2.0",
|
"tsconfig-paths": "4.2.0",
|
||||||
"typeorm": "0.3.20",
|
"typeorm": "0.3.20",
|
||||||
"typescript": "5.6.2",
|
"typescript": "5.6.3",
|
||||||
"ulid": "2.3.0",
|
"ulid": "2.3.0",
|
||||||
"vary": "1.1.2",
|
"vary": "1.1.2",
|
||||||
"web-push": "3.6.7",
|
"web-push": "3.6.7",
|
||||||
|
@ -189,28 +189,28 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@jest/globals": "29.7.0",
|
"@jest/globals": "29.7.0",
|
||||||
"@nestjs/platform-express": "10.4.4",
|
"@nestjs/platform-express": "10.4.7",
|
||||||
"@simplewebauthn/types": "10.0.0",
|
"@simplewebauthn/types": "10.0.0",
|
||||||
"@swc/jest": "0.2.36",
|
"@swc/jest": "0.2.37",
|
||||||
"@types/accepts": "1.3.7",
|
"@types/accepts": "1.3.7",
|
||||||
"@types/archiver": "6.0.2",
|
"@types/archiver": "6.0.3",
|
||||||
"@types/bcryptjs": "2.4.6",
|
"@types/bcryptjs": "2.4.6",
|
||||||
"@types/body-parser": "1.19.5",
|
"@types/body-parser": "1.19.5",
|
||||||
"@types/color-convert": "2.0.4",
|
"@types/color-convert": "2.0.4",
|
||||||
"@types/content-disposition": "0.5.8",
|
"@types/content-disposition": "0.5.8",
|
||||||
"@types/fluent-ffmpeg": "2.1.26",
|
"@types/fluent-ffmpeg": "2.1.27",
|
||||||
"@types/htmlescape": "1.1.3",
|
"@types/htmlescape": "1.1.3",
|
||||||
"@types/http-link-header": "1.0.7",
|
"@types/http-link-header": "1.0.7",
|
||||||
"@types/jest": "29.5.13",
|
"@types/jest": "29.5.14",
|
||||||
"@types/js-yaml": "4.0.9",
|
"@types/js-yaml": "4.0.9",
|
||||||
"@types/jsdom": "21.1.7",
|
"@types/jsdom": "21.1.7",
|
||||||
"@types/jsonld": "1.5.15",
|
"@types/jsonld": "1.5.15",
|
||||||
"@types/jsrsasign": "10.5.14",
|
"@types/jsrsasign": "10.5.14",
|
||||||
"@types/mime-types": "2.1.4",
|
"@types/mime-types": "2.1.4",
|
||||||
"@types/ms": "0.7.34",
|
"@types/ms": "0.7.34",
|
||||||
"@types/node": "20.14.12",
|
"@types/node": "22.9.0",
|
||||||
"@types/nodemailer": "6.4.16",
|
"@types/nodemailer": "6.4.16",
|
||||||
"@types/oauth": "0.9.5",
|
"@types/oauth": "0.9.6",
|
||||||
"@types/oauth2orize": "1.11.5",
|
"@types/oauth2orize": "1.11.5",
|
||||||
"@types/oauth2orize-pkce": "0.1.2",
|
"@types/oauth2orize-pkce": "0.1.2",
|
||||||
"@types/pg": "8.11.10",
|
"@types/pg": "8.11.10",
|
||||||
|
@ -227,14 +227,14 @@
|
||||||
"@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.3",
|
"@types/web-push": "3.6.4",
|
||||||
"@types/ws": "8.5.12",
|
"@types/ws": "8.5.13",
|
||||||
"@typescript-eslint/eslint-plugin": "7.17.0",
|
"@typescript-eslint/eslint-plugin": "7.17.0",
|
||||||
"@typescript-eslint/parser": "7.17.0",
|
"@typescript-eslint/parser": "7.17.0",
|
||||||
"aws-sdk-client-mock": "4.0.1",
|
"aws-sdk-client-mock": "4.0.1",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"eslint-plugin-import": "2.30.0",
|
"eslint-plugin-import": "2.30.0",
|
||||||
"execa": "9.4.0",
|
"execa": "8.0.1",
|
||||||
"fkill": "9.0.0",
|
"fkill": "9.0.0",
|
||||||
"jest": "29.7.0",
|
"jest": "29.7.0",
|
||||||
"jest-mock": "29.7.0",
|
"jest-mock": "29.7.0",
|
||||||
|
|
|
@ -5,11 +5,52 @@
|
||||||
|
|
||||||
import Redis from 'ioredis';
|
import Redis from 'ioredis';
|
||||||
import { loadConfig } from '../built/config.js';
|
import { loadConfig } from '../built/config.js';
|
||||||
|
import { createPostgresDataSource } from '../built/postgres.js';
|
||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
const redis = new Redis(config.redis);
|
|
||||||
|
|
||||||
redis.on('connect', () => redis.disconnect());
|
async function connectToPostgres() {
|
||||||
redis.on('error', (e) => {
|
const source = createPostgresDataSource(config);
|
||||||
throw e;
|
await source.initialize();
|
||||||
|
await source.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function connectToRedis(redisOptions) {
|
||||||
|
return await new Promise(async (resolve, reject) => {
|
||||||
|
const redis = new Redis({
|
||||||
|
...redisOptions,
|
||||||
|
lazyConnect: true,
|
||||||
|
reconnectOnError: false,
|
||||||
|
showFriendlyErrorStack: true,
|
||||||
});
|
});
|
||||||
|
redis.on('error', e => reject(e));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await redis.connect();
|
||||||
|
resolve();
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
reject(e);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
redis.disconnect(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not all of these are defined, the default one gets reused.
|
||||||
|
// so we use a Set to only try connecting once to each **uniq** redis.
|
||||||
|
const promises = Array
|
||||||
|
.from(new Set([
|
||||||
|
config.redis,
|
||||||
|
config.redisForPubsub,
|
||||||
|
config.redisForJobQueue,
|
||||||
|
config.redisForTimelines,
|
||||||
|
config.redisForReactions,
|
||||||
|
]))
|
||||||
|
.map(connectToRedis)
|
||||||
|
.concat([
|
||||||
|
connectToPostgres()
|
||||||
|
]);
|
||||||
|
|
||||||
|
await Promise.allSettled(promises);
|
||||||
|
|
|
@ -154,9 +154,9 @@ export class AbuseReportNotificationService implements OnApplicationShutdown {
|
||||||
const convertedReports = abuseReports.map(it => {
|
const convertedReports = abuseReports.map(it => {
|
||||||
return {
|
return {
|
||||||
...it,
|
...it,
|
||||||
reporter: usersMap.get(it.reporterId),
|
reporter: usersMap.get(it.reporterId) ?? null,
|
||||||
targetUser: usersMap.get(it.targetUserId),
|
targetUser: usersMap.get(it.targetUserId) ?? null,
|
||||||
assignee: it.assigneeId ? usersMap.get(it.assigneeId) : null,
|
assignee: it.assigneeId ? (usersMap.get(it.assigneeId) ?? null) : null,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ export class AnnouncementService {
|
||||||
updatedAt: null,
|
updatedAt: null,
|
||||||
title: values.title,
|
title: values.title,
|
||||||
text: values.text,
|
text: values.text,
|
||||||
imageUrl: values.imageUrl,
|
imageUrl: values.imageUrl || null,
|
||||||
icon: values.icon,
|
icon: values.icon,
|
||||||
display: values.display,
|
display: values.display,
|
||||||
forExistingUsers: values.forExistingUsers,
|
forExistingUsers: values.forExistingUsers,
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import * as stream from 'node:stream/promises';
|
import * as stream from 'node:stream/promises';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import ipaddr from 'ipaddr.js';
|
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import got, * as Got from 'got';
|
import got, * as Got from 'got';
|
||||||
import { parse } from 'content-disposition';
|
import { parse } from 'content-disposition';
|
||||||
|
@ -70,13 +69,6 @@ export class DownloadService {
|
||||||
},
|
},
|
||||||
enableUnixSockets: false,
|
enableUnixSockets: false,
|
||||||
}).on('response', (res: Got.Response) => {
|
}).on('response', (res: Got.Response) => {
|
||||||
if ((process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test') && !this.config.proxy && res.ip) {
|
|
||||||
if (this.isPrivateIp(res.ip)) {
|
|
||||||
this.logger.warn(`Blocked address: ${res.ip}`);
|
|
||||||
req.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const contentLength = res.headers['content-length'];
|
const contentLength = res.headers['content-length'];
|
||||||
if (contentLength != null) {
|
if (contentLength != null) {
|
||||||
const size = Number(contentLength);
|
const size = Number(contentLength);
|
||||||
|
@ -139,18 +131,4 @@ export class DownloadService {
|
||||||
cleanup();
|
cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
|
||||||
private isPrivateIp(ip: string): boolean {
|
|
||||||
const parsedIp = ipaddr.parse(ip);
|
|
||||||
|
|
||||||
for (const net of this.config.allowedPrivateNetworks ?? []) {
|
|
||||||
const cidr = ipaddr.parseCIDR(net);
|
|
||||||
if (cidr[0].kind() === parsedIp.kind() && parsedIp.match(ipaddr.parseCIDR(net))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsedIp.range() !== 'unicast';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,6 +312,7 @@ export class EmailService {
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
Authorization: truemailAuthKey,
|
Authorization: truemailAuthKey,
|
||||||
},
|
},
|
||||||
|
isLocalAddressAllowed: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const json = (await res.json()) as {
|
const json = (await res.json()) as {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import * as http from 'node:http';
|
import * as http from 'node:http';
|
||||||
import * as https from 'node:https';
|
import * as https from 'node:https';
|
||||||
import * as net from 'node:net';
|
import * as net from 'node:net';
|
||||||
|
import ipaddr from 'ipaddr.js';
|
||||||
import CacheableLookup from 'cacheable-lookup';
|
import CacheableLookup from 'cacheable-lookup';
|
||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent';
|
import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent';
|
||||||
|
@ -15,6 +16,7 @@ import type { Config } from '@/config.js';
|
||||||
import { StatusError } from '@/misc/status-error.js';
|
import { StatusError } from '@/misc/status-error.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
|
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
|
||||||
|
import { assertActivityMatchesUrls } from '@/core/activitypub/misc/check-against-url.js';
|
||||||
import type { IObject } from '@/core/activitypub/type.js';
|
import type { IObject } from '@/core/activitypub/type.js';
|
||||||
import type { Response } from 'node-fetch';
|
import type { Response } from 'node-fetch';
|
||||||
import type { URL } from 'node:url';
|
import type { URL } from 'node:url';
|
||||||
|
@ -24,8 +26,102 @@ export type HttpRequestSendOptions = {
|
||||||
validators?: ((res: Response) => void)[];
|
validators?: ((res: Response) => void)[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
declare module 'node:http' {
|
||||||
|
interface Agent {
|
||||||
|
createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HttpRequestServiceAgent extends http.Agent {
|
||||||
|
constructor(
|
||||||
|
private config: Config,
|
||||||
|
options?: http.AgentOptions,
|
||||||
|
) {
|
||||||
|
super(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket {
|
||||||
|
const socket = super.createConnection(options, callback)
|
||||||
|
.on('connect', () => {
|
||||||
|
const address = socket.remoteAddress;
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
if (address && ipaddr.isValid(address)) {
|
||||||
|
if (this.isPrivateIp(address)) {
|
||||||
|
socket.destroy(new Error(`Blocked address: ${address}`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
private isPrivateIp(ip: string): boolean {
|
||||||
|
const parsedIp = ipaddr.parse(ip);
|
||||||
|
|
||||||
|
for (const net of this.config.allowedPrivateNetworks ?? []) {
|
||||||
|
const cidr = ipaddr.parseCIDR(net);
|
||||||
|
if (cidr[0].kind() === parsedIp.kind() && parsedIp.match(ipaddr.parseCIDR(net))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedIp.range() !== 'unicast';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HttpsRequestServiceAgent extends https.Agent {
|
||||||
|
constructor(
|
||||||
|
private config: Config,
|
||||||
|
options?: https.AgentOptions,
|
||||||
|
) {
|
||||||
|
super(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket {
|
||||||
|
const socket = super.createConnection(options, callback)
|
||||||
|
.on('connect', () => {
|
||||||
|
const address = socket.remoteAddress;
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
if (address && ipaddr.isValid(address)) {
|
||||||
|
if (this.isPrivateIp(address)) {
|
||||||
|
socket.destroy(new Error(`Blocked address: ${address}`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
private isPrivateIp(ip: string): boolean {
|
||||||
|
const parsedIp = ipaddr.parse(ip);
|
||||||
|
|
||||||
|
for (const net of this.config.allowedPrivateNetworks ?? []) {
|
||||||
|
const cidr = ipaddr.parseCIDR(net);
|
||||||
|
if (cidr[0].kind() === parsedIp.kind() && parsedIp.match(ipaddr.parseCIDR(net))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedIp.range() !== 'unicast';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class HttpRequestService {
|
export class HttpRequestService {
|
||||||
|
/**
|
||||||
|
* Get http non-proxy agent (without local address filtering)
|
||||||
|
*/
|
||||||
|
private httpNative: http.Agent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get https non-proxy agent (without local address filtering)
|
||||||
|
*/
|
||||||
|
private httpsNative: https.Agent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get http non-proxy agent
|
* Get http non-proxy agent
|
||||||
*/
|
*/
|
||||||
|
@ -56,19 +152,20 @@ export class HttpRequestService {
|
||||||
lookup: false, // nativeのdns.lookupにfallbackしない
|
lookup: false, // nativeのdns.lookupにfallbackしない
|
||||||
});
|
});
|
||||||
|
|
||||||
this.http = new http.Agent({
|
const agentOption = {
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
keepAliveMsecs: 30 * 1000,
|
keepAliveMsecs: 30 * 1000,
|
||||||
lookup: cache.lookup as unknown as net.LookupFunction,
|
lookup: cache.lookup as unknown as net.LookupFunction,
|
||||||
localAddress: config.outgoingAddress,
|
localAddress: config.outgoingAddress,
|
||||||
});
|
};
|
||||||
|
|
||||||
this.https = new https.Agent({
|
this.httpNative = new http.Agent(agentOption);
|
||||||
keepAlive: true,
|
|
||||||
keepAliveMsecs: 30 * 1000,
|
this.httpsNative = new https.Agent(agentOption);
|
||||||
lookup: cache.lookup as unknown as net.LookupFunction,
|
|
||||||
localAddress: config.outgoingAddress,
|
this.http = new HttpRequestServiceAgent(config, agentOption);
|
||||||
});
|
|
||||||
|
this.https = new HttpsRequestServiceAgent(config, agentOption);
|
||||||
|
|
||||||
const maxSockets = Math.max(256, config.deliverJobConcurrency ?? 128);
|
const maxSockets = Math.max(256, config.deliverJobConcurrency ?? 128);
|
||||||
|
|
||||||
|
@ -103,16 +200,22 @@ export class HttpRequestService {
|
||||||
* @param bypassProxy Allways bypass proxy
|
* @param bypassProxy Allways bypass proxy
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public getAgentByUrl(url: URL, bypassProxy = false): http.Agent | https.Agent {
|
public getAgentByUrl(url: URL, bypassProxy = false, isLocalAddressAllowed = false): http.Agent | https.Agent {
|
||||||
if (bypassProxy || (this.config.proxyBypassHosts ?? []).includes(url.hostname)) {
|
if (bypassProxy || (this.config.proxyBypassHosts ?? []).includes(url.hostname)) {
|
||||||
|
if (isLocalAddressAllowed) {
|
||||||
|
return url.protocol === 'http:' ? this.httpNative : this.httpsNative;
|
||||||
|
}
|
||||||
return url.protocol === 'http:' ? this.http : this.https;
|
return url.protocol === 'http:' ? this.http : this.https;
|
||||||
} else {
|
} else {
|
||||||
|
if (isLocalAddressAllowed && (!this.config.proxy)) {
|
||||||
|
return url.protocol === 'http:' ? this.httpNative : this.httpsNative;
|
||||||
|
}
|
||||||
return url.protocol === 'http:' ? this.httpAgent : this.httpsAgent;
|
return url.protocol === 'http:' ? this.httpAgent : this.httpsAgent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async getActivityJson(url: string): Promise<IObject> {
|
public async getActivityJson(url: string, isLocalAddressAllowed = false): Promise<IObject> {
|
||||||
const res = await this.send(url, {
|
const res = await this.send(url, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -120,16 +223,22 @@ export class HttpRequestService {
|
||||||
},
|
},
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
size: 1024 * 256,
|
size: 1024 * 256,
|
||||||
|
isLocalAddressAllowed: isLocalAddressAllowed,
|
||||||
}, {
|
}, {
|
||||||
throwErrorWhenResponseNotOk: true,
|
throwErrorWhenResponseNotOk: true,
|
||||||
validators: [validateContentTypeSetAsActivityPub],
|
validators: [validateContentTypeSetAsActivityPub],
|
||||||
});
|
});
|
||||||
|
|
||||||
return await res.json() as IObject;
|
const finalUrl = res.url; // redirects may have been involved
|
||||||
|
const activity = await res.json() as IObject;
|
||||||
|
|
||||||
|
assertActivityMatchesUrls(activity, [finalUrl]);
|
||||||
|
|
||||||
|
return activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async getJson<T = unknown>(url: string, accept = 'application/json, */*', headers?: Record<string, string>): Promise<T> {
|
public async getJson<T = unknown>(url: string, accept = 'application/json, */*', headers?: Record<string, string>, isLocalAddressAllowed = false): Promise<T> {
|
||||||
const res = await this.send(url, {
|
const res = await this.send(url, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: Object.assign({
|
headers: Object.assign({
|
||||||
|
@ -137,19 +246,21 @@ export class HttpRequestService {
|
||||||
}, headers ?? {}),
|
}, headers ?? {}),
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
size: 1024 * 256,
|
size: 1024 * 256,
|
||||||
|
isLocalAddressAllowed: isLocalAddressAllowed,
|
||||||
});
|
});
|
||||||
|
|
||||||
return await res.json() as T;
|
return await res.json() as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async getHtml(url: string, accept = 'text/html, */*', headers?: Record<string, string>): Promise<string> {
|
public async getHtml(url: string, accept = 'text/html, */*', headers?: Record<string, string>, isLocalAddressAllowed = false): Promise<string> {
|
||||||
const res = await this.send(url, {
|
const res = await this.send(url, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: Object.assign({
|
headers: Object.assign({
|
||||||
Accept: accept,
|
Accept: accept,
|
||||||
}, headers ?? {}),
|
}, headers ?? {}),
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
|
isLocalAddressAllowed: isLocalAddressAllowed,
|
||||||
});
|
});
|
||||||
|
|
||||||
return await res.text();
|
return await res.text();
|
||||||
|
@ -164,6 +275,7 @@ export class HttpRequestService {
|
||||||
headers?: Record<string, string>,
|
headers?: Record<string, string>,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
size?: number,
|
size?: number,
|
||||||
|
isLocalAddressAllowed?: boolean,
|
||||||
} = {},
|
} = {},
|
||||||
extra: HttpRequestSendOptions = {
|
extra: HttpRequestSendOptions = {
|
||||||
throwErrorWhenResponseNotOk: true,
|
throwErrorWhenResponseNotOk: true,
|
||||||
|
@ -177,6 +289,8 @@ export class HttpRequestService {
|
||||||
controller.abort();
|
controller.abort();
|
||||||
}, timeout);
|
}, timeout);
|
||||||
|
|
||||||
|
const isLocalAddressAllowed = args.isLocalAddressAllowed ?? false;
|
||||||
|
|
||||||
const res = await fetch(url, {
|
const res = await fetch(url, {
|
||||||
method: args.method ?? 'GET',
|
method: args.method ?? 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -185,7 +299,7 @@ export class HttpRequestService {
|
||||||
},
|
},
|
||||||
body: args.body,
|
body: args.body,
|
||||||
size: args.size ?? 10 * 1024 * 1024,
|
size: args.size ?? 10 * 1024 * 1024,
|
||||||
agent: (url) => this.getAgentByUrl(url),
|
agent: (url) => this.getAgentByUrl(url, false, isLocalAddressAllowed),
|
||||||
signal: controller.signal,
|
signal: controller.signal,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -406,8 +406,10 @@ export class MfmService {
|
||||||
mention: (node) => {
|
mention: (node) => {
|
||||||
const a = doc.createElement('a');
|
const a = doc.createElement('a');
|
||||||
const { username, host, acct } = node.props;
|
const { username, host, acct } = node.props;
|
||||||
const remoteUserInfo = mentionedRemoteUsers.find(remoteUser => remoteUser.username === username && remoteUser.host === host);
|
const remoteUserInfo = mentionedRemoteUsers.find(remoteUser => remoteUser.username.toLowerCase() === username.toLowerCase() && remoteUser.host?.toLowerCase() === host?.toLowerCase());
|
||||||
a.setAttribute('href', remoteUserInfo ? (remoteUserInfo.url ? remoteUserInfo.url : remoteUserInfo.uri) : `${this.config.url}/${acct}`);
|
a.setAttribute('href', remoteUserInfo
|
||||||
|
? (remoteUserInfo.url ? remoteUserInfo.url : remoteUserInfo.uri)
|
||||||
|
: `${this.config.url}/${acct.endsWith(`@${this.config.url}`) ? acct.substring(0, acct.length - this.config.url.length - 1) : acct}`);
|
||||||
a.className = 'u-url mention';
|
a.className = 'u-url mention';
|
||||||
a.textContent = acct;
|
a.textContent = acct;
|
||||||
return a;
|
return a;
|
||||||
|
|
|
@ -56,6 +56,7 @@ import { isReply } from '@/misc/is-reply.js';
|
||||||
import { trackPromise } from '@/misc/promise-tracker.js';
|
import { trackPromise } from '@/misc/promise-tracker.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
import { CollapsedQueue } from '@/misc/collapsed-queue.js';
|
import { CollapsedQueue } from '@/misc/collapsed-queue.js';
|
||||||
|
import { CacheService } from '@/core/CacheService.js';
|
||||||
|
|
||||||
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
|
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
|
||||||
|
|
||||||
|
@ -217,6 +218,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
private instanceChart: InstanceChart,
|
private instanceChart: InstanceChart,
|
||||||
private utilityService: UtilityService,
|
private utilityService: UtilityService,
|
||||||
private userBlockingService: UserBlockingService,
|
private userBlockingService: UserBlockingService,
|
||||||
|
private cacheService: CacheService,
|
||||||
) {
|
) {
|
||||||
this.updateNotesCountQueue = new CollapsedQueue(process.env.NODE_ENV !== 'test' ? 60 * 1000 * 5 : 0, this.collapseNotesCount, this.performUpdateNotesCount);
|
this.updateNotesCountQueue = new CollapsedQueue(process.env.NODE_ENV !== 'test' ? 60 * 1000 * 5 : 0, this.collapseNotesCount, this.performUpdateNotesCount);
|
||||||
}
|
}
|
||||||
|
@ -543,15 +545,23 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
this.followingsRepository.findBy({
|
this.followingsRepository.findBy({
|
||||||
followeeId: user.id,
|
followeeId: user.id,
|
||||||
notify: 'normal',
|
notify: 'normal',
|
||||||
}).then(followings => {
|
}).then(async followings => {
|
||||||
if (note.visibility !== 'specified') {
|
if (note.visibility !== 'specified') {
|
||||||
|
const isPureRenote = this.isRenote(data) && !this.isQuote(data) ? true : false;
|
||||||
for (const following of followings) {
|
for (const following of followings) {
|
||||||
// TODO: ワードミュート考慮
|
// TODO: ワードミュート考慮
|
||||||
|
let isRenoteMuted = false;
|
||||||
|
if (isPureRenote) {
|
||||||
|
const userIdsWhoMeMutingRenotes = await this.cacheService.renoteMutingsCache.fetch(following.followerId);
|
||||||
|
isRenoteMuted = userIdsWhoMeMutingRenotes.has(user.id);
|
||||||
|
}
|
||||||
|
if (!isRenoteMuted) {
|
||||||
this.notificationService.createNotification(following.followerId, 'note', {
|
this.notificationService.createNotification(following.followerId, 'note', {
|
||||||
noteId: note.id,
|
noteId: note.id,
|
||||||
}, user.id);
|
}, user.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,15 @@ import { randomUUID } from 'node:crypto';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import type { IActivity } from '@/core/activitypub/type.js';
|
import type { IActivity } from '@/core/activitypub/type.js';
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import type { MiWebhook, webhookEventTypes } from '@/models/Webhook.js';
|
import type { MiWebhook, WebhookEventTypes } from '@/models/Webhook.js';
|
||||||
import type { MiSystemWebhook, SystemWebhookEventType } from '@/models/SystemWebhook.js';
|
import type { MiSystemWebhook, SystemWebhookEventType } from '@/models/SystemWebhook.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import type { Antenna } from '@/server/api/endpoints/i/import-antennas.js';
|
import type { Antenna } from '@/server/api/endpoints/i/import-antennas.js';
|
||||||
import { ApRequestCreator } from '@/core/activitypub/ApRequestService.js';
|
import { ApRequestCreator } from '@/core/activitypub/ApRequestService.js';
|
||||||
|
import { type SystemWebhookPayload } from '@/core/SystemWebhookService.js';
|
||||||
|
import { type UserWebhookPayload } from './UserWebhookService.js';
|
||||||
import type {
|
import type {
|
||||||
DbJobData,
|
DbJobData,
|
||||||
DeliverJobData,
|
DeliverJobData,
|
||||||
|
@ -30,8 +32,8 @@ import type {
|
||||||
ObjectStorageQueue,
|
ObjectStorageQueue,
|
||||||
RelationshipQueue,
|
RelationshipQueue,
|
||||||
SystemQueue,
|
SystemQueue,
|
||||||
UserWebhookDeliverQueue,
|
|
||||||
SystemWebhookDeliverQueue,
|
SystemWebhookDeliverQueue,
|
||||||
|
UserWebhookDeliverQueue,
|
||||||
} from './QueueModule.js';
|
} from './QueueModule.js';
|
||||||
import type httpSignature from '@peertube/http-signature';
|
import type httpSignature from '@peertube/http-signature';
|
||||||
import type * as Bull from 'bullmq';
|
import type * as Bull from 'bullmq';
|
||||||
|
@ -468,10 +470,10 @@ export class QueueService {
|
||||||
* @see UserWebhookDeliverProcessorService
|
* @see UserWebhookDeliverProcessorService
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public userWebhookDeliver(
|
public userWebhookDeliver<T extends WebhookEventTypes>(
|
||||||
webhook: MiWebhook,
|
webhook: MiWebhook,
|
||||||
type: typeof webhookEventTypes[number],
|
type: T,
|
||||||
content: unknown,
|
content: UserWebhookPayload<T>,
|
||||||
opts?: { attempts?: number },
|
opts?: { attempts?: number },
|
||||||
) {
|
) {
|
||||||
const data: UserWebhookDeliverJobData = {
|
const data: UserWebhookDeliverJobData = {
|
||||||
|
@ -500,10 +502,10 @@ export class QueueService {
|
||||||
* @see SystemWebhookDeliverProcessorService
|
* @see SystemWebhookDeliverProcessorService
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public systemWebhookDeliver(
|
public systemWebhookDeliver<T extends SystemWebhookEventType>(
|
||||||
webhook: MiSystemWebhook,
|
webhook: MiSystemWebhook,
|
||||||
type: SystemWebhookEventType,
|
type: T,
|
||||||
content: unknown,
|
content: SystemWebhookPayload<T>,
|
||||||
opts?: { attempts?: number },
|
opts?: { attempts?: number },
|
||||||
) {
|
) {
|
||||||
const data: SystemWebhookDeliverJobData = {
|
const data: SystemWebhookDeliverJobData = {
|
||||||
|
|
|
@ -56,7 +56,7 @@ export class RemoteUserResolveService {
|
||||||
|
|
||||||
host = this.utilityService.toPuny(host);
|
host = this.utilityService.toPuny(host);
|
||||||
|
|
||||||
if (this.config.host === host) {
|
if (host === this.utilityService.toPuny(this.config.host)) {
|
||||||
this.logger.info(`return local user: ${usernameLower}`);
|
this.logger.info(`return local user: ${usernameLower}`);
|
||||||
return await this.usersRepository.findOneBy({ usernameLower, host: IsNull() }).then(u => {
|
return await this.usersRepository.findOneBy({ usernameLower, host: IsNull() }).then(u => {
|
||||||
if (u == null) {
|
if (u == null) {
|
||||||
|
|
|
@ -15,8 +15,39 @@ import { QueueService } from '@/core/QueueService.js';
|
||||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||||
import { LoggerService } from '@/core/LoggerService.js';
|
import { LoggerService } from '@/core/LoggerService.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
|
import { Packed } from '@/misc/json-schema.js';
|
||||||
|
import { AbuseReportResolveType } from '@/models/AbuseUserReport.js';
|
||||||
|
import { ModeratorInactivityRemainingTime } from '@/queue/processors/CheckModeratorsActivityProcessorService.js';
|
||||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||||
|
|
||||||
|
export type AbuseReportPayload = {
|
||||||
|
id: string;
|
||||||
|
targetUserId: string;
|
||||||
|
targetUser: Packed<'UserLite'> | null;
|
||||||
|
targetUserHost: string | null;
|
||||||
|
reporterId: string;
|
||||||
|
reporter: Packed<'UserLite'> | null;
|
||||||
|
reporterHost: string | null;
|
||||||
|
assigneeId: string | null;
|
||||||
|
assignee: Packed<'UserLite'> | null;
|
||||||
|
resolved: boolean;
|
||||||
|
forwarded: boolean;
|
||||||
|
comment: string;
|
||||||
|
moderationNote: string;
|
||||||
|
resolvedAs: AbuseReportResolveType | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type InactiveModeratorsWarningPayload = {
|
||||||
|
remainingTime: ModeratorInactivityRemainingTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SystemWebhookPayload<T extends SystemWebhookEventType> =
|
||||||
|
T extends 'abuseReport' | 'abuseReportResolved' ? AbuseReportPayload :
|
||||||
|
T extends 'userCreated' ? Packed<'UserLite'> :
|
||||||
|
T extends 'inactiveModeratorsWarning' ? InactiveModeratorsWarningPayload :
|
||||||
|
T extends 'inactiveModeratorsInvitationOnlyChanged' ? Record<string, never> :
|
||||||
|
never;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SystemWebhookService implements OnApplicationShutdown {
|
export class SystemWebhookService implements OnApplicationShutdown {
|
||||||
private logger: Logger;
|
private logger: Logger;
|
||||||
|
@ -168,7 +199,7 @@ export class SystemWebhookService implements OnApplicationShutdown {
|
||||||
public async enqueueSystemWebhook<T extends SystemWebhookEventType>(
|
public async enqueueSystemWebhook<T extends SystemWebhookEventType>(
|
||||||
webhook: MiSystemWebhook | MiSystemWebhook['id'],
|
webhook: MiSystemWebhook | MiSystemWebhook['id'],
|
||||||
type: T,
|
type: T,
|
||||||
content: unknown,
|
content: SystemWebhookPayload<T>,
|
||||||
) {
|
) {
|
||||||
const webhookEntity = typeof webhook === 'string'
|
const webhookEntity = typeof webhook === 'string'
|
||||||
? (await this.fetchActiveSystemWebhooks()).find(a => a.id === webhook)
|
? (await this.fetchActiveSystemWebhooks()).find(a => a.id === webhook)
|
||||||
|
|
|
@ -6,11 +6,23 @@
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import * as Redis from 'ioredis';
|
import * as Redis from 'ioredis';
|
||||||
import { type WebhooksRepository } from '@/models/_.js';
|
import { type WebhooksRepository } from '@/models/_.js';
|
||||||
import { MiWebhook } from '@/models/Webhook.js';
|
import { MiWebhook, WebhookEventTypes } from '@/models/Webhook.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { GlobalEvents } from '@/core/GlobalEventService.js';
|
import { GlobalEvents } from '@/core/GlobalEventService.js';
|
||||||
import type { OnApplicationShutdown } from '@nestjs/common';
|
import type { OnApplicationShutdown } from '@nestjs/common';
|
||||||
|
import type { Packed } from '@/misc/json-schema.js';
|
||||||
|
|
||||||
|
export type UserWebhookPayload<T extends WebhookEventTypes> =
|
||||||
|
T extends 'note' | 'reply' | 'renote' |'mention' ? {
|
||||||
|
note: Packed<'Note'>,
|
||||||
|
} :
|
||||||
|
T extends 'follow' | 'unfollow' ? {
|
||||||
|
user: Packed<'UserDetailedNotMe'>,
|
||||||
|
} :
|
||||||
|
T extends 'followed' ? {
|
||||||
|
user: Packed<'UserLite'>,
|
||||||
|
} : never;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserWebhookService implements OnApplicationShutdown {
|
export class UserWebhookService implements OnApplicationShutdown {
|
||||||
|
|
|
@ -34,6 +34,11 @@ export class UtilityService {
|
||||||
return this.toPuny(this.config.host) === this.toPuny(host);
|
return this.toPuny(this.config.host) === this.toPuny(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public isUriLocal(uri: string): boolean {
|
||||||
|
return this.punyHost(uri) === this.toPuny(this.config.host);
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public isBlockedHost(blockedHosts: string[], host: string | null): boolean {
|
public isBlockedHost(blockedHosts: string[], host: string | null): boolean {
|
||||||
if (host == null) return false;
|
if (host == null) return false;
|
||||||
|
@ -96,7 +101,7 @@ export class UtilityService {
|
||||||
@bindThis
|
@bindThis
|
||||||
public extractDbHost(uri: string): string {
|
public extractDbHost(uri: string): string {
|
||||||
const url = new URL(uri);
|
const url = new URL(uri);
|
||||||
return this.toPuny(url.hostname);
|
return this.toPuny(url.host);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@ -110,6 +115,13 @@ export class UtilityService {
|
||||||
return toASCII(host.toLowerCase());
|
return toASCII(host.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public punyHost(url: string): string {
|
||||||
|
const urlObj = new URL(url);
|
||||||
|
const host = `${this.toPuny(urlObj.hostname)}${urlObj.port.length > 0 ? ':' + urlObj.port : ''}`;
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public isFederationAllowedHost(host: string): boolean {
|
public isFederationAllowedHost(host: string): boolean {
|
||||||
if (this.meta.federation === 'none') return false;
|
if (this.meta.federation === 'none') return false;
|
||||||
|
|
|
@ -246,14 +246,12 @@ export class WebAuthnService {
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async verifyAuthentication(userId: MiUser['id'], response: AuthenticationResponseJSON): Promise<boolean> {
|
public async verifyAuthentication(userId: MiUser['id'], response: AuthenticationResponseJSON): Promise<boolean> {
|
||||||
const challenge = await this.redisClient.get(`webauthn:challenge:${userId}`);
|
const challenge = await this.redisClient.getdel(`webauthn:challenge:${userId}`);
|
||||||
|
|
||||||
if (!challenge) {
|
if (!challenge) {
|
||||||
throw new IdentifiableError('2d16e51c-007b-4edd-afd2-f7dd02c947f6', 'challenge not found');
|
throw new IdentifiableError('2d16e51c-007b-4edd-afd2-f7dd02c947f6', 'challenge not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.redisClient.del(`webauthn:challenge:${userId}`);
|
|
||||||
|
|
||||||
const key = await this.userSecurityKeysRepository.findOneBy({
|
const key = await this.userSecurityKeysRepository.findOneBy({
|
||||||
id: response.id,
|
id: response.id,
|
||||||
userId: userId,
|
userId: userId,
|
||||||
|
|
|
@ -7,22 +7,16 @@ import { Injectable } from '@nestjs/common';
|
||||||
import { MiAbuseUserReport, MiNote, MiUser, MiWebhook } from '@/models/_.js';
|
import { MiAbuseUserReport, MiNote, MiUser, MiWebhook } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { MiSystemWebhook, type SystemWebhookEventType } from '@/models/SystemWebhook.js';
|
import { MiSystemWebhook, type SystemWebhookEventType } from '@/models/SystemWebhook.js';
|
||||||
import { SystemWebhookService } from '@/core/SystemWebhookService.js';
|
import { AbuseReportPayload, SystemWebhookPayload, SystemWebhookService } from '@/core/SystemWebhookService.js';
|
||||||
import { Packed } from '@/misc/json-schema.js';
|
import { Packed } from '@/misc/json-schema.js';
|
||||||
import { type WebhookEventTypes } from '@/models/Webhook.js';
|
import { type WebhookEventTypes } from '@/models/Webhook.js';
|
||||||
import { UserWebhookService } from '@/core/UserWebhookService.js';
|
import { type UserWebhookPayload, UserWebhookService } from '@/core/UserWebhookService.js';
|
||||||
import { QueueService } from '@/core/QueueService.js';
|
import { QueueService } from '@/core/QueueService.js';
|
||||||
import { ModeratorInactivityRemainingTime } from '@/queue/processors/CheckModeratorsActivityProcessorService.js';
|
import { ModeratorInactivityRemainingTime } from '@/queue/processors/CheckModeratorsActivityProcessorService.js';
|
||||||
|
|
||||||
const oneDayMillis = 24 * 60 * 60 * 1000;
|
const oneDayMillis = 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
type AbuseUserReportDto = Omit<MiAbuseUserReport, 'targetUser' | 'reporter' | 'assignee'> & {
|
function generateAbuseReport(override?: Partial<MiAbuseUserReport>): AbuseReportPayload {
|
||||||
targetUser: Packed<'UserLite'> | null,
|
|
||||||
reporter: Packed<'UserLite'> | null,
|
|
||||||
assignee: Packed<'UserLite'> | null,
|
|
||||||
};
|
|
||||||
|
|
||||||
function generateAbuseReport(override?: Partial<MiAbuseUserReport>): AbuseUserReportDto {
|
|
||||||
const result: MiAbuseUserReport = {
|
const result: MiAbuseUserReport = {
|
||||||
id: 'dummy-abuse-report1',
|
id: 'dummy-abuse-report1',
|
||||||
targetUserId: 'dummy-target-user',
|
targetUserId: 'dummy-target-user',
|
||||||
|
@ -306,10 +300,10 @@ export class WebhookTestService {
|
||||||
* - 送信対象イベント(on)に関する設定
|
* - 送信対象イベント(on)に関する設定
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public async testUserWebhook(
|
public async testUserWebhook<T extends WebhookEventTypes>(
|
||||||
params: {
|
params: {
|
||||||
webhookId: MiWebhook['id'],
|
webhookId: MiWebhook['id'],
|
||||||
type: WebhookEventTypes,
|
type: T,
|
||||||
override?: Partial<Omit<MiWebhook, 'id'>>,
|
override?: Partial<Omit<MiWebhook, 'id'>>,
|
||||||
},
|
},
|
||||||
sender: MiUser | null,
|
sender: MiUser | null,
|
||||||
|
@ -321,7 +315,7 @@ export class WebhookTestService {
|
||||||
}
|
}
|
||||||
|
|
||||||
const webhook = webhooks[0];
|
const webhook = webhooks[0];
|
||||||
const send = (contents: unknown) => {
|
const send = <U extends WebhookEventTypes>(type: U, contents: UserWebhookPayload<U>) => {
|
||||||
const merged = {
|
const merged = {
|
||||||
...webhook,
|
...webhook,
|
||||||
...params.override,
|
...params.override,
|
||||||
|
@ -329,7 +323,7 @@ export class WebhookTestService {
|
||||||
|
|
||||||
// テスト目的なのでUserWebhookServiceの機能を経由せず直接キューに追加する(チェック処理などをスキップする意図).
|
// テスト目的なのでUserWebhookServiceの機能を経由せず直接キューに追加する(チェック処理などをスキップする意図).
|
||||||
// また、Jobの試行回数も1回だけ.
|
// また、Jobの試行回数も1回だけ.
|
||||||
this.queueService.userWebhookDeliver(merged, params.type, contents, { attempts: 1 });
|
this.queueService.userWebhookDeliver(merged, type, contents, { attempts: 1 });
|
||||||
};
|
};
|
||||||
|
|
||||||
const dummyNote1 = generateDummyNote({
|
const dummyNote1 = generateDummyNote({
|
||||||
|
@ -361,33 +355,41 @@ export class WebhookTestService {
|
||||||
|
|
||||||
switch (params.type) {
|
switch (params.type) {
|
||||||
case 'note': {
|
case 'note': {
|
||||||
send(toPackedNote(dummyNote1));
|
send('note', { note: toPackedNote(dummyNote1) });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'reply': {
|
case 'reply': {
|
||||||
send(toPackedNote(dummyReply1));
|
send('reply', { note: toPackedNote(dummyReply1) });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'renote': {
|
case 'renote': {
|
||||||
send(toPackedNote(dummyRenote1));
|
send('renote', { note: toPackedNote(dummyRenote1) });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'mention': {
|
case 'mention': {
|
||||||
send(toPackedNote(dummyMention1));
|
send('mention', { note: toPackedNote(dummyMention1) });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'follow': {
|
case 'follow': {
|
||||||
send(toPackedUserDetailedNotMe(dummyUser1));
|
send('follow', { user: toPackedUserDetailedNotMe(dummyUser1) });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'followed': {
|
case 'followed': {
|
||||||
send(toPackedUserLite(dummyUser2));
|
send('followed', { user: toPackedUserLite(dummyUser2) });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'unfollow': {
|
case 'unfollow': {
|
||||||
send(toPackedUserDetailedNotMe(dummyUser3));
|
send('unfollow', { user: toPackedUserDetailedNotMe(dummyUser3) });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// まだ実装されていない (#9485)
|
||||||
|
case 'reaction':
|
||||||
|
return;
|
||||||
|
default: {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const _exhaustiveAssertion: never = params.type;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,10 +402,10 @@ export class WebhookTestService {
|
||||||
* - 送信対象イベント(on)に関する設定
|
* - 送信対象イベント(on)に関する設定
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public async testSystemWebhook(
|
public async testSystemWebhook<T extends SystemWebhookEventType>(
|
||||||
params: {
|
params: {
|
||||||
webhookId: MiSystemWebhook['id'],
|
webhookId: MiSystemWebhook['id'],
|
||||||
type: SystemWebhookEventType,
|
type: T,
|
||||||
override?: Partial<Omit<MiSystemWebhook, 'id'>>,
|
override?: Partial<Omit<MiSystemWebhook, 'id'>>,
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
@ -413,7 +415,7 @@ export class WebhookTestService {
|
||||||
}
|
}
|
||||||
|
|
||||||
const webhook = webhooks[0];
|
const webhook = webhooks[0];
|
||||||
const send = (contents: unknown) => {
|
const send = <U extends SystemWebhookEventType>(type: U, contents: SystemWebhookPayload<U>) => {
|
||||||
const merged = {
|
const merged = {
|
||||||
...webhook,
|
...webhook,
|
||||||
...params.override,
|
...params.override,
|
||||||
|
@ -421,12 +423,12 @@ export class WebhookTestService {
|
||||||
|
|
||||||
// テスト目的なのでSystemWebhookServiceの機能を経由せず直接キューに追加する(チェック処理などをスキップする意図).
|
// テスト目的なのでSystemWebhookServiceの機能を経由せず直接キューに追加する(チェック処理などをスキップする意図).
|
||||||
// また、Jobの試行回数も1回だけ.
|
// また、Jobの試行回数も1回だけ.
|
||||||
this.queueService.systemWebhookDeliver(merged, params.type, contents, { attempts: 1 });
|
this.queueService.systemWebhookDeliver(merged, type, contents, { attempts: 1 });
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (params.type) {
|
switch (params.type) {
|
||||||
case 'abuseReport': {
|
case 'abuseReport': {
|
||||||
send(generateAbuseReport({
|
send('abuseReport', generateAbuseReport({
|
||||||
targetUserId: dummyUser1.id,
|
targetUserId: dummyUser1.id,
|
||||||
targetUser: dummyUser1,
|
targetUser: dummyUser1,
|
||||||
reporterId: dummyUser2.id,
|
reporterId: dummyUser2.id,
|
||||||
|
@ -435,7 +437,7 @@ export class WebhookTestService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'abuseReportResolved': {
|
case 'abuseReportResolved': {
|
||||||
send(generateAbuseReport({
|
send('abuseReportResolved', generateAbuseReport({
|
||||||
targetUserId: dummyUser1.id,
|
targetUserId: dummyUser1.id,
|
||||||
targetUser: dummyUser1,
|
targetUser: dummyUser1,
|
||||||
reporterId: dummyUser2.id,
|
reporterId: dummyUser2.id,
|
||||||
|
@ -447,7 +449,7 @@ export class WebhookTestService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'userCreated': {
|
case 'userCreated': {
|
||||||
send(toPackedUserLite(dummyUser1));
|
send('userCreated', toPackedUserLite(dummyUser1));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'inactiveModeratorsWarning': {
|
case 'inactiveModeratorsWarning': {
|
||||||
|
@ -457,15 +459,20 @@ export class WebhookTestService {
|
||||||
asHours: 24,
|
asHours: 24,
|
||||||
};
|
};
|
||||||
|
|
||||||
send({
|
send('inactiveModeratorsWarning', {
|
||||||
remainingTime: dummyTime,
|
remainingTime: dummyTime,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'inactiveModeratorsInvitationOnlyChanged': {
|
case 'inactiveModeratorsInvitationOnlyChanged': {
|
||||||
send({});
|
send('inactiveModeratorsInvitationOnlyChanged', {});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default: {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const _exhaustiveAssertion: never = params.type;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import type { Config } from '@/config.js';
|
||||||
import { MemoryKVCache } from '@/misc/cache.js';
|
import { MemoryKVCache } from '@/misc/cache.js';
|
||||||
import type { MiUserPublickey } from '@/models/UserPublickey.js';
|
import type { MiUserPublickey } from '@/models/UserPublickey.js';
|
||||||
import { CacheService } from '@/core/CacheService.js';
|
import { CacheService } from '@/core/CacheService.js';
|
||||||
|
import { UtilityService } from '@/core/UtilityService.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 { MiLocalUser, MiRemoteUser } from '@/models/User.js';
|
import { MiLocalUser, MiRemoteUser } from '@/models/User.js';
|
||||||
|
@ -53,6 +54,7 @@ export class ApDbResolverService implements OnApplicationShutdown {
|
||||||
|
|
||||||
private cacheService: CacheService,
|
private cacheService: CacheService,
|
||||||
private apPersonService: ApPersonService,
|
private apPersonService: ApPersonService,
|
||||||
|
private utilityService: UtilityService,
|
||||||
) {
|
) {
|
||||||
this.publicKeyCache = new MemoryKVCache<MiUserPublickey | null>(1000 * 60 * 60 * 12); // 12h
|
this.publicKeyCache = new MemoryKVCache<MiUserPublickey | null>(1000 * 60 * 60 * 12); // 12h
|
||||||
this.publicKeyByUserIdCache = new MemoryKVCache<MiUserPublickey | null>(1000 * 60 * 60 * 12); // 12h
|
this.publicKeyByUserIdCache = new MemoryKVCache<MiUserPublickey | null>(1000 * 60 * 60 * 12); // 12h
|
||||||
|
@ -63,7 +65,9 @@ export class ApDbResolverService implements OnApplicationShutdown {
|
||||||
const separator = '/';
|
const separator = '/';
|
||||||
|
|
||||||
const uri = new URL(getApId(value));
|
const uri = new URL(getApId(value));
|
||||||
if (uri.origin !== this.config.url) return { local: false, uri: uri.href };
|
if (this.utilityService.toPuny(uri.host) !== this.utilityService.toPuny(this.config.host)) {
|
||||||
|
return { local: false, uri: uri.href };
|
||||||
|
}
|
||||||
|
|
||||||
const [, type, id, ...rest] = uri.pathname.split(separator);
|
const [, type, id, ...rest] = uri.pathname.split(separator);
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -89,15 +89,26 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async performActivity(actor: MiRemoteUser, activity: IObject): Promise<string | void> {
|
public async performActivity(actor: MiRemoteUser, activity: IObject, resolver?: Resolver): Promise<string | void> {
|
||||||
let result = undefined as string | void;
|
let result = undefined as string | void;
|
||||||
if (isCollectionOrOrderedCollection(activity)) {
|
if (isCollectionOrOrderedCollection(activity)) {
|
||||||
const results = [] as [string, string | void][];
|
const results = [] as [string, string | void][];
|
||||||
const resolver = this.apResolverService.createResolver();
|
// eslint-disable-next-line no-param-reassign
|
||||||
for (const item of toArray(isCollection(activity) ? activity.items : activity.orderedItems)) {
|
resolver ??= this.apResolverService.createResolver();
|
||||||
|
|
||||||
|
const items = toArray(isCollection(activity) ? activity.items : activity.orderedItems);
|
||||||
|
if (items.length >= resolver.getRecursionLimit()) {
|
||||||
|
throw new Error(`skipping activity: collection would surpass recursion limit: ${this.utilityService.extractDbHost(actor.uri)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
const act = await resolver.resolve(item);
|
const act = await resolver.resolve(item);
|
||||||
|
if (act.id == null || this.utilityService.extractDbHost(act.id) !== this.utilityService.extractDbHost(actor.uri)) {
|
||||||
|
this.logger.debug('skipping activity: activity id is null or mismatching');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
results.push([getApId(item), await this.performOneActivity(actor, act)]);
|
results.push([getApId(item), await this.performOneActivity(actor, act, resolver)]);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof Error || typeof err === 'string') {
|
if (err instanceof Error || typeof err === 'string') {
|
||||||
this.logger.error(err);
|
this.logger.error(err);
|
||||||
|
@ -112,13 +123,14 @@ export class ApInboxService {
|
||||||
result = results.map(([id, reason]) => `${id}: ${reason}`).join('\n');
|
result = results.map(([id, reason]) => `${id}: ${reason}`).join('\n');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = await this.performOneActivity(actor, activity);
|
result = await this.performOneActivity(actor, activity, resolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ついでにリモートユーザーの情報が古かったら更新しておく
|
// ついでにリモートユーザーの情報が古かったら更新しておく
|
||||||
if (actor.uri) {
|
if (actor.uri) {
|
||||||
if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
|
if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
|
||||||
setImmediate(() => {
|
setImmediate(() => {
|
||||||
|
// 同一ユーザーの情報を再度処理するので、使用済みのresolverを再利用してはいけない
|
||||||
this.apPersonService.updatePerson(actor.uri);
|
this.apPersonService.updatePerson(actor.uri);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -127,37 +139,37 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async performOneActivity(actor: MiRemoteUser, activity: IObject): Promise<string | void> {
|
public async performOneActivity(actor: MiRemoteUser, activity: IObject, resolver?: Resolver): Promise<string | void> {
|
||||||
if (actor.isSuspended) return;
|
if (actor.isSuspended) return;
|
||||||
|
|
||||||
if (isCreate(activity)) {
|
if (isCreate(activity)) {
|
||||||
return await this.create(actor, activity);
|
return await this.create(actor, activity, resolver);
|
||||||
} else if (isDelete(activity)) {
|
} else if (isDelete(activity)) {
|
||||||
return await this.delete(actor, activity);
|
return await this.delete(actor, activity);
|
||||||
} else if (isUpdate(activity)) {
|
} else if (isUpdate(activity)) {
|
||||||
return await this.update(actor, activity);
|
return await this.update(actor, activity, resolver);
|
||||||
} else if (isFollow(activity)) {
|
} else if (isFollow(activity)) {
|
||||||
return await this.follow(actor, activity);
|
return await this.follow(actor, activity);
|
||||||
} else if (isAccept(activity)) {
|
} else if (isAccept(activity)) {
|
||||||
return await this.accept(actor, activity);
|
return await this.accept(actor, activity, resolver);
|
||||||
} else if (isReject(activity)) {
|
} else if (isReject(activity)) {
|
||||||
return await this.reject(actor, activity);
|
return await this.reject(actor, activity, resolver);
|
||||||
} else if (isAdd(activity)) {
|
} else if (isAdd(activity)) {
|
||||||
return await this.add(actor, activity);
|
return await this.add(actor, activity, resolver);
|
||||||
} else if (isRemove(activity)) {
|
} else if (isRemove(activity)) {
|
||||||
return await this.remove(actor, activity);
|
return await this.remove(actor, activity, resolver);
|
||||||
} else if (isAnnounce(activity)) {
|
} else if (isAnnounce(activity)) {
|
||||||
return await this.announce(actor, activity);
|
return await this.announce(actor, activity, resolver);
|
||||||
} else if (isLike(activity)) {
|
} else if (isLike(activity)) {
|
||||||
return await this.like(actor, activity);
|
return await this.like(actor, activity);
|
||||||
} else if (isUndo(activity)) {
|
} else if (isUndo(activity)) {
|
||||||
return await this.undo(actor, activity);
|
return await this.undo(actor, activity, resolver);
|
||||||
} else if (isBlock(activity)) {
|
} else if (isBlock(activity)) {
|
||||||
return await this.block(actor, activity);
|
return await this.block(actor, activity);
|
||||||
} else if (isFlag(activity)) {
|
} else if (isFlag(activity)) {
|
||||||
return await this.flag(actor, activity);
|
return await this.flag(actor, activity);
|
||||||
} else if (isMove(activity)) {
|
} else if (isMove(activity)) {
|
||||||
return await this.move(actor, activity);
|
return await this.move(actor, activity, resolver);
|
||||||
} else {
|
} else {
|
||||||
return `unrecognized activity type: ${activity.type}`;
|
return `unrecognized activity type: ${activity.type}`;
|
||||||
}
|
}
|
||||||
|
@ -199,12 +211,13 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async accept(actor: MiRemoteUser, activity: IAccept): Promise<string> {
|
private async accept(actor: MiRemoteUser, activity: IAccept, resolver?: Resolver): Promise<string> {
|
||||||
const uri = activity.id ?? activity;
|
const uri = activity.id ?? activity;
|
||||||
|
|
||||||
this.logger.info(`Accept: ${uri}`);
|
this.logger.info(`Accept: ${uri}`);
|
||||||
|
|
||||||
const resolver = this.apResolverService.createResolver();
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
resolver ??= this.apResolverService.createResolver();
|
||||||
|
|
||||||
const object = await resolver.resolve(activity.object).catch(err => {
|
const object = await resolver.resolve(activity.object).catch(err => {
|
||||||
this.logger.error(`Resolution failed: ${err}`);
|
this.logger.error(`Resolution failed: ${err}`);
|
||||||
|
@ -241,7 +254,7 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async add(actor: MiRemoteUser, activity: IAdd): Promise<string | void> {
|
private async add(actor: MiRemoteUser, activity: IAdd, resolver?: Resolver): Promise<string | void> {
|
||||||
if (actor.uri !== activity.actor) {
|
if (actor.uri !== activity.actor) {
|
||||||
return 'invalid actor';
|
return 'invalid actor';
|
||||||
}
|
}
|
||||||
|
@ -251,7 +264,7 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activity.target === actor.featured) {
|
if (activity.target === actor.featured) {
|
||||||
const note = await this.apNoteService.resolveNote(activity.object);
|
const note = await this.apNoteService.resolveNote(activity.object, { resolver });
|
||||||
if (note == null) return 'note not found';
|
if (note == null) return 'note not found';
|
||||||
await this.notePiningService.addPinned(actor, note.id);
|
await this.notePiningService.addPinned(actor, note.id);
|
||||||
return;
|
return;
|
||||||
|
@ -261,12 +274,13 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async announce(actor: MiRemoteUser, activity: IAnnounce): Promise<string | void> {
|
private async announce(actor: MiRemoteUser, activity: IAnnounce, resolver?: Resolver): Promise<string | void> {
|
||||||
const uri = getApId(activity);
|
const uri = getApId(activity);
|
||||||
|
|
||||||
this.logger.info(`Announce: ${uri}`);
|
this.logger.info(`Announce: ${uri}`);
|
||||||
|
|
||||||
const resolver = this.apResolverService.createResolver();
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
resolver ??= this.apResolverService.createResolver();
|
||||||
|
|
||||||
if (!activity.object) return 'skip: activity has no object property';
|
if (!activity.object) return 'skip: activity has no object property';
|
||||||
const targetUri = getApId(activity.object);
|
const targetUri = getApId(activity.object);
|
||||||
|
@ -283,7 +297,7 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async announceNote(actor: MiRemoteUser, activity: IAnnounce, target: IPost): Promise<string | void> {
|
private async announceNote(actor: MiRemoteUser, activity: IAnnounce, target: IPost, resolver?: Resolver): Promise<string | void> {
|
||||||
const uri = getApId(activity);
|
const uri = getApId(activity);
|
||||||
|
|
||||||
if (actor.isSuspended) {
|
if (actor.isSuspended) {
|
||||||
|
@ -305,7 +319,7 @@ export class ApInboxService {
|
||||||
// Announce対象をresolve
|
// Announce対象をresolve
|
||||||
let renote;
|
let renote;
|
||||||
try {
|
try {
|
||||||
renote = await this.apNoteService.resolveNote(target);
|
renote = await this.apNoteService.resolveNote(target, { resolver });
|
||||||
if (renote == null) return 'announce target is null';
|
if (renote == null) return 'announce target is null';
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// 対象が4xxならスキップ
|
// 対象が4xxならスキップ
|
||||||
|
@ -324,7 +338,7 @@ export class ApInboxService {
|
||||||
|
|
||||||
this.logger.info(`Creating the (Re)Note: ${uri}`);
|
this.logger.info(`Creating the (Re)Note: ${uri}`);
|
||||||
|
|
||||||
const activityAudience = await this.apAudienceService.parseAudience(actor, activity.to, activity.cc);
|
const activityAudience = await this.apAudienceService.parseAudience(actor, activity.to, activity.cc, resolver);
|
||||||
const createdAt = activity.published ? new Date(activity.published) : null;
|
const createdAt = activity.published ? new Date(activity.published) : null;
|
||||||
|
|
||||||
if (createdAt && createdAt < this.idService.parse(renote.id).date) {
|
if (createdAt && createdAt < this.idService.parse(renote.id).date) {
|
||||||
|
@ -362,7 +376,7 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async create(actor: MiRemoteUser, activity: ICreate): Promise<string | void> {
|
private async create(actor: MiRemoteUser, activity: ICreate, resolver?: Resolver): Promise<string | void> {
|
||||||
const uri = getApId(activity);
|
const uri = getApId(activity);
|
||||||
|
|
||||||
this.logger.info(`Create: ${uri}`);
|
this.logger.info(`Create: ${uri}`);
|
||||||
|
@ -387,7 +401,8 @@ export class ApInboxService {
|
||||||
activity.object.attributedTo = activity.actor;
|
activity.object.attributedTo = activity.actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolver = this.apResolverService.createResolver();
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
resolver ??= this.apResolverService.createResolver();
|
||||||
|
|
||||||
const object = await resolver.resolve(activity.object).catch(e => {
|
const object = await resolver.resolve(activity.object).catch(e => {
|
||||||
this.logger.error(`Resolution failed: ${e}`);
|
this.logger.error(`Resolution failed: ${e}`);
|
||||||
|
@ -414,6 +429,8 @@ export class ApInboxService {
|
||||||
if (this.utilityService.extractDbHost(actor.uri) !== this.utilityService.extractDbHost(note.id)) {
|
if (this.utilityService.extractDbHost(actor.uri) !== this.utilityService.extractDbHost(note.id)) {
|
||||||
return 'skip: host in actor.uri !== note.id';
|
return 'skip: host in actor.uri !== note.id';
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return 'skip: note.id is not a string';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,7 +440,7 @@ export class ApInboxService {
|
||||||
const exist = await this.apNoteService.fetchNote(note);
|
const exist = await this.apNoteService.fetchNote(note);
|
||||||
if (exist) return 'skip: note exists';
|
if (exist) return 'skip: note exists';
|
||||||
|
|
||||||
await this.apNoteService.createNote(note, resolver, silent);
|
await this.apNoteService.createNote(note, actor, resolver, silent);
|
||||||
return 'ok';
|
return 'ok';
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof StatusError && !err.isRetryable) {
|
if (err instanceof StatusError && !err.isRetryable) {
|
||||||
|
@ -555,12 +572,13 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async reject(actor: MiRemoteUser, activity: IReject): Promise<string> {
|
private async reject(actor: MiRemoteUser, activity: IReject, resolver?: Resolver): Promise<string> {
|
||||||
const uri = activity.id ?? activity;
|
const uri = activity.id ?? activity;
|
||||||
|
|
||||||
this.logger.info(`Reject: ${uri}`);
|
this.logger.info(`Reject: ${uri}`);
|
||||||
|
|
||||||
const resolver = this.apResolverService.createResolver();
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
resolver ??= this.apResolverService.createResolver();
|
||||||
|
|
||||||
const object = await resolver.resolve(activity.object).catch(e => {
|
const object = await resolver.resolve(activity.object).catch(e => {
|
||||||
this.logger.error(`Resolution failed: ${e}`);
|
this.logger.error(`Resolution failed: ${e}`);
|
||||||
|
@ -597,7 +615,7 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async remove(actor: MiRemoteUser, activity: IRemove): Promise<string | void> {
|
private async remove(actor: MiRemoteUser, activity: IRemove, resolver?: Resolver): Promise<string | void> {
|
||||||
if (actor.uri !== activity.actor) {
|
if (actor.uri !== activity.actor) {
|
||||||
return 'invalid actor';
|
return 'invalid actor';
|
||||||
}
|
}
|
||||||
|
@ -607,7 +625,7 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activity.target === actor.featured) {
|
if (activity.target === actor.featured) {
|
||||||
const note = await this.apNoteService.resolveNote(activity.object);
|
const note = await this.apNoteService.resolveNote(activity.object, { resolver });
|
||||||
if (note == null) return 'note not found';
|
if (note == null) return 'note not found';
|
||||||
await this.notePiningService.removePinned(actor, note.id);
|
await this.notePiningService.removePinned(actor, note.id);
|
||||||
return;
|
return;
|
||||||
|
@ -617,7 +635,7 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async undo(actor: MiRemoteUser, activity: IUndo): Promise<string> {
|
private async undo(actor: MiRemoteUser, activity: IUndo, resolver?: Resolver): Promise<string> {
|
||||||
if (actor.uri !== activity.actor) {
|
if (actor.uri !== activity.actor) {
|
||||||
return 'invalid actor';
|
return 'invalid actor';
|
||||||
}
|
}
|
||||||
|
@ -626,7 +644,8 @@ export class ApInboxService {
|
||||||
|
|
||||||
this.logger.info(`Undo: ${uri}`);
|
this.logger.info(`Undo: ${uri}`);
|
||||||
|
|
||||||
const resolver = this.apResolverService.createResolver();
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
resolver ??= this.apResolverService.createResolver();
|
||||||
|
|
||||||
const object = await resolver.resolve(activity.object).catch(e => {
|
const object = await resolver.resolve(activity.object).catch(e => {
|
||||||
this.logger.error(`Resolution failed: ${e}`);
|
this.logger.error(`Resolution failed: ${e}`);
|
||||||
|
@ -750,14 +769,15 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async update(actor: MiRemoteUser, activity: IUpdate): Promise<string> {
|
private async update(actor: MiRemoteUser, activity: IUpdate, resolver?: Resolver): Promise<string> {
|
||||||
if (actor.uri !== activity.actor) {
|
if (actor.uri !== activity.actor) {
|
||||||
return 'skip: invalid actor';
|
return 'skip: invalid actor';
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug('Update');
|
this.logger.debug('Update');
|
||||||
|
|
||||||
const resolver = this.apResolverService.createResolver();
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
resolver ??= this.apResolverService.createResolver();
|
||||||
|
|
||||||
const object = await resolver.resolve(activity.object).catch(e => {
|
const object = await resolver.resolve(activity.object).catch(e => {
|
||||||
this.logger.error(`Resolution failed: ${e}`);
|
this.logger.error(`Resolution failed: ${e}`);
|
||||||
|
@ -768,7 +788,7 @@ export class ApInboxService {
|
||||||
await this.apPersonService.updatePerson(actor.uri, resolver, object);
|
await this.apPersonService.updatePerson(actor.uri, resolver, object);
|
||||||
return 'ok: Person updated';
|
return 'ok: Person updated';
|
||||||
} else if (getApType(object) === 'Question') {
|
} else if (getApType(object) === 'Question') {
|
||||||
await this.apQuestionService.updateQuestion(object, resolver).catch(err => console.error(err));
|
await this.apQuestionService.updateQuestion(object, actor, resolver).catch(err => console.error(err));
|
||||||
return 'ok: Question updated';
|
return 'ok: Question updated';
|
||||||
} else {
|
} else {
|
||||||
return `skip: Unknown type: ${getApType(object)}`;
|
return `skip: Unknown type: ${getApType(object)}`;
|
||||||
|
@ -776,11 +796,11 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async move(actor: MiRemoteUser, activity: IMove): Promise<string> {
|
private async move(actor: MiRemoteUser, activity: IMove, resolver?: Resolver): Promise<string> {
|
||||||
// fetch the new and old accounts
|
// fetch the new and old accounts
|
||||||
const targetUri = getApHrefNullable(activity.target);
|
const targetUri = getApHrefNullable(activity.target);
|
||||||
if (!targetUri) return 'skip: invalid activity target';
|
if (!targetUri) return 'skip: invalid activity target';
|
||||||
|
|
||||||
return await this.apPersonService.updatePerson(actor.uri) ?? 'skip: nothing to do';
|
return await this.apPersonService.updatePerson(actor.uri, resolver) ?? 'skip: nothing to do';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,14 @@ import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import { UserKeypairService } from '@/core/UserKeypairService.js';
|
import { UserKeypairService } from '@/core/UserKeypairService.js';
|
||||||
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||||
import { LoggerService } from '@/core/LoggerService.js';
|
import { LoggerService } from '@/core/LoggerService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
|
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
|
||||||
|
import { assertActivityMatchesUrls } from '@/core/activitypub/misc/check-against-url.js';
|
||||||
|
import type { IObject } from './type.js';
|
||||||
|
|
||||||
type Request = {
|
type Request = {
|
||||||
url: string;
|
url: string;
|
||||||
|
@ -145,6 +148,7 @@ export class ApRequestService {
|
||||||
private userKeypairService: UserKeypairService,
|
private userKeypairService: UserKeypairService,
|
||||||
private httpRequestService: HttpRequestService,
|
private httpRequestService: HttpRequestService,
|
||||||
private loggerService: LoggerService,
|
private loggerService: LoggerService,
|
||||||
|
private utilityService: UtilityService,
|
||||||
) {
|
) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
this.logger = this.loggerService?.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる
|
this.logger = this.loggerService?.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる
|
||||||
|
@ -238,7 +242,7 @@ export class ApRequestService {
|
||||||
const alternate = document.querySelector('head > link[rel="alternate"][type="application/activity+json"]');
|
const alternate = document.querySelector('head > link[rel="alternate"][type="application/activity+json"]');
|
||||||
if (alternate) {
|
if (alternate) {
|
||||||
const href = alternate.getAttribute('href');
|
const href = alternate.getAttribute('href');
|
||||||
if (href) {
|
if (href && this.utilityService.punyHost(url) === this.utilityService.punyHost(href)) {
|
||||||
return await this.signedGet(href, user, false);
|
return await this.signedGet(href, user, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,7 +255,11 @@ export class ApRequestService {
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
validateContentTypeSetAsActivityPub(res);
|
validateContentTypeSetAsActivityPub(res);
|
||||||
|
const finalUrl = res.url; // redirects may have been involved
|
||||||
|
const activity = await res.json() as IObject;
|
||||||
|
|
||||||
return await res.json();
|
assertActivityMatchesUrls(activity, [finalUrl]);
|
||||||
|
|
||||||
|
return activity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ export class Resolver {
|
||||||
private apRendererService: ApRendererService,
|
private apRendererService: ApRendererService,
|
||||||
private apDbResolverService: ApDbResolverService,
|
private apDbResolverService: ApDbResolverService,
|
||||||
private loggerService: LoggerService,
|
private loggerService: LoggerService,
|
||||||
private recursionLimit = 100,
|
private recursionLimit = 256,
|
||||||
) {
|
) {
|
||||||
this.history = new Set();
|
this.history = new Set();
|
||||||
this.logger = this.loggerService.getLogger('ap-resolve');
|
this.logger = this.loggerService.getLogger('ap-resolve');
|
||||||
|
@ -52,6 +52,11 @@ export class Resolver {
|
||||||
return Array.from(this.history);
|
return Array.from(this.history);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public getRecursionLimit(): number {
|
||||||
|
return this.recursionLimit;
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async resolveCollection(value: string | IObject): Promise<ICollection | IOrderedCollection> {
|
public async resolveCollection(value: string | IObject): Promise<ICollection | IOrderedCollection> {
|
||||||
const collection = typeof value === 'string'
|
const collection = typeof value === 'string'
|
||||||
|
@ -113,6 +118,18 @@ export class Resolver {
|
||||||
throw new Error('invalid response');
|
throw new Error('invalid response');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HttpRequestService / ApRequestService have already checked that
|
||||||
|
// `object.id` or `object.url` matches the URL used to fetch the
|
||||||
|
// object after redirects; here we double-check that no redirects
|
||||||
|
// bounced between hosts
|
||||||
|
if (object.id == null) {
|
||||||
|
throw new Error('invalid AP object: missing id');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.utilityService.punyHost(object.id) !== this.utilityService.punyHost(value)) {
|
||||||
|
throw new Error(`invalid AP object ${value}: id ${object.id} has different host`);
|
||||||
|
}
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: dakkar and sharkey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
import type { IObject } from '../type.js';
|
||||||
|
|
||||||
|
export function assertActivityMatchesUrls(activity: IObject, urls: string[]) {
|
||||||
|
const idOk = activity.id !== undefined && urls.includes(activity.id);
|
||||||
|
|
||||||
|
// technically `activity.url` could be an `ApObject = IObject |
|
||||||
|
// string | (IObject | string)[]`, but if it's a complicated thing
|
||||||
|
// and the `activity.id` doesn't match, I think we're fine
|
||||||
|
// rejecting the activity
|
||||||
|
const urlOk = typeof(activity.url) === 'string' && urls.includes(activity.url);
|
||||||
|
|
||||||
|
if (!idOk && !urlOk) {
|
||||||
|
throw new Error(`bad Activity: neither id(${activity?.id}) nor url(${activity?.url}) match location(${urls})`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,7 +77,7 @@ export class ApNoteService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public validateNote(object: IObject, uri: string): Error | null {
|
public validateNote(object: IObject, uri: string, actor?: MiRemoteUser): Error | null {
|
||||||
const expectHost = this.utilityService.extractDbHost(uri);
|
const expectHost = this.utilityService.extractDbHost(uri);
|
||||||
const apType = getApType(object);
|
const apType = getApType(object);
|
||||||
|
|
||||||
|
@ -98,6 +98,14 @@ export class ApNoteService {
|
||||||
return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', 'invalid Note: published timestamp is malformed');
|
return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', 'invalid Note: published timestamp is malformed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (actor) {
|
||||||
|
const attribution = (object.attributedTo) ? getOneApId(object.attributedTo) : actor.uri;
|
||||||
|
|
||||||
|
if (attribution !== actor.uri) {
|
||||||
|
return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', `invalid Note: attribution does not match the actor that send it. attribution: ${attribution}, actor: ${actor.uri}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,14 +123,14 @@ export class ApNoteService {
|
||||||
* Noteを作成します。
|
* Noteを作成します。
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public async createNote(value: string | IObject, resolver?: Resolver, silent = false): Promise<MiNote | null> {
|
public async createNote(value: string | IObject, actor?: MiRemoteUser, resolver?: Resolver, silent = false): Promise<MiNote | null> {
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
if (resolver == null) resolver = this.apResolverService.createResolver();
|
if (resolver == null) resolver = this.apResolverService.createResolver();
|
||||||
|
|
||||||
const object = await resolver.resolve(value);
|
const object = await resolver.resolve(value);
|
||||||
|
|
||||||
const entryUri = getApId(value);
|
const entryUri = getApId(value);
|
||||||
const err = this.validateNote(object, entryUri);
|
const err = this.validateNote(object, entryUri, actor);
|
||||||
if (err) {
|
if (err) {
|
||||||
this.logger.error(err.message, {
|
this.logger.error(err.message, {
|
||||||
resolver: { history: resolver.getHistory() },
|
resolver: { history: resolver.getHistory() },
|
||||||
|
@ -136,16 +144,26 @@ export class ApNoteService {
|
||||||
|
|
||||||
this.logger.debug(`Note fetched: ${JSON.stringify(note, null, 2)}`);
|
this.logger.debug(`Note fetched: ${JSON.stringify(note, null, 2)}`);
|
||||||
|
|
||||||
if (note.id && !checkHttps(note.id)) {
|
if (note.id == null) {
|
||||||
|
throw new Error('Refusing to create note without id');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!checkHttps(note.id)) {
|
||||||
throw new Error('unexpected schema of note.id: ' + note.id);
|
throw new Error('unexpected schema of note.id: ' + note.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = getOneApHrefNullable(note.url);
|
const url = getOneApHrefNullable(note.url);
|
||||||
|
|
||||||
if (url && !checkHttps(url)) {
|
if (url != null) {
|
||||||
|
if (!checkHttps(url)) {
|
||||||
throw new Error('unexpected schema of note url: ' + url);
|
throw new Error('unexpected schema of note url: ' + url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.utilityService.punyHost(url) !== this.utilityService.punyHost(note.id)) {
|
||||||
|
throw new Error(`note url & uri host mismatch: note url: ${url}, note uri: ${note.id}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.info(`Creating the Note: ${note.id}`);
|
this.logger.info(`Creating the Note: ${note.id}`);
|
||||||
|
|
||||||
// 投稿者をフェッチ
|
// 投稿者をフェッチ
|
||||||
|
@ -156,8 +174,9 @@ export class ApNoteService {
|
||||||
const uri = getOneApId(note.attributedTo);
|
const uri = getOneApId(note.attributedTo);
|
||||||
|
|
||||||
// ローカルで投稿者を検索し、もし凍結されていたらスキップ
|
// ローカルで投稿者を検索し、もし凍結されていたらスキップ
|
||||||
const cachedActor = await this.apPersonService.fetchPerson(uri) as MiRemoteUser;
|
// eslint-disable-next-line no-param-reassign
|
||||||
if (cachedActor && cachedActor.isSuspended) {
|
actor ??= await this.apPersonService.fetchPerson(uri) as MiRemoteUser | undefined;
|
||||||
|
if (actor && actor.isSuspended) {
|
||||||
throw new IdentifiableError('85ab9bd7-3a41-4530-959d-f07073900109', 'actor has been suspended');
|
throw new IdentifiableError('85ab9bd7-3a41-4530-959d-f07073900109', 'actor has been suspended');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +208,8 @@ export class ApNoteService {
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
const actor = cachedActor ?? await this.apPersonService.resolvePerson(uri, resolver) as MiRemoteUser;
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
actor ??= await this.apPersonService.resolvePerson(uri, resolver) as MiRemoteUser;
|
||||||
|
|
||||||
// 解決した投稿者が凍結されていたらスキップ
|
// 解決した投稿者が凍結されていたらスキップ
|
||||||
if (actor.isSuspended) {
|
if (actor.isSuspended) {
|
||||||
|
@ -348,7 +368,7 @@ export class ApNoteService {
|
||||||
if (exist) return exist;
|
if (exist) return exist;
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
if (uri.startsWith(this.config.url)) {
|
if (this.utilityService.isUriLocal(uri)) {
|
||||||
throw new StatusError('cannot resolve local note', 400, 'cannot resolve local note');
|
throw new StatusError('cannot resolve local note', 400, 'cannot resolve local note');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +376,7 @@ export class ApNoteService {
|
||||||
// ここでuriの代わりに添付されてきたNote Objectが指定されていると、サーバーフェッチを経ずにノートが生成されるが
|
// ここでuriの代わりに添付されてきたNote Objectが指定されていると、サーバーフェッチを経ずにノートが生成されるが
|
||||||
// 添付されてきたNote Objectは偽装されている可能性があるため、常にuriを指定してサーバーフェッチを行う。
|
// 添付されてきたNote Objectは偽装されている可能性があるため、常にuriを指定してサーバーフェッチを行う。
|
||||||
const createFrom = options.sentFrom?.origin === new URL(uri).origin ? value : uri;
|
const createFrom = options.sentFrom?.origin === new URL(uri).origin ? value : uri;
|
||||||
return await this.createNote(createFrom, options.resolver, true);
|
return await this.createNote(createFrom, undefined, options.resolver, true);
|
||||||
} finally {
|
} finally {
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,12 +129,6 @@ export class ApPersonService implements OnModuleInit {
|
||||||
this.logger = this.apLoggerService.logger;
|
this.logger = this.apLoggerService.logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
private punyHost(url: string): string {
|
|
||||||
const urlObj = new URL(url);
|
|
||||||
const host = `${this.utilityService.toPuny(urlObj.hostname)}${urlObj.port.length > 0 ? ':' + urlObj.port : ''}`;
|
|
||||||
return host;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate and convert to actor object
|
* Validate and convert to actor object
|
||||||
* @param x Fetched object
|
* @param x Fetched object
|
||||||
|
@ -142,7 +136,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
private validateActor(x: IObject, uri: string): IActor {
|
private validateActor(x: IObject, uri: string): IActor {
|
||||||
const expectHost = this.punyHost(uri);
|
const expectHost = this.utilityService.punyHost(uri);
|
||||||
|
|
||||||
if (!isActor(x)) {
|
if (!isActor(x)) {
|
||||||
throw new Error(`invalid Actor type '${x.type}'`);
|
throw new Error(`invalid Actor type '${x.type}'`);
|
||||||
|
@ -156,6 +150,32 @@ export class ApPersonService implements OnModuleInit {
|
||||||
throw new Error('invalid Actor: wrong inbox');
|
throw new Error('invalid Actor: wrong inbox');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.utilityService.punyHost(x.inbox) !== expectHost) {
|
||||||
|
throw new Error('invalid Actor: inbox has different host');
|
||||||
|
}
|
||||||
|
|
||||||
|
const sharedInboxObject = x.sharedInbox ?? (x.endpoints ? x.endpoints.sharedInbox : undefined);
|
||||||
|
if (sharedInboxObject != null) {
|
||||||
|
const sharedInbox = getApId(sharedInboxObject);
|
||||||
|
if (!(typeof sharedInbox === 'string' && sharedInbox.length > 0 && this.utilityService.punyHost(sharedInbox) === expectHost)) {
|
||||||
|
throw new Error('invalid Actor: wrong shared inbox');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const collection of ['outbox', 'followers', 'following'] as (keyof IActor)[]) {
|
||||||
|
const xCollection = (x as IActor)[collection];
|
||||||
|
if (xCollection != null) {
|
||||||
|
const collectionUri = getApId(xCollection);
|
||||||
|
if (typeof collectionUri === 'string' && collectionUri.length > 0) {
|
||||||
|
if (this.utilityService.punyHost(collectionUri) !== expectHost) {
|
||||||
|
throw new Error(`invalid Actor: ${collection} has different host`);
|
||||||
|
}
|
||||||
|
} else if (collectionUri != null) {
|
||||||
|
throw new Error(`invalid Actor: wrong ${collection}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!(typeof x.preferredUsername === 'string' && x.preferredUsername.length > 0 && x.preferredUsername.length <= 128 && /^\w([\w-.]*\w)?$/.test(x.preferredUsername))) {
|
if (!(typeof x.preferredUsername === 'string' && x.preferredUsername.length > 0 && x.preferredUsername.length <= 128 && /^\w([\w-.]*\w)?$/.test(x.preferredUsername))) {
|
||||||
throw new Error('invalid Actor: wrong username');
|
throw new Error('invalid Actor: wrong username');
|
||||||
}
|
}
|
||||||
|
@ -179,7 +199,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
x.summary = truncate(x.summary, summaryLength);
|
x.summary = truncate(x.summary, summaryLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
const idHost = this.punyHost(x.id);
|
const idHost = this.utilityService.punyHost(x.id);
|
||||||
if (idHost !== expectHost) {
|
if (idHost !== expectHost) {
|
||||||
throw new Error('invalid Actor: id has different host');
|
throw new Error('invalid Actor: id has different host');
|
||||||
}
|
}
|
||||||
|
@ -189,7 +209,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
throw new Error('invalid Actor: publicKey.id is not a string');
|
throw new Error('invalid Actor: publicKey.id is not a string');
|
||||||
}
|
}
|
||||||
|
|
||||||
const publicKeyIdHost = this.punyHost(x.publicKey.id);
|
const publicKeyIdHost = this.utilityService.punyHost(x.publicKey.id);
|
||||||
if (publicKeyIdHost !== expectHost) {
|
if (publicKeyIdHost !== expectHost) {
|
||||||
throw new Error('invalid Actor: publicKey.id has different host');
|
throw new Error('invalid Actor: publicKey.id has different host');
|
||||||
}
|
}
|
||||||
|
@ -232,6 +252,12 @@ export class ApPersonService implements OnModuleInit {
|
||||||
if (user == null) throw new Error('failed to create user: user is null');
|
if (user == null) throw new Error('failed to create user: user is null');
|
||||||
|
|
||||||
const [avatar, banner] = await Promise.all([icon, image].map(img => {
|
const [avatar, banner] = await Promise.all([icon, image].map(img => {
|
||||||
|
// icon and image may be arrays
|
||||||
|
// see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-icon
|
||||||
|
if (Array.isArray(img)) {
|
||||||
|
img = img.find(item => item && item.url) ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
// if we have an explicitly missing image, return an
|
// if we have an explicitly missing image, return an
|
||||||
// explicitly-null set of values
|
// explicitly-null set of values
|
||||||
if ((img == null) || (typeof img === 'object' && img.url == null)) {
|
if ((img == null) || (typeof img === 'object' && img.url == null)) {
|
||||||
|
@ -274,7 +300,8 @@ export class ApPersonService implements OnModuleInit {
|
||||||
public async createPerson(uri: string, resolver?: Resolver): Promise<MiRemoteUser> {
|
public async createPerson(uri: string, resolver?: Resolver): Promise<MiRemoteUser> {
|
||||||
if (typeof uri !== 'string') throw new Error('uri is not string');
|
if (typeof uri !== 'string') throw new Error('uri is not string');
|
||||||
|
|
||||||
if (uri.startsWith(this.config.url)) {
|
const host = this.utilityService.punyHost(uri);
|
||||||
|
if (host === this.utilityService.toPuny(this.config.host)) {
|
||||||
throw new StatusError('cannot resolve local user', 400, 'cannot resolve local user');
|
throw new StatusError('cannot resolve local user', 400, 'cannot resolve local user');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,8 +315,6 @@ export class ApPersonService implements OnModuleInit {
|
||||||
|
|
||||||
this.logger.info(`Creating the Person: ${person.id}`);
|
this.logger.info(`Creating the Person: ${person.id}`);
|
||||||
|
|
||||||
const host = this.punyHost(object.id);
|
|
||||||
|
|
||||||
const fields = this.analyzeAttachments(person.attachment ?? []);
|
const fields = this.analyzeAttachments(person.attachment ?? []);
|
||||||
|
|
||||||
const tags = extractApHashtags(person.tag).map(normalizeForSearch).splice(0, 32);
|
const tags = extractApHashtags(person.tag).map(normalizeForSearch).splice(0, 32);
|
||||||
|
@ -315,10 +340,20 @@ export class ApPersonService implements OnModuleInit {
|
||||||
|
|
||||||
const url = getOneApHrefNullable(person.url);
|
const url = getOneApHrefNullable(person.url);
|
||||||
|
|
||||||
if (url && !checkHttps(url)) {
|
if (person.id == null) {
|
||||||
|
throw new Error('Refusing to create person without id');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url != null) {
|
||||||
|
if (!checkHttps(url)) {
|
||||||
throw new Error('unexpected schema of person url: ' + url);
|
throw new Error('unexpected schema of person url: ' + url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.utilityService.punyHost(url) !== this.utilityService.punyHost(person.id)) {
|
||||||
|
throw new Error(`person url <> uri host mismatch: ${url} <> ${person.id}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create user
|
// Create user
|
||||||
let user: MiRemoteUser | null = null;
|
let user: MiRemoteUser | null = null;
|
||||||
|
|
||||||
|
@ -349,7 +384,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
usernameLower: person.preferredUsername?.toLowerCase(),
|
usernameLower: person.preferredUsername?.toLowerCase(),
|
||||||
host,
|
host,
|
||||||
inbox: person.inbox,
|
inbox: person.inbox,
|
||||||
sharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox,
|
sharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox ?? null,
|
||||||
followersUri: person.followers ? getApId(person.followers) : undefined,
|
followersUri: person.followers ? getApId(person.followers) : undefined,
|
||||||
featured: person.featured ? getApId(person.featured) : undefined,
|
featured: person.featured ? getApId(person.featured) : undefined,
|
||||||
uri: person.id,
|
uri: person.id,
|
||||||
|
@ -459,7 +494,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
if (typeof uri !== 'string') throw new Error('uri is not string');
|
if (typeof uri !== 'string') throw new Error('uri is not string');
|
||||||
|
|
||||||
// URIがこのサーバーを指しているならスキップ
|
// URIがこのサーバーを指しているならスキップ
|
||||||
if (uri.startsWith(`${this.config.url}/`)) return;
|
if (this.utilityService.isUriLocal(uri)) return;
|
||||||
|
|
||||||
//#region このサーバーに既に登録されているか
|
//#region このサーバーに既に登録されているか
|
||||||
const exist = await this.fetchPerson(uri) as MiRemoteUser | null;
|
const exist = await this.fetchPerson(uri) as MiRemoteUser | null;
|
||||||
|
@ -508,14 +543,24 @@ export class ApPersonService implements OnModuleInit {
|
||||||
|
|
||||||
const url = getOneApHrefNullable(person.url);
|
const url = getOneApHrefNullable(person.url);
|
||||||
|
|
||||||
if (url && !checkHttps(url)) {
|
if (person.id == null) {
|
||||||
|
throw new Error('Refusing to update person without id');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url != null) {
|
||||||
|
if (!checkHttps(url)) {
|
||||||
throw new Error('unexpected schema of person url: ' + url);
|
throw new Error('unexpected schema of person url: ' + url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.utilityService.punyHost(url) !== this.utilityService.punyHost(person.id)) {
|
||||||
|
throw new Error(`person url <> uri host mismatch: ${url} <> ${person.id}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const updates = {
|
const updates = {
|
||||||
lastFetchedAt: new Date(),
|
lastFetchedAt: new Date(),
|
||||||
inbox: person.inbox,
|
inbox: person.inbox,
|
||||||
sharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox,
|
sharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox ?? null,
|
||||||
followersUri: person.followers ? getApId(person.followers) : undefined,
|
followersUri: person.followers ? getApId(person.followers) : undefined,
|
||||||
featured: person.featured,
|
featured: person.featured,
|
||||||
emojis: emojiNames,
|
emojis: emojiNames,
|
||||||
|
@ -587,7 +632,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
// 該当ユーザーが既にフォロワーになっていた場合はFollowingもアップデートする
|
// 該当ユーザーが既にフォロワーになっていた場合はFollowingもアップデートする
|
||||||
await this.followingsRepository.update(
|
await this.followingsRepository.update(
|
||||||
{ followerId: exist.id },
|
{ followerId: exist.id },
|
||||||
{ followerSharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox },
|
{ followerSharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox ?? null },
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.updateFeatured(exist.id, resolver).catch(err => this.logger.error(err));
|
await this.updateFeatured(exist.id, resolver).catch(err => this.logger.error(err));
|
||||||
|
@ -722,7 +767,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
await this.updatePerson(src.movedToUri, undefined, undefined, [...movePreventUris, src.uri]);
|
await this.updatePerson(src.movedToUri, undefined, undefined, [...movePreventUris, src.uri]);
|
||||||
dst = await this.fetchPerson(src.movedToUri) ?? dst;
|
dst = await this.fetchPerson(src.movedToUri) ?? dst;
|
||||||
} else {
|
} else {
|
||||||
if (src.movedToUri.startsWith(`${this.config.url}/`)) {
|
if (this.utilityService.isUriLocal(src.movedToUri)) {
|
||||||
// ローカルユーザーっぽいのにfetchPersonで見つからないということはmovedToUriが間違っている
|
// ローカルユーザーっぽいのにfetchPersonで見つからないということはmovedToUriが間違っている
|
||||||
return 'failed: movedTo is local but not found';
|
return 'failed: movedTo is local but not found';
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,16 +5,18 @@
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { NotesRepository, PollsRepository } from '@/models/_.js';
|
import type { UsersRepository, NotesRepository, PollsRepository } from '@/models/_.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import type { IPoll } from '@/models/Poll.js';
|
import type { IPoll } from '@/models/Poll.js';
|
||||||
|
import type { MiRemoteUser } from '@/models/User.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { isQuestion } from '../type.js';
|
import { getOneApId, isQuestion } from '../type.js';
|
||||||
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { ApLoggerService } from '../ApLoggerService.js';
|
import { ApLoggerService } from '../ApLoggerService.js';
|
||||||
import { ApResolverService } from '../ApResolverService.js';
|
import { ApResolverService } from '../ApResolverService.js';
|
||||||
import type { Resolver } from '../ApResolverService.js';
|
import type { Resolver } from '../ApResolverService.js';
|
||||||
import type { IObject, IQuestion } from '../type.js';
|
import type { IObject } from '../type.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApQuestionService {
|
export class ApQuestionService {
|
||||||
|
@ -24,6 +26,9 @@ export class ApQuestionService {
|
||||||
@Inject(DI.config)
|
@Inject(DI.config)
|
||||||
private config: Config,
|
private config: Config,
|
||||||
|
|
||||||
|
@Inject(DI.usersRepository)
|
||||||
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
@Inject(DI.notesRepository)
|
@Inject(DI.notesRepository)
|
||||||
private notesRepository: NotesRepository,
|
private notesRepository: NotesRepository,
|
||||||
|
|
||||||
|
@ -32,6 +37,7 @@ export class ApQuestionService {
|
||||||
|
|
||||||
private apResolverService: ApResolverService,
|
private apResolverService: ApResolverService,
|
||||||
private apLoggerService: ApLoggerService,
|
private apLoggerService: ApLoggerService,
|
||||||
|
private utilityService: UtilityService,
|
||||||
) {
|
) {
|
||||||
this.logger = this.apLoggerService.logger;
|
this.logger = this.apLoggerService.logger;
|
||||||
}
|
}
|
||||||
|
@ -65,12 +71,12 @@ export class ApQuestionService {
|
||||||
* @returns true if updated
|
* @returns true if updated
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public async updateQuestion(value: string | IObject, resolver?: Resolver): Promise<boolean> {
|
public async updateQuestion(value: string | IObject, actor?: MiRemoteUser, resolver?: Resolver): Promise<boolean> {
|
||||||
const uri = typeof value === 'string' ? value : value.id;
|
const uri = typeof value === 'string' ? value : value.id;
|
||||||
if (uri == null) throw new Error('uri is null');
|
if (uri == null) throw new Error('uri is null');
|
||||||
|
|
||||||
// URIがこのサーバーを指しているならスキップ
|
// URIがこのサーバーを指しているならスキップ
|
||||||
if (uri.startsWith(this.config.url + '/')) throw new Error('uri points local');
|
if (this.utilityService.isUriLocal(uri)) throw new Error('uri points local');
|
||||||
|
|
||||||
//#region このサーバーに既に登録されているか
|
//#region このサーバーに既に登録されているか
|
||||||
const note = await this.notesRepository.findOneBy({ uri });
|
const note = await this.notesRepository.findOneBy({ uri });
|
||||||
|
@ -78,15 +84,26 @@ export class ApQuestionService {
|
||||||
|
|
||||||
const poll = await this.pollsRepository.findOneBy({ noteId: note.id });
|
const poll = await this.pollsRepository.findOneBy({ noteId: note.id });
|
||||||
if (poll == null) throw new Error('Question is not registered');
|
if (poll == null) throw new Error('Question is not registered');
|
||||||
|
|
||||||
|
const user = await this.usersRepository.findOneBy({ id: poll.userId });
|
||||||
|
if (user == null) throw new Error('Question is not registered');
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
// resolve new Question object
|
// resolve new Question object
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
if (resolver == null) resolver = this.apResolverService.createResolver();
|
if (resolver == null) resolver = this.apResolverService.createResolver();
|
||||||
const question = await resolver.resolve(value) as IQuestion;
|
const question = await resolver.resolve(value);
|
||||||
this.logger.debug(`fetched question: ${JSON.stringify(question, null, 2)}`);
|
this.logger.debug(`fetched question: ${JSON.stringify(question, null, 2)}`);
|
||||||
|
|
||||||
if (question.type !== 'Question') throw new Error('object is not a Question');
|
if (!isQuestion(question)) throw new Error('object is not a Question');
|
||||||
|
|
||||||
|
const attribution = (question.attributedTo) ? getOneApId(question.attributedTo) : user.uri;
|
||||||
|
const attributionMatchesExisting = attribution === user.uri;
|
||||||
|
const actorMatchesAttribution = (actor) ? attribution === actor.uri : true;
|
||||||
|
|
||||||
|
if (!attributionMatchesExisting || !actorMatchesAttribution) {
|
||||||
|
throw new Error('Refusing to ingest update for poll by different user');
|
||||||
|
}
|
||||||
|
|
||||||
const apChoices = question.oneOf ?? question.anyOf;
|
const apChoices = question.oneOf ?? question.anyOf;
|
||||||
if (apChoices == null) throw new Error('invalid apChoices: ' + apChoices);
|
if (apChoices == null) throw new Error('invalid apChoices: ' + apChoices);
|
||||||
|
@ -96,7 +113,7 @@ export class ApQuestionService {
|
||||||
for (const choice of poll.choices) {
|
for (const choice of poll.choices) {
|
||||||
const oldCount = poll.votes[poll.choices.indexOf(choice)];
|
const oldCount = poll.votes[poll.choices.indexOf(choice)];
|
||||||
const newCount = apChoices.filter(ap => ap.name === choice).at(0)?.replies?.totalItems;
|
const newCount = apChoices.filter(ap => ap.name === choice).at(0)?.replies?.totalItems;
|
||||||
if (newCount == null) throw new Error('invalid newCount: ' + newCount);
|
if (newCount == null || !(Number.isInteger(newCount) && newCount >= 0)) throw new Error('invalid newCount: ' + newCount);
|
||||||
|
|
||||||
if (oldCount !== newCount) {
|
if (oldCount !== newCount) {
|
||||||
changed = true;
|
changed = true;
|
||||||
|
|
|
@ -4,5 +4,5 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function sqlLikeEscape(s: string) {
|
export function sqlLikeEscape(s: string) {
|
||||||
return s.replace(/([%_])/g, '\\$1');
|
return s.replace(/([\\%_])/g, '\\$1');
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typ
|
||||||
import { id } from './util/id.js';
|
import { id } from './util/id.js';
|
||||||
import { MiUser } from './User.js';
|
import { MiUser } from './User.js';
|
||||||
|
|
||||||
|
export type AbuseReportResolveType = 'accept' | 'reject';
|
||||||
|
|
||||||
@Entity('abuse_user_report')
|
@Entity('abuse_user_report')
|
||||||
export class MiAbuseUserReport {
|
export class MiAbuseUserReport {
|
||||||
@PrimaryColumn(id())
|
@PrimaryColumn(id())
|
||||||
|
@ -76,7 +78,7 @@ export class MiAbuseUserReport {
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 128, nullable: true,
|
length: 128, nullable: true,
|
||||||
})
|
})
|
||||||
public resolvedAs: 'accept' | 'reject' | null;
|
public resolvedAs: AbuseReportResolveType | null;
|
||||||
|
|
||||||
//#region Denormalized fields
|
//#region Denormalized fields
|
||||||
@Index()
|
@Index()
|
||||||
|
|
|
@ -190,6 +190,8 @@ export class InboxProcessorService implements OnApplicationShutdown {
|
||||||
if (signerHost !== activityIdHost) {
|
if (signerHost !== activityIdHost) {
|
||||||
throw new Bull.UnrecoverableError(`skip: signerHost(${signerHost}) !== activity.id host(${activityIdHost}`);
|
throw new Bull.UnrecoverableError(`skip: signerHost(${signerHost}) !== activity.id host(${activityIdHost}`);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
throw new Bull.UnrecoverableError('skip: activity id is not a string');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.apRequestChart.inbox();
|
this.apRequestChart.inbox();
|
||||||
|
|
|
@ -29,6 +29,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { IActivity } from '@/core/activitypub/type.js';
|
import { IActivity } from '@/core/activitypub/type.js';
|
||||||
import { isQuote, isRenote } from '@/misc/is-renote.js';
|
import { isQuote, isRenote } from '@/misc/is-renote.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';
|
||||||
|
|
||||||
|
@ -104,7 +105,7 @@ export class ActivityPubServerService {
|
||||||
let signature;
|
let signature;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
signature = httpSignature.parseRequest(request.raw, { 'headers': [] });
|
signature = httpSignature.parseRequest(request.raw, { 'headers': ['(request-target)', 'host', 'date'], authorizationHeaderName: 'signature' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
reply.code(401);
|
reply.code(401);
|
||||||
return;
|
return;
|
||||||
|
@ -486,6 +487,16 @@ export class ActivityPubServerService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// リモートだったらリダイレクト
|
||||||
|
if (user.host != null) {
|
||||||
|
if (user.uri == null || this.utilityService.isSelfHost(user.host)) {
|
||||||
|
reply.code(500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reply.redirect(user.uri, 301);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
reply.header('Cache-Control', 'public, max-age=180');
|
reply.header('Cache-Control', 'public, max-age=180');
|
||||||
this.setResponseType(request, reply);
|
this.setResponseType(request, reply);
|
||||||
return (this.apRendererService.addContext(await this.apRendererService.renderPerson(user as MiLocalUser)));
|
return (this.apRendererService.addContext(await this.apRendererService.renderPerson(user as MiLocalUser)));
|
||||||
|
@ -654,19 +665,20 @@ export class ActivityPubServerService {
|
||||||
|
|
||||||
const user = await this.usersRepository.findOneBy({
|
const user = await this.usersRepository.findOneBy({
|
||||||
id: userId,
|
id: userId,
|
||||||
host: IsNull(),
|
|
||||||
isSuspended: false,
|
isSuspended: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
return await this.userInfo(request, reply, user);
|
return await this.userInfo(request, reply, user);
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.get<{ Params: { user: string; } }>('/@:user', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
|
fastify.get<{ Params: { acct: string; } }>('/@:acct', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
|
||||||
vary(reply.raw, 'Accept');
|
vary(reply.raw, 'Accept');
|
||||||
|
|
||||||
|
const acct = Acct.parse(request.params.acct);
|
||||||
|
|
||||||
const user = await this.usersRepository.findOneBy({
|
const user = await this.usersRepository.findOneBy({
|
||||||
usernameLower: request.params.user.toLowerCase(),
|
usernameLower: acct.username,
|
||||||
host: IsNull(),
|
host: acct.host ?? IsNull(),
|
||||||
isSuspended: false,
|
isSuspended: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -187,6 +187,7 @@ import * as ep___following_invalidate from './endpoints/following/invalidate.js'
|
||||||
import * as ep___following_requests_accept from './endpoints/following/requests/accept.js';
|
import * as ep___following_requests_accept from './endpoints/following/requests/accept.js';
|
||||||
import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js';
|
import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js';
|
||||||
import * as ep___following_requests_list from './endpoints/following/requests/list.js';
|
import * as ep___following_requests_list from './endpoints/following/requests/list.js';
|
||||||
|
import * as ep___following_requests_sent from './endpoints/following/requests/sent.js';
|
||||||
import * as ep___following_requests_reject from './endpoints/following/requests/reject.js';
|
import * as ep___following_requests_reject from './endpoints/following/requests/reject.js';
|
||||||
import * as ep___gallery_featured from './endpoints/gallery/featured.js';
|
import * as ep___gallery_featured from './endpoints/gallery/featured.js';
|
||||||
import * as ep___gallery_popular from './endpoints/gallery/popular.js';
|
import * as ep___gallery_popular from './endpoints/gallery/popular.js';
|
||||||
|
@ -574,6 +575,7 @@ const $following_invalidate: Provider = { provide: 'ep:following/invalidate', us
|
||||||
const $following_requests_accept: Provider = { provide: 'ep:following/requests/accept', useClass: ep___following_requests_accept.default };
|
const $following_requests_accept: Provider = { provide: 'ep:following/requests/accept', useClass: ep___following_requests_accept.default };
|
||||||
const $following_requests_cancel: Provider = { provide: 'ep:following/requests/cancel', useClass: ep___following_requests_cancel.default };
|
const $following_requests_cancel: Provider = { provide: 'ep:following/requests/cancel', useClass: ep___following_requests_cancel.default };
|
||||||
const $following_requests_list: Provider = { provide: 'ep:following/requests/list', useClass: ep___following_requests_list.default };
|
const $following_requests_list: Provider = { provide: 'ep:following/requests/list', useClass: ep___following_requests_list.default };
|
||||||
|
const $following_requests_sent: Provider = { provide: 'ep:following/requests/sent', useClass: ep___following_requests_sent.default };
|
||||||
const $following_requests_reject: Provider = { provide: 'ep:following/requests/reject', useClass: ep___following_requests_reject.default };
|
const $following_requests_reject: Provider = { provide: 'ep:following/requests/reject', useClass: ep___following_requests_reject.default };
|
||||||
const $gallery_featured: Provider = { provide: 'ep:gallery/featured', useClass: ep___gallery_featured.default };
|
const $gallery_featured: Provider = { provide: 'ep:gallery/featured', useClass: ep___gallery_featured.default };
|
||||||
const $gallery_popular: Provider = { provide: 'ep:gallery/popular', useClass: ep___gallery_popular.default };
|
const $gallery_popular: Provider = { provide: 'ep:gallery/popular', useClass: ep___gallery_popular.default };
|
||||||
|
@ -965,6 +967,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
|
||||||
$following_requests_accept,
|
$following_requests_accept,
|
||||||
$following_requests_cancel,
|
$following_requests_cancel,
|
||||||
$following_requests_list,
|
$following_requests_list,
|
||||||
|
$following_requests_sent,
|
||||||
$following_requests_reject,
|
$following_requests_reject,
|
||||||
$gallery_featured,
|
$gallery_featured,
|
||||||
$gallery_popular,
|
$gallery_popular,
|
||||||
|
|
|
@ -193,6 +193,7 @@ import * as ep___following_invalidate from './endpoints/following/invalidate.js'
|
||||||
import * as ep___following_requests_accept from './endpoints/following/requests/accept.js';
|
import * as ep___following_requests_accept from './endpoints/following/requests/accept.js';
|
||||||
import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js';
|
import * as ep___following_requests_cancel from './endpoints/following/requests/cancel.js';
|
||||||
import * as ep___following_requests_list from './endpoints/following/requests/list.js';
|
import * as ep___following_requests_list from './endpoints/following/requests/list.js';
|
||||||
|
import * as ep___following_requests_sent from './endpoints/following/requests/sent.js';
|
||||||
import * as ep___following_requests_reject from './endpoints/following/requests/reject.js';
|
import * as ep___following_requests_reject from './endpoints/following/requests/reject.js';
|
||||||
import * as ep___gallery_featured from './endpoints/gallery/featured.js';
|
import * as ep___gallery_featured from './endpoints/gallery/featured.js';
|
||||||
import * as ep___gallery_popular from './endpoints/gallery/popular.js';
|
import * as ep___gallery_popular from './endpoints/gallery/popular.js';
|
||||||
|
@ -578,6 +579,7 @@ const eps = [
|
||||||
['following/requests/accept', ep___following_requests_accept],
|
['following/requests/accept', ep___following_requests_accept],
|
||||||
['following/requests/cancel', ep___following_requests_cancel],
|
['following/requests/cancel', ep___following_requests_cancel],
|
||||||
['following/requests/list', ep___following_requests_list],
|
['following/requests/list', ep___following_requests_list],
|
||||||
|
['following/requests/sent', ep___following_requests_sent],
|
||||||
['following/requests/reject', ep___following_requests_reject],
|
['following/requests/reject', ep___following_requests_reject],
|
||||||
['gallery/featured', ep___gallery_featured],
|
['gallery/featured', ep___gallery_featured],
|
||||||
['gallery/popular', ep___gallery_popular],
|
['gallery/popular', ep___gallery_popular],
|
||||||
|
|
|
@ -46,7 +46,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new Error('cannot delete a root account');
|
throw new Error('cannot delete a root account');
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.deleteAccoountService.deleteAccount(user);
|
await this.deleteAccoountService.deleteAccount(user, me);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ export const paramDef = {
|
||||||
properties: {
|
properties: {
|
||||||
title: { type: 'string', minLength: 1 },
|
title: { type: 'string', minLength: 1 },
|
||||||
text: { type: 'string', minLength: 1 },
|
text: { type: 'string', minLength: 1 },
|
||||||
imageUrl: { type: 'string', nullable: true, minLength: 1 },
|
imageUrl: { type: 'string', nullable: true, minLength: 0 },
|
||||||
icon: { type: 'string', enum: ['info', 'warning', 'error', 'success'], default: 'info' },
|
icon: { type: 'string', enum: ['info', 'warning', 'error', 'success'], default: 'info' },
|
||||||
display: { type: 'string', enum: ['normal', 'banner', 'dialog'], default: 'normal' },
|
display: { type: 'string', enum: ['normal', 'banner', 'dialog'], default: 'normal' },
|
||||||
forExistingUsers: { type: 'boolean', default: false },
|
forExistingUsers: { type: 'boolean', default: false },
|
||||||
|
@ -76,7 +76,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
updatedAt: null,
|
updatedAt: null,
|
||||||
title: ps.title,
|
title: ps.title,
|
||||||
text: ps.text,
|
text: ps.text,
|
||||||
imageUrl: ps.imageUrl,
|
/* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- 空の文字列の場合、nullを渡すようにするため */
|
||||||
|
imageUrl: ps.imageUrl || null,
|
||||||
icon: ps.icon,
|
icon: ps.icon,
|
||||||
display: ps.display,
|
display: ps.display,
|
||||||
forExistingUsers: ps.forExistingUsers,
|
forExistingUsers: ps.forExistingUsers,
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
||||||
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
@ -13,6 +14,49 @@ export const meta = {
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageAvatarDecorations',
|
requireRolePolicy: 'canManageAvatarDecorations',
|
||||||
kind: 'write:admin:avatar-decorations',
|
kind: 'write:admin:avatar-decorations',
|
||||||
|
|
||||||
|
res: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
format: 'id',
|
||||||
|
},
|
||||||
|
createdAt: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
format: 'date-time',
|
||||||
|
},
|
||||||
|
updatedAt: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
format: 'date-time',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
roleIdsThatCanBeUsedThisDecoration: {
|
||||||
|
type: 'array',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
format: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
@ -32,14 +76,25 @@ export const paramDef = {
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
constructor(
|
constructor(
|
||||||
private avatarDecorationService: AvatarDecorationService,
|
private avatarDecorationService: AvatarDecorationService,
|
||||||
|
private idService: IdService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
await this.avatarDecorationService.create({
|
const created = await this.avatarDecorationService.create({
|
||||||
name: ps.name,
|
name: ps.name,
|
||||||
description: ps.description,
|
description: ps.description,
|
||||||
url: ps.url,
|
url: ps.url,
|
||||||
roleIdsThatCanBeUsedThisDecoration: ps.roleIdsThatCanBeUsedThisDecoration,
|
roleIdsThatCanBeUsedThisDecoration: ps.roleIdsThatCanBeUsedThisDecoration,
|
||||||
}, me);
|
}, me);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: created.id,
|
||||||
|
createdAt: this.idService.parse(created.id).date.toISOString(),
|
||||||
|
updatedAt: null,
|
||||||
|
name: created.name,
|
||||||
|
description: created.description,
|
||||||
|
url: created.url,
|
||||||
|
roleIdsThatCanBeUsedThisDecoration: created.roleIdsThatCanBeUsedThisDecoration,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import type { AnnouncementsRepository, AnnouncementReadsRepository } from '@/models/_.js';
|
|
||||||
import type { MiAnnouncement } from '@/models/Announcement.js';
|
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { QueryService } from '@/core/QueryService.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
||||||
|
|
|
@ -33,13 +33,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
private deleteAccountService: DeleteAccountService,
|
private deleteAccountService: DeleteAccountService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const user = await this.usersRepository.findOneByOrFail({ id: ps.userId });
|
const user = await this.usersRepository.findOneByOrFail({ id: ps.userId });
|
||||||
if (user.isDeleted) {
|
if (user.isDeleted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.deleteAccountService.deleteAccount(user);
|
await this.deleteAccountService.deleteAccount(user, me);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { ApResolverService } from '@/core/activitypub/ApResolverService.js';
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['federation'],
|
tags: ['federation'],
|
||||||
|
|
||||||
|
requireAdmin: true,
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
kind: 'read:federation',
|
kind: 'read:federation',
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
]));
|
]));
|
||||||
if (local != null) return local;
|
if (local != null) return local;
|
||||||
|
|
||||||
|
const host = this.utilityService.extractDbHost(uri);
|
||||||
|
|
||||||
|
// local object, not found in db? fail
|
||||||
|
if (this.utilityService.isSelfHost(host)) return null;
|
||||||
|
|
||||||
// リモートから一旦オブジェクトフェッチ
|
// リモートから一旦オブジェクトフェッチ
|
||||||
const resolver = this.apResolverService.createResolver();
|
const resolver = this.apResolverService.createResolver();
|
||||||
const object = await resolver.resolve(uri) as any;
|
const object = await resolver.resolve(uri) as any;
|
||||||
|
@ -132,10 +137,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
if (local != null) return local;
|
if (local != null) return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 同一ユーザーの情報を再度処理するので、使用済みのresolverを再利用してはいけない
|
||||||
return await this.mergePack(
|
return await this.mergePack(
|
||||||
me,
|
me,
|
||||||
isActor(object) ? await this.apPersonService.createPerson(getApId(object)) : null,
|
isActor(object) ? await this.apPersonService.createPerson(getApId(object)) : null,
|
||||||
isPost(object) ? await this.apNoteService.createNote(getApId(object), undefined, true) : null,
|
isPost(object) ? await this.apNoteService.createNote(getApId(object), undefined, undefined, true) : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
|
import { QueryService } from '@/core/QueryService.js';
|
||||||
|
import type { FollowRequestsRepository } from '@/models/_.js';
|
||||||
|
import { FollowRequestEntityService } from '@/core/entities/FollowRequestEntityService.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['following', 'account'],
|
||||||
|
|
||||||
|
requireCredential: true,
|
||||||
|
|
||||||
|
kind: 'read:following',
|
||||||
|
|
||||||
|
res: {
|
||||||
|
type: 'array',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
format: 'id',
|
||||||
|
},
|
||||||
|
follower: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
ref: 'UserLite',
|
||||||
|
},
|
||||||
|
followee: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
ref: 'UserLite',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const paramDef = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
|
},
|
||||||
|
required: [],
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
|
constructor(
|
||||||
|
@Inject(DI.followRequestsRepository)
|
||||||
|
private followRequestsRepository: FollowRequestsRepository,
|
||||||
|
|
||||||
|
private followRequestEntityService: FollowRequestEntityService,
|
||||||
|
private queryService: QueryService,
|
||||||
|
) {
|
||||||
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
const query = this.queryService.makePaginationQuery(this.followRequestsRepository.createQueryBuilder('request'), ps.sinceId, ps.untilId)
|
||||||
|
.andWhere('request.followerId = :meId', { meId: me.id });
|
||||||
|
|
||||||
|
const requests = await query
|
||||||
|
.limit(ps.limit)
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
return await this.followRequestEntityService.packMany(requests, me);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -465,6 +465,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
const newName = updates.name === undefined ? user.name : updates.name;
|
const newName = updates.name === undefined ? user.name : updates.name;
|
||||||
const newDescription = profileUpdates.description === undefined ? profile.description : profileUpdates.description;
|
const newDescription = profileUpdates.description === undefined ? profile.description : profileUpdates.description;
|
||||||
const newFields = profileUpdates.fields === undefined ? profile.fields : profileUpdates.fields;
|
const newFields = profileUpdates.fields === undefined ? profile.fields : profileUpdates.fields;
|
||||||
|
const newFollowedMessage = profileUpdates.followedMessage === undefined ? profile.followedMessage : profileUpdates.followedMessage;
|
||||||
|
|
||||||
if (newName != null) {
|
if (newName != null) {
|
||||||
let hasProhibitedWords = false;
|
let hasProhibitedWords = false;
|
||||||
|
@ -494,6 +495,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newFollowedMessage != null) {
|
||||||
|
const tokens = mfm.parse(newFollowedMessage);
|
||||||
|
emojis = emojis.concat(extractCustomEmojisFromMfm(tokens));
|
||||||
|
}
|
||||||
|
|
||||||
updates.emojis = emojis;
|
updates.emojis = emojis;
|
||||||
updates.tags = tags;
|
updates.tags = tags;
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
const policies = await this.roleService.getUserPolicies(me.id);
|
const policies = await this.roleService.getUserPolicies(me.id);
|
||||||
|
|
||||||
const count = policies.inviteLimit ? await this.registrationTicketsRepository.countBy({
|
const count = policies.inviteLimit ? await this.registrationTicketsRepository.countBy({
|
||||||
id: MoreThan(this.idService.gen(Date.now() - (policies.inviteExpirationTime * 60 * 1000))),
|
id: MoreThan(this.idService.gen(Date.now() - (policies.inviteLimitCycle * 60 * 1000))),
|
||||||
createdById: me.id,
|
createdById: me.id,
|
||||||
}) : null;
|
}) : null;
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
this.activeUsersChart.read(me);
|
this.activeUsersChart.read(me);
|
||||||
|
|
||||||
await this.noteEntityService.packMany(timeline, me);
|
return await this.noteEntityService.packMany(timeline, me);
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeline = await this.fanoutTimelineEndpointService.timeline({
|
const timeline = await this.fanoutTimelineEndpointService.timeline({
|
||||||
|
|
|
@ -42,13 +42,26 @@ import { MetaEntityService } from '@/core/entities/MetaEntityService.js';
|
||||||
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
||||||
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
|
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
|
||||||
import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
|
import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
|
||||||
import type { ChannelsRepository, ClipsRepository, FlashsRepository, GalleryPostsRepository, MiMeta, NotesRepository, PagesRepository, ReversiGamesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
import type {
|
||||||
|
AnnouncementsRepository,
|
||||||
|
ChannelsRepository,
|
||||||
|
ClipsRepository,
|
||||||
|
FlashsRepository,
|
||||||
|
GalleryPostsRepository,
|
||||||
|
MiMeta,
|
||||||
|
NotesRepository,
|
||||||
|
PagesRepository,
|
||||||
|
ReversiGamesRepository,
|
||||||
|
UserProfilesRepository,
|
||||||
|
UsersRepository,
|
||||||
|
} from '@/models/_.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { handleRequestRedirectToOmitSearch } from '@/misc/fastify-hook-handlers.js';
|
import { handleRequestRedirectToOmitSearch } from '@/misc/fastify-hook-handlers.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { FlashEntityService } from '@/core/entities/FlashEntityService.js';
|
import { FlashEntityService } from '@/core/entities/FlashEntityService.js';
|
||||||
import { RoleService } from '@/core/RoleService.js';
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
import { ReversiGameEntityService } from '@/core/entities/ReversiGameEntityService.js';
|
import { ReversiGameEntityService } from '@/core/entities/ReversiGameEntityService.js';
|
||||||
|
import { AnnouncementEntityService } from '@/core/entities/AnnouncementEntityService.js';
|
||||||
import { FeedService } from './FeedService.js';
|
import { FeedService } from './FeedService.js';
|
||||||
import { UrlPreviewService } from './UrlPreviewService.js';
|
import { UrlPreviewService } from './UrlPreviewService.js';
|
||||||
import { ClientLoggerService } from './ClientLoggerService.js';
|
import { ClientLoggerService } from './ClientLoggerService.js';
|
||||||
|
@ -103,6 +116,9 @@ export class ClientServerService {
|
||||||
@Inject(DI.reversiGamesRepository)
|
@Inject(DI.reversiGamesRepository)
|
||||||
private reversiGamesRepository: ReversiGamesRepository,
|
private reversiGamesRepository: ReversiGamesRepository,
|
||||||
|
|
||||||
|
@Inject(DI.announcementsRepository)
|
||||||
|
private announcementsRepository: AnnouncementsRepository,
|
||||||
|
|
||||||
private flashEntityService: FlashEntityService,
|
private flashEntityService: FlashEntityService,
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
|
@ -112,6 +128,7 @@ export class ClientServerService {
|
||||||
private clipEntityService: ClipEntityService,
|
private clipEntityService: ClipEntityService,
|
||||||
private channelEntityService: ChannelEntityService,
|
private channelEntityService: ChannelEntityService,
|
||||||
private reversiGameEntityService: ReversiGameEntityService,
|
private reversiGameEntityService: ReversiGameEntityService,
|
||||||
|
private announcementEntityService: AnnouncementEntityService,
|
||||||
private urlPreviewService: UrlPreviewService,
|
private urlPreviewService: UrlPreviewService,
|
||||||
private feedService: FeedService,
|
private feedService: FeedService,
|
||||||
private roleService: RoleService,
|
private roleService: RoleService,
|
||||||
|
@ -542,7 +559,7 @@ export class ClientServerService {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//#region SSR (for crawlers)
|
//#region SSR
|
||||||
// User
|
// User
|
||||||
fastify.get<{ Params: { user: string; sub?: string; } }>('/@:user/:sub?', async (request, reply) => {
|
fastify.get<{ Params: { user: string; sub?: string; } }>('/@:user/:sub?', async (request, reply) => {
|
||||||
const { username, host } = Acct.parse(request.params.user);
|
const { username, host } = Acct.parse(request.params.user);
|
||||||
|
@ -567,11 +584,17 @@ export class ClientServerService {
|
||||||
reply.header('X-Robots-Tag', 'noimageai');
|
reply.header('X-Robots-Tag', 'noimageai');
|
||||||
reply.header('X-Robots-Tag', 'noai');
|
reply.header('X-Robots-Tag', 'noai');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _user = await this.userEntityService.pack(user);
|
||||||
|
|
||||||
return await reply.view('user', {
|
return await reply.view('user', {
|
||||||
user, profile, me,
|
user, profile, me,
|
||||||
avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user),
|
avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user),
|
||||||
sub: request.params.sub,
|
sub: request.params.sub,
|
||||||
...await this.generateCommonPugData(this.meta),
|
...await this.generateCommonPugData(this.meta),
|
||||||
|
clientCtx: htmlSafeJsonStringify({
|
||||||
|
user: _user,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// リモートユーザーなので
|
// リモートユーザーなので
|
||||||
|
@ -624,6 +647,9 @@ export class ClientServerService {
|
||||||
// TODO: Let locale changeable by instance setting
|
// TODO: Let locale changeable by instance setting
|
||||||
summary: getNoteSummary(_note),
|
summary: getNoteSummary(_note),
|
||||||
...await this.generateCommonPugData(this.meta),
|
...await this.generateCommonPugData(this.meta),
|
||||||
|
clientCtx: htmlSafeJsonStringify({
|
||||||
|
note: _note,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -712,6 +738,9 @@ export class ClientServerService {
|
||||||
profile,
|
profile,
|
||||||
avatarUrl: _clip.user.avatarUrl,
|
avatarUrl: _clip.user.avatarUrl,
|
||||||
...await this.generateCommonPugData(this.meta),
|
...await this.generateCommonPugData(this.meta),
|
||||||
|
clientCtx: htmlSafeJsonStringify({
|
||||||
|
clip: _clip,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -776,6 +805,24 @@ export class ClientServerService {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 個別お知らせページ
|
||||||
|
fastify.get<{ Params: { announcementId: string; } }>('/announcements/:announcementId', async (request, reply) => {
|
||||||
|
const announcement = await this.announcementsRepository.findOneBy({
|
||||||
|
id: request.params.announcementId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (announcement) {
|
||||||
|
const _announcement = await this.announcementEntityService.pack(announcement);
|
||||||
|
reply.header('Cache-Control', 'public, max-age=3600');
|
||||||
|
return await reply.view('announcement', {
|
||||||
|
announcement: _announcement,
|
||||||
|
...await this.generateCommonPugData(this.meta),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return await renderBase(reply);
|
||||||
|
}
|
||||||
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region noindex pages
|
//#region noindex pages
|
||||||
|
|
|
@ -145,6 +145,6 @@ export class UrlPreviewService {
|
||||||
contentLengthRequired: meta.urlPreviewRequireContentLength,
|
contentLengthRequired: meta.urlPreviewRequireContentLength,
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.httpRequestService.getJson<SummalyResult>(`${proxy}?${queryStr}`);
|
return this.httpRequestService.getJson<SummalyResult>(`${proxy}?${queryStr}`, 'application/json, */*', undefined, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
21
packages/backend/src/server/web/views/announcement.pug
Normal file
21
packages/backend/src/server/web/views/announcement.pug
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
extends ./base
|
||||||
|
|
||||||
|
block vars
|
||||||
|
- const title = announcement.title;
|
||||||
|
- const description = announcement.text.length > 100 ? announcement.text.slice(0, 100) + '…' : announcement.text;
|
||||||
|
- const url = `${config.url}/announcements/${announcement.id}`;
|
||||||
|
|
||||||
|
block title
|
||||||
|
= `${title} | ${instanceName}`
|
||||||
|
|
||||||
|
block desc
|
||||||
|
meta(name='description' content=description)
|
||||||
|
|
||||||
|
block og
|
||||||
|
meta(property='og:type' content='article')
|
||||||
|
meta(property='og:title' content= title)
|
||||||
|
meta(property='og:description' content= description)
|
||||||
|
meta(property='og:url' content= url)
|
||||||
|
if announcement.imageUrl
|
||||||
|
meta(property='og:image' content=announcement.imageUrl)
|
||||||
|
meta(property='twitter:card' content='summary_large_image')
|
|
@ -2,6 +2,7 @@ block vars
|
||||||
|
|
||||||
block loadClientEntry
|
block loadClientEntry
|
||||||
- const entry = config.frontendEntry;
|
- const entry = config.frontendEntry;
|
||||||
|
- const baseUrl = config.url;
|
||||||
|
|
||||||
doctype html
|
doctype html
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ html
|
||||||
link(rel='icon' href= icon || '/favicon.ico')
|
link(rel='icon' href= icon || '/favicon.ico')
|
||||||
link(rel='apple-touch-icon' href= appleTouchIcon || '/apple-touch-icon.png')
|
link(rel='apple-touch-icon' href= appleTouchIcon || '/apple-touch-icon.png')
|
||||||
link(rel='manifest' href='/manifest.json')
|
link(rel='manifest' href='/manifest.json')
|
||||||
link(rel='search' type='application/opensearchdescription+xml' title=(title || "Misskey") href=`${url}/opensearch.xml`)
|
link(rel='search' type='application/opensearchdescription+xml' title=(title || "Misskey") href=`${baseUrl}/opensearch.xml`)
|
||||||
link(rel='prefetch' href=serverErrorImageUrl)
|
link(rel='prefetch' href=serverErrorImageUrl)
|
||||||
link(rel='prefetch' href=infoImageUrl)
|
link(rel='prefetch' href=infoImageUrl)
|
||||||
link(rel='prefetch' href=notFoundImageUrl)
|
link(rel='prefetch' href=notFoundImageUrl)
|
||||||
|
@ -73,6 +74,9 @@ html
|
||||||
script(type='application/json' id='misskey_meta' data-generated-at=now)
|
script(type='application/json' id='misskey_meta' data-generated-at=now)
|
||||||
!= metaJson
|
!= metaJson
|
||||||
|
|
||||||
|
script(type='application/json' id='misskey_clientCtx' data-generated-at=now)
|
||||||
|
!= clientCtx
|
||||||
|
|
||||||
script
|
script
|
||||||
include ../boot.js
|
include ../boot.js
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ proxyBypassHosts:
|
||||||
- challenges.cloudflare.com
|
- challenges.cloudflare.com
|
||||||
proxyRemoteFiles: true
|
proxyRemoteFiles: true
|
||||||
signToActivityPubGet: true
|
signToActivityPubGet: true
|
||||||
allowedPrivateNetworks: [
|
allowedPrivateNetworks:
|
||||||
'127.0.0.1/32',
|
- 127.0.0.1/32
|
||||||
'172.20.0.0/16'
|
- 172.20.0.0/16
|
||||||
]
|
|
||||||
|
|
|
@ -232,7 +232,6 @@ export async function isFired<C extends keyof Misskey.Channels, T extends keyof
|
||||||
params?: Misskey.Channels[C]['params'],
|
params?: Misskey.Channels[C]['params'],
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
return new Promise<boolean>(async (resolve, reject) => {
|
return new Promise<boolean>(async (resolve, reject) => {
|
||||||
// @ts-expect-error TODO: why?
|
|
||||||
const stream = new Misskey.Stream(`wss://${host}`, { token: user.i }, { WebSocket });
|
const stream = new Misskey.Stream(`wss://${host}`, { token: user.i }, { WebSocket });
|
||||||
const connection = stream.useChannel(channel, params);
|
const connection = stream.useChannel(channel, params);
|
||||||
connection.on(type as any, ((msg: any) => {
|
connection.on(type as any, ((msg: any) => {
|
||||||
|
@ -266,7 +265,6 @@ export async function isNoteUpdatedEventFired(
|
||||||
cond: (msg: Parameters<Misskey.StreamEvents['noteUpdated']>[0]) => boolean,
|
cond: (msg: Parameters<Misskey.StreamEvents['noteUpdated']>[0]) => boolean,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
return new Promise<boolean>(async (resolve, reject) => {
|
return new Promise<boolean>(async (resolve, reject) => {
|
||||||
// @ts-expect-error TODO: why?
|
|
||||||
const stream = new Misskey.Stream(`wss://${host}`, { token: user.i }, { WebSocket });
|
const stream = new Misskey.Stream(`wss://${host}`, { token: user.i }, { WebSocket });
|
||||||
stream.send('s', { id: noteId });
|
stream.send('s', { id: noteId });
|
||||||
stream.on('noteUpdated', msg => {
|
stream.on('noteUpdated', msg => {
|
||||||
|
|
|
@ -230,6 +230,7 @@ describe('Webリソース', () => {
|
||||||
path: path('xxxxxxxxxx'),
|
path: path('xxxxxxxxxx'),
|
||||||
type: HTML,
|
type: HTML,
|
||||||
}));
|
}));
|
||||||
|
test.todo('HTMLとしてGETできる。(リモートユーザーでもリダイレクトせず)');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe.each([
|
describe.each([
|
||||||
|
@ -249,6 +250,7 @@ describe('Webリソース', () => {
|
||||||
path: path('xxxxxxxxxx'),
|
path: path('xxxxxxxxxx'),
|
||||||
accept,
|
accept,
|
||||||
}));
|
}));
|
||||||
|
test.todo('はオリジナルにリダイレクトされる。(リモートユーザー)');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { beforeAll, describe, jest } from '@jest/globals';
|
import { beforeAll, describe, jest } from '@jest/globals';
|
||||||
import { WebhookTestService } from '@/core/WebhookTestService.js';
|
import { WebhookTestService } from '@/core/WebhookTestService.js';
|
||||||
import { UserWebhookService } from '@/core/UserWebhookService.js';
|
import { UserWebhookPayload, UserWebhookService } from '@/core/UserWebhookService.js';
|
||||||
import { SystemWebhookService } from '@/core/SystemWebhookService.js';
|
import { SystemWebhookService } from '@/core/SystemWebhookService.js';
|
||||||
import { GlobalModule } from '@/GlobalModule.js';
|
import { GlobalModule } from '@/GlobalModule.js';
|
||||||
import { MiSystemWebhook, MiUser, MiWebhook, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
import { MiSystemWebhook, MiUser, MiWebhook, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
||||||
|
@ -122,7 +122,7 @@ describe('WebhookTestService', () => {
|
||||||
const calls = queueService.userWebhookDeliver.mock.calls[0];
|
const calls = queueService.userWebhookDeliver.mock.calls[0];
|
||||||
expect((calls[0] as any).id).toBe('dummy-webhook');
|
expect((calls[0] as any).id).toBe('dummy-webhook');
|
||||||
expect(calls[1]).toBe('note');
|
expect(calls[1]).toBe('note');
|
||||||
expect((calls[2] as any).id).toBe('dummy-note-1');
|
expect((calls[2] as UserWebhookPayload<'note'>).note.id).toBe('dummy-note-1');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('reply', async () => {
|
test('reply', async () => {
|
||||||
|
@ -131,7 +131,7 @@ describe('WebhookTestService', () => {
|
||||||
const calls = queueService.userWebhookDeliver.mock.calls[0];
|
const calls = queueService.userWebhookDeliver.mock.calls[0];
|
||||||
expect((calls[0] as any).id).toBe('dummy-webhook');
|
expect((calls[0] as any).id).toBe('dummy-webhook');
|
||||||
expect(calls[1]).toBe('reply');
|
expect(calls[1]).toBe('reply');
|
||||||
expect((calls[2] as any).id).toBe('dummy-reply-1');
|
expect((calls[2] as UserWebhookPayload<'reply'>).note.id).toBe('dummy-reply-1');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('renote', async () => {
|
test('renote', async () => {
|
||||||
|
@ -140,7 +140,7 @@ describe('WebhookTestService', () => {
|
||||||
const calls = queueService.userWebhookDeliver.mock.calls[0];
|
const calls = queueService.userWebhookDeliver.mock.calls[0];
|
||||||
expect((calls[0] as any).id).toBe('dummy-webhook');
|
expect((calls[0] as any).id).toBe('dummy-webhook');
|
||||||
expect(calls[1]).toBe('renote');
|
expect(calls[1]).toBe('renote');
|
||||||
expect((calls[2] as any).id).toBe('dummy-renote-1');
|
expect((calls[2] as UserWebhookPayload<'renote'>).note.id).toBe('dummy-renote-1');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('mention', async () => {
|
test('mention', async () => {
|
||||||
|
@ -149,7 +149,7 @@ describe('WebhookTestService', () => {
|
||||||
const calls = queueService.userWebhookDeliver.mock.calls[0];
|
const calls = queueService.userWebhookDeliver.mock.calls[0];
|
||||||
expect((calls[0] as any).id).toBe('dummy-webhook');
|
expect((calls[0] as any).id).toBe('dummy-webhook');
|
||||||
expect(calls[1]).toBe('mention');
|
expect(calls[1]).toBe('mention');
|
||||||
expect((calls[2] as any).id).toBe('dummy-mention-1');
|
expect((calls[2] as UserWebhookPayload<'mention'>).note.id).toBe('dummy-mention-1');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('follow', async () => {
|
test('follow', async () => {
|
||||||
|
@ -158,7 +158,7 @@ describe('WebhookTestService', () => {
|
||||||
const calls = queueService.userWebhookDeliver.mock.calls[0];
|
const calls = queueService.userWebhookDeliver.mock.calls[0];
|
||||||
expect((calls[0] as any).id).toBe('dummy-webhook');
|
expect((calls[0] as any).id).toBe('dummy-webhook');
|
||||||
expect(calls[1]).toBe('follow');
|
expect(calls[1]).toBe('follow');
|
||||||
expect((calls[2] as any).id).toBe('dummy-user-1');
|
expect((calls[2] as UserWebhookPayload<'follow'>).user.id).toBe('dummy-user-1');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('followed', async () => {
|
test('followed', async () => {
|
||||||
|
@ -167,7 +167,7 @@ describe('WebhookTestService', () => {
|
||||||
const calls = queueService.userWebhookDeliver.mock.calls[0];
|
const calls = queueService.userWebhookDeliver.mock.calls[0];
|
||||||
expect((calls[0] as any).id).toBe('dummy-webhook');
|
expect((calls[0] as any).id).toBe('dummy-webhook');
|
||||||
expect(calls[1]).toBe('followed');
|
expect(calls[1]).toBe('followed');
|
||||||
expect((calls[2] as any).id).toBe('dummy-user-2');
|
expect((calls[2] as UserWebhookPayload<'followed'>).user.id).toBe('dummy-user-2');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('unfollow', async () => {
|
test('unfollow', async () => {
|
||||||
|
@ -176,7 +176,7 @@ describe('WebhookTestService', () => {
|
||||||
const calls = queueService.userWebhookDeliver.mock.calls[0];
|
const calls = queueService.userWebhookDeliver.mock.calls[0];
|
||||||
expect((calls[0] as any).id).toBe('dummy-webhook');
|
expect((calls[0] as any).id).toBe('dummy-webhook');
|
||||||
expect(calls[1]).toBe('unfollow');
|
expect(calls[1]).toBe('unfollow');
|
||||||
expect((calls[2] as any).id).toBe('dummy-user-3');
|
expect((calls[2] as UserWebhookPayload<'unfollow'>).user.id).toBe('dummy-user-3');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('NoSuchWebhookError', () => {
|
describe('NoSuchWebhookError', () => {
|
||||||
|
|
|
@ -176,7 +176,7 @@ describe('ActivityPub', () => {
|
||||||
resolver.register(actor.id, actor);
|
resolver.register(actor.id, actor);
|
||||||
resolver.register(post.id, post);
|
resolver.register(post.id, post);
|
||||||
|
|
||||||
const note = await noteService.createNote(post.id, resolver, true);
|
const note = await noteService.createNote(post.id, undefined, resolver, true);
|
||||||
|
|
||||||
assert.deepStrictEqual(note?.uri, post.id);
|
assert.deepStrictEqual(note?.uri, post.id);
|
||||||
assert.deepStrictEqual(note.visibility, 'public');
|
assert.deepStrictEqual(note.visibility, 'public');
|
||||||
|
@ -336,7 +336,7 @@ describe('ActivityPub', () => {
|
||||||
resolver.register(actor.featured, featured);
|
resolver.register(actor.featured, featured);
|
||||||
resolver.register(firstNote.id, firstNote);
|
resolver.register(firstNote.id, firstNote);
|
||||||
|
|
||||||
const note = await noteService.createNote(firstNote.id as string, resolver);
|
const note = await noteService.createNote(firstNote.id as string, undefined, resolver);
|
||||||
assert.strictEqual(note?.uri, firstNote.id);
|
assert.strictEqual(note?.uri, firstNote.id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,11 +14,11 @@
|
||||||
"@discordapp/twemoji": "15.1.0",
|
"@discordapp/twemoji": "15.1.0",
|
||||||
"@rollup/plugin-json": "6.1.0",
|
"@rollup/plugin-json": "6.1.0",
|
||||||
"@rollup/plugin-replace": "5.0.7",
|
"@rollup/plugin-replace": "5.0.7",
|
||||||
"@rollup/pluginutils": "5.1.2",
|
"@rollup/pluginutils": "5.1.3",
|
||||||
"@tabler/icons-webfont": "3.3.0",
|
"@tabler/icons-webfont": "3.3.0",
|
||||||
"@twemoji/parser": "15.1.1",
|
"@twemoji/parser": "15.1.1",
|
||||||
"@vitejs/plugin-vue": "5.1.4",
|
"@vitejs/plugin-vue": "5.2.0",
|
||||||
"@vue/compiler-sfc": "3.5.11",
|
"@vue/compiler-sfc": "3.5.12",
|
||||||
"astring": "1.9.0",
|
"astring": "1.9.0",
|
||||||
"buraha": "0.0.1",
|
"buraha": "0.0.1",
|
||||||
"estree-walker": "3.0.3",
|
"estree-walker": "3.0.3",
|
||||||
|
@ -26,47 +26,47 @@
|
||||||
"misskey-js": "workspace:*",
|
"misskey-js": "workspace:*",
|
||||||
"frontend-shared": "workspace:*",
|
"frontend-shared": "workspace:*",
|
||||||
"punycode": "2.3.1",
|
"punycode": "2.3.1",
|
||||||
"rollup": "4.22.5",
|
"rollup": "4.26.0",
|
||||||
"sass": "1.79.4",
|
"sass": "1.79.4",
|
||||||
"shiki": "1.21.0",
|
"shiki": "1.22.2",
|
||||||
"tinycolor2": "1.6.0",
|
"tinycolor2": "1.6.0",
|
||||||
"tsc-alias": "1.8.10",
|
"tsc-alias": "1.8.10",
|
||||||
"tsconfig-paths": "4.2.0",
|
"tsconfig-paths": "4.2.0",
|
||||||
"typescript": "5.6.2",
|
"typescript": "5.6.3",
|
||||||
"uuid": "10.0.0",
|
"uuid": "10.0.0",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"vite": "5.4.8",
|
"vite": "5.4.11",
|
||||||
"vue": "3.5.11"
|
"vue": "3.5.12"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@misskey-dev/summaly": "5.1.0",
|
"@misskey-dev/summaly": "5.1.0",
|
||||||
"@testing-library/vue": "8.1.0",
|
"@testing-library/vue": "8.1.0",
|
||||||
"@types/estree": "1.0.6",
|
"@types/estree": "1.0.6",
|
||||||
"@types/micromatch": "4.0.9",
|
"@types/micromatch": "4.0.9",
|
||||||
"@types/node": "20.14.12",
|
"@types/node": "22.9.0",
|
||||||
"@types/punycode": "2.1.4",
|
"@types/punycode": "2.1.4",
|
||||||
"@types/tinycolor2": "1.4.6",
|
"@types/tinycolor2": "1.4.6",
|
||||||
"@types/uuid": "10.0.0",
|
"@types/uuid": "10.0.0",
|
||||||
"@types/ws": "8.5.12",
|
"@types/ws": "8.5.13",
|
||||||
"@typescript-eslint/eslint-plugin": "7.17.0",
|
"@typescript-eslint/eslint-plugin": "7.17.0",
|
||||||
"@typescript-eslint/parser": "7.17.0",
|
"@typescript-eslint/parser": "7.17.0",
|
||||||
"@vitest/coverage-v8": "1.6.0",
|
"@vitest/coverage-v8": "1.6.0",
|
||||||
"@vue/runtime-core": "3.5.11",
|
"@vue/runtime-core": "3.5.12",
|
||||||
"acorn": "8.12.1",
|
"acorn": "8.14.0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"eslint-plugin-import": "2.31.0",
|
"eslint-plugin-import": "2.31.0",
|
||||||
"eslint-plugin-vue": "9.28.0",
|
"eslint-plugin-vue": "9.31.0",
|
||||||
"fast-glob": "3.3.2",
|
"fast-glob": "3.3.2",
|
||||||
"happy-dom": "10.0.3",
|
"happy-dom": "10.0.3",
|
||||||
"intersection-observer": "0.12.2",
|
"intersection-observer": "0.12.2",
|
||||||
"micromatch": "4.0.8",
|
"micromatch": "4.0.8",
|
||||||
"msw": "2.3.4",
|
"msw": "2.6.4",
|
||||||
"nodemon": "3.1.7",
|
"nodemon": "3.1.7",
|
||||||
"prettier": "3.3.3",
|
"prettier": "3.3.3",
|
||||||
"start-server-and-test": "2.0.8",
|
"start-server-and-test": "2.0.8",
|
||||||
"vite-plugin-turbosnap": "1.0.3",
|
"vite-plugin-turbosnap": "1.0.3",
|
||||||
"vue-component-type-helpers": "2.1.6",
|
"vue-component-type-helpers": "2.1.10",
|
||||||
"vue-eslint-parser": "9.4.3",
|
"vue-eslint-parser": "9.4.3",
|
||||||
"vue-tsc": "2.1.6"
|
"vue-tsc": "2.1.10"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue